Force whole-output repaint when the standalone overlay shows or clears
The standalone overlay is rendered into the scene output buffer in a second pass outside the scene graph, so wlroots' damage tracking never learns about its pixels; a reused swapchain buffer therefore keeps the stale overlay baked in after Alt is released. A transparent full-output sentinel rect is transiently raised to the top so the reorder traversal repopulates its full-screen visible region, then its size is bumped to re-damage that region through the public scene API, and the z-order is restored so it never intercepts pointer hit-testing. Both swapchain slots then repaint within the next two frames and the overlay fully clears on release. The set_enabled-based alternatives produce no output damage (wlroots only damages the post-change visible region, which is empty for a disabled rect), and the sentinel's visible region is otherwise emptied by the opaque client occluding the shared update region before it is reached.
This commit is contained in:
parent
98879be1fc
commit
c4a4b73393
2 changed files with 104 additions and 20 deletions
|
|
@ -123,6 +123,9 @@ struct tabbed_server {
|
|||
struct wlr_output *output;
|
||||
struct wlr_scene_output *scene_output;
|
||||
struct wlr_scene_rect *bg_rect;
|
||||
/* Transparent full-output sentinel used to force whole-output damage on
|
||||
overlay transitions; see standalone_overlay_damage(). */
|
||||
struct wlr_scene_rect *overlay_damage_rect;
|
||||
struct wlr_seat *seat;
|
||||
struct wlr_xdg_shell *xdg_shell;
|
||||
struct wlr_keyboard keyboard;
|
||||
|
|
@ -1676,6 +1679,18 @@ server.output = output;
|
|||
if (server.bg_rect)
|
||||
wlr_scene_node_lower_to_bottom(&server.bg_rect->node);
|
||||
}
|
||||
|
||||
/* Standalone-only damage sentinel for the overlay; see
|
||||
standalone_overlay_damage(). A fully transparent rect, sized to the
|
||||
output and left enabled (it renders nothing). It sits at the bottom of
|
||||
the z-order and is transiently raised inside standalone_overlay_damage()
|
||||
to re-populate its visible region and force whole-output damage. */
|
||||
if (server.overlay_damage_rect) {
|
||||
wlr_scene_rect_set_size(server.overlay_damage_rect, w, h);
|
||||
} else if (server.standalone) {
|
||||
server.overlay_damage_rect = wlr_scene_rect_create(
|
||||
&server.scene->tree, w, h, (float[]){ 0.0f, 0.0f, 0.0f, 0.0f });
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_toplevel_destroy(struct wl_listener *listener, void *data) {
|
||||
|
|
@ -3278,6 +3293,38 @@ static void host_kbd_key(void *data, struct wl_keyboard *kbd, uint32_t serial,
|
|||
}
|
||||
}
|
||||
|
||||
/* Standalone overlay visibility. The overlay is drawn into the scene output
|
||||
buffer outside the scene graph, so the scene's damage trackers never learn
|
||||
about its pixels; a swapchain buffer reused after the overlay was drawn
|
||||
keeps the stale overlay baked in unless we force a repaint on transition.
|
||||
Bumping the sentinel rect's size routes through wlr_scene_rect_set_size ->
|
||||
wlr_scene_node_update() with NULL damage, which re-damages the node's whole
|
||||
populated "visible" region, so both swapchain slots repaint within the next
|
||||
two frames: the overlay fully appears on press and fully clears on release. */
|
||||
static void standalone_overlay_damage(void) {
|
||||
if (!server.output || !server.overlay_damage_rect) return;
|
||||
struct wlr_scene_rect *r = server.overlay_damage_rect;
|
||||
/* The sentinel's "visible" region is only kept populated while it is the
|
||||
topmost sibling (the scene's damage traversal walks children in reverse
|
||||
z-order, and an opaque client surface above it would empty the shared
|
||||
update region before the sentinel is visited). Raise it, so the reorder
|
||||
traversal populates its full-screen visible region, then bump its size
|
||||
to re-damage that whole region; restore the z-order immediately so the
|
||||
always-enabled transparent rect never intercepts pointer hit-testing. */
|
||||
wlr_scene_node_raise_to_top(&r->node);
|
||||
wlr_scene_rect_set_size(r, r->width, r->height - 1);
|
||||
wlr_scene_rect_set_size(r, r->width, r->height);
|
||||
wlr_scene_node_lower_to_bottom(&r->node);
|
||||
}
|
||||
|
||||
static void update_overlay_visible(bool alt) {
|
||||
if (alt == host.overlay_visible) return;
|
||||
host.overlay_visible = alt;
|
||||
if (server.standalone)
|
||||
standalone_overlay_damage();
|
||||
needs_redraw = true;
|
||||
}
|
||||
|
||||
/* Shared key handling for both the host keyboard and native input devices:
|
||||
tab-switch bindings + overlay visibility, with the caller forwarding the
|
||||
key to the seat afterwards. `mods_depressed` uses the wl_keyboard modifier
|
||||
|
|
@ -3300,10 +3347,8 @@ static bool process_key_event(uint32_t time, uint32_t key, uint32_t state,
|
|||
? xkb_state_mod_index_is_active(server.xkb_state,
|
||||
server.xkb_alt_mod, XKB_STATE_MODS_EFFECTIVE)
|
||||
: (mods_depressed & (1u << 3)) != 0;
|
||||
if (alt != host.overlay_visible) {
|
||||
host.overlay_visible = alt;
|
||||
needs_redraw = true;
|
||||
}
|
||||
if (alt != host.overlay_visible)
|
||||
update_overlay_visible(alt);
|
||||
char symbuf[32];
|
||||
xkb_keysym_get_name(sym, symbuf, sizeof(symbuf));
|
||||
tabbed_log(TABBED_LOG_DEBUG,
|
||||
|
|
@ -3404,10 +3449,8 @@ static void process_modifiers(uint32_t mods_depressed, uint32_t mods_latched,
|
|||
? xkb_state_mod_index_is_active(server.xkb_state,
|
||||
server.xkb_alt_mod, XKB_STATE_MODS_EFFECTIVE)
|
||||
: (mods_depressed & (1u << 3)) != 0;
|
||||
if (alt != host.overlay_visible) {
|
||||
host.overlay_visible = alt;
|
||||
needs_redraw = true;
|
||||
}
|
||||
if (alt != host.overlay_visible)
|
||||
update_overlay_visible(alt);
|
||||
if (host.repeat_key && !alt)
|
||||
kbd_repeat_cancel();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue