Skip to content

Commit

Permalink
core: recheck focus when client windows change
Browse files Browse the repository at this point in the history
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 <yshuiv7@gmail.com>
  • Loading branch information
yshui committed Jul 29, 2024
1 parent 5da5a93 commit c7fc878
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 17 deletions.
2 changes: 2 additions & 0 deletions src/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
49 changes: 32 additions & 17 deletions src/event.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)));
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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)) {
Expand Down
1 change: 1 addition & 0 deletions src/event.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
1 change: 1 addition & 0 deletions src/picom.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down

0 comments on commit c7fc878

Please sign in to comment.