Merge pull request #969 from yshui/detect-dpms-off
This commit is contained in:
2
.github/workflows/codeql-analysis.yml
vendored
2
.github/workflows/codeql-analysis.yml
vendored
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
51
src/picom.c
51
src/picom.c
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user