WINGs/wview_wl,wclient_wl: fix rendering and input for child views
Rendering: wl_map only triggered wl_redisplay for topLevel views. Non-toplevel views (buttons, frames, labels) were mapped but never painted. Now wl_map calls wl_redisplay for any realized view. wl_redisplay already recurses into children, so wl_map_subviews is simplified to just set mapped flags then redisplay the parent. Input: pointer events were delivered to the toplevel view because Wayland has a single surface per window (unlike X11 where each widget has its own window). Added hit-testing via W_FindViewAtPoint to route button press/release and motion events to the correct child view. Also synthesizes enter/leave events as the pointer moves between child views (needed for button highlight on hover).
This commit is contained in:
parent
c70fec7f56
commit
50096c7487
|
|
@ -509,6 +509,34 @@ static uint32_t wlc_ptr_focus_serial;
|
|||
static WLClientToplevel *wlc_ptr_focused;
|
||||
static unsigned int wlc_ptr_button_state;
|
||||
static unsigned int wlc_ptr_mods;
|
||||
static W_View *wlc_ptr_child_focus;
|
||||
|
||||
/*
|
||||
* Hit-test: find the deepest child view at (x,y) relative to the toplevel,
|
||||
* and compute local coordinates within that view.
|
||||
*/
|
||||
extern W_View *W_FindViewAtPoint(W_View *parent, int x, int y);
|
||||
|
||||
static W_View *
|
||||
wlc_hit_test(WLClientToplevel *top, int x, int y, int *lx, int *ly)
|
||||
{
|
||||
if (!top || !top->view) return NULL;
|
||||
W_View *hit = W_FindViewAtPoint(top->view, x, y);
|
||||
if (!hit) {
|
||||
*lx = x;
|
||||
*ly = y;
|
||||
return top->view;
|
||||
}
|
||||
/* Compute local coords by walking up from hit to toplevel */
|
||||
int ox = 0, oy = 0;
|
||||
for (W_View *v = hit; v && v != top->view; v = v->parent) {
|
||||
ox += v->pos.x;
|
||||
oy += v->pos.y;
|
||||
}
|
||||
*lx = x - ox;
|
||||
*ly = y - oy;
|
||||
return hit;
|
||||
}
|
||||
|
||||
static WLClientToplevel *
|
||||
wlc_top_for_surface(struct wl_surface *surf)
|
||||
|
|
@ -564,6 +592,7 @@ pointer_handle_leave(void *data, struct wl_pointer *p, uint32_t serial,
|
|||
ev.u.crossing.detail = WM_NOTIFY_ANCESTOR;
|
||||
W_WL_EnqueueEvent(ctx->scr, &ev, NULL);
|
||||
wlc_ptr_focused = NULL;
|
||||
wlc_ptr_child_focus = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -576,18 +605,48 @@ pointer_handle_motion(void *data, struct wl_pointer *p, uint32_t time,
|
|||
wlc_ptr_y = wl_fixed_to_double(sy);
|
||||
if (!wlc_ptr_focused) return;
|
||||
|
||||
int lx, ly;
|
||||
W_View *target = wlc_hit_test(wlc_ptr_focused, (int)wlc_ptr_x, (int)wlc_ptr_y, &lx, &ly);
|
||||
|
||||
/* Synthesize enter/leave when pointer moves between child views */
|
||||
if (target != wlc_ptr_child_focus) {
|
||||
if (wlc_ptr_child_focus) {
|
||||
WMEvent lev;
|
||||
memset(&lev, 0, sizeof(lev));
|
||||
lev.type = WME_LEAVE;
|
||||
lev.window = wlc_ptr_child_focus->window;
|
||||
lev.u.crossing.window = lev.window;
|
||||
lev.u.crossing.mode = WM_NOTIFY_NORMAL;
|
||||
lev.u.crossing.detail = WM_NOTIFY_ANCESTOR;
|
||||
W_WL_EnqueueEvent(ctx->scr, &lev, wlc_ptr_child_focus);
|
||||
}
|
||||
wlc_ptr_child_focus = target;
|
||||
if (target) {
|
||||
WMEvent eev;
|
||||
memset(&eev, 0, sizeof(eev));
|
||||
eev.type = WME_ENTER;
|
||||
eev.window = target->window;
|
||||
eev.u.crossing.window = eev.window;
|
||||
eev.u.crossing.x = lx;
|
||||
eev.u.crossing.y = ly;
|
||||
eev.u.crossing.mode = WM_NOTIFY_NORMAL;
|
||||
eev.u.crossing.detail = WM_NOTIFY_ANCESTOR;
|
||||
W_WL_EnqueueEvent(ctx->scr, &eev, target);
|
||||
}
|
||||
}
|
||||
|
||||
WMEvent ev;
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
ev.type = WME_MOTION;
|
||||
ev.window = wlc_ptr_focused->view->window;
|
||||
ev.window = target ? target->window : wlc_ptr_focused->view->window;
|
||||
ev.u.motion.window = ev.window;
|
||||
ev.u.motion.time = time;
|
||||
ev.u.motion.x = (int)wlc_ptr_x;
|
||||
ev.u.motion.y = (int)wlc_ptr_y;
|
||||
ev.u.motion.x = lx;
|
||||
ev.u.motion.y = ly;
|
||||
ev.u.motion.x_root = (int)wlc_ptr_x;
|
||||
ev.u.motion.y_root = (int)wlc_ptr_y;
|
||||
ev.u.motion.state = wlc_ptr_button_state | wlc_ptr_mods;
|
||||
W_WL_EnqueueEvent(ctx->scr, &ev, NULL);
|
||||
W_WL_EnqueueEvent(ctx->scr, &ev, target);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -622,16 +681,20 @@ pointer_handle_button(void *data, struct wl_pointer *p, uint32_t serial,
|
|||
memset(&ev, 0, sizeof(ev));
|
||||
ev.type = (state == WL_POINTER_BUTTON_STATE_PRESSED)
|
||||
? WME_BUTTON_PRESS : WME_BUTTON_RELEASE;
|
||||
ev.window = wlc_ptr_focused->view->window;
|
||||
|
||||
int lx, ly;
|
||||
W_View *target = wlc_hit_test(wlc_ptr_focused, (int)wlc_ptr_x, (int)wlc_ptr_y, &lx, &ly);
|
||||
|
||||
ev.window = target ? target->window : wlc_ptr_focused->view->window;
|
||||
ev.u.button.window = ev.window;
|
||||
ev.u.button.button = wmb;
|
||||
ev.u.button.state = wlc_ptr_button_state | wlc_ptr_mods;
|
||||
ev.u.button.time = time;
|
||||
ev.u.button.x = (int)wlc_ptr_x;
|
||||
ev.u.button.y = (int)wlc_ptr_y;
|
||||
ev.u.button.x = lx;
|
||||
ev.u.button.y = ly;
|
||||
ev.u.button.x_root = (int)wlc_ptr_x;
|
||||
ev.u.button.y_root = (int)wlc_ptr_y;
|
||||
W_WL_EnqueueEvent(ctx->scr, &ev, NULL);
|
||||
W_WL_EnqueueEvent(ctx->scr, &ev, target);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -265,20 +265,8 @@ static void wl_map(void *vctx, W_View *view)
|
|||
{
|
||||
(void)vctx;
|
||||
view->flags.mapped = 1;
|
||||
if (view->flags.topLevel && view->flags.realized) {
|
||||
if (view->flags.realized) {
|
||||
wl_redisplay(vctx, view);
|
||||
wl_map_subviews(vctx, view);
|
||||
/* Re-composite top-level after children have drawn into it */
|
||||
if (view->parent) {
|
||||
pixman_image_t *src = (pixman_image_t *)W_GetViewBacking(view->window);
|
||||
pixman_image_t *dst = (pixman_image_t *)W_GetViewBacking(view->parent->window);
|
||||
if (src && dst) {
|
||||
pixman_image_composite32(PIXMAN_OP_OVER, src, NULL, dst,
|
||||
0, 0, 0, 0,
|
||||
view->pos.x, view->pos.y,
|
||||
view->size.width, view->size.height);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -288,25 +276,14 @@ static void wl_map_subviews(void *vctx, W_View *view)
|
|||
while (child) {
|
||||
if (child->flags.realized) {
|
||||
child->flags.mapped = 1;
|
||||
wl_redisplay(vctx, child);
|
||||
/* Recurse into grandchildren */
|
||||
if (child->childrenList)
|
||||
wl_map_subviews(vctx, child);
|
||||
/* Re-composite child after grandchildren have drawn into it */
|
||||
pixman_image_t *src = (pixman_image_t *)W_GetViewBacking(child->window);
|
||||
pixman_image_t *dst = (pixman_image_t *)W_GetViewBacking(view->window);
|
||||
if (src && dst) {
|
||||
pixman_image_composite32(PIXMAN_OP_OVER, src, NULL, dst,
|
||||
0, 0, 0, 0,
|
||||
child->pos.x, child->pos.y,
|
||||
child->size.width, child->size.height);
|
||||
}
|
||||
} else {
|
||||
if (child->childrenList)
|
||||
wl_map_subviews(vctx, child);
|
||||
}
|
||||
if (child->childrenList)
|
||||
wl_map_subviews(vctx, child);
|
||||
child = child->nextSister;
|
||||
}
|
||||
/* Redisplay the parent which will recurse into all now-mapped children */
|
||||
if (view->flags.mapped)
|
||||
wl_redisplay(vctx, view);
|
||||
}
|
||||
|
||||
static void wl_move(void *vctx, W_View *view, int x, int y)
|
||||
|
|
|
|||
Loading…
Reference in New Issue