wayland: fix click delay after shade and modal dialog parenting
After shading a window, clicks on the lower titlebar would be routed to the resizebar handler, requiring multiple clicks before one landed in a region where frame_buf_button_at didn't return the (disabled) resizebar. Two related bugs: 1. frame_buf_button_at iterated all child frame_bufs without checking enabled state. The shaded resizebar's bounds still recorded in fb->x/y/width/height but its scene_buf was disabled. Since the shaded resizebar was repositioned ON TOP of the titlebar, clicks in the overlapping region returned the (smaller, disabled) resizebar instead of the titlebar. Added an enabled-state check. 2. wlroots scene graph caches buffer dimensions for hit-testing. Mutating fb->base.width/height directly leaves stale bounds. Use wlr_scene_buffer_set_dest_size() whenever the buffer is resized. Also fixes: - WINGs dialog content was placed in WL_LAYER_FLOATING instead of under the parent frame's tree, so the content didn't follow the WM-managed decorations on move. Now parented under the frame tree and positioned at relative offset. - wl_window_map called wlr_scene_node_raise_to_top on the client scene_node, which raised it above the titlebar within the frame tree. After unshade this hid the titlebar. Removed. - xdg_activation focus path: raise the frame tree, not the client scene_node, for the same reason.
This commit is contained in:
parent
13101c53c3
commit
bc25aa4b8a
|
|
@ -4076,6 +4076,7 @@ frame_buf_button_at(int px, int py)
|
||||||
wl_list_for_each(fb, &wl_state.frame_list, link) {
|
wl_list_for_each(fb, &wl_state.frame_list, link) {
|
||||||
if (!fb->parent_id) continue; /* top-level root */
|
if (!fb->parent_id) continue; /* top-level root */
|
||||||
if (!fb->scene_buf) continue; /* no scene node */
|
if (!fb->scene_buf) continue; /* no scene node */
|
||||||
|
if (!fb->scene_buf->node.enabled) continue; /* hidden */
|
||||||
/* Buttons are small children of the titlebar with enabled scene_bufs.
|
/* Buttons are small children of the titlebar with enabled scene_bufs.
|
||||||
* Skip large nodes (titlebars, resizebars) by size threshold. */
|
* Skip large nodes (titlebars, resizebars) by size threshold. */
|
||||||
if (px < fb->x || px >= fb->x + fb->width) continue;
|
if (px < fb->x || px >= fb->x + fb->width) continue;
|
||||||
|
|
@ -4270,9 +4271,11 @@ wl_frame_configure(WNativeWindow win, int x, int y, int width, int height)
|
||||||
fb->height = height;
|
fb->height = height;
|
||||||
fb->base.width = width;
|
fb->base.width = width;
|
||||||
fb->base.height = height;
|
fb->base.height = height;
|
||||||
/* Detach old buffer from scene so it picks up new dimensions on next commit */
|
/* Notify scene graph of new size — required for hit-testing.
|
||||||
|
* wlroots caches buffer dimensions; without this, clicks beyond
|
||||||
|
* the old size would miss this scene_buf. */
|
||||||
if (fb->scene_buf)
|
if (fb->scene_buf)
|
||||||
wlr_scene_buffer_set_buffer(fb->scene_buf, NULL);
|
wlr_scene_buffer_set_dest_size(fb->scene_buf, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update absolute position tracking for children (used by hit-testing) */
|
/* Update absolute position tracking for children (used by hit-testing) */
|
||||||
|
|
@ -4347,6 +4350,9 @@ wl_frame_paint(struct WFrameWindow *fwin)
|
||||||
tb_fb->base.width = tb_w;
|
tb_fb->base.width = tb_w;
|
||||||
tb_fb->base.height = tb_h;
|
tb_fb->base.height = tb_h;
|
||||||
tb_img = tb_fb->image;
|
tb_img = tb_fb->image;
|
||||||
|
/* Notify scene graph so hit-testing covers the new size. */
|
||||||
|
if (tb_fb->scene_buf)
|
||||||
|
wlr_scene_buffer_set_dest_size(tb_fb->scene_buf, tb_w, tb_h);
|
||||||
}
|
}
|
||||||
WTexture *tex = fwin->title_texture[state];
|
WTexture *tex = fwin->title_texture[state];
|
||||||
|
|
||||||
|
|
@ -5147,8 +5153,16 @@ handle_xdg_activation_request(struct wl_listener *listener, void *data)
|
||||||
if (desc && desc->parent_type == WCLASS_WINDOW) {
|
if (desc && desc->parent_type == WCLASS_WINDOW) {
|
||||||
WWindow *wwin = (WWindow *)desc->parent;
|
WWindow *wwin = (WWindow *)desc->parent;
|
||||||
wSetFocusTo(wScreenWithNumber(0), wwin);
|
wSetFocusTo(wScreenWithNumber(0), wwin);
|
||||||
if (view->scene_node)
|
/* Raise the entire window assembly (frame tree), not just the
|
||||||
|
* client scene_node — raising the client alone would push it
|
||||||
|
* above the titlebar and hide decorations. */
|
||||||
|
if (view->frame_id) {
|
||||||
|
struct wl_frame_buf *fb = frame_buf_find(view->frame_id);
|
||||||
|
if (fb && fb->tree)
|
||||||
|
wlr_scene_node_raise_to_top(&fb->tree->node);
|
||||||
|
} else if (view->scene_node) {
|
||||||
wlr_scene_node_raise_to_top(&view->scene_node->node);
|
wlr_scene_node_raise_to_top(&view->scene_node->node);
|
||||||
|
}
|
||||||
/* Move to front of toplevel list (Z-order). */
|
/* Move to front of toplevel list (Z-order). */
|
||||||
wl_list_remove(&view->link);
|
wl_list_remove(&view->link);
|
||||||
wl_list_insert(wl_state.toplevel_list.prev, &view->link);
|
wl_list_insert(wl_state.toplevel_list.prev, &view->link);
|
||||||
|
|
@ -6395,7 +6409,6 @@ wl_window_map(WNativeWindow win)
|
||||||
struct wl_toplevel_view *v = wl_find_view_by_id(win);
|
struct wl_toplevel_view *v = wl_find_view_by_id(win);
|
||||||
if (v && v->scene_node) {
|
if (v && v->scene_node) {
|
||||||
wlr_scene_node_set_enabled(&v->scene_node->node, true);
|
wlr_scene_node_set_enabled(&v->scene_node->node, true);
|
||||||
wlr_scene_node_raise_to_top(&v->scene_node->node);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (v)
|
if (v)
|
||||||
|
|
@ -6581,8 +6594,9 @@ static void wl_window_resize(WNativeWindow win, int w, int h)
|
||||||
fb->height = h;
|
fb->height = h;
|
||||||
fb->base.width = w;
|
fb->base.width = w;
|
||||||
fb->base.height = h;
|
fb->base.height = h;
|
||||||
|
/* Update scene graph's cached buffer size for hit-testing. */
|
||||||
if (fb->scene_buf)
|
if (fb->scene_buf)
|
||||||
wlr_scene_buffer_set_buffer(fb->scene_buf, NULL);
|
wlr_scene_buffer_set_dest_size(fb->scene_buf, w, h);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static void wl_window_set_border(WNativeWindow win, unsigned long pixel)
|
static void wl_window_set_border(WNativeWindow win, unsigned long pixel)
|
||||||
|
|
@ -6856,8 +6870,20 @@ wl_client_reparent(WNativeWindow client, WNativeWindow new_parent, int x, int y)
|
||||||
existing->rel_y = y;
|
existing->rel_y = y;
|
||||||
existing->x = parent_fb->x + x;
|
existing->x = parent_fb->x + x;
|
||||||
existing->y = parent_fb->y + y;
|
existing->y = parent_fb->y + y;
|
||||||
if (existing->scene_buf)
|
if (existing->scene_buf) {
|
||||||
wlr_scene_node_set_position(&existing->scene_buf->node, x, y);
|
/* Ensure it's under the parent frame's tree, then position
|
||||||
|
* at relative offset within the tree. */
|
||||||
|
if (parent_fb->tree &&
|
||||||
|
existing->scene_buf->node.parent != parent_fb->tree) {
|
||||||
|
wlr_scene_node_reparent(&existing->scene_buf->node,
|
||||||
|
parent_fb->tree);
|
||||||
|
}
|
||||||
|
if (parent_fb->tree)
|
||||||
|
wlr_scene_node_set_position(&existing->scene_buf->node, x, y);
|
||||||
|
else
|
||||||
|
wlr_scene_node_set_position(&existing->scene_buf->node,
|
||||||
|
existing->x, existing->y);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -6888,13 +6914,20 @@ wl_client_reparent(WNativeWindow client, WNativeWindow new_parent, int x, int y)
|
||||||
fb->height = h;
|
fb->height = h;
|
||||||
|
|
||||||
if (wl_state.scene) {
|
if (wl_state.scene) {
|
||||||
/* WINGs dialog box: place in WL_LAYER_FLOATING so it renders
|
/* Place the WINGs content under the parent frame's tree so it
|
||||||
* above normal windows but below menus and dock. */
|
* moves with the WM-managed dialog decorations. */
|
||||||
struct wlr_scene_tree *_wp = wl_state.level_trees[WL_LAYER_FLOATING]
|
struct wlr_scene_tree *_wp = parent_fb->tree
|
||||||
? wl_state.level_trees[WL_LAYER_FLOATING] : &wl_state.scene->tree;
|
? parent_fb->tree
|
||||||
|
: (wl_state.level_trees[WL_LAYER_FLOATING]
|
||||||
|
? wl_state.level_trees[WL_LAYER_FLOATING]
|
||||||
|
: &wl_state.scene->tree);
|
||||||
fb->scene_buf = wlr_scene_buffer_create(_wp, &fb->base);
|
fb->scene_buf = wlr_scene_buffer_create(_wp, &fb->base);
|
||||||
if (fb->scene_buf) {
|
if (fb->scene_buf) {
|
||||||
wlr_scene_node_set_position(&fb->scene_buf->node, fb->x, fb->y);
|
/* If under the frame tree, use relative coords; otherwise absolute. */
|
||||||
|
if (parent_fb->tree)
|
||||||
|
wlr_scene_node_set_position(&fb->scene_buf->node, x, y);
|
||||||
|
else
|
||||||
|
wlr_scene_node_set_position(&fb->scene_buf->node, fb->x, fb->y);
|
||||||
wlr_scene_node_set_enabled(&fb->scene_buf->node, false);
|
wlr_scene_node_set_enabled(&fb->scene_buf->node, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue