Feature: Add power management to keep macOS client always responsive

This commit is contained in:
yuanyuanxiang
2026-05-01 21:43:55 +02:00
parent 36ba9ccc1d
commit 3607f1d768
3 changed files with 61 additions and 0 deletions

View File

@@ -2,6 +2,7 @@
#import <CoreGraphics/CoreGraphics.h> #import <CoreGraphics/CoreGraphics.h>
#import <dispatch/dispatch.h> #import <dispatch/dispatch.h>
#import <IOKit/pwr_mgt/IOPMLib.h>
#import "../client/IOCPClient.h" #import "../client/IOCPClient.h"
#include <vector> #include <vector>
#include <atomic> #include <atomic>
@@ -132,4 +133,7 @@ private:
// Input handler for mouse/keyboard control // Input handler for mouse/keyboard control
std::unique_ptr<InputHandler> m_inputHandler; std::unique_ptr<InputHandler> m_inputHandler;
// Power management: prevent display sleep during remote desktop
IOPMAssertionID m_displayAssertionID;
}; };

View File

@@ -26,6 +26,7 @@ ScreenHandler::ScreenHandler(IOCPClient* client)
, m_maxFPS(15) , m_maxFPS(15)
, m_qualityLevel(QUALITY_GOOD) // Use fixed QUALITY_GOOD (H264) for web compatibility , m_qualityLevel(QUALITY_GOOD) // Use fixed QUALITY_GOOD (H264) for web compatibility
, m_h264Bitrate(3000000) // 3 Mbps (matches Windows QUALITY_GOOD) , m_h264Bitrate(3000000) // 3 Mbps (matches Windows QUALITY_GOOD)
, m_displayAssertionID(0)
{ {
memset(&m_bmpHeader, 0, sizeof(m_bmpHeader)); memset(&m_bmpHeader, 0, sizeof(m_bmpHeader));
@@ -115,6 +116,21 @@ void ScreenHandler::start(IOCPClient* client, uint64_t clientID)
m_clientID = clientID; m_clientID = clientID;
m_running = true; m_running = true;
// Prevent display sleep during remote desktop session
if (m_displayAssertionID == 0) {
IOReturn result = IOPMAssertionCreateWithName(
kIOPMAssertionTypeNoDisplaySleep,
kIOPMAssertionLevelOn,
CFSTR("SimpleRemoter - remote desktop session active"),
&m_displayAssertionID
);
if (result == kIOReturnSuccess) {
NSLog(@"Display sleep disabled for remote desktop (ID: %u)", m_displayAssertionID);
} else {
NSLog(@"Warning: Failed to prevent display sleep (error: 0x%x)", result);
}
}
m_captureThread = std::thread(&ScreenHandler::captureLoop, this); m_captureThread = std::thread(&ScreenHandler::captureLoop, this);
} }
@@ -130,6 +146,13 @@ void ScreenHandler::stop()
m_h264Encoder->close(); m_h264Encoder->close();
m_h264Encoder.reset(); m_h264Encoder.reset();
} }
// Release display sleep assertion - allow screen to turn off
if (m_displayAssertionID != 0) {
IOPMAssertionRelease(m_displayAssertionID);
NSLog(@"Display sleep re-enabled (released ID: %u)", m_displayAssertionID);
m_displayAssertionID = 0;
}
} }
void ScreenHandler::sendBitmapInfo() void ScreenHandler::sendBitmapInfo()

View File

@@ -6,6 +6,7 @@
#import <signal.h> #import <signal.h>
#import <unistd.h> #import <unistd.h>
#import <IOKit/IOKitLib.h> #import <IOKit/IOKitLib.h>
#import <IOKit/pwr_mgt/IOPMLib.h>
#import <fstream> #import <fstream>
#import <thread> #import <thread>
#import <atomic> #import <atomic>
@@ -478,6 +479,30 @@ int main(int argc, const char* argv[])
@autoreleasepool { @autoreleasepool {
NSLog(@"=== macOS Ghost Client ==="); NSLog(@"=== macOS Ghost Client ===");
// ============== Power Management: Keep System Awake ==============
// 1. Disable App Nap - prevent macOS from suspending this process
id<NSObject> powerActivity = [[NSProcessInfo processInfo]
beginActivityWithOptions:(NSActivityUserInitiated | NSActivityIdleSystemSleepDisabled)
reason:@"Remote control client must maintain persistent connection"];
NSLog(@"App Nap disabled, activity token acquired");
// 2. Prevent system idle sleep using IOKit power assertion
IOPMAssertionID sleepAssertionID = 0;
IOReturn result = IOPMAssertionCreateWithName(
kIOPMAssertionTypeNoIdleSleep,
kIOPMAssertionLevelOn,
CFSTR("SimpleRemoter macOS client - maintaining remote connection"),
&sleepAssertionID
);
if (result == kIOReturnSuccess) {
NSLog(@"Power assertion created: system idle sleep disabled (ID: %u)", sleepAssertionID);
} else {
NSLog(@"Warning: Failed to create power assertion (error: 0x%x)", result);
}
// 3. Display sleep: managed by ScreenHandler - only prevents display sleep
// when remote desktop is actively connected (saves power when idle)
// Setup signal handlers // Setup signal handlers
setupSignals(); setupSignals();
@@ -549,6 +574,15 @@ int main(int argc, const char* argv[])
} }
NSLog(@"Shutting down..."); NSLog(@"Shutting down...");
// Release power assertions
if (sleepAssertionID) {
IOPMAssertionRelease(sleepAssertionID);
NSLog(@"Released sleep assertion");
}
// Display assertion is managed by ScreenHandler (released in stop())
// powerActivity is automatically released when exiting @autoreleasepool
(void)powerActivity; // Suppress unused variable warning
} }
return 0; return 0;