From befe66d93f34e040312afdc3d34e3055cc7f0dec Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Sat, 26 Feb 2022 01:21:39 +0100 Subject: [PATCH] cursor.c: Keep sending adjusted motion events while button is pressed This allows to keep dragging a scrollbar or selecting text even when moving outside of the window. Fixes #241 --- include/labwc.h | 12 ++++++++++++ src/cursor.c | 16 ++++++++++++++++ src/xdg.c | 3 +++ src/xwayland.c | 3 +++ 4 files changed, 34 insertions(+) diff --git a/include/labwc.h b/include/labwc.h index 43ce6d2d..07909228 100644 --- a/include/labwc.h +++ b/include/labwc.h @@ -82,6 +82,18 @@ struct seat { /* if set, views cannot receive focus */ struct wlr_layer_surface_v1 *focused_layer; + /** + * active_view will usually be NULL and is only set on button press + * while the mouse is over a view surface and reset to NULL on button + * release. + * It is used to send cursor motion events to a surface even though + * the cursor has left the surface in the meantime. + * + * This allows to keep dragging a scrollbar or selecting text even + * when moving outside of the window. + */ + struct view *active_view; + struct wl_client *active_client_while_inhibited; struct wl_list inputs; struct wl_listener new_input; diff --git a/src/cursor.c b/src/cursor.c index a3590eab..29e8eb5f 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -195,6 +195,15 @@ process_cursor_motion(struct server *server, uint32_t time) } else if (server->input_mode == LAB_INPUT_STATE_RESIZE) { process_cursor_resize(server, time); return; + } else if (server->seat.active_view && !server->seat.drag_icon) { + /* Button has been pressed while over a view surface */ + struct view *view = server->seat.active_view; + double sx = server->seat.cursor->x - view->x; + double sy = server->seat.cursor->y - view->y; + sx = sx < 0 ? 0 : (sx > view->w ? view->w : sx); + sy = sy < 0 ? 0 : (sy > view->h ? view->h : sy); + wlr_seat_pointer_notify_motion(server->seat.seat, time, sx, sy); + return; } /* Otherwise, find view under the pointer and send the event along */ @@ -317,6 +326,7 @@ start_drag(struct wl_listener *listener, void *data) { struct seat *seat = wl_container_of(listener, seat, start_drag); struct wlr_drag *wlr_drag = data; + seat->active_view = NULL; seat->drag_icon = wlr_drag->icon; wl_signal_add(&seat->drag_icon->events.destroy, &seat->destroy_drag); } @@ -647,6 +657,8 @@ cursor_button(struct wl_listener *listener, void *data) /* handle _release_ */ if (event->state == WLR_BUTTON_RELEASED) { + server->seat.active_view = NULL; + if (server->input_mode == LAB_INPUT_STATE_MENU) { if (close_menu) { if (server->menu_current) { @@ -674,6 +686,10 @@ cursor_button(struct wl_listener *listener, void *data) } /* Handle _press */ + if (view_area == LAB_SSD_CLIENT) { + server->seat.active_view = view; + } + if (server->input_mode == LAB_INPUT_STATE_MENU) { if (view_area != LAB_SSD_MENU) { /* We close the menu on release so we don't leak a stray release */ diff --git a/src/xdg.c b/src/xdg.c index dc534499..2e01a3c9 100644 --- a/src/xdg.c +++ b/src/xdg.c @@ -85,6 +85,9 @@ handle_destroy(struct wl_listener *listener, void *data) wlr_foreign_toplevel_handle_v1_destroy(view->toplevel_handle); } interactive_end(view); + if (view->server->seat.active_view == view) { + view->server->seat.active_view = NULL; + } wl_list_remove(&view->link); wl_list_remove(&view->destroy.link); if (view->scene_tree) { diff --git a/src/xwayland.c b/src/xwayland.c index a3da7b90..88f8c5f0 100644 --- a/src/xwayland.c +++ b/src/xwayland.c @@ -99,6 +99,9 @@ handle_destroy(struct wl_listener *listener, void *data) wlr_foreign_toplevel_handle_v1_destroy(view->toplevel_handle); } interactive_end(view); + if (view->server->seat.active_view == view) { + view->server->seat.active_view = NULL; + } view->xwayland_surface = NULL; wl_list_remove(&view->link); wl_list_remove(&view->map.link);