Has anyone had luck setting the ScreenSaver idle activation time outside of the SystemPreferences application – and having the value change be correctly observed by the system? The following bit of code makes the requisite changes in the ~/Library/Preferences/ByHost/com.apple.screensaver.xxxxx.plist file:
CFStringRef appID = CFSTR(“com.apple.screensaver”); CFStringRef key = CFSTR(“idleTime”);
// Set up the preference. CFPreferencesSetValue(key, [NSNumber numberWithInt:[foo intValue]], appID, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
// Write out the preference data. CFPreferencesSynchronize(appID, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
// Let apps know this changed? [[NSWorkspace sharedWorkspace] noteUserDefaultsChanged];
…however, the change doesn’t always seem to take effect. What does the Screen Saver preferences panel do to notify the system that this value has changed?
I had the same problem when writing my menu extra, Dockyard. Dynamically loaded bundles just don’t have a good way to access preferences. Anyway, the solution seems to be using the following code:
NSDictionary *screenSaverDefaults = [[NSUserDefaults standardUserDefaults] persistentDomainForName:@”com.apple.screensaver”]; * … // Change screenSaverDefaults somehow, probably through mutableCopy/setObject:forKey: … * [[NSUserDefaults standardUserDefaults] setPersistentDomain:screenSaverDefaults forName:@”com.apple.screensaver”]; [[NSUserDefaults standardUserDefaults] synchronize];
Thanks for the tips! The code I pasted above does make changes to the actual plist files… that part works great. What I’m having trouble with is getting whatever process (the loginwindow?) that watches the idle time and kicks off the screensaver to notice that I’ve updated the file and changed the idle time.
You can send a notification to loginwindow to reload preferences with the following code:
CFMessagePortRef port = CFMessagePortCreateRemote(NULL, CFSTR("com.apple.loginwindow.notify"));
CFMessagePortSendRequest(port, 500, 0, 0, 0, 0, 0);
CFRelease(port);
Preference changes will take immediate effect after sending that notification.
Thanks to posts by Guillaume O. and Jesse Hollington for figuring this out and sharing it.
–Noah