Linux xorg screensaver
Screensaver Xorg 內建螢幕保護程式
-
常見 commnad
-
xset s on, 開啟螢幕保護程式
-
xset x off, 關閉螢幕保護程式
-
xset s reset, 重設螢幕保護程式, 重設 clock, 直接喚醒進入睡眠的螢幕保護程式
設定螢幕保護
- xset s {seconds} {interval seconds}, 設定螢幕保護時間
- xset s 900 900, 閒置15分鐘進入休眠
- xset s blank, 進入休眠 黑畫面
串接 API
#pragma once
#include <functional>
#include <memory>
enum STATE : int {
E_SCREEN_SAVER_UNKNOW = -1,
E_SCREEN_SAVER_WAKE = 0,
E_SCREEN_SAVER_SLEEP = 1,
E_SCREEN_SAVER_DISABLE = 3,
};
class ScreenSaver {
public:
ScreenSaver();
~ScreenSaver();
// enable default screensaver idle 10min into screensaver
void enable();
// enable screensaver idle seconds into screensaver
void enable(int seconds);
// disable screensaver
void disable();
STATE getState();
void wake();
void nap();
void registerWakeNotifyFn(std::function<void(void)> fn);
void registerSleepNotifyFn(std::function<void(void)> fn);
// monitor screensaver state, trigger notify callback after state changed
void monitor();
private:
struct ScreenSaverImpl;
std::unique_ptr<ScreenSaverImpl> m_impl;
};
#include "screensaver.h"
#include <error.h>
#include <string.h>
#include <vector>
extern "C" {
#include <X11/X.h>
#include <X11/extensions/Xrandr.h>
#include <X11/extensions/scrnsaver.h>
}
struct ScreenSaver::ScreenSaverImpl {
Display *m_dpy;
Window m_root;
XScreenSaverInfo *m_info;
int m_saverEvent = 0;
std::vector<std::function<void(void)>> m_wakeNotifyFnVec;
std::vector<std::function<void(void)>> m_sleepNotifyFnVec;
enum TIMEOUT : int {
SERVER_DEFAULT = -1,
DEFAULT_TIMEOUT = -600,
};
enum MASK : int {
ALL = -1,
TIMEOUT = 1,
INTERVAL = 2,
PREFER_BLANK = 3,
ALLOW_EXP = 4,
};
ScreenSaverImpl()
: m_dpy{XOpenDisplay(getenv("DISPLAY"))},
m_root{RootWindow(m_dpy, DefaultScreen(m_dpy))},
m_info{XScreenSaverAllocInfo()} {
if (!subscribeScreenSaver_()) {
fprintf(stderr, "could not subsrube screensaver:%s", strerror(errno));
}
}
~ScreenSaverImpl() { XFree(m_info); }
static void setSaver_(Display *dpy, MASK mask, int value) {
int timeout, interval, prefer_blank, allow_exp;
XGetScreenSaver(dpy, &timeout, &interval, &prefer_blank, &allow_exp);
if (mask == TIMEOUT) timeout = value;
if (mask == INTERVAL) interval = value;
if (mask == PREFER_BLANK) prefer_blank = value;
if (mask == ALLOW_EXP) allow_exp = value;
if (mask == ALL) {
timeout = SERVER_DEFAULT;
interval = SERVER_DEFAULT;
prefer_blank = DefaultBlanking;
allow_exp = DefaultExposures;
}
XSetScreenSaver(dpy, timeout, interval, prefer_blank, allow_exp);
if (mask == ALL && value == DEFAULT_TIMEOUT) {
XGetScreenSaver(dpy, &timeout, &interval, &prefer_blank, &allow_exp);
if (!timeout) XSetScreenSaver(dpy, -DEFAULT_TIMEOUT, interval, prefer_blank, allow_exp);
}
return;
}
void disable() {
setSaver_(m_dpy, TIMEOUT, 0);
setSaver_(m_dpy, INTERVAL, 0);
}
void resetSaver_() {
setSaver_(m_dpy, PREFER_BLANK, DontPreferBlanking);
disable();
}
void reset() { resetSaver_(); }
void enable() { setSaver_(m_dpy, ALL, DEFAULT_TIMEOUT); }
void enable(int seconds) { setSaver(seconds); }
void setSaver(int timeout) {
setSaver_(m_dpy, ALL, 0);
setSaver_(m_dpy, TIMEOUT, timeout);
}
void wake() { XResetScreenSaver(m_dpy); }
void nap() { XActivateScreenSaver(m_dpy); }
int getState() {
try {
XInitThreads();
XScreenSaverQueryInfo(m_dpy, m_root, m_info);
return m_info->state;
} catch (const std::exception &e) {
fprintf(stderr, "could not query: %s", e.what());
return E_SCREEN_SAVER_UNKNOW;
}
}
bool subscribeScreenSaver_() {
int error = 0, event = 0;
if (!XScreenSaverQueryExtension(m_dpy, &event, &error)) {
fprintf(stderr, "could not query screensaver extension");
return false;
}
m_saverEvent = event;
XScreenSaverSelectInput(m_dpy, DefaultRootWindow(m_dpy), ScreenSaverNotifyMask);
return true;
}
void notifyStateChanged_(int state) {
if (state == STATE::E_SCREEN_SAVER_WAKE) {
for (const auto &fn : m_wakeNotifyFnVec) {
fn();
}
} else if (state == STATE::E_SCREEN_SAVER_SLEEP) {
for (const auto &fn : m_sleepNotifyFnVec) {
fn();
}
}
}
void monitor() {
int state = getState();
for (;;) {
XEvent ev;
u_long mask;
XNextEvent(m_dpy, &ev);
if (ev.type == m_saverEvent) {
XScreenSaverNotifyEvent *se = (XScreenSaverNotifyEvent *)&ev;
printf("state: %d\n", se->state);
if (se->state != state) {
printf("screensaver state changed\n");
state = se->state;
notifyStateChanged_(state);
}
}
printf("next loop\n");
}
}
void registerWakeNotifyFn(std::function<void(void)> fn) { m_wakeNotifyFnVec.push_back(fn); }
void registerSleepNotifyFn(std::function<void(void)> fn) { m_sleepNotifyFnVec.push_back(fn); }
};
ScreenSaver::ScreenSaver() : m_impl{std::make_unique<ScreenSaverImpl>()} {}
ScreenSaver::~ScreenSaver() {}
STATE ScreenSaver::getState() { return static_cast<STATE>(m_impl->getState()); }
void ScreenSaver::enable() { m_impl->enable(); }
void ScreenSaver::enable(int seconds) { m_impl->enable(seconds); }
void ScreenSaver::disable() { m_impl->disable(); }
void ScreenSaver::wake() { m_impl->wake(); }
void ScreenSaver::nap() { m_impl->nap(); }
void ScreenSaver::monitor() { m_impl->monitor(); }
void ScreenSaver::registerWakeNotifyFn(std::function<void(void)> fn) {
m_impl->registerWakeNotifyFn(fn);
}
void ScreenSaver::registerSleepNotifyFn(std::function<void(void)> fn) {
m_impl->registerSleepNotifyFn(fn);
}
example
#include <stdio.h>
#include "screensaver.h"
static void wake_() { printf("wake\n"); }
static void sleep_() { printf("sleep\n"); }
int main(int argc, char const *argv[]) {
auto screenSaver = std::make_unique<ScreenSaver>();
screenSaver->registerSleepNotifyFn(sleep_);
screenSaver->registerWakeNotifyFn(wake_);
screenSaver->monitor();
return 0;
}