Add wxCocoaPowerModule and CocoaPowerEventsObserver

Add support for wxPowerEvent generation under macOS.

Register observers with notifications center, with callbacks for
NSWorkspaceWillSleepNotification and NSWorkspaceDidWakeNotification
notifications.

These callbacks inform the top level window to handle POWER SUSPENDED
and/or RESUME.

For consistency with wxGTK/Linux, only generate these events once
wxPowerResource::Acquire() has been called.

Signed-off-by: Tijs Van Buggenhout <tijs.van.buggenhout@axsguard.com>

Closes #25778.
This commit is contained in:
Tijs Van Buggenhout
2025-09-19 17:56:35 +02:00
committed by Vadim Zeitlin
parent ace3d4d936
commit 5a3a7f5f48
3 changed files with 100 additions and 8 deletions
+1 -1
View File
@@ -40,7 +40,7 @@ enum wxBatteryState
// compiling in the code for handling them which is never going to be invoked
// under the other platforms, we define wxHAS_POWER_EVENTS symbol if this event
// is available, it should be used to guard all code using wxPowerEvent
#if defined(__WINDOWS__) || defined(__WXGTK__)
#if defined(__WINDOWS__) || defined(__WXGTK__) || defined(__WXOSX_COCOA__)
#define wxHAS_POWER_EVENTS
+3 -3
View File
@@ -67,9 +67,9 @@ enum wxPowerBlockKind
system is suspended, hibernated, plugged into or unplugged from the wall socket
and so on. wxPowerEvents are emitted by wxWindows.
Notice that currently these events are generated only under MSW and Linux
and that under Linux you @e must use wxPowerResource::Acquire() to receive
them, e.g. typically an application interested in these events should
Notice that currently these events are generated only under MSW, Linux and
MacOS (cocoa). Under Linux and MacOS you @e must use wxPowerResource::Acquire()
to receive them, e.g. typically an application interested in these events should
initialize wxPowerResourceBlocker for ::wxPOWER_RESOURCE_SYSTEM resource
using ::wxPOWER_DELAY block kind when initializing either the application
itself or its main window. E.g. for an application that wants to handle
+96 -4
View File
@@ -13,6 +13,11 @@
#include "wx/wxprec.h"
#ifndef WX_PRECOMP
#include "wx/module.h"
#include "wx/window.h"
#endif
#include "wx/power.h"
#include "wx/atomic.h"
#include "wx/osx/private.h"
@@ -20,11 +25,89 @@
#include <IOKit/pwr_mgt/IOPMLib.h>
#import <Cocoa/Cocoa.h>
static wxAtomicInt g_powerResourceSystemRefCount = 0;
// ----------------------------------------------------------------------------
// wxCocoaPowerModule
// ----------------------------------------------------------------------------
@interface wxCocoaPowerEventsObserver : NSObject
@end
@implementation wxCocoaPowerEventsObserver
- (id)init {
self = [super init];
if (self) {
NSNotificationCenter *center = [[NSWorkspace sharedWorkspace] notificationCenter];
// Register for "will sleep" notification
[center addObserver:self
selector:@selector(handleWillSleep:)
name:NSWorkspaceWillSleepNotification
object:nil];
// Register for "did wake" notification
[center addObserver:self
selector:@selector(handleDidWake:)
name:NSWorkspaceDidWakeNotification
object:nil];
}
return self;
}
- (void)dealloc {
[[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self];
[super dealloc];
}
- (void)handleWillSleep:(NSNotification *)notification {
wxPowerEvent event(wxEVT_POWER_SUSPENDED);
for ( auto tlw : wxTopLevelWindows )
tlw->HandleWindowEvent(event);
}
- (void)handleDidWake:(NSNotification *)notification {
wxPowerEvent event(wxEVT_POWER_RESUME);
for ( auto tlw : wxTopLevelWindows )
tlw->HandleWindowEvent(event);
}
@end
namespace {
// the global power events observer
static wxCFRef<wxCocoaPowerEventsObserver*> g_powerEventsObserver;
// add power observers on init and remove on exit
class wxCocoaPowerModule : public wxModule
{
public:
bool OnInit() override { return true; }
void OnExit() override
{
// There should be no other threads by now, so no locking is needed.
if ( g_powerResourceSystemRefCount )
{
g_powerEventsObserver.reset();
g_powerResourceSystemRefCount = 0;
}
}
private:
wxDECLARE_NO_COPY_CLASS(wxCocoaPowerModule);
};
}; // anonymous namespace
// ----------------------------------------------------------------------------
// wxPowerResource
// ----------------------------------------------------------------------------
static wxAtomicInt g_powerResourceSystemRefCount = 0;
static NSObject* g_processInfoActivity = nil;
bool UpdatePowerResourceUsage(wxPowerResourceKind kind, const wxString& reason)
@@ -58,9 +141,9 @@ bool UpdatePowerResourceUsage(wxPowerResourceKind kind, const wxString& reason)
[[NSProcessInfo processInfo]
endActivity:(id)g_processInfoActivity];
g_processInfoActivity = nil;
return true;
}
g_powerEventsObserver.reset();
}
return true;
@@ -73,7 +156,16 @@ wxPowerResource::Acquire(wxPowerResourceKind kind,
{
if ( blockKind == wxPOWER_DELAY )
{
// We don't support this mode under macOS because it's not needed there.
if ( kind == wxPOWER_RESOURCE_SYSTEM )
{
wxAtomicInc(g_powerResourceSystemRefCount);
if ( g_powerEventsObserver.get() == nullptr )
{
g_powerEventsObserver = [[wxCocoaPowerEventsObserver alloc] init];
}
}
return true;
}