Технические вопросы и ответы QA1340

Регистрация и нерегистрация для сна и уведомлений следа

Q: Когда компьютер засыпает или просыпается от сна, как может быть уведомлено мое приложение? Как я предотвращаю сон?

A: Какао (Перечисление 1) и Набор I/O (Перечисление 3, Перечисление 4) может и использоваться для получения сна и уведомлений следа. В то время как Набор I/O может также предотвратить или задержать (Перечисление 2, Перечисление 3) неактивный сон, какао может использоваться для получения сна и уведомлений следа. Однако даже с Набором I/O, не возможно предотвратить вызванный сон, только задержать его.

Перечисление 1  , Устанавливающее сон Какао и уведомление следа.

- (void) receiveSleepNote: (NSNotification*) note
{
    NSLog(@"receiveSleepNote: %@", [note name]);
}
 
- (void) receiveWakeNote: (NSNotification*) note
{
    NSLog(@"receiveWakeNote: %@", [note name]);
}
 
- (void) fileNotifications
{
    //These notifications are filed on NSWorkspace's notification center, not the default
    // notification center. You will not receive sleep/wake notifications if you file
    //with the default notification center.
    [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver: self
            selector: @selector(receiveSleepNote:)
            name: NSWorkspaceWillSleepNotification object: NULL];
 
    [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver: self
            selector: @selector(receiveWakeNote:)
            name: NSWorkspaceDidWakeNotification object: NULL];
}

Перечисление 2  , Предотвращающее сон с помощью Набора I/O в Mac OS X 10,6 Snow Leopard

...
 
#import <IOKit/pwr_mgt/IOPMLib.h>
 
...
// kIOPMAssertionTypeNoDisplaySleep prevents display sleep,
// kIOPMAssertionTypeNoIdleSleep prevents idle sleep
 
//reasonForActivity is a descriptive string used by the system whenever it needs
//  to tell the user why the system is not sleeping. For example,
//  "Mail Compacting Mailboxes" would be a useful string.
 
//  NOTE: IOPMAssertionCreateWithName limits the string to 128 characters.
CFStringRef* reasonForActivity= CFSTR("Describe Activity Type");
 
IOPMAssertionID assertionID;
IOReturn success = IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep,
                                    kIOPMAssertionLevelOn, reasonForActivity, &assertionID);
if (success == kIOReturnSuccess)
{
 
    //Add the work you need to do without
    //  the system sleeping here.
 
    success = IOPMAssertionRelease(assertionID);
    //The system will be able to sleep again.
}
...

Перечисление 3  , Устанавливающее уведомление сна/следа Набора I/O.

#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. This message will not be sent for forced sleep.
                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.
            */
 
            //Uncomment to cancel idle sleep
            //IOCancelPowerChange( root_port, (long)messageArgument );
            // 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.
            */
 
            IOAllowPowerChange( root_port, (long)messageArgument );
            break;
 
        case kIOMessageSystemWillPowerOn:
            //System has started the wake up process...
            break;
 
        case kIOMessageSystemHasPoweredOn:
            //System has finished waking up...
        break;
 
        default:
            break;
 
    }
}
 
 
int main( int argc, char **argv )
{
    // notification port allocated by IORegisterForSystemPower
    IONotificationPortRef  notifyPortRef;
 
    // notifier object, used to deregister later
    io_object_t            notifierObject;
   // this parameter is passed to the callback
    void*                  refCon;
 
    // register to receive system sleep notifications
 
    root_port = IORegisterForSystemPower( refCon, &notifyPortRef, MySleepCallBack, &notifierObject );
    if ( root_port == 0 )
    {
        printf("IORegisterForSystemPower failed\n");
        return 1;
    }
 
    // add the notification port to the application runloop
    CFRunLoopAddSource( CFRunLoopGetCurrent(),
            IONotificationPortGetRunLoopSource(notifyPortRef), kCFRunLoopCommonModes );
 
    /* Start the run loop to receive sleep notifications. Don't call CFRunLoopRun if this code
        is running on the main thread of a Cocoa or Carbon application. Cocoa and Carbon
        manage the main thread's run loop for you as part of their event handling
        mechanisms.
    */
    CFRunLoopRun();
 
    //Not reached, CFRunLoopRun doesn't return in this case.
    return (0);
}

Чтобы прекратить получать уведомления сна Набора I/O, необходимо удалить источник события из приложения runloop и сделать немного очистки.

Перечисление 4  , Демонтирующее обработчик уведомления сна/следа Набора I/O.

...
    // 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 );
...


История версии документа


ДатаПримечания
13.01.2014

Исправленная маленькая ошибка в сообщении вошла в систему receiveWakeNote

01.03.2011

Обновленный код для использования IOPMAssertionCreateWithName.

08.08.2008

Добавленная информация о принудительном/неактивном сне, как получить уведомление сна/следа в Какао и развернул выборку IOKit для включения сообщений следа и IOPMAssert.

17.10.2005

Добавленный пример того, как вычеркнуть из списка для уведомлений сна.

25.10.2004

Новый документ, объясняющий, как приложения могут зарегистрироваться и не зарегистрироваться для сна и разбудить уведомления на Mac OS X.