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 #################################