wayland: implement pointer grab for icon drag-and-move
Implement wl_pointer_grab (type 3 WM policy grab) that suppresses client pointer focus delivery during WM-internal drags while letting WME_MOTION events flow to WMMaskEvent. Implement wl_pointer_ungrab and wl_pointer_change_cursor (maps WCUR_* to xcursor names). Fix button release handler to not terminate type 3 grabs early — the policy code calls pointer_ungrab itself. Fix overlay surface blocking hit-testing: the iconify animation's full-screen overlay (WL_LAYER_OVERLAY) was left enabled after the animation completed, causing wlr_scene_node_at to hit it instead of frame_bufs. Now server_ungrab disables the overlay node after flush.
This commit is contained in:
parent
6d42151d2e
commit
37ecea7c07
|
|
@ -806,6 +806,7 @@ Bool wHandleAppIconMove(WAppIcon *aicon, WMEvent *event)
|
||||||
while (1) {
|
while (1) {
|
||||||
WMMaskEvent(scr->wmscreen, PointerMotionMask | ButtonReleaseMask | ButtonPressMask
|
WMMaskEvent(scr->wmscreen, PointerMotionMask | ButtonReleaseMask | ButtonPressMask
|
||||||
| ButtonMotionMask | ExposureMask | EnterWindowMask, &ev);
|
| ButtonMotionMask | ExposureMask | EnterWindowMask, &ev);
|
||||||
|
wwarning("wHandleAppIconMove: got event type=%d", ev.type);
|
||||||
switch (ev.type) {
|
switch (ev.type) {
|
||||||
case WME_EXPOSE:
|
case WME_EXPOSE:
|
||||||
WMHandleEvent(&ev);
|
WMHandleEvent(&ev);
|
||||||
|
|
|
||||||
|
|
@ -409,8 +409,12 @@ struct wl_compositor_state {
|
||||||
int sigfd;
|
int sigfd;
|
||||||
struct wl_event_source *sigfd_source;
|
struct wl_event_source *sigfd_source;
|
||||||
/* Phase 22: interactive move/resize grab state.
|
/* Phase 22: interactive move/resize grab state.
|
||||||
* grab_type: 0=none, 1=move, 2=resize.
|
* grab_type: 0=none, 1=move, 2=resize, 3=WM policy grab.
|
||||||
* grab_view: the toplevel being moved/resized (NULL when grab_type==0).
|
* Type 3 is used by wl_pointer_grab for WM-internal drags (dock icons,
|
||||||
|
* app icons, menus). It suppresses wl_update_pointer_focus (so client
|
||||||
|
* surfaces don't steal pointer events) but does NOT intercept motion —
|
||||||
|
* WME_MOTION events flow normally to the WMMaskEvent loop.
|
||||||
|
* grab_view: the toplevel being moved/resized (NULL when grab_type==0 or 3).
|
||||||
* grab_start_ptr_{x,y}: pointer position when grab started.
|
* grab_start_ptr_{x,y}: pointer position when grab started.
|
||||||
* grab_start_win_{x,y,w,h}: window geometry when grab started.
|
* grab_start_win_{x,y,w,h}: window geometry when grab started.
|
||||||
* grab_resize_edges: WL_SHELL_SURFACE_RESIZE_* bitmask (resize only). */
|
* grab_resize_edges: WL_SHELL_SURFACE_RESIZE_* bitmask (resize only). */
|
||||||
|
|
@ -5130,10 +5134,12 @@ 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;
|
||||||
/* Phase 22: any button release ends an active grab. */
|
/* Phase 22: any button release ends an active compositor grab (move/resize).
|
||||||
if (wl_state.grab_type &&
|
* Type 3 (WM policy grab) is NOT ended here — the policy code calls
|
||||||
|
* pointer_ungrab itself after processing the button release event. */
|
||||||
|
if (wl_state.grab_type && wl_state.grab_type != 3 &&
|
||||||
ev->state == WLR_BUTTON_RELEASED) {
|
ev->state == WLR_BUTTON_RELEASED) {
|
||||||
wwarning("wl_backend: grab ended (button release)");
|
wwarning("wl_backend: grab ended (button release) grab_type=%d", wl_state.grab_type);
|
||||||
wl_grab_end();
|
wl_grab_end();
|
||||||
wl_update_pointer_focus(ev->time_msec);
|
wl_update_pointer_focus(ev->time_msec);
|
||||||
return;
|
return;
|
||||||
|
|
@ -5233,12 +5239,33 @@ wl_pointer_grab(WNativeWindow grab_win, WNativeWindow confine_to,
|
||||||
unsigned int event_mask, int cursor_id,
|
unsigned int event_mask, int cursor_id,
|
||||||
int owner_events, unsigned long timestamp)
|
int owner_events, unsigned long timestamp)
|
||||||
{
|
{
|
||||||
(void)grab_win; (void)confine_to; (void)event_mask;
|
(void)confine_to; (void)event_mask;
|
||||||
(void)cursor_id; (void)owner_events; (void)timestamp;
|
(void)timestamp; (void)grab_win;
|
||||||
return 0;
|
wwarning("wl_pointer_grab: win=0x%lx owner_events=%d cursor_id=%d grab_type_before=%d",
|
||||||
|
grab_win, owner_events, cursor_id, wl_state.grab_type);
|
||||||
|
/* Only set up a WM policy grab (type 3) for actual drags (owner_events=True).
|
||||||
|
* Brief protective grabs (e.g., during icon creation) don't need to suppress
|
||||||
|
* pointer focus — they just need to return success. */
|
||||||
|
if (owner_events) {
|
||||||
|
wl_state.grab_type = 3;
|
||||||
|
wl_state.grab_view = NULL;
|
||||||
|
if (wl_state.seat)
|
||||||
|
wlr_seat_pointer_clear_focus(wl_state.seat);
|
||||||
|
}
|
||||||
|
if (cursor_id > 0)
|
||||||
|
wl_set_cursor_image("left_ptr");
|
||||||
|
return 1; /* success */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wl_pointer_ungrab(unsigned long timestamp) { (void)timestamp; }
|
static void wl_pointer_ungrab(unsigned long timestamp)
|
||||||
|
{
|
||||||
|
(void)timestamp;
|
||||||
|
wwarning("wl_pointer_ungrab: grab_type=%d", wl_state.grab_type);
|
||||||
|
if (wl_state.grab_type == 3) {
|
||||||
|
wl_state.grab_type = 0;
|
||||||
|
wl_state.grab_view = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------ */
|
||||||
/* Phase 13: pointer focus delivery to Wayland surfaces */
|
/* Phase 13: pointer focus delivery to Wayland surfaces */
|
||||||
|
|
@ -5690,6 +5717,8 @@ overlay_flush(void)
|
||||||
wm_shm_surface_commit(s, _op, 0, 0);
|
wm_shm_surface_commit(s, _op, 0, 0);
|
||||||
}
|
}
|
||||||
if (s->scene_buf) {
|
if (s->scene_buf) {
|
||||||
|
/* Ensure the node is visible for the animation frame. */
|
||||||
|
wlr_scene_node_set_enabled(&s->scene_buf->node, true);
|
||||||
/* Notify wlroots that the pixel data has changed. */
|
/* Notify wlroots that the pixel data has changed. */
|
||||||
wlr_scene_buffer_set_buffer(s->scene_buf, &s->wlr_buf);
|
wlr_scene_buffer_set_buffer(s->scene_buf, &s->wlr_buf);
|
||||||
}
|
}
|
||||||
|
|
@ -5704,7 +5733,16 @@ overlay_flush(void)
|
||||||
/* ------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
static void wl_server_grab(void) {} /* no-op: Wayland double-buffers for us */
|
static void wl_server_grab(void) {} /* no-op: Wayland double-buffers for us */
|
||||||
static void wl_server_ungrab(void) { overlay_flush(); }
|
static void wl_server_ungrab(void)
|
||||||
|
{
|
||||||
|
overlay_flush();
|
||||||
|
/* Disable the overlay scene node so it doesn't intercept hit-testing.
|
||||||
|
* The XOR animation has already erased its pixels; leaving the node
|
||||||
|
* enabled blocks frame_buf_at (wlr_scene_node_at hits the overlay
|
||||||
|
* before any frame_buf). */
|
||||||
|
if (wl_state.overlay_surf && wl_state.overlay_surf->scene_buf)
|
||||||
|
wlr_scene_node_set_enabled(&wl_state.overlay_surf->scene_buf->node, false);
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------ */
|
||||||
/* Stacking */
|
/* Stacking */
|
||||||
|
|
@ -7931,7 +7969,20 @@ static int wl_noop_cursor_create_from_files(WScreen *scr, const char *bitmap_pat
|
||||||
{ (void)scr; (void)bitmap_path; (void)mask_path; (void)cursor_out; return 0; }
|
{ (void)scr; (void)bitmap_path; (void)mask_path; (void)cursor_out; return 0; }
|
||||||
static void wl_noop_cursor_free(Cursor cursor) { (void)cursor; }
|
static void wl_noop_cursor_free(Cursor cursor) { (void)cursor; }
|
||||||
static void wl_noop_cursor_set(WNativeWindow window, Cursor cursor) { (void)window; (void)cursor; }
|
static void wl_noop_cursor_set(WNativeWindow window, Cursor cursor) { (void)window; (void)cursor; }
|
||||||
static void wl_noop_pointer_change_cursor(int cursor_id) { (void)cursor_id; }
|
static void wl_pointer_change_cursor(int cursor_id)
|
||||||
|
{
|
||||||
|
const char *name;
|
||||||
|
switch (cursor_id) {
|
||||||
|
case 1: /* WCUR_MOVE */ name = "fleur"; break;
|
||||||
|
case 2: /* WCUR_RESIZE */ name = "bottom_right_corner"; break;
|
||||||
|
case 7: /* WCUR_WAIT */ name = "watch"; break;
|
||||||
|
case 8: /* WCUR_ARROW */ name = "left_ptr"; break;
|
||||||
|
case 9: /* WCUR_QUESTION */name = "question_arrow"; break;
|
||||||
|
case 10:/* WCUR_TEXT */ name = "xterm"; break;
|
||||||
|
default: name = "left_ptr"; break;
|
||||||
|
}
|
||||||
|
wl_set_cursor_image(name);
|
||||||
|
}
|
||||||
static void wl_noop_appicon_paint_dock_dots(WAppIcon *aicon, void *wapp)
|
static void wl_noop_appicon_paint_dock_dots(WAppIcon *aicon, void *wapp)
|
||||||
{ (void)aicon; (void)wapp; }
|
{ (void)aicon; (void)wapp; }
|
||||||
|
|
||||||
|
|
@ -8217,7 +8268,7 @@ const WMBackend wl_backend = {
|
||||||
.cursor_create_from_files = wl_noop_cursor_create_from_files,
|
.cursor_create_from_files = wl_noop_cursor_create_from_files,
|
||||||
.cursor_free = wl_noop_cursor_free,
|
.cursor_free = wl_noop_cursor_free,
|
||||||
.cursor_set = wl_noop_cursor_set,
|
.cursor_set = wl_noop_cursor_set,
|
||||||
.pointer_change_cursor = wl_noop_pointer_change_cursor,
|
.pointer_change_cursor = wl_pointer_change_cursor,
|
||||||
.appicon_paint_dock_dots = wl_noop_appicon_paint_dock_dots,
|
.appicon_paint_dock_dots = wl_noop_appicon_paint_dock_dots,
|
||||||
.pixmap_get_size = wl_noop_pixmap_get_size,
|
.pixmap_get_size = wl_noop_pixmap_get_size,
|
||||||
.icon_paint_title_bg = wl_noop_icon_paint_title_bg,
|
.icon_paint_title_bg = wl_noop_icon_paint_title_bg,
|
||||||
|
|
|
||||||
|
|
@ -3899,6 +3899,10 @@ static void iconMouseDown(WObjDescriptor *desc, WBackendEvent *event)
|
||||||
WDock *dock = aicon->dock;
|
WDock *dock = aicon->dock;
|
||||||
WScreen *scr = aicon->icon->core->screen_ptr;
|
WScreen *scr = aicon->icon->core->screen_ptr;
|
||||||
|
|
||||||
|
wwarning("iconMouseDown: aicon=%p dock=%p button=%d xindex=%d yindex=%d",
|
||||||
|
(void*)aicon, (void*)dock, event->u.button.button,
|
||||||
|
aicon->xindex, aicon->yindex);
|
||||||
|
|
||||||
if (aicon->editing || WCHECK_STATE(WSTATE_MODAL))
|
if (aicon->editing || WCHECK_STATE(WSTATE_MODAL))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue