MacOS suspend mode handler draft
This commit is contained in:
parent
f767171c06
commit
5ef8254cba
2 changed files with 110 additions and 0 deletions
|
|
@ -10,8 +10,28 @@
|
||||||
#include "../ios/iosnetworkwatcher.h"
|
#include "../ios/iosnetworkwatcher.h"
|
||||||
#include "networkwatcherimpl.h"
|
#include "networkwatcherimpl.h"
|
||||||
|
|
||||||
|
#include <IOKit/pwr_mgt/IOPMLib.h>
|
||||||
|
#include <IOKit/IOMessage.h>
|
||||||
|
|
||||||
|
|
||||||
class QString;
|
class QString;
|
||||||
|
|
||||||
|
// Inspired by https://ladydebug.com/blog/2020/05/21/programmatically-capture-energy-saver-event-on-mac/
|
||||||
|
class PowerNotificationsListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void registerForNotifications();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void sleepWakeupCallBack(void *refParam, io_service_t service, natural_t messageType, void *messageArgument);
|
||||||
|
|
||||||
|
private:
|
||||||
|
IONotificationPortRef notifyPortRef = nullptr; // notification port allocated by IORegisterForSystemPower
|
||||||
|
io_object_t notifierObj = IO_OBJECT_NULL; // notifier object, used to deregister later
|
||||||
|
io_connect_t rootPowerDomain = IO_OBJECT_NULL; // a reference to the Root Power Domain IOService
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class MacOSNetworkWatcher final : public IOSNetworkWatcher {
|
class MacOSNetworkWatcher final : public IOSNetworkWatcher {
|
||||||
public:
|
public:
|
||||||
MacOSNetworkWatcher(QObject* parent);
|
MacOSNetworkWatcher(QObject* parent);
|
||||||
|
|
@ -25,6 +45,7 @@ class MacOSNetworkWatcher final : public IOSNetworkWatcher {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void* m_delegate = nullptr;
|
void* m_delegate = nullptr;
|
||||||
|
PowerNotificationsListener m_powerlistener;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MACOSNETWORKWATCHER_H
|
#endif // MACOSNETWORKWATCHER_H
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,93 @@ Logger logger("MacOSNetworkWatcher");
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
void PowerNotificationsListener::registerForNotifications()
|
||||||
|
{
|
||||||
|
rootPowerDomain = IORegisterForSystemPower(this, ¬ifyPortRef, sleepWakeupCallBack, ¬ifierObj);
|
||||||
|
if (rootPowerDomain == IO_OBJECT_NULL) {
|
||||||
|
logger.debug() << "Failed to register for system power notifications!";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug() << "IORegisterForSystemPower OK! Root port:" << rootPowerDomain;
|
||||||
|
|
||||||
|
// add the notification port to the application runloop
|
||||||
|
CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(notifyPortRef), kCFRunLoopCommonModes);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PowerNotificationsListener::sleepWakeupCallBack(void *refParam, io_service_t service, natural_t messageType, void *messageArgument)
|
||||||
|
{
|
||||||
|
Q_UNUSED(service)
|
||||||
|
|
||||||
|
auto listener = static_cast<PowerNotificationsListener *>(refParam);
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
logger.debug() << "System power message: can system sleep?";
|
||||||
|
|
||||||
|
// Uncomment to cancel idle sleep
|
||||||
|
// IOCancelPowerChange(thiz->rootPowerDomain, reinterpret_cast<long>(messageArgument));
|
||||||
|
|
||||||
|
// Allow idle sleep
|
||||||
|
IOAllowPowerChange(listener->rootPowerDomain, reinterpret_cast<long>(messageArgument));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kIOMessageSystemWillNotSleep:
|
||||||
|
/* Announces that the system has retracted a previous attempt to sleep; it
|
||||||
|
* follows `kIOMessageCanSystemSleep`.
|
||||||
|
*/
|
||||||
|
logger.debug() << "System power message: system will NOT sleep.";
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
logger.debug() << "System power message: system WILL sleep.";
|
||||||
|
|
||||||
|
IOAllowPowerChange(listener->rootPowerDomain, reinterpret_cast<long>(messageArgument));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kIOMessageSystemWillPowerOn:
|
||||||
|
/* Announces that the system is beginning to power the device tree; most devices
|
||||||
|
* are still unavailable at this point.
|
||||||
|
*/
|
||||||
|
/* From the documentation:
|
||||||
|
*
|
||||||
|
* - kIOMessageSystemWillPowerOn is delivered at early wakeup time, before most hardware
|
||||||
|
* has been powered on. Be aware that any attempts to access disk, network, the display,
|
||||||
|
* etc. may result in errors or blocking your process until those resources become
|
||||||
|
* available.
|
||||||
|
*
|
||||||
|
* So we do NOT log this event.
|
||||||
|
*/
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kIOMessageSystemHasPoweredOn:
|
||||||
|
/* Announces that the system and its devices have woken up. */
|
||||||
|
logger.debug() << "System power message: system has powered on.";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
logger.debug() << "System power message: other event: " << messageType;
|
||||||
|
/* Not a system sleep and wake notification. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MacOSNetworkWatcher::MacOSNetworkWatcher(QObject* parent) : IOSNetworkWatcher(parent) {
|
MacOSNetworkWatcher::MacOSNetworkWatcher(QObject* parent) : IOSNetworkWatcher(parent) {
|
||||||
MZ_COUNT_CTOR(MacOSNetworkWatcher);
|
MZ_COUNT_CTOR(MacOSNetworkWatcher);
|
||||||
}
|
}
|
||||||
|
|
@ -66,6 +153,8 @@ void MacOSNetworkWatcher::start() {
|
||||||
logger.debug() << "Delegate already registered";
|
logger.debug() << "Delegate already registered";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_powerlistener.registerForNotifications();
|
||||||
|
|
||||||
CWWiFiClient* client = CWWiFiClient.sharedWiFiClient;
|
CWWiFiClient* client = CWWiFiClient.sharedWiFiClient;
|
||||||
if (!client) {
|
if (!client) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue