How can I reload the com.apple.systemuiserver preferences into the SystemUIServer application?

3.9k Views Asked by At

For my Mac OSX application, I have a feature that removes the system clock in the upper right hand corner of the screen when a button is clicked. The preferences that control which system menus are displayed (including the system clock) is stored in ~/Library/Preferences/com.apple.systemuiserver.plist. I was able to update the relevant preferences in that file to remove the system clock. However, the SystemUIServer application needs to be restarted so that the new preferences can be reloaded and the clock can be removed. Here is the code I have used to restart SystemUIServer.

NSTask *killSystemUITask = [[NSTask alloc] init];
NSMutableArray *args = [NSMutableArray array];
[args addObject:@"SystemUIServer"];
[killSystemUITask setLaunchPath:@"/usr/bin/killall"];
[killSystemUITask setArguments:args];
[killSystemUITask launch];

When SystemUIServer is killed, OSX automatically restarts it. The above code works, but the removal of the system clock is not as clean as I would like. The entire system bar is removed for a second. Can anyone think of a better way to reload the preferences into SystemUIServer? Ideally, I'd like the removal of the system clock to be as clean as the clock display function in the Date & Time Preferences of the System Preferences application.

1

There are 1 best solutions below

0
On BEST ANSWER

Have you considered trying to drive the pref pane itself using AppleEvents/OSAScript? While the Network prefs pane seems to be the only one with fully built-out scriptability, you can drive any UI with System Events. It was easy enough to prototype in AppleScript. Here's what I came up with:

tell application "System Preferences"
    reveal pane "Date & Time"
    reveal anchor "ClockPref" of pane "Date & Time"
    tell application "System Events"            
        tell tab group 1 of window 1 of process "System Preferences"
            repeat with cbIndex from 0 to count of checkboxes
                tell checkbox cbIndex
                    if title contains "menu bar" then
                        click
                        exit repeat
                    end if
                end tell
            end repeat
        end tell
    end tell
    quit
end tell

You can either use it as is by using an NSAppleScript object, or if you're feeling masochistic, you can dive in to the minutia of figuring out just the right AppleEvents to send. (I recommend the former approach for sanity, but the latter will execute faster at runtime.)

Pros: Easy.

Cons: Launches System Preferences (which can be seen to be bouncing in the Dock), Requires "Enable Access for assistive devices" to be enabled (like many other things)

Hard to say if this is visually better or worse that killing SystemUIServer, but it's almost certainly kinder to any other components that might be interacting with SystemUIServer.

As far as getting rid of the dock bounce, this question over here mentions how to get things to start up without a dock icon. To this I can add that in the past, I've wrangled with this problem, and the solution I came up with was, at a high level, this:

  • Get a unique/safe temp directory
  • Make a hard-links only mirror of the entire bundle of the app in question (pax -rwl will help with this)
  • Replace the hard-linked Info.plist with a real copy of Info.plist
  • Edit the copy per the directions in the other question. (Note: There are other options than setting NSUIElement = true here, but I leave those as an exercise for the reader and google.)
  • Use the application from the temp directory
  • Delete the temp directory.

This approach has proven quite robust for me when trying to drive 3rd party applications. I'm guessing that you might, in the future, run into problems with system applications which are signed/sandboxed. (i.e. changing their Info.plist changes the signature, they may refuse to run.) Also, naturally, any sandboxed app will require a specific entitlement or exception to send AppleEvents at all, but I would guess this is also true of killing system processes (if that's even possible to do from a sandboxed app at all.)

Lastly, you should file a bug report with Apple requesting first-class API or scriptability for this if you feel it's important.