From 986b3c1cb3b4771eb35de04e7f8b284ce781d208 Mon Sep 17 00:00:00 2001 From: Maxim Solovyov Date: Fri, 13 Jan 2023 14:27:45 +0300 Subject: [PATCH] core: drop xinerama there are two x extensions for working with monitors (especially multiple): xinerama and randr. xinerama is old, feature-poor and in general isn't used anymore compared to the randr: new, feature-rich and widely-used. for some reason we were using both of them, so let's drop xinerama to keep things simple, clean and small. and to be modern. the drop was done in three steps: * first step was to replace all the xinerama-based code with the randr-based one and to replace or remove all the xinerama mentions; * second step was to replace the xinerama's terminology with the randr's one. xinerama was referring only to the word "screen", while randr refers to multiple words and i think the word "monitor" is the most suitable for us and, hopefully, clear both to a contributor and to an end user; * third step was to refactor the new randr-based code if needed and to address related todo's (mostly about moving related functions elsewhere). all the steps were done well except addressing a leftover todo about moving the win_update_monitor function to the x.c which wasn't done. the xinerama-shadow-crop option was renamed to crop-shadow-to-monitor, but it's previous name is still accepted, has effect and the deprecation message is printed to preserve backwards-compatibility. --- .github/workflows/codeql-analysis.yml | 2 +- README.md | 3 +- man/picom.1.asciidoc | 4 +- picom.sample.conf | 5 +- src/backend/backend.c | 12 ++-- src/common.h | 10 ++-- src/config.c | 2 +- src/config.h | 4 +- src/config_libconfig.c | 8 ++- src/dbus.c | 2 +- src/diagnostic.c | 12 ++-- src/event.c | 4 +- src/meson.build | 3 +- src/options.c | 17 ++++-- src/picom.c | 80 ++++----------------------- src/picom.h | 2 - src/render.c | 19 ++++--- src/win.c | 44 ++++++--------- src/win.h | 10 +++- src/x.c | 38 +++++++++++++ src/x.h | 10 ++++ tests/configs/parsing_test.conf | 5 +- 22 files changed, 143 insertions(+), 153 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 224c4628..2e3dfe7e 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -36,7 +36,7 @@ jobs: languages: ${{ matrix.language }} # Install dependencies - - 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 + - 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-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 diff --git a/README.md b/README.md index a23dfd05..0fecde19 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,6 @@ Assuming you already have all the usual building tools installed (e.g. gcc, pyth * xcb-composite * xcb-image * xcb-present -* xcb-xinerama * xcb-glx * pixman * libdbus (optional, disable with the `-Ddbus=false` meson configure flag) @@ -45,7 +44,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-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 +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-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 diff --git a/man/picom.1.asciidoc b/man/picom.1.asciidoc index fdf0198d..e7a91315 100644 --- a/man/picom.1.asciidoc +++ b/man/picom.1.asciidoc @@ -217,8 +217,8 @@ May also be one of the predefined kernels: `3x3box` (default), `5x5box`, `7x7box *--shadow-exclude-reg* 'GEOMETRY':: Specify a X geometry that describes the region in which shadow should not be painted in, such as a dock window region. Use `--shadow-exclude-reg x10+0-0`, for example, if the 10 pixels on the bottom of the screen should not have shadows painted on. -*--xinerama-shadow-crop*:: - Crop shadow of a window fully on a particular Xinerama screen to the screen. +*--crop-shadow-to-monitor*:: + Crop shadow of a window fully on a particular monitor to that monitor. This is currently implemented using the X RandR extension. *--backend* 'BACKEND':: Specify the backend to use: `xrender`, `glx`, or `xr_glx_hybrid`. `xrender` is the default one. diff --git a/picom.sample.conf b/picom.sample.conf index f0c7a795..5d02e7d7 100644 --- a/picom.sample.conf +++ b/picom.sample.conf @@ -61,8 +61,9 @@ shadow-exclude = [ # # shadow-exclude-reg = "" -# Crop shadow of a window fully on a particular Xinerama screen to the screen. -# xinerama-shadow-crop = false +# Crop shadow of a window fully on a particular monitor to that monitor. This is +# currently implemented using the X RandR extension. +# crop-shadow-to-monitor = false ################################# diff --git a/src/backend/backend.c b/src/backend/backend.c index 83af8fb6..59ddcaf2 100644 --- a/src/backend/backend.c +++ b/src/backend/backend.c @@ -327,18 +327,18 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) { ®_shadow_clip); } - if (ps->o.xinerama_shadow_crop && w->xinerama_scr >= 0 && - w->xinerama_scr < ps->xinerama_nscrs) { - // There can be a window where number of screens is - // updated, but the screen number attached to the windows + if (ps->o.crop_shadow_to_monitor && w->randr_monitor >= 0 && + w->randr_monitor < ps->randr_nmonitors) { + // There can be a window where number of monitors is + // updated, but the monitor number attached to the window // have not. // - // Window screen number will be updated eventually, so + // Window monitor number will be updated eventually, so // here we just check to make sure we don't access out of // bounds. pixman_region32_intersect( ®_shadow, ®_shadow, - &ps->xinerama_scr_regs[w->xinerama_scr]); + &ps->randr_monitor_regs[w->randr_monitor]); } if (ps->o.transparent_clipping) { diff --git a/src/common.h b/src/common.h index 2e5495e6..8f307dc9 100644 --- a/src/common.h +++ b/src/common.h @@ -368,12 +368,10 @@ typedef struct session { int glx_event; /// Error base number for X GLX extension. int glx_error; - /// Whether X Xinerama extension exists. - bool xinerama_exists; - /// Xinerama screen regions. - region_t *xinerama_scr_regs; - /// Number of Xinerama screens. - int xinerama_nscrs; + /// Number of X RandR monitors. + int randr_nmonitors; + /// X RandR monitor regions. + region_t *randr_monitor_regs; /// Whether X Sync extension exists. bool xsync_exists; /// Event base number for X Sync extension. diff --git a/src/config.c b/src/config.c index d9b2dd91..dd231470 100644 --- a/src/config.c +++ b/src/config.c @@ -747,7 +747,7 @@ char *parse_config(options_t *opt, const char *config_file, bool *shadow_enable, .shadow_opacity = .75, .shadow_blacklist = NULL, .shadow_ignore_shaped = false, - .xinerama_shadow_crop = false, + .crop_shadow_to_monitor = false, .shadow_clip_list = NULL, .corner_radius = 0, diff --git a/src/config.h b/src/config.h index 3f11e1e7..632800c3 100644 --- a/src/config.h +++ b/src/config.h @@ -153,8 +153,8 @@ typedef struct options { c2_lptr_t *shadow_blacklist; /// Whether bounding-shaped window should be ignored. bool shadow_ignore_shaped; - /// Whether to crop shadow to the very Xinerama screen. - bool xinerama_shadow_crop; + /// Whether to crop shadow to the very X RandR monitor. + bool crop_shadow_to_monitor; /// Don't draw shadow over these windows. A linked list of conditions. c2_lptr_t *shadow_clip_list; diff --git a/src/config_libconfig.c b/src/config_libconfig.c index ba987a89..589e139b 100644 --- a/src/config_libconfig.c +++ b/src/config_libconfig.c @@ -384,8 +384,12 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad lcfg_lookup_bool(&cfg, "shadow-ignore-shaped", &opt->shadow_ignore_shaped); // --detect-rounded-corners lcfg_lookup_bool(&cfg, "detect-rounded-corners", &opt->detect_rounded_corners); - // --xinerama-shadow-crop - lcfg_lookup_bool(&cfg, "xinerama-shadow-crop", &opt->xinerama_shadow_crop); + // --crop-shadow-to-monitor + if (lcfg_lookup_bool(&cfg, "xinerama-shadow-crop", &opt->crop_shadow_to_monitor)) { + log_warn("xinerama-shadow-crop is deprecated. Use crop-shadow-to-monitor " + "instead."); + } + lcfg_lookup_bool(&cfg, "crop-shadow-to-monitor", &opt->crop_shadow_to_monitor); // --detect-client-opacity lcfg_lookup_bool(&cfg, "detect-client-opacity", &opt->detect_client_opacity); // --refresh-rate diff --git a/src/dbus.c b/src/dbus.c index 2b17341e..baff2bcc 100644 --- a/src/dbus.c +++ b/src/dbus.c @@ -1202,7 +1202,7 @@ static bool cdbus_process_opts_get(session_t *ps, DBusMessage *msg) { cdbus_m_opts_get_do(shadow_offset_x, cdbus_reply_int32); cdbus_m_opts_get_do(shadow_offset_y, cdbus_reply_int32); cdbus_m_opts_get_do(shadow_opacity, cdbus_reply_double); - cdbus_m_opts_get_do(xinerama_shadow_crop, cdbus_reply_bool); + cdbus_m_opts_get_do(crop_shadow_to_monitor, cdbus_reply_bool); cdbus_m_opts_get_do(fade_delta, cdbus_reply_int32); cdbus_m_opts_get_do(fade_in_step, cdbus_reply_double); diff --git a/src/diagnostic.c b/src/diagnostic.c index 79ac5ac8..1159d9ea 100644 --- a/src/diagnostic.c +++ b/src/diagnostic.c @@ -2,21 +2,21 @@ // Copyright (c) 2018 Yuxuan Shui #include -#include #include +#include #include "backend/driver.h" -#include "diagnostic.h" -#include "config.h" -#include "picom.h" #include "common.h" +#include "config.h" +#include "diagnostic.h" +#include "picom.h" void print_diagnostics(session_t *ps, const char *config_file, bool compositor_running) { printf("**Version:** " PICOM_VERSION "\n"); - //printf("**CFLAGS:** %s\n", "??"); + // printf("**CFLAGS:** %s\n", "??"); printf("\n### Extensions:\n\n"); printf("* Shape: %s\n", ps->shape_exists ? "Yes" : "No"); - printf("* XRandR: %s\n", ps->randr_exists ? "Yes" : "No"); + printf("* RandR: %s\n", ps->randr_exists ? "Yes" : "No"); printf("* Present: %s\n", ps->present_exists ? "Present" : "Not Present"); printf("\n### Misc:\n\n"); printf("* Use Overlay: %s\n", ps->overlay != XCB_NONE ? "Yes" : "No"); diff --git a/src/event.c b/src/event.c index 082686b3..afaa02c4 100644 --- a/src/event.c +++ b/src/event.c @@ -237,8 +237,8 @@ static void configure_win(session_t *ps, xcb_configure_notify_event_t *ce) { win_set_flags(mw, WIN_FLAGS_SIZE_STALE); } - // Recalculate which screen this window is on - win_update_screen(ps->xinerama_nscrs, ps->xinerama_scr_regs, mw); + // Recalculate which monitor this window is on + win_update_monitor(ps->randr_nmonitors, ps->randr_monitor_regs, mw); } // override_redirect flag cannot be changed after window creation, as far diff --git a/src/meson.build b/src/meson.build index b6b24b56..0cd87c89 100644 --- a/src/meson.build +++ b/src/meson.build @@ -16,8 +16,7 @@ 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-dpms', 'xcb' + 'xcb-shape', 'xcb-xfixes', 'xcb-present', 'xcb-glx', 'xcb-dpms', 'xcb' ] required_packages = [ diff --git a/src/options.c b/src/options.c index e69bbb02..d2020c6a 100644 --- a/src/options.c +++ b/src/options.c @@ -72,6 +72,9 @@ static const struct picom_option picom_options[] = { "managers not passing _NET_WM_WINDOW_OPACITY of client windows to frame"}, {"refresh-rate" , required_argument, 269, NULL , NULL}, {"vsync" , optional_argument, 270, NULL , "Enable VSync"}, + {"crop-shadow-to-monitor" , no_argument , 271, NULL , "Crop shadow of a window fully on a particular monitor to that monitor. " + "This is currently implemented using the X RandR extension"}, + {"xinerama-shadow-crop" , no_argument , 272, NULL , NULL}, {"sw-opti" , no_argument , 274, NULL , NULL}, {"vsync-aggressive" , no_argument , 275, NULL , NULL}, {"use-ewmh-active-win" , no_argument , 276, NULL , "Use _NET_WM_ACTIVE_WINDOW on the root window to determine which window is " @@ -119,7 +122,6 @@ static const struct picom_option picom_options[] = { {"opacity-rule" , required_argument, 304, "OPACITY:COND", "Specify a list of opacity rules, see man page for more details"}, {"shadow-exclude-reg" , required_argument, 305, NULL , NULL}, {"paint-exclude" , required_argument, 306, NULL , NULL}, - {"xinerama-shadow-crop" , no_argument , 307, NULL , "Crop shadow of a window fully on a particular Xinerama screen to the screen."}, {"unredir-if-possible-exclude" , required_argument, 308, "COND" , "Conditions of windows that shouldn't be considered full-screen for " "unredirecting screen."}, {"unredir-if-possible-delay" , required_argument, 309, NULL, "Delay before unredirecting the window, in milliseconds. Defaults to 0."}, @@ -485,8 +487,8 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable, P_CASEBOOL(267, detect_rounded_corners); P_CASEBOOL(268, detect_client_opacity); case 269: - log_warn("--refresh-rate has been deprecated, please remove it from" - "your command line options"); + log_warn("--refresh-rate has been deprecated, please remove it " + "from your command line options"); break; case 270: if (optarg) { @@ -499,6 +501,12 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable, opt->vsync = true; } break; + P_CASEBOOL(271, crop_shadow_to_monitor); + case 272: + opt->crop_shadow_to_monitor = true; + log_warn("--xinerama-shadow-crop is deprecated. Use " + "--crop-shadow-to-monitor instead."); + break; case 274: log_warn("--sw-opti has been deprecated, please remove it from the " "command line options"); @@ -506,7 +514,7 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable, case 275: // --vsync-aggressive log_error("--vsync-aggressive has been removed, please remove it" - " from the command line options"); + " from the command line options"); failed = true; break; P_CASEBOOL(276, use_ewmh_active_win); @@ -625,7 +633,6 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable, // --paint-exclude condlst_add(&opt->paint_blacklist, optarg); break; - P_CASEBOOL(307, xinerama_shadow_crop); case 308: // --unredir-if-possible-exclude condlst_add(&opt->unredir_if_possible_blacklist, optarg); diff --git a/src/picom.c b/src/picom.c index 149ffc55..8a7a9670 100644 --- a/src/picom.c +++ b/src/picom.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include @@ -111,21 +110,6 @@ void quit(session_t *ps) { ev_break(ps->loop, EVBREAK_ALL); } -/** - * Free Xinerama screen info. - * - * XXX consider moving to x.c - */ -static inline void free_xinerama_info(session_t *ps) { - if (ps->xinerama_scr_regs) { - for (int i = 0; i < ps->xinerama_nscrs; ++i) - pixman_region32_fini(&ps->xinerama_scr_regs[i]); - free(ps->xinerama_scr_regs); - ps->xinerama_scr_regs = NULL; - } - ps->xinerama_nscrs = 0; -} - /** * Get current system clock in milliseconds. */ @@ -135,41 +119,6 @@ static inline int64_t get_time_ms(void) { return (int64_t)tp.tv_sec * 1000 + (int64_t)tp.tv_nsec / 1000000; } -// XXX Move to x.c -void cxinerama_upd_scrs(session_t *ps) { - // XXX Consider deprecating Xinerama, switch to RandR when necessary - free_xinerama_info(ps); - - if (!ps->o.xinerama_shadow_crop || !ps->xinerama_exists) - return; - - xcb_xinerama_is_active_reply_t *active = - xcb_xinerama_is_active_reply(ps->c, xcb_xinerama_is_active(ps->c), NULL); - if (!active || !active->state) { - free(active); - return; - } - free(active); - - auto xinerama_scrs = - xcb_xinerama_query_screens_reply(ps->c, xcb_xinerama_query_screens(ps->c), NULL); - if (!xinerama_scrs) { - return; - } - - xcb_xinerama_screen_info_t *scrs = - xcb_xinerama_query_screens_screen_info(xinerama_scrs); - ps->xinerama_nscrs = xcb_xinerama_query_screens_screen_info_length(xinerama_scrs); - - ps->xinerama_scr_regs = ccalloc(ps->xinerama_nscrs, region_t); - for (int i = 0; i < ps->xinerama_nscrs; ++i) { - const xcb_xinerama_screen_info_t *const s = &scrs[i]; - pixman_region32_init_rect(&ps->xinerama_scr_regs[i], s->x_org, s->y_org, - s->width, s->height); - } - 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); @@ -691,8 +640,8 @@ static void configure_root(session_t *ps) { static void handle_root_flags(session_t *ps) { if ((ps->root_flags & ROOT_FLAGS_SCREEN_CHANGE) != 0) { - if (ps->o.xinerama_shadow_crop) { - cxinerama_upd_scrs(ps); + if (ps->o.crop_shadow_to_monitor) { + x_update_randr_monitors(ps); } ps->root_flags &= ~(uint64_t)ROOT_FLAGS_SCREEN_CHANGE; } @@ -1834,7 +1783,6 @@ static session_t *session_init(int argc, char **argv, Display *dpy, xcb_prefetch_extension_data(ps->c, &xcb_shape_id); xcb_prefetch_extension_data(ps->c, &xcb_xfixes_id); xcb_prefetch_extension_data(ps->c, &xcb_randr_id); - xcb_prefetch_extension_data(ps->c, &xcb_xinerama_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_glx_id); @@ -2092,18 +2040,10 @@ static session_t *session_init(int argc, char **argv, Display *dpy, } // Query X RandR - if (ps->o.xinerama_shadow_crop) { - if (!ps->randr_exists) { - log_fatal("No XRandR extension. xinerama-shadow-crop cannot be " - "enabled."); - goto err; - } - } - - // Query X Xinerama extension - if (ps->o.xinerama_shadow_crop) { - ext_info = xcb_get_extension_data(ps->c, &xcb_xinerama_id); - ps->xinerama_exists = ext_info && ext_info->present; + if (ps->o.crop_shadow_to_monitor && !ps->randr_exists) { + log_fatal("No X RandR extension. crop-shadow-to-monitor cannot be " + "enabled."); + goto err; } rebuild_screen_reg(ps); @@ -2198,12 +2138,12 @@ static session_t *session_init(int argc, char **argv, Display *dpy, } // Monitor screen changes if vsync_sw is enabled and we are using - // an auto-detected refresh rate, or when Xinerama features are enabled - if (ps->randr_exists && ps->o.xinerama_shadow_crop) { + // an auto-detected refresh rate, or when X RandR features are enabled + if (ps->randr_exists && ps->o.crop_shadow_to_monitor) { xcb_randr_select_input(ps->c, ps->root, XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE); } - cxinerama_upd_scrs(ps); + x_update_randr_monitors(ps); { xcb_render_create_picture_value_list_t pa = { @@ -2436,7 +2376,7 @@ static void session_destroy(session_t *ps) { } free(ps->o.blur_kerns); free(ps->o.glx_fshader_win_str); - free_xinerama_info(ps); + x_free_randr_info(ps); // Release custom window shaders free(ps->o.window_shader_fg); diff --git a/src/picom.h b/src/picom.h index b5a1e8a7..6f14cd08 100644 --- a/src/picom.h +++ b/src/picom.h @@ -42,8 +42,6 @@ void circulate_win(session_t *ps, xcb_circulate_notify_event_t *ce); void root_damaged(session_t *ps); -void cxinerama_upd_scrs(session_t *ps); - void queue_redraw(session_t *ps); void discard_pending(session_t *ps, uint32_t sequence); diff --git a/src/render.c b/src/render.c index db627de3..afde7db8 100644 --- a/src/render.c +++ b/src/render.c @@ -1098,18 +1098,19 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) { if (!ps->o.wintype_option[w->window_type].full_shadow) pixman_region32_subtract(®_tmp, ®_tmp, &bshape_no_corners); - if (ps->o.xinerama_shadow_crop && w->xinerama_scr >= 0 && - w->xinerama_scr < ps->xinerama_nscrs) - // There can be a window where number of screens - // is updated, but the screen number attached to - // the windows have not. + if (ps->o.crop_shadow_to_monitor && w->randr_monitor >= 0 && + w->randr_monitor < ps->randr_nmonitors) { + // There can be a window where number of monitors is + // updated, but the monitor number attached to the window + // have not. // - // Window screen number will be updated - // eventually, so here we just check to make sure - // we don't access out of bounds. + // Window monitor number will be updated eventually, so + // here we just check to make sure we don't access out of + // bounds. pixman_region32_intersect( ®_tmp, ®_tmp, - &ps->xinerama_scr_regs[w->xinerama_scr]); + &ps->randr_monitor_regs[w->randr_monitor]); + } // Detect if the region is empty before painting if (pixman_region32_not_empty(®_tmp)) { diff --git a/src/win.c b/src/win.c index cef94fe0..a52b4e1a 100644 --- a/src/win.c +++ b/src/win.c @@ -14,7 +14,6 @@ #include #include #include -#include #include "atom.h" #include "backend/backend.h" @@ -517,7 +516,7 @@ void win_process_update_flags(session_t *ps, struct managed_win *w) { win_clear_flags(w, WIN_FLAGS_POSITION_STALE); } - win_update_screen(ps->xinerama_nscrs, ps->xinerama_scr_regs, w); + win_update_monitor(ps->randr_nmonitors, ps->randr_monitor_regs, w); } if (win_check_flags_all(w, WIN_FLAGS_PROPERTY_STALE)) { @@ -1550,7 +1549,7 @@ struct win *fill_win(session_t *ps, struct win *w) { .shadow = false, .clip_shadow_above = false, .fg_shader = NULL, - .xinerama_scr = -1, + .randr_monitor = -1, .mode = WMODE_TRANS, .ever_damaged = false, .client_win = XCB_NONE, @@ -2434,33 +2433,24 @@ bool win_skip_fading(session_t *ps, struct managed_win *w) { return win_check_fade_finished(ps, w); } -/** - * Get the Xinerama screen a window is on. - * - * Return an index >= 0, or -1 if not found. - * - * TODO(yshui) move to x.c - * TODO(yshui) use xrandr - */ -void win_update_screen(int nscreens, region_t *screens, struct managed_win *w) { - w->xinerama_scr = -1; - - for (int i = 0; i < nscreens; i++) { - auto e = pixman_region32_extents(&screens[i]); - if (e->x1 <= w->g.x && e->y1 <= w->g.y && e->x2 >= w->g.x + w->widthb && - e->y2 >= w->g.y + w->heightb) { - w->xinerama_scr = i; - log_debug("Window %#010x (%s), %dx%d+%dx%d, is on screen " - "%d " - "(%dx%d+%dx%d)", - w->base.id, w->name, w->g.x, w->g.y, w->widthb, w->heightb, - i, e->x1, e->y1, e->x2 - e->x1, e->y2 - e->y1); +// TODO(absolutelynothelix): rename to x_update_win_(randr_?)monitor and move to +// the x.c. +void win_update_monitor(int nmons, region_t *mons, struct managed_win *mw) { + mw->randr_monitor = -1; + for (int i = 0; i < nmons; i++) { + auto e = pixman_region32_extents(&mons[i]); + if (e->x1 <= mw->g.x && e->y1 <= mw->g.y && + e->x2 >= mw->g.x + mw->widthb && e->y2 >= mw->g.y + mw->heightb) { + mw->randr_monitor = i; + log_debug("Window %#010x (%s), %dx%d+%dx%d, is entirely on the " + "monitor %d (%dx%d+%dx%d)", + mw->base.id, mw->name, mw->g.x, mw->g.y, mw->widthb, + mw->heightb, i, e->x1, e->y1, e->x2 - e->x1, e->y2 - e->y1); return; } } - log_debug("Window %#010x (%s), %dx%d+%dx%d, is not contained by any " - "screen", - w->base.id, w->name, w->g.x, w->g.y, w->g.width, w->g.height); + log_debug("Window %#010x (%s), %dx%d+%dx%d, is not entirely on any monitor", + mw->base.id, mw->name, mw->g.x, mw->g.y, mw->widthb, mw->heightb); } /// Map an already registered window diff --git a/src/win.h b/src/win.h index abc03d97..fe733408 100644 --- a/src/win.h +++ b/src/win.h @@ -123,8 +123,8 @@ struct managed_win { struct win_geometry g; /// Updated geometry received in events struct win_geometry pending_g; - /// Xinerama screen this window is on. - int xinerama_scr; + /// X RandR monitor this window is on. + int randr_monitor; /// Window visual pict format const xcb_render_pictforminfo_t *pictfmt; /// Client window visual pict format @@ -345,7 +345,11 @@ void win_recheck_client(session_t *ps, struct managed_win *w); */ double attr_pure win_calc_opacity_target(session_t *ps, const struct managed_win *w); bool attr_pure win_should_dim(session_t *ps, const struct managed_win *w); -void win_update_screen(int nscreens, region_t *screens, struct managed_win *w); + +// TODO(absolutelynothelix): rename to x_update_win_(randr_?)monitor and move to +// the x.h. +void win_update_monitor(int nmons, region_t *mons, struct managed_win *mw); + /** * Retrieve the bounding shape of a window. */ diff --git a/src/x.c b/src/x.c index d00c9c2f..6121e773 100644 --- a/src/x.c +++ b/src/x.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -787,3 +788,40 @@ xcb_screen_t *x_screen_of_display(xcb_connection_t *c, int screen) { return NULL; } + +void x_update_randr_monitors(session_t *ps) { + x_free_randr_info(ps); + + if (!ps->o.crop_shadow_to_monitor || !ps->randr_exists) { + return; + } + + xcb_randr_get_monitors_reply_t *r = xcb_randr_get_monitors_reply( + ps->c, xcb_randr_get_monitors(ps->c, ps->root, true), NULL); + if (!r) { + return; + } + + ps->randr_nmonitors = xcb_randr_get_monitors_monitors_length(r); + ps->randr_monitor_regs = ccalloc(ps->randr_nmonitors, region_t); + xcb_randr_monitor_info_iterator_t monitor_info_it = + xcb_randr_get_monitors_monitors_iterator(r); + for (int i = 0; monitor_info_it.rem; xcb_randr_monitor_info_next(&monitor_info_it)) { + xcb_randr_monitor_info_t *mi = monitor_info_it.data; + pixman_region32_init_rect(&ps->randr_monitor_regs[i++], mi->x, mi->y, + mi->width, mi->height); + } + + free(r); +} + +void x_free_randr_info(session_t *ps) { + if (ps->randr_monitor_regs) { + for (int i = 0; i < ps->randr_nmonitors; i++) { + pixman_region32_fini(&ps->randr_monitor_regs[i]); + } + free(ps->randr_monitor_regs); + ps->randr_monitor_regs = NULL; + } + ps->randr_nmonitors = 0; +} diff --git a/src/x.h b/src/x.h index 78efea39..fc105c78 100644 --- a/src/x.h +++ b/src/x.h @@ -302,4 +302,14 @@ x_get_pictfmt_for_standard(xcb_connection_t *c, xcb_pict_standard_t std); xcb_screen_t *x_screen_of_display(xcb_connection_t *c, int screen); +/** + * X RandR-related functions. + * + * The x_update_randr_monitors function populates ps->randr_nmonitors and + * ps->randr_monitor_regs with the data X RandR provided and the + * x_free_randr_info function frees them. + */ +void x_update_randr_monitors(session_t *ps); +void x_free_randr_info(session_t *ps); + uint32_t attr_deprecated xcb_generate_id(xcb_connection_t *c); diff --git a/tests/configs/parsing_test.conf b/tests/configs/parsing_test.conf index 72360173..2476d49a 100644 --- a/tests/configs/parsing_test.conf +++ b/tests/configs/parsing_test.conf @@ -64,8 +64,9 @@ shadow-exclude = [ # # shadow-exclude-reg = "" -# Crop shadow of a window fully on a particular Xinerama screen to the screen. -# xinerama-shadow-crop = false +# Crop shadow of a window fully on a particular monitor to that monitor. This is +# currently implemented using the X RandR extension. +# crop-shadow-to-monitor = false #################################