diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 2e3dfe7..c9ebfa6 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-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 libxcb-util-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 856a094..bfa2bb7 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ __picom__ is a compositor for X, and a [fork of Compton](History.md). **This is a development branch, bugs to be expected** -You can leave your feedback or thoughts in the [discussion tab](https://github.com/yshui/picom/discussions), or chat with other users on [discord](https://discord.gg/uqmNX6dR)! +You can leave your feedback or thoughts in the [discussion tab](https://github.com/yshui/picom/discussions), or chat with other users on [discord](https://discord.gg/SY5JJzPgME)! ## Change Log @@ -26,6 +26,7 @@ Assuming you already have all the usual building tools installed (e.g. gcc, pyth * libXext * xproto * xcb +* xcb-util * xcb-damage * xcb-dpms * xcb-xfixes diff --git a/src/atom.h b/src/atom.h index 6f4eae6..5ea7701 100644 --- a/src/atom.h +++ b/src/atom.h @@ -3,8 +3,8 @@ #include -#include "meta.h" #include "cache.h" +#include "meta.h" // clang-format off // Splitted into 2 lists because of the limitation of our macros @@ -23,7 +23,10 @@ WM_CLIENT_MACHINE, \ _NET_ACTIVE_WINDOW, \ _COMPTON_SHADOW, \ - _NET_WM_WINDOW_TYPE + _NET_WM_WINDOW_TYPE, \ + _XROOTPMAP_ID, \ + ESETROOT_PMAP_ID, \ + _XSETROOT_ID #define ATOM_LIST2 \ _NET_WM_WINDOW_TYPE_DESKTOP, \ diff --git a/src/backend/gl/egl.c b/src/backend/gl/egl.c index 9f65154..761eb63 100644 --- a/src/backend/gl/egl.c +++ b/src/backend/gl/egl.c @@ -67,7 +67,7 @@ const char *eglGetErrorString(EGLint error) { } /** - * Free a glx_texture_t. + * Free a gl_texture_t. */ static void egl_release_image(backend_t *base, struct gl_texture *tex) { struct egl_data *gd = (void *)base; @@ -88,14 +88,14 @@ static void egl_release_image(backend_t *base, struct gl_texture *tex) { } /** - * Destroy GLX related resources. + * Destroy EGL related resources. */ void egl_deinit(backend_t *base) { struct egl_data *gd = (void *)base; gl_deinit(&gd->gl); - // Destroy GLX context + // Destroy EGL context if (gd->ctx != EGL_NO_CONTEXT) { eglMakeCurrent(gd->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroyContext(gd->display, gd->ctx); @@ -225,12 +225,12 @@ static backend_t *egl_init(session_t *ps) { gd->ctx = eglCreateContext(gd->display, config, NULL, NULL); if (gd->ctx == EGL_NO_CONTEXT) { - log_error("Failed to get GLX context."); + log_error("Failed to get EGL context."); goto end; } if (!eglMakeCurrent(gd->display, gd->target_win, gd->target_win, gd->ctx)) { - log_error("Failed to attach GLX context."); + log_error("Failed to attach EGL context."); goto end; } @@ -423,7 +423,7 @@ struct backend_operations egl_ops = { PFNEGLGETDISPLAYDRIVERNAMEPROC eglGetDisplayDriverName; /** - * Check if a GLX extension exists. + * Check if a EGL extension exists. */ static inline bool egl_has_extension(EGLDisplay dpy, const char *ext) { const char *egl_exts = eglQueryString(dpy, EGL_EXTENSIONS); diff --git a/src/backend/gl/egl.h b/src/backend/gl/egl.h index 171b173..f482032 100644 --- a/src/backend/gl/egl.h +++ b/src/backend/gl/egl.h @@ -1,13 +1,11 @@ // SPDX-License-Identifier: MPL-2.0 // Copyright (c) Yuxuan Shui #pragma once -#include -// Older version of glx.h defines function prototypes for these extensions... -// Rename them to avoid conflicts #include #include #include #include +#include #include #include diff --git a/src/backend/gl/gl_common.c b/src/backend/gl/gl_common.c index b5347de..0bef277 100644 --- a/src/backend/gl/gl_common.c +++ b/src/backend/gl/gl_common.c @@ -817,7 +817,7 @@ bool gl_init(struct gl_data *gd, session_t *ps) { glGenQueries(2, gd->frame_timing); gd->current_frame_timing = 0; - // Initialize GLX data structure + // Initialize GL data structure glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); diff --git a/src/backend/gl/gl_common.h b/src/backend/gl/gl_common.h index f40c380..a8eb475 100644 --- a/src/backend/gl/gl_common.h +++ b/src/backend/gl/gl_common.h @@ -77,7 +77,7 @@ typedef struct { GLint color_loc; } gl_fill_shader_t; -/// @brief Wrapper of a binded GLX texture. +/// @brief Wrapper of a binded GL texture. struct gl_texture { int refcount; bool has_alpha; @@ -214,7 +214,7 @@ static inline const char *gl_get_err_str(GLenum err) { } /** - * Check for GLX error. + * Check for GL error. * * http://blog.nobel-joergensen.com/2013/01/29/debugging-opengl-using-glgeterror/ */ @@ -225,10 +225,10 @@ static inline void gl_check_err_(const char *func, int line) { const char *errtext = gl_get_err_str(err); if (errtext) { log_printf(tls_logger, LOG_LEVEL_ERROR, func, - "GLX error at line %d: %s", line, errtext); + "GL error at line %d: %s", line, errtext); } else { log_printf(tls_logger, LOG_LEVEL_ERROR, func, - "GLX error at line %d: %d", line, err); + "GL error at line %d: %d", line, err); } } } @@ -265,7 +265,7 @@ static inline bool gl_check_fb_complete_(const char *func, int line, GLenum fb) #define gl_check_fb_complete(fb) gl_check_fb_complete_(__func__, __LINE__, (fb)) /** - * Check if a GLX extension exists. + * Check if a GL extension exists. */ static inline bool gl_has_extension(const char *ext) { int nexts = 0; diff --git a/src/backend/xrender/xrender.c b/src/backend/xrender/xrender.c index 5d3c314..2a42ec4 100644 --- a/src/backend/xrender/xrender.c +++ b/src/backend/xrender/xrender.c @@ -520,8 +520,9 @@ bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, bool inner->height = img->base.eheight = r->height; inner->pixmap = pixmap; inner->has_alpha = fmt.alpha_size != 0; - inner->pict = - x_create_picture_with_visual_and_pixmap(base->c, fmt.visual, pixmap, 0, NULL); + xcb_render_create_picture_value_list_t pic_attrs = {.repeat = XCB_RENDER_REPEAT_NORMAL}; + inner->pict = x_create_picture_with_visual_and_pixmap( + base->c, fmt.visual, pixmap, XCB_RENDER_CP_REPEAT, &pic_attrs); inner->owned = owned; inner->visual = fmt.visual; inner->refcount = 1; diff --git a/src/event.c b/src/event.c index bdcc17b..90ff3b6 100644 --- a/src/event.c +++ b/src/event.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "atom.h" #include "common.h" @@ -106,7 +107,7 @@ static inline xcb_window_t attr_pure ev_window(session_t *ps, xcb_generic_event_ static inline const char *ev_name(session_t *ps, xcb_generic_event_t *ev) { static char buf[128]; - switch (ev->response_type & 0x7f) { + switch (XCB_EVENT_RESPONSE_TYPE(ev)) { CASESTRRET(FocusIn); CASESTRRET(FocusOut); CASESTRRET(CreateNotify); @@ -666,7 +667,7 @@ ev_selection_clear(session_t *ps, xcb_selection_clear_event_t attr_unused *ev) { } void ev_handle(session_t *ps, xcb_generic_event_t *ev) { - if ((ev->response_type & 0x7f) != KeymapNotify) { + if (XCB_EVENT_RESPONSE_TYPE(ev) != KeymapNotify) { discard_pending(ps, ev->full_sequence); } @@ -688,9 +689,10 @@ void ev_handle(session_t *ps, xcb_generic_event_t *ev) { // For even more details, see: // https://bugs.freedesktop.org/show_bug.cgi?id=35945 // https://lists.freedesktop.org/archives/xcb/2011-November/007337.html - auto proc = XESetWireToEvent(ps->dpy, ev->response_type, 0); + auto response_type = XCB_EVENT_RESPONSE_TYPE(ev); + auto proc = XESetWireToEvent(ps->dpy, response_type, 0); if (proc) { - XESetWireToEvent(ps->dpy, ev->response_type, proc); + XESetWireToEvent(ps->dpy, response_type, proc); XEvent dummy; // Stop Xlib from complaining about lost sequence numbers. @@ -709,6 +711,7 @@ void ev_handle(session_t *ps, xcb_generic_event_t *ev) { // XXX redraw needs to be more fine grained queue_redraw(ps); + // the events sent from SendEvent will be ignored switch (ev->response_type) { case FocusIn: ev_focus_in(ps, (xcb_focus_in_event_t *)ev); break; case FocusOut: ev_focus_out(ps, (xcb_focus_out_event_t *)ev); break; diff --git a/src/meson.build b/src/meson.build index 074683b..ddecc64 100644 --- a/src/meson.build +++ b/src/meson.build @@ -20,7 +20,7 @@ required_xcb_packages = [ ] required_packages = [ - 'x11', 'x11-xcb', 'xcb-renderutil', 'xcb-image', 'xext', 'pixman-1' + 'x11', 'x11-xcb', 'xcb-renderutil', 'xcb-image', 'xext', 'pixman-1', 'xcb-util' ] foreach i : required_packages diff --git a/src/options.c b/src/options.c index 93004a1..73b2e05 100644 --- a/src/options.c +++ b/src/options.c @@ -860,10 +860,10 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable, if (opt->window_shader_fg || opt->window_shader_fg_rules) { if (opt->backend == BKEND_XRENDER || opt->legacy_backends) { log_warn(opt->backend == BKEND_XRENDER - ? "Shader interface is not available for the " - "xrender backend." - : "The new shader interface is not available for " - "the legacy glx backend. You may want to use " + ? "Shader interface is not supported by the xrender " + "backend." + : "The new shader interface is not supported by the " + "legacy glx backend. You may want to use " "--glx-fshader-win instead."); opt->window_shader_fg = NULL; c2_list_free(&opt->window_shader_fg_rules, free); @@ -879,18 +879,16 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable, opt->inactive_dim = normalize_d(opt->inactive_dim); opt->frame_opacity = normalize_d(opt->frame_opacity); opt->shadow_opacity = normalize_d(opt->shadow_opacity); - opt->max_brightness = normalize_d(opt->max_brightness); if (opt->max_brightness < 1.0) { - if (opt->use_damage) { - log_warn("--max-brightness requires --no-use-damage. Falling " - "back to 1.0"); + if (opt->backend == BKEND_XRENDER || opt->legacy_backends) { + log_warn("--max-brightness is not supported by the %s backend. " + "Falling back to 1.0.", + opt->backend == BKEND_XRENDER ? "xrender" : "legacy glx"); opt->max_brightness = 1.0; - } - - if (opt->legacy_backends || opt->backend != BKEND_GLX) { - log_warn("--max-brightness requires the new glx " - "backend. Falling back to 1.0"); + } else if (opt->use_damage) { + log_warn("--max-brightness requires --no-use-damage. Falling " + "back to 1.0."); opt->max_brightness = 1.0; } } diff --git a/src/render.c b/src/render.c index 80cb59a..f4b3a97 100644 --- a/src/render.c +++ b/src/render.c @@ -583,8 +583,6 @@ void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint) } } -extern const char *background_props_str[]; - static bool get_root_tile(session_t *ps) { /* if (ps->o.paint_on_overlay) { diff --git a/src/x.c b/src/x.c index da37c4b..5215e0b 100644 --- a/src/x.c +++ b/src/x.c @@ -628,22 +628,27 @@ bool x_validate_pixmap(xcb_connection_t *c, xcb_pixmap_t pixmap) { free(r); return ret; } -/// Names of root window properties that could point to a pixmap of -/// background. -static const char *background_props_str[] = { - "_XROOTPMAP_ID", - "_XSETROOT_ID", - 0, -}; + +/// We don't use the _XSETROOT_ID root window property as a source of the background +/// pixmap because it most likely points to a dummy pixmap used to keep the colormap +/// associated with the background pixmap alive but we listen for it's changes and update +/// the background pixmap accordingly. +/// +/// For details on the _XSETROOT_ID root window property and it's usage see: +/// https://metacpan.org/pod/X11::Protocol::XSetRoot#_XSETROOT_ID +/// https://gitlab.freedesktop.org/xorg/app/xsetroot/-/blob/435d35409768de7cbc2c47a6322192dd4b480545/xsetroot.c#L318-352 +/// https://github.com/ImageMagick/ImageMagick/blob/d04a47227637dbb3af9231b0107ccf9677bf985e/MagickCore/xwindow.c#L9203-L9260 +/// https://github.com/ImageMagick/ImageMagick/blob/d04a47227637dbb3af9231b0107ccf9677bf985e/MagickCore/xwindow.c#L1853-L1922 +/// https://www.fvwm.org/Archive/Manpages/fvwm-root.html xcb_pixmap_t x_get_root_back_pixmap(xcb_connection_t *c, xcb_window_t root, struct atom *atoms) { xcb_pixmap_t pixmap = XCB_NONE; - // Get the values of background attributes - for (int p = 0; background_props_str[p]; p++) { - xcb_atom_t prop_atom = get_atom(atoms, background_props_str[p]); - winprop_t prop = x_get_prop(c, root, prop_atom, 1, XCB_ATOM_PIXMAP, 32); + xcb_atom_t root_back_pixmap_atoms[] = {atoms->a_XROOTPMAP_ID, atoms->aESETROOT_PMAP_ID}; + for (size_t i = 0; i < ARR_SIZE(root_back_pixmap_atoms); i++) { + winprop_t prop = + x_get_prop(c, root, root_back_pixmap_atoms[i], 1, XCB_ATOM_PIXMAP, 32); if (prop.nitems) { pixmap = (xcb_pixmap_t)*prop.p32; free_winprop(&prop); @@ -656,13 +661,8 @@ x_get_root_back_pixmap(xcb_connection_t *c, xcb_window_t root, struct atom *atom } bool x_is_root_back_pixmap_atom(struct atom *atoms, xcb_atom_t atom) { - for (int p = 0; background_props_str[p]; p++) { - xcb_atom_t prop_atom = get_atom(atoms, background_props_str[p]); - if (prop_atom == atom) { - return true; - } - } - return false; + return atom == atoms->a_XROOTPMAP_ID || atom == atoms->aESETROOT_PMAP_ID || + atom == atoms->a_XSETROOT_ID; } /**