Search code examples
cmacosshutdown

Receiving power notifications (especially shutdown) on Mac OSX


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, &notificationPort, 
                                        PowerCallback, &notifier);
    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!


Solution

  • I know you can register for the NSWorkspaceWillPowerOffNotification notification from NSWorkspace, which is not a C function but does work.

    #import <AppKit/AppKit.h>
    #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");
    }