feat: keep hidden overlay-preview thumbnails live while held
Hidden tabs live in disabled scene trees, so wlr_scene_output_send_frame_done() never reaches them and frame-callback-throttled clients stop committing: only the shown window's thumbnail tracked live while the rest sat at their last frame. Fan frame-done out to every hidden tab window once per output frame while the overlay is held (overlay_send_hidden_frames after the scene frame-done in both render_standalone and render_and_present). The walk covers main plus subsurface trees for both xdg and X11 windows via window_surface(), and skips the shown window the scene path already handles. Gated on --overlay-previews plus overlay_visible, so the steady state with the menu hidden costs nothing and background clients are not woken. The existing thumb_capture snapshot and draw-time tree composite paths are unchanged; they simply receive the commits they were missing. Tests: new test_standalone_headless_overlay_previews_hidden_live uses a hidden --pulse tab and asserts the red thumbnail count swings while Alt is held. README overlay-previews paragraph updated from freeze to live-while-held. Verified: ./build.sh clean; overlay-previews suite 6 passed; full suite 179 passed with -n4.
This commit is contained in:
parent
b04f6a2826
commit
80e4e288ad
3 changed files with 71 additions and 4 deletions
|
|
@ -266,10 +266,11 @@ past a quarter of the screen height. A header row at the top of the menu
|
|||
names the selected window (icon plus ellipsized title) without affecting
|
||||
the menu size. The
|
||||
shown window keeps its thumbnail live -- it commits continuously, so the
|
||||
preview tracks it. Hidden windows freeze with no frame callbacks while
|
||||
another tab is shown, so their thumbnails sit at the last-shown frame
|
||||
until they paint again on their own (a newly mapped window still appears
|
||||
mid-hold). Both software (SHM) and GPU (DMA-BUF) clients are covered, and
|
||||
preview tracks it. While the overlay is held, hidden windows are sent
|
||||
frame callbacks too, so every thumbnail tracks live; with the overlay
|
||||
hidden they freeze again (no background wakeups), sitting at the last
|
||||
frame from the hold until they paint again on their own (a newly mapped
|
||||
window still appears mid-hold). Both software (SHM) and GPU (DMA-BUF) clients are covered, and
|
||||
a tab with no mapped window keeps its command-line text row. The plain
|
||||
title list never wakes background clients this way.
|
||||
|
||||
|
|
|
|||
36
kick.c
36
kick.c
|
|
@ -3086,6 +3086,40 @@ static void thumb_sub_wire_tree(struct kick_window *w) {
|
|||
wlr_surface_for_each_surface(s, thumb_wire_iter, w);
|
||||
}
|
||||
|
||||
/* Live thumbnails while the overlay is held: hidden windows sit in disabled
|
||||
scene trees, so wlr_scene_output_send_frame_done() never reaches them and
|
||||
frame-callback-throttled clients stop committing (only the shown window's
|
||||
thumbnail tracks live). Fan frame-done out to every hidden tab window's
|
||||
surface tree once per output frame while held, so each hidden client keeps
|
||||
producing frames that thumb_capture() snapshots. Gated on
|
||||
--overlay-previews + overlay_visible, so the steady state (menu hidden)
|
||||
costs nothing. */
|
||||
static void overlay_hidden_frame_iter(struct wlr_surface *surface, int sx,
|
||||
int sy, void *data) {
|
||||
(void)sx;
|
||||
(void)sy;
|
||||
struct timespec *now = data;
|
||||
if (surface && now)
|
||||
wlr_surface_send_frame_done(surface, now);
|
||||
}
|
||||
|
||||
static void overlay_send_hidden_frames(struct timespec *now) {
|
||||
if (!opt_overlay_previews || !host.overlay_visible || !now)
|
||||
return;
|
||||
struct kick_tab *t;
|
||||
wl_list_for_each(t, &server.tabs, link) {
|
||||
struct kick_window *w;
|
||||
wl_list_for_each(w, &t->windows, link) {
|
||||
if (!w->tree || w->tree->node.enabled)
|
||||
continue; /* shown: scene path already sent frame-done */
|
||||
struct wlr_surface *s = window_surface(w);
|
||||
if (!s)
|
||||
continue;
|
||||
wlr_surface_for_each_surface(s, overlay_hidden_frame_iter, now);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct wlr_texture *overlay_thumb_tex(struct kick_window *w) {
|
||||
if (!w || !server.renderer) return NULL;
|
||||
if (w->thumb_src == THUMB_SRC_LIVE) {
|
||||
|
|
@ -13127,6 +13161,7 @@ frame_done:
|
|||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
wlr_scene_output_send_frame_done(server.scene_output, &now);
|
||||
overlay_send_hidden_frames(&now);
|
||||
}
|
||||
|
||||
static void render_and_present(void) {
|
||||
|
|
@ -13227,6 +13262,7 @@ frame_done:
|
|||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
wlr_scene_output_send_frame_done(server.scene_output, &now);
|
||||
overlay_send_hidden_frames(&now);
|
||||
|
||||
wlr_output_state_finish(&state);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6855,3 +6855,33 @@ def test_standalone_headless_overlay_previews_live():
|
|||
finally:
|
||||
s.mods(0)
|
||||
_assert_alive(s)
|
||||
|
||||
|
||||
def test_standalone_headless_overlay_previews_hidden_live():
|
||||
"""Hidden tabs keep live thumbnails while the overlay is held.
|
||||
|
||||
The hidden tab pulses red/black on frame callbacks, so it only
|
||||
animates while the compositor fans frame-done out to hidden
|
||||
windows. While Alt is held the red thumbnail pixel count must
|
||||
swing between phases; without the fan-out it stays frozen."""
|
||||
with _run_standalone(
|
||||
{}, "--overlay-previews",
|
||||
"%s --pulse 400 '#ff0000'" % WL,
|
||||
"%s '#0000ff'" % WL, wait="any_frame") as s:
|
||||
s.wait_surface_mapped(0)
|
||||
s.wait_surface_mapped(1)
|
||||
s.mods(ALT)
|
||||
try:
|
||||
reds = []
|
||||
deadline = time.monotonic() + 12.0
|
||||
while time.monotonic() < deadline:
|
||||
red, _ = _dominant_counts(s, s.dump_host())
|
||||
reds.append(red)
|
||||
time.sleep(0.3)
|
||||
if reds and max(reds) - min(reds) > 1500:
|
||||
break
|
||||
assert reds and max(reds) - min(reds) > 1500, \
|
||||
f"hidden pulse thumbnail frozen while held: range={reds}"
|
||||
finally:
|
||||
s.mods(0)
|
||||
_assert_alive(s)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue