OSX下監(jiān)聽休眠(sleep)和喚醒(wake)通知

前言

很多時候我們的客戶端軟件在電腦休眠之前都需要做一些事情,比如保存,清理工作等事件簿煌。這個時候我們就希望在電腦休眠前能夠接收到通知磁携,然后有足夠的時間去處理這些事情褒侧,讓我們的軟件更好的運行,帶來更好的用戶體驗谊迄。

正文

Cocoa 和 I/O Kit都可以用來接收休眠和喚醒通知闷供,除了正常的接收通知以外,I/O Kit還可以阻止和延遲閑置休眠鳞上。注意这吻,即使是I/O Kit,也無法阻止強制休眠篙议,只能延遲強制休眠唾糯。

提示:Mac OS X 有兩種休眠模式- 強制休眠和閑置休眠.

  • 當用戶執(zhí)行一些操作導(dǎo)致的電腦休眠是強制休眠怠硼。 盒上筆記本的蓋子,從右上角的蘋果菜單中選擇休眠都會導(dǎo)致強制休眠. 在一些特定的情況下移怯,系統(tǒng)也會觸發(fā)強制休眠, 比如, 溫度過高或電量過低.

  • 在系統(tǒng)設(shè)置中節(jié)能下設(shè)置的時間長度下香璃,電腦都沒有被使用,則會進入閑置休眠舟误。

清單1:在Cocoa下注冊休眠和喚醒通知

- (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];
}

提示:IOPMAssertionCreateWithName 是一個在Mac OS X 10.6雪豹系統(tǒng)下新增的API葡秒。IOPMAssertionCreateWithName 允許應(yīng)用彈出一個帶有簡要說明的提示框,告訴用戶為什么要阻止休眠嵌溢。如果你想要支持早期的Mac OS X 版本眯牧,你可能會使用到基于清單3和4的API,或者已經(jīng)被啟動的API——IOPMAssertionCreate 赖草。

清單2:在Mac OS X 10.6中使用I/O Kit阻止休眠

...
 
#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 Kit下注冊休眠和喚醒通知

#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 Kit 的休眠通知, 你需要從應(yīng)用程序的runloop中刪除事件源学少,并做一些清理工作。

清單4:移除 I/O Kit休眠/喚醒通知

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子梢灭,更是在濱河造成了極大的恐慌,老刑警劉巖绒疗,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異骂澄,居然都是意外死亡吓蘑,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門酗洒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來士修,“玉大人,你說我怎么就攤上這事樱衷∑宄埃” “怎么了?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵矩桂,是天一觀的道長沸移。 經(jīng)常有香客問我,道長侄榴,這世上最難降的妖魔是什么雹锣? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮癞蚕,結(jié)果婚禮上蕊爵,老公的妹妹穿的比我還像新娘。我一直安慰自己桦山,他們只是感情好攒射,可當我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布醋旦。 她就那樣靜靜地躺著,像睡著了一般会放。 火紅的嫁衣襯著肌膚如雪饲齐。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天咧最,我揣著相機與錄音捂人,去河邊找鬼。 笑死矢沿,一個胖子當著我的面吹牛滥搭,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播捣鲸,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼论熙,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了摄狱?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤无午,失蹤者是張志新(化名)和其女友劉穎媒役,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體宪迟,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡酣衷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了次泽。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片穿仪。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖意荤,靈堂內(nèi)的尸體忽然破棺而出啊片,到底是詐尸還是另有隱情,我是刑警寧澤玖像,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布紫谷,位于F島的核電站,受9級特大地震影響捐寥,放射性物質(zhì)發(fā)生泄漏笤昨。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一握恳、第九天 我趴在偏房一處隱蔽的房頂上張望瞒窒。 院中可真熱鬧,春花似錦乡洼、人聲如沸崇裁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽寇壳。三九已至醒颖,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間壳炎,已是汗流浹背泞歉。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留匿辩,地道東北人腰耙。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像铲球,于是被迫代替她去往敵國和親挺庞。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內(nèi)容