1
0
Fork 0
mirror of https://github.com/yshui/picom.git synced 2024-11-25 14:06:08 -05:00

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 <yshuiv7@gmail.com>
This commit is contained in:
Yuxuan Shui 2024-07-29 17:54:02 +01:00
parent 5da5a93dcc
commit c7fc8784d5
No known key found for this signature in database
GPG key ID: D3A4405BE6CC17F4
4 changed files with 36 additions and 17 deletions

View file

@ -224,6 +224,8 @@ typedef struct session {
struct render_statistics render_stats; struct render_statistics render_stats;
// === Operation related === // === Operation related ===
/// Whether there is a pending quest to get the focused window
bool pending_focus_check;
/// Flags related to the root window /// Flags related to the root window
uint64_t root_flags; uint64_t root_flags;
/// Program options. /// Program options.

View file

@ -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; auto ps = ((struct ev_ewmh_active_win_request *)req_base)->ps;
free(req_base); free(req_base);
ps->pending_focus_check = false;
if (reply_or_error->response_type == 0) { if (reply_or_error->response_type == 0) {
log_error("Failed to get _NET_ACTIVE_WINDOW: %s", log_error("Failed to get _NET_ACTIVE_WINDOW: %s",
x_strerror(((xcb_generic_error_t *)reply_or_error))); 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; auto ps = ((struct ev_ewmh_active_win_request *)req_base)->ps;
free(req_base); free(req_base);
ps->pending_focus_check = false;
// Determine the currently focused window so we can apply appropriate // Determine the currently focused window so we can apply appropriate
// opacity on it // opacity on it
if (reply_or_error->response_type == 0) { if (reply_or_error->response_type == 0) {
@ -288,18 +291,39 @@ static void recheck_focus(struct x_connection * /*c*/, struct x_async_request_ba
} }
} }
static inline void ev_focus_change(session_t *ps) { void ev_update_focused(struct session *ps) {
if (ps->o.use_ewmh_active_win) { if (ps->pending_focus_check) {
// Not using focus_in/focus_out events.
return; 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); auto req = ccalloc(1, struct ev_recheck_focus_request);
req->base.sequence = xcb_get_input_focus(ps->c.c).sequence; req->base.sequence = xcb_get_input_focus(ps->c.c).sequence;
req->base.callback = recheck_focus; req->base.callback = recheck_focus;
req->ps = ps; req->ps = ps;
x_await_request(&ps->c, &req->base); x_await_request(&ps->c, &req->base);
log_debug("Started async request to recheck focus"); 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;
}
ev_update_focused(ps);
} }
static inline void ev_focus_in(session_t *ps, xcb_focus_in_event_t *ev) { 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->c.screen_info->root == ev->window) {
if (ps->o.use_ewmh_active_win && ps->atoms->a_NET_ACTIVE_WINDOW == ev->atom) { 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); ev_update_focused(ps);
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 { } else {
// Destroy the root "image" if the wallpaper probably changed // Destroy the root "image" if the wallpaper probably changed
if (x_is_root_back_pixmap_atom(ps->atoms, ev->atom)) { if (x_is_root_back_pixmap_atom(ps->atoms, ev->atom)) {

View file

@ -7,3 +7,4 @@
#include "common.h" #include "common.h"
void ev_handle(session_t *ps, xcb_generic_event_t *ev); void ev_handle(session_t *ps, xcb_generic_event_t *ev);
void ev_update_focused(struct session *ps);

View file

@ -1590,6 +1590,7 @@ static void handle_new_windows(session_t *ps) {
wm_ref_win_id(wm_change.toplevel), wm_ref_win_id(wm_change.toplevel),
wm_change.client.new_.x); wm_change.client.new_.x);
} }
ev_update_focused(ps);
break; break;
case WM_TREE_CHANGE_TOPLEVEL_RESTACKED: invalidate_reg_ignore(ps); break; case WM_TREE_CHANGE_TOPLEVEL_RESTACKED: invalidate_reg_ignore(ps); break;
default: unreachable(); default: unreachable();