diff --git a/src/atom.h b/src/atom.h index 2164afd..9f66183 100644 --- a/src/atom.h +++ b/src/atom.h @@ -6,6 +6,7 @@ #include "meta.h" #include "cache.h" +// clang-format off // Splitted into 2 lists because of the limitation of our macros #define ATOM_LIST \ _NET_WM_WINDOW_OPACITY, \ @@ -36,7 +37,9 @@ _NET_WM_WINDOW_TYPE_COMBO, \ _NET_WM_WINDOW_TYPE_DND, \ _NET_WM_STATE, \ - _NET_WM_STATE_FULLSCREEN + _NET_WM_STATE_FULLSCREEN, \ + _NET_WM_BYPASS_COMPOSITOR +// clang-format on #define ATOM_DEF(x) xcb_atom_t a##x diff --git a/src/event.c b/src/event.c index 921a3c7..3a3369d 100644 --- a/src/event.c +++ b/src/event.c @@ -461,6 +461,11 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t win_update_wintype(ps, w); } + if (ev->atom == ps->atoms->a_NET_WM_BYPASS_COMPOSITOR) { + // Unnecessay until we remove the queue_redraw in ev_handle + queue_redraw(ps); + } + // If _NET_WM_OPACITY changes if (ev->atom == ps->atoms->a_NET_WM_WINDOW_OPACITY) { auto w = find_managed_win(ps, ev->window) ?: find_toplevel(ps, ev->window); diff --git a/src/picom.c b/src/picom.c index 99c7ae7..93d425e 100644 --- a/src/picom.c +++ b/src/picom.c @@ -81,12 +81,14 @@ const char *const WINTYPES[NUM_WINTYPES] = { "popup_menu", "tooltip", "notify", "combo", "dnd", }; +// clang-format off /// Names of backends. const char *const BACKEND_STRS[] = {[BKEND_XRENDER] = "xrender", [BKEND_GLX] = "glx", [BKEND_XR_GLX_HYBRID] = "xr_glx_hybrid", [BKEND_DUMMY] = "dummy", NULL}; +// clang-format on // === Global variables === @@ -582,6 +584,17 @@ static struct managed_win *paint_preprocess(session_t *ps, bool *fade_running) { } } + // Unredirect screen if some window is requesting compositor bypass, even + // if that window is not on the top. + if (ps->o.unredir_if_possible && win_is_bypassing_compositor(ps, w) && + !w->unredir_if_possible_excluded) { + // Here we deviate from EWMH a bit. EWMH says we must not + // unredirect the screen if the window requesting bypassing would + // look different after unredirecting. Instead we always follow + // the request. + unredir_possible = true; + } + w->prev_trans = bottom; if (bottom) { w->stacking_rank = bottom->stacking_rank + 1; diff --git a/src/win.c b/src/win.c index c733058..281a153 100644 --- a/src/win.c +++ b/src/win.c @@ -2251,6 +2251,8 @@ static inline bool rect_is_fullscreen(const session_t *ps, int x, int y, int wid /** * Check if a window is fulscreen using EWMH + * + * TODO cache this property */ static inline bool win_is_fullscreen_xcb(xcb_connection_t *c, const struct atom *a, const xcb_window_t w) { @@ -2312,6 +2314,25 @@ bool win_is_fullscreen(const session_t *ps, const struct managed_win *w) { (!w->bounding_shaped || w->rounded_corners); } +/** + * Check if a window has BYPASS_COMPOSITOR property set + * + * TODO cache this property + */ +bool win_is_bypassing_compositor(const session_t *ps, const struct managed_win *w) { + bool ret = false; + + auto prop = x_get_prop(ps, w->client_win, ps->atoms->a_NET_WM_BYPASS_COMPOSITOR, + 1L, XCB_ATOM_CARDINAL, 32); + + if (prop.nitems && *prop.c32 == 1) { + ret = true; + } + + free_winprop(&prop); + return ret; +} + /** * Check if a window is really focused. */ diff --git a/src/win.h b/src/win.h index 90c2b68..3b374e5 100644 --- a/src/win.h +++ b/src/win.h @@ -330,6 +330,10 @@ void win_update_leader(session_t *ps, struct managed_win *w); */ // XXX was win_border_size void win_update_bounding_shape(session_t *ps, struct managed_win *w); +/** + * Check if a window has BYPASS_COMPOSITOR property set + */ +bool win_is_bypassing_compositor(const session_t *ps, const struct managed_win *w); /** * Get a rectangular region in global coordinates a window (and possibly * its shadow) occupies.