Question or issue on macOS:
I’m writing an application in C for the Mac (Leopard) that needs to do some work on receipt of power notifications, e.g. sleep, wake-up, shutdown, restart. It runs via launchd as a launchagent on login then begins monitoring for notifications. The code I’m using to do this is as follows:
/* ask for power notifications */ static void StartPowerNotification(void) { static io_connect_t rootPort; IONotificationPortRef notificationPort; io_object_t notifier; rootPort = IORegisterForSystemPower(&rootPort, ¬ificationPort, PowerCallback, ¬ifier); if (!rootPort) exit (1); CFRunLoopAddSource (CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(notificationPort), kCFRunLoopDefaultMode); } /* perform actions on receipt of power notifications */ void PowerCallback (void *rootPort, io_service_t y, natural_t msgType, void *msgArgument) { switch (msgType) { case kIOMessageSystemWillSleep: /* perform sleep actions */ break; case kIOMessageSystemHasPoweredOn: /* perform wakeup actions */ break; case kIOMessageSystemWillRestart: /* perform restart actions */ break; case kIOMessageSystemWillPowerOff: /* perform shutdown actions */ break; } }
However, only the top two for sleep and wake (kIOMessageSystemWillSleep and kIOMessageSystemHasPoweredOn) ever get called. I never get any notifcations for restart or shutdown (kIOMessageSystemWillRestart and kIOMessageSystemWillPowerOff).
Am I doing something wrong? Or is there another API that would give me the restart and shutdown notifications? I’d prefer to keep it as a C program (as thats what I’m familiar with) but am open to any sensible suggestions of alternatives (I’ve had a look at login/logout hooks but these seem to be deprecated in favour of launchd).
Thanks in advance for any help/tips!
How to solve this problem?
Solution no. 1:
I know you can register for the NSWorkspaceWillPowerOffNotification notification from NSWorkspace, which is not a C function but does work.
#import #import "WorkspaceResponder.h" int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; NSNotificationCenter *nc = [[NSWorkspace sharedWorkspace] notificationCenter]; WorkspaceResponder *mainController = [[WorkspaceResponder alloc] init]; //register for shutdown notications [nc addObserver:mainController selector:@selector(computerWillShutDownNotification:) name:NSWorkspaceWillPowerOffNotification object:nil]; [[NSRunLoop currentRunLoop] run]; [pool release]; return 0; }
Then in WorkspaceResponder.m:
- (void) computerWillShutDownNotification:(NSNotification *)notification { NSLog(@"Received Shutdown Notification"); }
Solution no. 2:
Using IORegisterForSystemPower
doesn’t provide the events you seek. Quoting from function documentation :
/*! @function IORegisterForSystemPower
@abstract Connects the caller to the Root Power Domain IOService
for the purpose of receiving sleep & wake notifications for the system.
Does not provide system shutdown and restart notifications.