diff --git a/WINGs/wclient_wl.c b/WINGs/wclient_wl.c index 7aab6d5..71b8327 100644 --- a/WINGs/wclient_wl.c +++ b/WINGs/wclient_wl.c @@ -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 diff --git a/WINGs/wview_wl.c b/WINGs/wview_wl.c index 0ab87b0..732cf64 100644 --- a/WINGs/wview_wl.c +++ b/WINGs/wview_wl.c @@ -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)