现代macOS如何实现帧渲染时重置屏幕保护程序计时器功能?
macOS 动态重置屏幕保护计时器实现方案
在旧版本 macOS 中,开发者通常使用如下代码重置屏幕保护程序计时器:
UpdateSystemActivity(UsrActivity);
现代 macOS 版本中常见的推荐方案有两种:
第一种:
static IOPMAssertionID activity_assertion_id = kIOPMNullAssertionID; IOReturn r = IOPMAssertionDeclareUserActivity(CFSTR("FractalUserActivity"), kIOPMUserActiveLocal, &activity_assertion_id);
第二种:
IOReturn result = IOPMAssertionCreateWithName( kIOPMAssertionTypeNoDisplaySleep, kIOPMAssertionLevelOn, CFSTR("FractalNewFrameActivity"), &power_assertion_id); IOPMAssertionRelease(power_assertion_id);
但这两种方案都无法满足「每次渲染新帧重置屏保计时器,无新帧时按系统设置时长正常触发屏保」的需求:
IOPMAssertionDeclareUserActivity从 macOS 10.13 开始仅重置系统睡眠计时器,不再影响屏保对应的显示空闲计时器- 频繁创建释放
kIOPMAssertionTypeNoDisplaySleep断言没有重置计时器的效果,只有持续持有该断言才会强制阻止显示器休眠,不符合空闲后允许触发屏保的需求
可行解决方案
使用 CoreGraphics 框架提供的公开API CGDisplayResetActivity,每次渲染完成新帧后调用即可重置系统显示空闲计时器,完全适配用户自行设置的屏保触发时长,无需硬编码参数。
代码示例
#include <CoreGraphics/CoreGraphics.h> // 每次渲染新帧后调用该方法即可重置屏保计时器 void reset_screensaver_timer() { // 单显示器场景直接传入主显示器ID CGDisplayResetActivity(kCGDirectMainDisplay); // 多显示器场景可遍历所有活跃显示器调用 // uint32_t displayCount; // CGGetActiveDisplayList(0, NULL, &displayCount); // CGDirectDisplayID* displays = malloc(displayCount * sizeof(CGDirectDisplayID)); // CGGetActiveDisplayList(displayCount, displays, &displayCount); // for (int i = 0; i < displayCount; i++) { // CGDisplayResetActivity(displays[i]); // } // free(displays); }
注意事项
- 该API为系统公开API,可正常提交Mac App Store,无审核风险
- 调用频率无需过高,每30秒调用一次即可满足绝大多数场景需求,不需要跟随帧率每秒调用数十次,减少不必要的性能消耗
内容的提问来源于stack exchange,提问作者Nicholas Pipitone
相关产品推荐
相关产品推荐

