wayland: fix dockapp drag-to-dock and pointer input routing

- appIconMouseDown: allow drag (Button1) even when icon->owner is NULL,
  which happens for dockapps whose WWindow is unmanaged after docking
- canBeDocked: fall back to aicon->wm_class/wm_instance when owner is
  NULL so dockapps can be snapped into dock slots
- wl_pointer_focus: don't give seat pointer focus to views embedded in
  frame_bufs (dockapps) — let WM handle input via frame_buf path
- wl_handlers button hittest: route clicks on embedded views to their
  parent frame_buf instead of the client surface
- wl_window_unmap: don't disable scene_node if view is reparented into
  a frame (docked)
This commit is contained in:
lkn 2026-06-28 01:49:50 +02:00
parent 5ead98b986
commit 2cfbd7d34b
6 changed files with 42 additions and 6 deletions

View File

@ -171,8 +171,11 @@ wl_flush(void *ectx, Bool discard)
W_WLClientCommitAllToplevels(); W_WLClientCommitAllToplevels();
/* Pump the wlroots event loop so pointer/key events arrive in our queue. /* Pump the wlroots event loop so pointer/key events arrive in our queue.
* This is called from waitForEvent/WMMaskEvent when the queue is empty. */ * This is called from waitForEvent/WMMaskEvent when the queue is empty. */
if (ctx->dispatch_fn) if (ctx->dispatch_fn) {
ctx->dispatch_fn(16, ctx->dispatch_ud); ctx->dispatch_fn(16, ctx->dispatch_ud);
if (ctx->head != ctx->tail)
wwarning("wl_flush: after dispatch, queue has events (head=%d tail=%d)", ctx->head, ctx->tail);
}
} }
static int static int

View File

@ -315,6 +315,8 @@ static WAppIcon *wAppIconCreate(WWindow *leader_win)
/* will be overriden if docked */ /* will be overriden if docked */
aicon->icon->core->descriptor.handle_mousedown = appIconMouseDown; aicon->icon->core->descriptor.handle_mousedown = appIconMouseDown;
wwarning("appicon: SET appIconMouseDown on core->window=0x%lx (wAppIconCreate)",
(unsigned long)aicon->icon->core->window);
aicon->icon->core->descriptor.handle_expose = iconExpose; aicon->icon->core->descriptor.handle_expose = iconExpose;
aicon->icon->core->descriptor.parent_type = WCLASS_APPICON; aicon->icon->core->descriptor.parent_type = WCLASS_APPICON;
aicon->icon->core->descriptor.parent = aicon; aicon->icon->core->descriptor.parent = aicon;
@ -634,8 +636,13 @@ void appIconMouseDown(WObjDescriptor * desc, WBackendEvent * event)
if (aicon->editing || WCHECK_STATE(WSTATE_MODAL)) if (aicon->editing || WCHECK_STATE(WSTATE_MODAL))
return; return;
if (!aicon->icon->owner) if (!aicon->icon->owner) {
/* No running app — only allow drag (Button1) for docking */
if (event->u.button.button == Button1) {
wHandleAppIconMove(aicon, event);
}
return; return;
}
if (IsDoubleClick(scr, event)) { if (IsDoubleClick(scr, event)) {
/* Middle or right mouse actions were handled on first click */ /* Middle or right mouse actions were handled on first click */
@ -740,7 +747,8 @@ Bool wHandleAppIconMove(WAppIcon *aicon, WMEvent *event)
if (wPreferences.flags.nodock && wPreferences.flags.noclip && wPreferences.flags.nodrawer) if (wPreferences.flags.nodock && wPreferences.flags.noclip && wPreferences.flags.nodrawer)
dockable = 0; dockable = 0;
else else
dockable = canBeDocked(icon->owner); dockable = canBeDocked(icon->owner)
|| aicon->wm_class || aicon->wm_instance;
} }
/* We try the various docks in that order: /* We try the various docks in that order:
@ -785,6 +793,7 @@ Bool wHandleAppIconMove(WAppIcon *aicon, WMEvent *event)
while (1) { while (1) {
WMMaskEvent(scr->wmscreen, WM_EVMASK_POINTER_MOTION | WM_EVMASK_BUTTON_RELEASE | WM_EVMASK_BUTTON_PRESS WMMaskEvent(scr->wmscreen, WM_EVMASK_POINTER_MOTION | WM_EVMASK_BUTTON_RELEASE | WM_EVMASK_BUTTON_PRESS
| WM_EVMASK_BUTTON_MOTION | WM_EVMASK_EXPOSURE | WM_EVMASK_ENTER_WINDOW, &ev); | WM_EVMASK_BUTTON_MOTION | WM_EVMASK_EXPOSURE | WM_EVMASK_ENTER_WINDOW, &ev);
wwarning("wHandleAppIconMove: ev.type=%d", ev.type);
switch (ev.type) { switch (ev.type) {
case WME_EXPOSE: case WME_EXPOSE:
WMHandleEvent(&ev); WMHandleEvent(&ev);

View File

@ -176,6 +176,9 @@ handle_pointer_button(struct wl_listener *listener, void *data)
struct wlr_pointer_button_event *ev = data; struct wlr_pointer_button_event *ev = data;
if (!wl_state.seat) if (!wl_state.seat)
return; return;
wwarning("BUTTON TOP: btn=%u state=%d pos=(%d,%d) grab_type=%d",
ev->button, ev->state,
wl_state.pointer_x, wl_state.pointer_y, wl_state.grab_type);
/* any button release ends an active compositor grab (move/resize). /* any button release ends an active compositor grab (move/resize).
* Type 3 (WM policy grab) is NOT ended here — the policy code calls * Type 3 (WM policy grab) is NOT ended here — the policy code calls
* pointer_ungrab itself after processing the button release event. */ * pointer_ungrab itself after processing the button release event. */
@ -252,7 +255,9 @@ handle_pointer_button(struct wl_listener *listener, void *data)
struct wl_toplevel_view *_tv = NULL; struct wl_toplevel_view *_tv = NULL;
struct wlr_surface *_surf = view_surface_at(wl_state.pointer_x, wl_state.pointer_y, struct wlr_surface *_surf = view_surface_at(wl_state.pointer_x, wl_state.pointer_y,
&_sx, &_sy, &_tv); &_sx, &_sy, &_tv);
if (_surf && _tv) { if (_surf && _tv && !_tv->frame_id) {
/* Normal client window — use the view's ID or find a
* WINGs frame_buf overlay at this position. */
struct wl_frame_buf *_wtb = NULL; struct wl_frame_buf *_wtb = NULL;
wl_list_for_each(_wtb, &wl_state.frame_list, link) { wl_list_for_each(_wtb, &wl_state.frame_list, link) {
if (_wtb->id >= 0x20000000 && if (_wtb->id >= 0x20000000 &&
@ -268,9 +273,18 @@ handle_pointer_button(struct wl_listener *listener, void *data)
wev.u.button.window = wev.window; wev.u.button.window = wev.window;
wev.u.button.x = (int)_sx; wev.u.button.x = (int)_sx;
wev.u.button.y = (int)_sy; wev.u.button.y = (int)_sy;
wwarning("btn hittest: CLIENT view=0x%lx frame_id=0x%lx wev.window=0x%lx",
(unsigned long)_tv->id, (unsigned long)_tv->frame_id, (unsigned long)wev.window);
} else { } else {
/* Decorations, dockapp tile, or empty area — use frame_buf */
struct wl_frame_buf *fb = frame_buf_hit(wl_state.pointer_x, struct wl_frame_buf *fb = frame_buf_hit(wl_state.pointer_x,
wl_state.pointer_y); wl_state.pointer_y);
if (!fb && _tv && _tv->frame_id)
fb = frame_buf_find(_tv->frame_id);
wwarning("btn hittest: FRAME surf=%p tv=%p tv_frame=0x%lx fb=%p fb_id=0x%lx",
(void*)_surf, (void*)_tv,
_tv ? (unsigned long)_tv->frame_id : 0,
(void*)fb, fb ? (unsigned long)fb->id : 0);
if (fb) { if (fb) {
wev.window = fb->id; wev.window = fb->id;
wev.u.button.window = fb->id; wev.u.button.window = fb->id;

View File

@ -176,11 +176,14 @@ wl_update_pointer_focus(uint32_t time_msec)
struct wl_toplevel_view *v = NULL; struct wl_toplevel_view *v = NULL;
struct wlr_surface *cs = view_surface_at( struct wlr_surface *cs = view_surface_at(
wl_state.pointer_x, wl_state.pointer_y, &sx, &sy, &v); wl_state.pointer_x, wl_state.pointer_y, &sx, &sy, &v);
if (cs) { if (cs && v && !v->frame_id) {
/* Normal window content area — give client pointer focus */
surface = cs; surface = cs;
view = v; view = v;
fb = NULL; /* not over decorations */ fb = NULL; /* not over decorations */
} }
/* If v->frame_id is set, the surface is embedded (dockapp) —
* let the WM handle input via the frame_buf path. */
} }
if (!fb && !surface) { if (!fb && !surface) {
surface = view_surface_at( surface = view_surface_at(

View File

@ -1593,6 +1593,8 @@ static WAppIcon *restore_icon_state(WScreen *scr, WMPropList *info, int type, in
wfree(command); wfree(command);
aicon->icon->core->descriptor.handle_mousedown = iconMouseDown; aicon->icon->core->descriptor.handle_mousedown = iconMouseDown;
wwarning("dock: SET iconMouseDown on core->window=0x%lx (restoreIcon/attach)",
(unsigned long)aicon->icon->core->window);
aicon->icon->core->descriptor.handle_enternotify = clipEnterNotify; aicon->icon->core->descriptor.handle_enternotify = clipEnterNotify;
aicon->icon->core->descriptor.handle_leavenotify = clipLeaveNotify; aicon->icon->core->descriptor.handle_leavenotify = clipLeaveNotify;
aicon->icon->core->descriptor.parent_type = WCLASS_DOCK_ICON; aicon->icon->core->descriptor.parent_type = WCLASS_DOCK_ICON;

View File

@ -685,8 +685,13 @@ static void handleButtonPress(WMEvent * event)
desc = wm_backend->context_find(event->u.button.window, WM_CTX_CLIENT_WIN); desc = wm_backend->context_find(event->u.button.window, WM_CTX_CLIENT_WIN);
if (!desc) if (!desc)
desc = wm_backend->context_find(event->u.button.window, WM_CTX_CLIENT_WIN); desc = wm_backend->context_find(event->u.button.window, WM_CTX_CLIENT_WIN);
if (!desc) if (!desc) {
wwarning("handleButtonPress: NO DESC for window=0x%lx", (unsigned long)event->u.button.window);
return; return;
}
wwarning("handleButtonPress: window=0x%lx desc=%p parent_type=%d handle_mousedown=%p",
(unsigned long)event->u.button.window, (void*)desc, desc->parent_type,
(void*)desc->handle_mousedown);
if (desc->parent_type == WCLASS_WINDOW) { if (desc->parent_type == WCLASS_WINDOW) {
wm_backend->event_sync(0); wm_backend->event_sync(0);