mirror of
https://github.com/yshui/picom.git
synced 2024-10-27 05:24:17 -04:00
core: detect screen off
Use the DPMS extension to detect if screen is turned off, and unredirect if it is. This also helps working around the problem where OpenGL buffers lose data when screen is turned off, causing screen to flicker later when it turns back on if use-damage is enabled. Unfortunately the DPMS extension doesn't define an event, so we have to periodically poll the screen state. Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
parent
c28462673e
commit
37ecb4b496
5 changed files with 62 additions and 3 deletions
2
.github/workflows/codeql-analysis.yml
vendored
2
.github/workflows/codeql-analysis.yml
vendored
|
@ -36,7 +36,7 @@ jobs:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
|
|
||||||
# Install dependencies
|
# 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' }}
|
if: ${{ matrix.language == 'cpp' }}
|
||||||
|
|
||||||
# Autobuild
|
# Autobuild
|
||||||
|
|
|
@ -23,6 +23,7 @@ Assuming you already have all the usual building tools installed (e.g. gcc, pyth
|
||||||
* xproto
|
* xproto
|
||||||
* xcb
|
* xcb
|
||||||
* xcb-damage
|
* xcb-damage
|
||||||
|
* xcb-dpms
|
||||||
* xcb-xfixes
|
* xcb-xfixes
|
||||||
* xcb-shape
|
* xcb-shape
|
||||||
* xcb-renderutil
|
* 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
|
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
|
On Fedora, the needed packages are
|
||||||
|
|
|
@ -150,6 +150,8 @@ typedef struct session {
|
||||||
// === Event handlers ===
|
// === Event handlers ===
|
||||||
/// ev_io for X connection
|
/// ev_io for X connection
|
||||||
ev_io xiow;
|
ev_io xiow;
|
||||||
|
/// Timer for checking DPMS power level
|
||||||
|
ev_timer dpms_check_timer;
|
||||||
/// Timeout for delayed unredirection.
|
/// Timeout for delayed unredirection.
|
||||||
ev_timer unredir_timer;
|
ev_timer unredir_timer;
|
||||||
/// Timer for fading
|
/// Timer for fading
|
||||||
|
@ -236,6 +238,8 @@ typedef struct session {
|
||||||
xcb_sync_fence_t sync_fence;
|
xcb_sync_fence_t sync_fence;
|
||||||
/// Whether we are rendering the first frame after screen is redirected
|
/// Whether we are rendering the first frame after screen is redirected
|
||||||
bool first_frame;
|
bool first_frame;
|
||||||
|
/// Whether screen has been turned off
|
||||||
|
bool screen_is_off;
|
||||||
|
|
||||||
// === Operation related ===
|
// === Operation related ===
|
||||||
/// Flags related to the root window
|
/// Flags related to the root window
|
||||||
|
@ -342,6 +346,8 @@ typedef struct session {
|
||||||
int composite_error;
|
int composite_error;
|
||||||
/// Major opcode for X Composite extension.
|
/// Major opcode for X Composite extension.
|
||||||
int composite_opcode;
|
int composite_opcode;
|
||||||
|
/// Whether X DPMS extension exists
|
||||||
|
bool dpms_exists;
|
||||||
/// Whether X Shape extension exists.
|
/// Whether X Shape extension exists.
|
||||||
bool shape_exists;
|
bool shape_exists;
|
||||||
/// Event base number for X Shape extension.
|
/// Event base number for X Shape extension.
|
||||||
|
|
|
@ -16,7 +16,8 @@ cflags = []
|
||||||
|
|
||||||
required_xcb_packages = [
|
required_xcb_packages = [
|
||||||
'xcb-render', 'xcb-damage', 'xcb-randr', 'xcb-sync', 'xcb-composite',
|
'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 = [
|
required_packages = [
|
||||||
|
|
51
src/picom.c
51
src/picom.c
|
@ -21,6 +21,7 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <xcb/composite.h>
|
#include <xcb/composite.h>
|
||||||
#include <xcb/damage.h>
|
#include <xcb/damage.h>
|
||||||
|
#include <xcb/dpms.h>
|
||||||
#include <xcb/glx.h>
|
#include <xcb/glx.h>
|
||||||
#include <xcb/present.h>
|
#include <xcb/present.h>
|
||||||
#include <xcb/randr.h>
|
#include <xcb/randr.h>
|
||||||
|
@ -169,6 +170,26 @@ void cxinerama_upd_scrs(session_t *ps) {
|
||||||
free(xinerama_scrs);
|
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.
|
* 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,
|
// If there's no window to paint, and the screen isn't redirected,
|
||||||
// don't redirect it.
|
// don't redirect it.
|
||||||
unredir_possible = true;
|
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 (unredir_possible) {
|
||||||
if (ps->redirected) {
|
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_present_id);
|
||||||
xcb_prefetch_extension_data(ps->c, &xcb_sync_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_glx_id);
|
||||||
|
xcb_prefetch_extension_data(ps->c, &xcb_dpms_id);
|
||||||
|
|
||||||
ext_info = xcb_get_extension_data(ps->c, &xcb_render_id);
|
ext_info = xcb_get_extension_data(ps->c, &xcb_render_id);
|
||||||
if (!ext_info || !ext_info->present) {
|
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;
|
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
|
// Parse configuration file
|
||||||
win_option_mask_t winopt_mask[NUM_WINTYPES] = {{0}};
|
win_option_mask_t winopt_mask[NUM_WINTYPES] = {{0}};
|
||||||
bool shadow_enabled = false, fading_enable = false, hasneg = false;
|
bool shadow_enabled = false, fading_enable = false, hasneg = false;
|
||||||
|
@ -2462,6 +2512,7 @@ static void session_destroy(session_t *ps) {
|
||||||
// Stop libev event handlers
|
// Stop libev event handlers
|
||||||
ev_timer_stop(ps->loop, &ps->unredir_timer);
|
ev_timer_stop(ps->loop, &ps->unredir_timer);
|
||||||
ev_timer_stop(ps->loop, &ps->fade_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_idle_stop(ps->loop, &ps->draw_idle);
|
||||||
ev_prepare_stop(ps->loop, &ps->event_check);
|
ev_prepare_stop(ps->loop, &ps->event_check);
|
||||||
ev_signal_stop(ps->loop, &ps->usr1_signal);
|
ev_signal_stop(ps->loop, &ps->usr1_signal);
|
||||||
|
|
Loading…
Reference in a new issue