From c7fc8784d5bd1845a74c49d1424ca73251a49a83 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Mon, 29 Jul 2024 17:54:02 +0100 Subject: [PATCH] core: recheck focus when client windows change A toplevel is marked active if its client window is focused. So when a toplevel's client window changes, focus must be rechecked. Fix the problem that no window is marked active from the point when picom is just started, until the first focus change. Signed-off-by: Yuxuan Shui --- src/common.h | 2 ++ src/event.c | 49 ++++++++++++++++++++++++++++++++----------------- src/event.h | 1 + src/picom.c | 1 + 4 files changed, 36 insertions(+), 17 deletions(-) diff --git a/src/common.h b/src/common.h index 635fb9733b..94b0ac2709 100644 --- a/src/common.h +++ b/src/common.h @@ -224,6 +224,8 @@ typedef struct session { struct render_statistics render_stats; // === Operation related === + /// Whether there is a pending quest to get the focused window + bool pending_focus_check; /// Flags related to the root window uint64_t root_flags; /// Program options. diff --git a/src/event.c b/src/event.c index b2e9558ea5..7289a2bdcd 100644 --- a/src/event.c +++ b/src/event.c @@ -205,6 +205,7 @@ update_ewmh_active_win(struct x_connection * /*c*/, struct x_async_request_base auto ps = ((struct ev_ewmh_active_win_request *)req_base)->ps; free(req_base); + ps->pending_focus_check = false; if (reply_or_error->response_type == 0) { log_error("Failed to get _NET_ACTIVE_WINDOW: %s", x_strerror(((xcb_generic_error_t *)reply_or_error))); @@ -247,6 +248,8 @@ static void recheck_focus(struct x_connection * /*c*/, struct x_async_request_ba auto ps = ((struct ev_ewmh_active_win_request *)req_base)->ps; free(req_base); + ps->pending_focus_check = false; + // Determine the currently focused window so we can apply appropriate // opacity on it if (reply_or_error->response_type == 0) { @@ -288,18 +291,39 @@ static void recheck_focus(struct x_connection * /*c*/, struct x_async_request_ba } } +void ev_update_focused(struct session *ps) { + if (ps->pending_focus_check) { + return; + } + + if (ps->o.use_ewmh_active_win) { + auto req = ccalloc(1, struct ev_ewmh_active_win_request); + req->base.sequence = + xcb_get_property(ps->c.c, 0, ps->c.screen_info->root, + ps->atoms->a_NET_ACTIVE_WINDOW, XCB_ATOM_WINDOW, 0, 1) + .sequence; + req->base.callback = update_ewmh_active_win; + req->ps = ps; + x_await_request(&ps->c, &req->base); + log_debug("Started async request to get _NET_ACTIVE_WINDOW"); + } else { + auto req = ccalloc(1, struct ev_recheck_focus_request); + req->base.sequence = xcb_get_input_focus(ps->c.c).sequence; + req->base.callback = recheck_focus; + req->ps = ps; + x_await_request(&ps->c, &req->base); + log_debug("Started async request to recheck focus"); + } + + ps->pending_focus_check = true; +} + static inline void ev_focus_change(session_t *ps) { if (ps->o.use_ewmh_active_win) { // Not using focus_in/focus_out events. return; } - - auto req = ccalloc(1, struct ev_recheck_focus_request); - req->base.sequence = xcb_get_input_focus(ps->c.c).sequence; - req->base.callback = recheck_focus; - req->ps = ps; - x_await_request(&ps->c, &req->base); - log_debug("Started async request to recheck focus"); + ev_update_focused(ps); } static inline void ev_focus_in(session_t *ps, xcb_focus_in_event_t *ev) { @@ -556,16 +580,7 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t if (ps->c.screen_info->root == ev->window) { if (ps->o.use_ewmh_active_win && ps->atoms->a_NET_ACTIVE_WINDOW == ev->atom) { - auto req = ccalloc(1, struct ev_ewmh_active_win_request); - req->base.sequence = - xcb_get_property(ps->c.c, 0, ps->c.screen_info->root, - ps->atoms->a_NET_ACTIVE_WINDOW, - XCB_ATOM_WINDOW, 0, 1) - .sequence; - req->base.callback = update_ewmh_active_win; - req->ps = ps; - x_await_request(&ps->c, &req->base); - log_debug("Started async request to get _NET_ACTIVE_WINDOW"); + ev_update_focused(ps); } else { // Destroy the root "image" if the wallpaper probably changed if (x_is_root_back_pixmap_atom(ps->atoms, ev->atom)) { diff --git a/src/event.h b/src/event.h index 675b4d8c10..f4815b3b53 100644 --- a/src/event.h +++ b/src/event.h @@ -7,3 +7,4 @@ #include "common.h" void ev_handle(session_t *ps, xcb_generic_event_t *ev); +void ev_update_focused(struct session *ps); diff --git a/src/picom.c b/src/picom.c index a49c91295a..9d0e734401 100644 --- a/src/picom.c +++ b/src/picom.c @@ -1590,6 +1590,7 @@ static void handle_new_windows(session_t *ps) { wm_ref_win_id(wm_change.toplevel), wm_change.client.new_.x); } + ev_update_focused(ps); break; case WM_TREE_CHANGE_TOPLEVEL_RESTACKED: invalidate_reg_ignore(ps); break; default: unreachable();