From 176718ad3b187f121054261532623234b4c6b387 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Fri, 10 Apr 2020 03:26:13 +0100 Subject: [PATCH] Revert "Revert previous fix for #299" This reverts commit 04fe4a76b23aa1196ffcdb822510e0a3c84ab3b3. This brings back the previous incomplete fix attempt for #299. See the commit message of the revert for why it's incomplete. A different fix is then attempted, see commit xxxxxxx for how that fix works. However, the second fix is incomplete by itself as well. The reason is that i3 reparent the real window to the frame first, before destroying the placeholder client of that frame. So briefly, that frame would have 2 client windows. And the frame is mapped before the placeholder is destroyed. So even though we only call win_recheck_client when/if the frame window is mapped, it can still be called when there are 2 client windows, it would pick up the wrong client window in that case. So what we need is to combine both fixes. The second fix makes sure we are up to date on the client window information when we starts to listen for events on the frame window; while the first fix would keep us up to date afterwards. This revert also includes a fix for assertion failure raised in #371 See #299 for root cause of the bug. Signed-off-by: Yuxuan Shui --- src/event.c | 20 +++++++++++++++++--- src/picom.c | 4 ++-- src/win.c | 10 +++++----- src/win.h | 1 + 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/event.c b/src/event.c index f21e346..69b326b 100644 --- a/src/event.c +++ b/src/event.c @@ -180,8 +180,9 @@ static inline void ev_focus_out(session_t *ps, xcb_focus_out_event_t *ev) { } static inline void ev_create_notify(session_t *ps, xcb_create_notify_event_t *ev) { - assert(ev->parent == ps->root); - add_win_top(ps, ev->window); + if (ev->parent == ps->root) { + add_win_top(ps, ev->window); + } } /// Handle configure event of a regular window @@ -263,8 +264,21 @@ static inline void ev_configure_notify(session_t *ps, xcb_configure_notify_event static inline void ev_destroy_notify(session_t *ps, xcb_destroy_notify_event_t *ev) { auto w = find_win(ps, ev->window); - if (w) { + auto mw = find_toplevel(ps, ev->window); + if (mw && mw->client_win == mw->base.id) { + // We only want _real_ frame window + assert(&mw->base == w); + mw = NULL; + } + assert(w == NULL || mw == NULL); + + if (w != NULL) { auto _ attr_unused = destroy_win_start(ps, w); + } else if (mw != NULL) { + win_recheck_client(ps, mw); + } else { + log_debug("Received a destroy notify from an unknown window, %#010x", + ev->window); } } diff --git a/src/picom.c b/src/picom.c index bbade20..fcc2a41 100644 --- a/src/picom.c +++ b/src/picom.c @@ -303,9 +303,9 @@ uint32_t determine_evmask(session_t *ps, xcb_window_t wid, win_evmode_t mode) { struct managed_win *w = NULL; // Check if it's a mapped frame window - if (WIN_EVMODE_FRAME == mode || + if (mode == WIN_EVMODE_FRAME || ((w = find_managed_win(ps, wid)) && w->a.map_state == XCB_MAP_STATE_VIEWABLE)) { - evmask |= XCB_EVENT_MASK_PROPERTY_CHANGE; + evmask |= XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY; if (!ps->o.use_ewmh_active_win) { evmask |= XCB_EVENT_MASK_FOCUS_CHANGE; } diff --git a/src/win.c b/src/win.c index 10f4424..1a10e06 100644 --- a/src/win.c +++ b/src/win.c @@ -53,8 +53,6 @@ static const int WIN_GET_LEADER_MAX_RECURSION = 20; static const int ROUNDED_PIXELS = 1; static const double ROUNDED_PERCENT = 0.05; -static void win_recheck_client(session_t *ps, struct managed_win *w); - /// Generate a "return by value" function, from a function that returns the /// region via a region_t pointer argument. /// Function signature has to be (win *, region_t *) @@ -1031,6 +1029,8 @@ void win_mark_client(session_t *ps, struct managed_win *w, xcb_window_t client) */ void win_unmark_client(session_t *ps, struct managed_win *w) { xcb_window_t client = w->client_win; + log_debug("Detaching client window %#010x from frame %#010x (%s)", client, + w->base.id, w->name); w->client_win = XCB_NONE; @@ -1074,7 +1074,7 @@ static xcb_window_t find_client_win(session_t *ps, xcb_window_t w) { * @param ps current session * @param w struct _win of the parent window */ -static void win_recheck_client(session_t *ps, struct managed_win *w) { +void win_recheck_client(session_t *ps, struct managed_win *w) { // Initialize wmwin to false w->wmwin = false; @@ -1084,14 +1084,14 @@ static void win_recheck_client(session_t *ps, struct managed_win *w) { // sets override-redirect flags on all frame windows. xcb_window_t cw = find_client_win(ps, w->base.id); if (cw) { - log_trace("(%#010x): client %#010x", w->base.id, cw); + log_debug("(%#010x): client %#010x", w->base.id, cw); } // Set a window's client window to itself if we couldn't find a // client window if (!cw) { cw = w->base.id; w->wmwin = !w->a.override_redirect; - log_trace("(%#010x): client self (%s)", w->base.id, + log_debug("(%#010x): client self (%s)", w->base.id, (w->wmwin ? "wmwin" : "override-redirected")); } diff --git a/src/win.h b/src/win.h index d6778b6..4f1ee41 100644 --- a/src/win.h +++ b/src/win.h @@ -298,6 +298,7 @@ void win_on_win_size_change(session_t *ps, struct managed_win *w); void win_update_wintype(session_t *ps, struct managed_win *w); void win_mark_client(session_t *ps, struct managed_win *w, xcb_window_t client); void win_unmark_client(session_t *ps, struct managed_win *w); +void win_recheck_client(session_t *ps, struct managed_win *w); bool win_get_class(session_t *ps, struct managed_win *w); /**