Apple Developer Connection
Advanced Search
Member Login Log In | Not a Member? Contact ADC

Registering and unregistering for sleep notifications

Q: How can my application get notified when the computer is going to sleep or waking from sleep? How do I stop receiving these notifications?

A: The following code snippets show how to install (Listing 1) and remove (Listing 2) a sleep notification handler. Your application can use this notification to take action on system sleep and on system wakeup.

Note: Your application can use the sleep callback to deny idle sleep, i.e. sleep after a period of inactivity. Applications should not deny idle sleep unless absolutely necessary.

Listing 1: Installing a sleep notification handler.

#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>

#include <mach/mach_port.h>
#include <mach/mach_interface.h>
#include <mach/mach_init.h>

#include <IOKit/pwr_mgt/IOPMLib.h>
#include <IOKit/IOMessage.h>

io_connect_t  root_port;    // a reference to the Root Power Domain IOService

void
MySleepCallBack( void * refCon, io_service_t service, natural_t messageType, void * messageArgument )
{
    printf( "messageType %08lx, arg %08lx\n",
            (long unsigned int)messageType,
            (long unsigned int)messageArgument );

    switch ( messageType )
    {

        case kIOMessageCanSystemSleep:
            /*
               Idle sleep is about to kick in.
               Applications have a chance to prevent sleep by calling IOCancelPowerChange.
               Most applications should not prevent idle sleep.

               Power Management waits up to 30 seconds for you to either allow or deny idle sleep.
               If you don't acknowledge this power change by calling either IOAllowPowerChange
               or IOCancelPowerChange, the system will wait 30 seconds then go to sleep.
            */

            // we will allow idle sleep
            IOAllowPowerChange( root_port, (long)messageArgument );
            break;

        case kIOMessageSystemWillSleep:
            /* The system WILL go to sleep. If you do not call IOAllowPowerChange or
                IOCancelPowerChange to acknowledge this message, sleep will be
               delayed by 30 seconds.

               NOTE: If you call IOCancelPowerChange to deny sleep it returns kIOReturnSuccess,
               however the system WILL still go to sleep.
            */

            // we cannot deny forced sleep
            IOAllowPowerChange( root_port, (long)messageArgument );
            break;


        default:
            break;

    }
}


int main( int argc, char **argv )
{
    IONotificationPortRef  notifyPortRef;   // notification port allocated by IORegisterForSystemPower
    io_object_t            notifierObject;  // notifier object, used to deregister later
    void*                  refCon;          // this parameter is passed to the callback

    // register to receive system sleep notifications
    root_port = IORegisterForSystemPower( refCon, &notifyPortRef, MySleepCallBack, &notifierObject );
    if ( root_port == NULL )
    {
            printf("IORegisterForSystemPower failed\n");
            return 1;
    }

    // add the notification port to the application runloop
    CFRunLoopAddSource( CFRunLoopGetCurrent(),
                        IONotificationPortGetRunLoopSource(notifyPortRef),
                        kCFRunLoopCommonModes );

    printf( "waiting...\n\n" );

    /*
       Start the run loop to receive sleep notifications.  You don't need to
       call this if you already have a Carbon or Cocoa EventLoop running.
    */
    CFRunLoopRun();


    return (0);
}

If you no longer desire to receive sleep notifications, you need to remove your event source from the application runloop and do a bit of cleanup:

Listing 2: Removing a sleep notification handler.

...
    // we no longer want sleep notifications:

    // remove the sleep notification port from the application runloop
    CFRunLoopRemoveSource( CFRunLoopGetCurrent(),
                         IONotificationPortGetRunLoopSource(notifyPortRef),
                         kCFRunLoopCommonModes );

    // deregister for system sleep notifications
    IODeregisterForSystemPower( &notifierObject );

    // IORegisterForSystemPower implicitly opens the Root Power Domain IOService
    // so we close it here
    IOServiceClose( root_port );

    // destroy the notification port allocated by IORegisterForSystemPower
    IONotificationPortDestroy( notifyPortRef );
...

Document Revision History

DateNotes
2005-10-17Added an example of how to deregister for sleep notifications.
2004-10-25Explains how applications can register and unregister for sleep notifications on Mac OS X.

Posted: 2005-10-17




Did this document help you?
Yes: Tell us what works for you.

It’s good, but: Report typos, inaccuracies, and so forth.

It wasn’t helpful: Tell us what would have helped.