From 9a3d6b0a4f7d94ffc86b921310908830d8955c19 Mon Sep 17 00:00:00 2001 From: StaszeKrk Date: Fri, 29 May 2026 06:43:58 +0200 Subject: [PATCH] fix: keep window shadow attached during move animations client_draw_shadow() clamps the shadow box to the monitor bounds so a window's shadow does not bleed onto adjacent monitors. But this clamp also fires while a window is animating past its monitor edge: during a tag switch the outgoing/incoming window slides off-screen, and in the scroller layout a focus change scrolls windows horizontally. In both cases the clamp pins the shadow's leading edge to the screen border, so the shadow visibly lags behind and only catches up once the window has fully moved out. While the window is animating, only keep the clamp on edges that actually border another enabled monitor (so the shadow still does not bleed onto it) and release it on free edges so the shadow travels with the window. At rest the full clamp applies as before, and interactive moves (c == grabc) stay fully unclamped. --- src/animation/client.h | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/animation/client.h b/src/animation/client.h index 238da9fb..194b9265 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -363,6 +363,8 @@ void client_draw_shadow(Client *c) { int32_t right_offset, bottom_offset, left_offset, top_offset; if (c == grabc) { + // Interactive move: the window (and its shadow) genuinely follow the + // cursor, possibly across monitors, so never clamp. right_offset = 0; bottom_offset = 0; left_offset = 0; @@ -377,6 +379,46 @@ void client_draw_shadow(Client *c) { left_offset = GEZERO(c->mon->m.x - absolute_shadow_box.x); top_offset = GEZERO(c->mon->m.y - absolute_shadow_box.y); + + // While the window is animating (tag switch, scroller focus scroll, + // generic move) it legitimately slides past its monitor edge. Clamping + // the shadow to the monitor bounds then pins the shadow's leading edge + // to the screen border, so it lags behind the moving window. Only keep + // the clamp on edges that actually border another monitor (to stop the + // shadow bleeding onto it); release it on free edges so the shadow + // travels with the window. The clamp is fully active again at rest. + if (c->animation.running) { + struct wlr_box *me = &c->mon->m; + bool nb_right = false, nb_left = false, nb_below = false, + nb_above = false; + Monitor *om; + wl_list_for_each(om, &mons, link) { + if (om == c->mon || !om->wlr_output || + !om->wlr_output->enabled) + continue; + struct wlr_box *o = &om->m; + bool voverlap = + o->y < me->y + me->height && o->y + o->height > me->y; + bool hoverlap = + o->x < me->x + me->width && o->x + o->width > me->x; + if (voverlap && o->x >= me->x + me->width) + nb_right = true; + if (voverlap && o->x + o->width <= me->x) + nb_left = true; + if (hoverlap && o->y >= me->y + me->height) + nb_below = true; + if (hoverlap && o->y + o->height <= me->y) + nb_above = true; + } + if (!nb_right) + right_offset = 0; + if (!nb_left) + left_offset = 0; + if (!nb_below) + bottom_offset = 0; + if (!nb_above) + top_offset = 0; + } } left_offset = MIN(left_offset, shadow_box.width);