Developer Tip

In System Preferences > Sound > Sound Effects, users have the choice to turn off user interface sound effects (as an example, that might be a “tick” sound when adjusting a slider, or a “lock/unlock” sound when clicking a Lock button).

But how do you respect that setting? NSSound surely doesn’t.
Well, I found two ways to do it:

The “Easy” Way

macOS has a key in the standard UserDefaults object

com.apple.sound.uiaudio.enabled

If it is present and set to true, it’s safe to play the ui sound.

The “Safe” Way

What if the UserDefaults key isn’t present? Or you just want to be absolutely certain that your sound respects the user’s setting?

Use the AudioToolbox APIs. It offers

AudioServicesSetProperty(kAudioServicesPropertyIsUISound,...)

which marks sounds as UI sounds, thus not playing if the user wishes them not to.

It’s a bit more work, but might be the safer way to do it.

Read more

In an effort to support macOS Monterey’s new Shortcuts in Transloader‘s Link– and File Actions, I decided to run all the necessary CLI commands and AppleScripts in an external XPC service, mostly to separate privileges (running Apple Scripts (which aren’t precompiled and reside in the Application Scripts folder) in a sandboxed Mac app requires specific sandbox entitlements, which Transloader itself just doesn’t need).

I didn’t start with an XPC service, though. For testing and debugging purposes, I began with a new app in Xcode and ran all the Apple Scripts from there, which, after a bit of tweaking because I’m not “fluent” in Apple Script, worked just fine.

After subsequently moving them into an XPC service and thinking it would “just work”, I found that it didn’t. At least not reliably. Maybe every 8th or 9th time, yes, it did all it was asked to do, but every other time, it outright refused to execute Apple Scripts.

After two days of desperate attempts to get it working correctly, and almost giving up on the XPC privilege separation entirely for this, I figured I’d check to see if the Apple Scripts were being executed on the main thread.
I did recall reading quite some time ago (I don’t know where, sorry) that Apple Scripts on background threads are iffy in their execution. Lo and behold, the methods weren’t run on the main thread. One quick dispatch_async to the main queue later, and everything worked as I expected it to.

So, the takeaway of all this, and the TLDR, is this post’s title: An XPC service’s methods aren’t necessarily run on the main thread. Go figure.

Addendum

If you’re wondering what my configuration for the XPC service is:

RunLoop = NSRunLoop
ServiceType = Application

I did try dispatch_main as RunLoop as well, which worked too, but I just figured, for Apple Scripts, NSRunLoop would be required, but I don’t know for sure.

Read more

Since I’ve had to go re-watch WWDC20’s “Adopt the New Look of macOS” session (at around the 07:03 mark), I thought I’d note it down here – for anyone else late to the update-for-macOS-Big-Sur-game 😉

What we want to achieve is go from this UI (basically standard on any macOS before Big Sur):

Screenshot of Yoink's preferences on macOS Catalina and earlier

to this UI (new UI for Preferences windows on macOS Big Sur):

Screenshot of Yoink's Preferences on macOS Big Sur

And it’s fairly easy to do so. All you need to call is (pardon the Objective-C, Yoink for Mac (and iPad and iPhone, for that matter), is still 100% Swift-free..)

self.window.toolbarStyle = NSWindowToolbarStylePreference;

and update your toolbar items’ icons, and you’re all set.

Screenshot of Xcode  24 09 2020 08 48 22

 

 

– Matthias
mail | website | twitter | instagram | facebook

Read more