Merge pull request #969 from yshui/detect-dpms-off

This commit is contained in:
Yuxuan Shui
2022-12-21 18:12:51 +00:00
committed by GitHub
5 changed files with 62 additions and 3 deletions

View File

@@ -36,7 +36,7 @@ jobs:
languages: ${{ matrix.language }}
# Install dependencies
- run: sudo apt update && sudo apt install libxext-dev libxcb1-dev libxcb-damage0-dev libxcb-xfixes0-dev libxcb-shape0-dev libxcb-render-util0-dev libxcb-render0-dev libxcb-randr0-dev libxcb-composite0-dev libxcb-image0-dev libxcb-present-dev libxcb-xinerama0-dev libxcb-glx0-dev libpixman-1-dev libdbus-1-dev libconfig-dev libgl1-mesa-dev libpcre2-dev libevdev-dev uthash-dev libev-dev libx11-xcb-dev meson ninja-build
- run: sudo apt update && sudo apt install libxext-dev libxcb1-dev libxcb-dpms0-dev libxcb-damage0-dev libxcb-xfixes0-dev libxcb-shape0-dev libxcb-render-util0-dev libxcb-render0-dev libxcb-randr0-dev libxcb-composite0-dev libxcb-image0-dev libxcb-present-dev libxcb-xinerama0-dev libxcb-glx0-dev libpixman-1-dev libdbus-1-dev libconfig-dev libgl1-mesa-dev libpcre2-dev libevdev-dev uthash-dev libev-dev libx11-xcb-dev meson ninja-build
if: ${{ matrix.language == 'cpp' }}
# Autobuild

View File

@@ -23,6 +23,7 @@ Assuming you already have all the usual building tools installed (e.g. gcc, pyth
* xproto
* xcb
* xcb-damage
* xcb-dpms
* xcb-xfixes
* xcb-shape
* xcb-renderutil
@@ -44,7 +45,7 @@ Assuming you already have all the usual building tools installed (e.g. gcc, pyth
On Debian based distributions (e.g. Ubuntu), the needed packages are
```
libxext-dev libxcb1-dev libxcb-damage0-dev libxcb-xfixes0-dev libxcb-shape0-dev libxcb-render-util0-dev libxcb-render0-dev libxcb-randr0-dev libxcb-composite0-dev libxcb-image0-dev libxcb-present-dev libxcb-xinerama0-dev libxcb-glx0-dev libpixman-1-dev libdbus-1-dev libconfig-dev libgl-dev libegl-dev libpcre2-dev libevdev-dev uthash-dev libev-dev libx11-xcb-dev meson
libxext-dev libxcb1-dev libxcb-damage0-dev libxcb-dpms0-dev libxcb-xfixes0-dev libxcb-shape0-dev libxcb-render-util0-dev libxcb-render0-dev libxcb-randr0-dev libxcb-composite0-dev libxcb-image0-dev libxcb-present-dev libxcb-xinerama0-dev libxcb-glx0-dev libpixman-1-dev libdbus-1-dev libconfig-dev libgl-dev libegl-dev libpcre2-dev libevdev-dev uthash-dev libev-dev libx11-xcb-dev meson
```
On Fedora, the needed packages are

View File

@@ -150,6 +150,8 @@ typedef struct session {
// === Event handlers ===
/// ev_io for X connection
ev_io xiow;
/// Timer for checking DPMS power level
ev_timer dpms_check_timer;
/// Timeout for delayed unredirection.
ev_timer unredir_timer;
/// Timer for fading
@@ -236,6 +238,8 @@ typedef struct session {
xcb_sync_fence_t sync_fence;
/// Whether we are rendering the first frame after screen is redirected
bool first_frame;
/// Whether screen has been turned off
bool screen_is_off;
// === Operation related ===
/// Flags related to the root window
@@ -342,6 +346,8 @@ typedef struct session {
int composite_error;
/// Major opcode for X Composite extension.
int composite_opcode;
/// Whether X DPMS extension exists
bool dpms_exists;
/// Whether X Shape extension exists.
bool shape_exists;
/// Event base number for X Shape extension.

View File

@@ -16,7 +16,8 @@ cflags = []
required_xcb_packages = [
'xcb-render', 'xcb-damage', 'xcb-randr', 'xcb-sync', 'xcb-composite',
'xcb-shape', 'xcb-xinerama', 'xcb-xfixes', 'xcb-present', 'xcb-glx', 'xcb'
'xcb-shape', 'xcb-xinerama', 'xcb-xfixes', 'xcb-present', 'xcb-glx',
'xcb-dpms', 'xcb'
]
required_packages = [

View File

@@ -21,6 +21,7 @@
#include <unistd.h>
#include <xcb/composite.h>
#include <xcb/damage.h>
#include <xcb/dpms.h>
#include <xcb/glx.h>
#include <xcb/present.h>
#include <xcb/randr.h>
@@ -169,6 +170,26 @@ void cxinerama_upd_scrs(session_t *ps) {
free(xinerama_scrs);
}
static inline bool dpms_screen_is_off(xcb_dpms_info_reply_t *info) {
// state is a bool indicating whether dpms is enabled
return info->state && (info->power_level != XCB_DPMS_DPMS_MODE_ON);
}
void check_dpms_status(EV_P attr_unused, ev_timer *w, int revents attr_unused) {
auto ps = session_ptr(w, dpms_check_timer);
auto r = xcb_dpms_info_reply(ps->c, xcb_dpms_info(ps->c), NULL);
if (!r) {
log_fatal("Failed to query DPMS status.");
abort();
}
auto now_screen_is_off = dpms_screen_is_off(r);
if (ps->screen_is_off != now_screen_is_off) {
ps->screen_is_off = now_screen_is_off;
queue_redraw(ps);
}
free(r);
}
/**
* Find matched window.
*
@@ -920,6 +941,19 @@ paint_preprocess(session_t *ps, bool *fade_running, bool *animation) {
// If there's no window to paint, and the screen isn't redirected,
// don't redirect it.
unredir_possible = true;
} else if (ps->screen_is_off) {
// Screen is off, unredirect
// We do this unconditionally disregarding "unredir_if_possible"
// because it's important for correctness, because we need to
// workaround problems X server has around screen off.
//
// Known problems:
// 1. Sometimes OpenGL front buffer can lose content, and if we
// are doing partial updates (i.e. use-damage = true), the
// result will be wrong.
// 2. For frame pacing, X server sends bogus
// PresentCompleteNotify events when screen is off.
unredir_possible = true;
}
if (unredir_possible) {
if (ps->redirected) {
@@ -1800,6 +1834,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
xcb_prefetch_extension_data(ps->c, &xcb_present_id);
xcb_prefetch_extension_data(ps->c, &xcb_sync_id);
xcb_prefetch_extension_data(ps->c, &xcb_glx_id);
xcb_prefetch_extension_data(ps->c, &xcb_dpms_id);
ext_info = xcb_get_extension_data(ps->c, &xcb_render_id);
if (!ext_info || !ext_info->present) {
@@ -1868,6 +1903,21 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
ps->glx_event = ext_info->first_event;
}
ext_info = xcb_get_extension_data(ps->c, &xcb_dpms_id);
ps->dpms_exists = ext_info && ext_info->present;
if (ps->dpms_exists) {
auto r = xcb_dpms_info_reply(ps->c, xcb_dpms_info(ps->c), NULL);
if (!r) {
log_fatal("Failed to query DPMS info");
goto err;
}
ps->screen_is_off = dpms_screen_is_off(r);
// Check screen status every half second
ev_timer_init(&ps->dpms_check_timer, check_dpms_status, 0, 0.5);
ev_timer_start(ps->loop, &ps->dpms_check_timer);
free(r);
}
// Parse configuration file
win_option_mask_t winopt_mask[NUM_WINTYPES] = {{0}};
bool shadow_enabled = false, fading_enable = false, hasneg = false;
@@ -2462,6 +2512,7 @@ static void session_destroy(session_t *ps) {
// Stop libev event handlers
ev_timer_stop(ps->loop, &ps->unredir_timer);
ev_timer_stop(ps->loop, &ps->fade_timer);
ev_timer_stop(ps->loop, &ps->dpms_check_timer);
ev_idle_stop(ps->loop, &ps->draw_idle);
ev_prepare_stop(ps->loop, &ps->event_check);
ev_signal_stop(ps->loop, &ps->usr1_signal);