Revision: 4034
Updated Code
at February 14, 2008 04:52 by 0xced
Updated Code
// gcc -Wall -arch i386 -arch ppc -mmacosx-version-min=10.4 -framework AppKit -framework Carbon -weak_framework ScriptingBridge -o reload reload.m 2>&1 | egrep -v "(In file included from reload.m:8:)|(Mac OS X version 10.5 or later is needed for use of property)" #import <AppKit/AppKit.h> #import <Carbon/Carbon.h> // Generate this header with // sdef "/Applications/System Preferences.app" | sdp -fh --basename SystemPreferences #import "SystemPreferences.h" @interface TerminationListener : NSObject { const char *prefPaneIdentifier; pid_t parentProcessId; } - (void) reload; - (void) exit; @end @implementation TerminationListener - (id) initWithPrefPaneIdentifier:(const char *)paneId parentProcessId:(pid_t)ppid { self = [super init]; if (self != nil) { prefPaneIdentifier = paneId ; parentProcessId = ppid; // This adds the input source required by the run loop [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(applicationDidTerminate:) name:NSWorkspaceDidTerminateApplicationNotification object:nil]; if (getppid() == 1) { // ppid is launchd (1) => parent terminated already [self reload]; } } return self; } - (void) applicationDidTerminate:(NSNotification *)notification { if (parentProcessId == [[[notification userInfo] valueForKey:@"NSApplicationProcessIdentifier"] intValue]) { // parent just terminated [self reload]; } } - (void) applicationDidLaunch:(NSNotification *)notification { NSDictionary *notificationInfo = [notification userInfo]; if ([[notificationInfo valueForKey:@"NSApplicationName"] isEqualToString:@"System Preferences"]) { // System Preferences just relaunched ProcessSerialNumber psn = {[[notificationInfo valueForKey:@"NSApplicationProcessSerialNumberHigh"] intValue], [[notificationInfo valueForKey:@"NSApplicationProcessSerialNumberLow"] intValue]}; SetFrontProcess(&psn); // Load the pref pane by sending the appropriate apple event AppleEvent event = {typeNull, NULL}; NSString *gizmo = [NSString stringWithFormat:@"'data':obj{'form':enum('ID '), 'want':type('xppb'), 'seld':\"%s\", 'from':'null'()}, '----':obj{'form':enum('prop'), 'want':type('prop'), 'seld':type('xpcp'), 'from':'null'()}", prefPaneIdentifier]; AEBuildAppleEvent(kAECoreSuite, kAESetData, typeProcessSerialNumber, &psn, sizeof(psn), kAutoGenerateReturnID, kAnyTransactionID, &event, NULL, [gizmo UTF8String]); AESend(&event, NULL, kAENoReply, kAENormalPriority, kAEDefaultTimeout, NULL, NULL); AEDisposeDesc(&event); [self exit]; } } - (void) reload { if (NSClassFromString(@"SBApplication")) { SystemPreferencesApplication *SystemPreferences = [SBApplication applicationWithBundleIdentifier:@"com.apple.systempreferences"]; @try { [SystemPreferences activate]; SystemPreferences.currentPane = [SystemPreferences.panes objectWithID:[NSString stringWithCString:prefPaneIdentifier encoding:NSUTF8StringEncoding]]; } @catch (NSException *exception) { NSLog(@"%@", [exception description]); } [self exit]; } else { [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(applicationDidLaunch:) name:NSWorkspaceDidLaunchApplicationNotification object:nil]; if (![[NSWorkspace sharedWorkspace] launchApplication:@"System Preferences"]) { [self exit]; } } } - (void) exit { /* As it is impossible to get the right combination of {[NSApp stop:self] call, [NSApp abortModal] call, [NSApp terminate:self] call, on Tiger, on Leopard, from Terminal, from NSTask} to work (that is, exit the run loop), just call the more radical exit() function. */ exit(0); } @end int main (int argc, const char * argv[]) { if (argc != 3) return EXIT_FAILURE; NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; [[[TerminationListener alloc] initWithPrefPaneIdentifier:argv[1] parentProcessId:atoi(argv[2])] autorelease]; [[NSApplication sharedApplication] run]; [pool release]; return EXIT_SUCCESS; }
Revision: 4033
Updated Code
at January 24, 2008 16:56 by 0xced
Updated Code
// gcc -Wall -arch i386 -arch ppc -mmacosx-version-min=10.4 -framework AppKit -framework Carbon -weak_framework ScriptingBridge -o reload reload.m 2>&1 | egrep -v "(In file included from reload.m:8:)|(Mac OS X version 10.5 or later is needed for use of property)" #import <AppKit/AppKit.h> #import <Carbon/Carbon.h> // Generate this header with // sdef "/Applications/System Preferences.app" | sdp -fh --basename SystemPreferences #import "SystemPreferences.h" @interface TerminationListener : NSObject { const char *prefPaneIdentifier; pid_t parentProcessId; } - (void) reload; - (void) exit; @end @implementation TerminationListener - (id) initWithPrefPaneIdentifier:(const char *)paneId parentProcessId:(pid_t)ppid { self = [super init]; if (self != nil) { prefPaneIdentifier = paneId ; parentProcessId = ppid; [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(applicationDidTerminate:) name:NSWorkspaceDidTerminateApplicationNotification object:nil]; if (getppid() == 1) { // ppid is launchd (1) => parent terminated already [self reload]; } } return self; } - (void) applicationDidTerminate:(NSNotification *)notification { if (parentProcessId == [[[notification userInfo] valueForKey:@"NSApplicationProcessIdentifier"] intValue]) { // parent just terminated [self reload]; } } - (void) applicationDidLaunch:(NSNotification *)notification { NSDictionary *notificationInfo = [notification userInfo]; if ([[notificationInfo valueForKey:@"NSApplicationName"] isEqualToString:@"System Preferences"]) { // System Preferences just relaunched ProcessSerialNumber psn = {[[notificationInfo valueForKey:@"NSApplicationProcessSerialNumberHigh"] intValue], [[notificationInfo valueForKey:@"NSApplicationProcessSerialNumberLow"] intValue]}; SetFrontProcess(&psn); // Load the pref pane by sending the appropriate apple event AppleEvent event = {typeNull, NULL}; NSString *gizmo = [NSString stringWithFormat:@"'data':obj{'form':enum('ID '), 'want':type('xppb'), 'seld':\"%s\", 'from':'null'()}, '----':obj{'form':enum('prop'), 'want':type('prop'), 'seld':type('xpcp'), 'from':'null'()}", prefPaneIdentifier]; AEBuildAppleEvent(kAECoreSuite, kAESetData, typeProcessSerialNumber, &psn, sizeof(psn), kAutoGenerateReturnID, kAnyTransactionID, &event, NULL, [gizmo UTF8String]); AESend(&event, NULL, kAENoReply, kAENormalPriority, kAEDefaultTimeout, NULL, NULL); AEDisposeDesc(&event); [self exit]; } } - (void) reload { if (NSClassFromString(@"SBApplication")) { SystemPreferencesApplication *SystemPreferences = [SBApplication applicationWithBundleIdentifier:@"com.apple.systempreferences"]; @try { [SystemPreferences activate]; SystemPreferences.currentPane = [SystemPreferences.panes objectWithID:[NSString stringWithCString:prefPaneIdentifier encoding:NSUTF8StringEncoding]]; } @catch (NSException *exception) { NSLog(@"%@", [exception description]); } [self exit]; } else { [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(applicationDidLaunch:) name:NSWorkspaceDidLaunchApplicationNotification object:nil]; if (![[NSWorkspace sharedWorkspace] launchApplication:@"System Preferences"]) { [self exit]; } } } - (void) exit { [NSApp abortModal]; [NSApp stop:self]; } @end int main (int argc, const char * argv[]) { if (argc != 3) return EXIT_FAILURE; NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; [[[TerminationListener alloc] initWithPrefPaneIdentifier:argv[1] parentProcessId:atoi(argv[2])] autorelease]; [[NSApplication sharedApplication] run]; [pool release]; return EXIT_SUCCESS; }
Revision: 4032
Updated Code
at November 13, 2007 05:57 by 0xced
Updated Code
// gcc -Wall -arch i386 -arch ppc -Os -s -framework AppKit -o reload reload.m #import <AppKit/AppKit.h> #import <unistd.h> @interface TerminationListener : NSObject { const char *prefPaneIdentifier; pid_t parentProcessId; } - (void) reload; @end @implementation TerminationListener - (id) initWithPrefPaneIdentifier:(const char *)paneId parentProcessId:(pid_t)ppid { self = [super init]; if (self != nil) { prefPaneIdentifier = paneId ; parentProcessId = ppid; [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(applicationDidTerminate:) name:NSWorkspaceDidTerminateApplicationNotification object:nil]; if (getppid() == 1) { // ppid is launchd (1) => parent terminated already [self reload]; } } return self; } - (void) applicationDidTerminate:(NSNotification *)notification { if (parentProcessId == [[[notification userInfo] valueForKey:@"NSApplicationProcessIdentifier"] intValue]) { // parent just terminated [self reload]; } } - (void) reload { NSAppleEventDescriptor *returnDescriptor = NULL; NSString *scriptSource = [NSString stringWithFormat: @"\ tell application \"System Preferences\"\n\ activate\n\ set current pane to pane id \"%s\"\n\ end tell", prefPaneIdentifier]; NSAppleScript *scriptObject = [[NSAppleScript alloc] initWithSource:scriptSource]; returnDescriptor = [scriptObject executeAndReturnError:nil]; [scriptObject release]; if (returnDescriptor == NULL) { // unsuccessful script execution, just launch System Preferences [[NSWorkspace sharedWorkspace] launchApplication:@"System Preferences"]; } [NSApp stop:self]; } @end int main (int argc, const char * argv[]) { if (argc != 3) return EXIT_FAILURE; NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; [[[TerminationListener alloc] initWithPrefPaneIdentifier:argv[1] parentProcessId:atoi(argv[2])] autorelease]; [[NSApplication sharedApplication] run]; [pool release]; return EXIT_SUCCESS; }
Revision: 4031
Updated Code
at November 13, 2007 05:47 by 0xced
Updated Code
// gcc -Wall -arch i386 -arch ppc -Os -s -framework AppKit -o reload reload.m #import <AppKit/AppKit.h> #import <unistd.h> @interface TerminationListener : NSObject { const char *prefPaneIdentifier; pid_t parentProcessId; } - (void) reload; @end @implementation TerminationListener - (id) initWithPrefPaneIdentifier:(const char *)paneId parentProcessId:(pid_t)ppid { self = [super init]; if (self != nil) { prefPaneIdentifier = paneId ; parentProcessId = ppid; [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(applicationDidTerminate:) name:NSWorkspaceDidTerminateApplicationNotification object:nil]; if (getppid() == 1) { // ppid is launchd (1) => parent terminated already [self reload]; } } return self; } - (void) applicationDidTerminate:(NSNotification *)notification { if (parentProcessId == [[[notification userInfo] valueForKey:@"NSApplicationProcessIdentifier"] intValue]) { // parent just terminated [self reload]; } } - (void) reload { NSAppleEventDescriptor *returnDescriptor = NULL; NSString *scriptSource = [NSString stringWithFormat: @"\ tell application \"System Preferences\"\n\ activate\n\ set current pane to pane id \"%s\"\n\ end tell", prefPaneIdentifier]; NSAppleScript *scriptObject = [[NSAppleScript alloc] initWithSource:scriptSource]; returnDescriptor = [scriptObject executeAndReturnError:nil]; [scriptObject release]; if (returnDescriptor == NULL) { // unsuccessful script execution, just launch System Preferences [[NSWorkspace sharedWorkspace] launchApplication:@"System Preferences"]; } [NSApp terminate:self]; } @end int main (int argc, const char * argv[]) { if (argc != 3) return EXIT_FAILURE; NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; [[[TerminationListener alloc] initWithPrefPaneIdentifier:argv[1] parentProcessId:atoi(argv[2])] autorelease]; [[NSApplication sharedApplication] run]; // This will not be executed because -[NSApp terminate:] is called [pool release]; return EXIT_SUCCESS; }
Revision: 4030
Initial Code
Initial URL
Initial Description
Initial Title
Initial Tags
Initial Language
at October 18, 2007 15:16 by 0xced
Initial Code
// gcc -Wall -arch i386 -arch ppc -Os -s -framework AppKit -o reload reload.m #import <AppKit/AppKit.h> #import <unistd.h> @interface TerminationListener : NSObject { const char *prefPaneIdentifier; pid_t parentProcessId; } - (void) reload; @end @implementation TerminationListener - (id) initWithPrefPaneIdentifier:(const char *)paneId parentProcessId:(pid_t)ppid { self = [super init]; if (self != nil) { prefPaneIdentifier = paneId ; parentProcessId = ppid; [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(applicationDidTerminate:) name:NSWorkspaceDidTerminateApplicationNotification object:nil]; if (getppid() == 1) { // ppid is launchd (1) => parent terminated already [self reload]; } } return self; } - (void) applicationDidTerminate:(NSNotification *)notification { if (parentProcessId == [[[notification userInfo] valueForKey:@"NSApplicationProcessIdentifier"] intValue]) { // parent just terminated [self reload]; } } - (void) reload { NSAppleEventDescriptor *returnDescriptor = NULL; NSString *scriptSource = [NSString stringWithFormat: @"\ tell application \"System Preferences\"\n\ activate\n\ set current pane to pane id \"%s\"\n\ end tell", prefPaneIdentifier]; NSAppleScript *scriptObject = [[NSAppleScript alloc] initWithSource:scriptSource]; returnDescriptor = [scriptObject executeAndReturnError:nil]; [scriptObject release]; if (returnDescriptor == NULL) { // unsuccessful script execution, just launch System Preferences [[NSWorkspace sharedWorkspace] launchApplication:@"System Preferences"]; } [NSApp terminate:self]; } @end int main (int argc, const char * argv[]) { if (argc != 3) return EXIT_FAILURE; NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; [[[TerminationListener alloc] initWithPrefPaneIdentifier:argv[1] parentProcessId:atoi(argv[2])] autorelease]; [NSApp run]; // This will not be executed because -[NSApp terminate:] is called [pool release]; return EXIT_SUCCESS; }
Initial URL
Initial Description
The preference pane that need to be reloaded must fork 'reload' with two arguments, then terminate System Preferences. In Cocoa, the fork is easily achieved with a NSTask. The first argument must be the bundle identifier of the preference pane to reload. The second argument must be the process identifier of the terminating application, i.e. System Preferences. In Cocoa, you can get it with [[NSProcessInfo processInfo] processIdentifier], which is equivalent to getpid().
Initial Title
Reload a preference pane
Initial Tags
Initial Language
Objective C