-
Notifications
You must be signed in to change notification settings - Fork 21
/
hook.c
131 lines (97 loc) · 3.74 KB
/
hook.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// https://developer.apple.com/library/archive/qa/qa1340/_index.html
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <mach/mach_init.h>
#include <mach/mach_interface.h>
#include <mach/mach_port.h>
#include <IOKit/IOMessage.h>
#include <IOKit/pwr_mgt/IOPMLib.h>
#include "hook.h"
io_connect_t root_port; // a reference to the Root Power Domain IOService
// notification port allocated by IORegisterForSystemPower
IONotificationPortRef notifyPortRef;
// notifier object, used to deregister later
io_object_t notifierObject;
long gMessageArgument;
int AllowPowerChange()
{
return IOAllowPowerChange(root_port, gMessageArgument);
}
int CancelPowerChange()
{
return IOCancelPowerChange(root_port, gMessageArgument);
}
void sleepCallBack(void* refCon, io_service_t service, natural_t messageType, void* messageArgument)
{
gMessageArgument = (long)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.
*/
// Cancel idle sleep
// IOCancelPowerChange( root_port, (long)messageArgument );
// Allow idle sleep
// IOAllowPowerChange(root_port, (long)messageArgument);
canSystemSleepCallback();
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.
*/
systemWillSleepCallback();
break;
case kIOMessageSystemWillPowerOn:
// System has started the wake up process...
systemWillPowerOnCallback();
break;
case kIOMessageSystemHasPoweredOn:
// System has finished waking up...
systemHasPoweredOnCallback();
break;
default:
break;
}
}
int ListenNotifications()
{
// this parameter is passed to the callback
void* refCon;
// register to receive system sleep notifications
root_port = IORegisterForSystemPower(refCon, ¬ifyPortRef, sleepCallBack, ¬ifierObject);
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.
CFRunLoopRun();
// Not reached, CFRunLoopRun doesn't return in this case.
return 0;
}
int StopListeningNotifications()
{
// remove the sleep notification port from the application runloop
CFRunLoopRemoveSource(CFRunLoopGetCurrent(),
IONotificationPortGetRunLoopSource(notifyPortRef),
kCFRunLoopCommonModes);
// deregister for system sleep notifications
IODeregisterForSystemPower(¬ifierObject);
// 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);
return 0;
}