]> git.mdlowis.com Git - proto/labwc.git/commitdiff
cursor: generalize seat->pressed
authortokyo4j <hrak1529@gmail.com>
Thu, 20 Nov 2025 16:25:19 +0000 (01:25 +0900)
committerHiroaki Yamamoto <hrak1529@gmail.com>
Sun, 30 Nov 2025 11:55:54 +0000 (20:55 +0900)
This commit moduralize seat_{set,reset}_pressed() into
cursor_context_save() so that we can also have seat->hovered later.

include/input/cursor.h
include/labwc.h
src/dnd.c
src/input/cursor.c
src/seat.c
src/view.c
src/xdg.c
src/xwayland.c

index 13ab72d10191efcac04592772793b28c255cd9e5..12b96aacac349d51a470248f714b2a4bab9241ea 100644 (file)
@@ -38,6 +38,14 @@ struct cursor_context {
        double sx, sy;
 };
 
+/* Used to persistently store cursor context (e.g. in seat->pressed) */
+struct cursor_context_saved {
+       struct cursor_context ctx;
+       struct wl_listener view_destroy;
+       struct wl_listener node_destroy;
+       struct wl_listener surface_destroy;
+};
+
 /**
  * get_cursor_context - find view, surface and scene_node at cursor
  *
@@ -65,6 +73,13 @@ void cursor_set(struct seat *seat, enum lab_cursors cursor);
 
 void cursor_set_visible(struct seat *seat, bool visible);
 
+/*
+ * Safely store a cursor context to saved_ctx. saved_ctx is cleared when either
+ * of its node, surface and view is destroyed.
+ */
+void cursor_context_save(struct cursor_context_saved *saved_ctx,
+       const struct cursor_context *ctx);
+
 /**
  * cursor_get_resize_edges - calculate resize edge based on cursor position
  * @cursor - the current cursor (usually server->seat.cursor)
index d6fd78ffcc8ec13f722ca8288f224a420a81f24c..999db395afeafd7d8ca2a3a8eb5289385855e7c1 100644 (file)
@@ -65,8 +65,7 @@ struct seat {
        struct input_method_relay *input_method_relay;
 
        /**
-        * This is usually zeroed and is only set on button press while the
-        * mouse is over a view or surface, and zeroed on button release.
+        * Cursor context saved when a mouse button is pressed on a view/surface.
         * It is used to send cursor motion events to a surface even though
         * the cursor has left the surface in the meantime.
         *
@@ -76,10 +75,8 @@ struct seat {
         * It is also used to:
         * - determine the target view for action in "Drag" mousebind
         * - validate view move/resize requests from CSD clients
-        *
-        * Both (view && !surface) and (surface && !view) are possible.
         */
-       struct cursor_context pressed;
+       struct cursor_context_saved pressed;
 
        struct lab_set bound_buttons;
 
@@ -139,7 +136,6 @@ struct seat {
        struct wl_list tablet_pads;
 
        struct wl_listener constraint_commit;
-       struct wl_listener pressed_surface_destroy;
 
        struct wlr_virtual_pointer_manager_v1 *virtual_pointer;
        struct wl_listener new_virtual_pointer;
@@ -392,8 +388,6 @@ void seat_pointer_end_grab(struct seat *seat, struct wlr_surface *surface);
 void seat_focus_lock_surface(struct seat *seat, struct wlr_surface *surface);
 
 void seat_set_focus_layer(struct seat *seat, struct wlr_layer_surface_v1 *layer);
-void seat_set_pressed(struct seat *seat, struct cursor_context *ctx);
-void seat_reset_pressed(struct seat *seat);
 void seat_output_layout_changed(struct seat *seat);
 
 /*
index 8ed7c3116070dcf3eea6b223aebc253d535a488f..ff65cffaca8a1f4c9d3fffaebd57f9fe0284060c 100644 (file)
--- a/src/dnd.c
+++ b/src/dnd.c
@@ -34,7 +34,7 @@ handle_drag_start(struct wl_listener *listener, void *data)
        struct wlr_drag *drag = data;
 
        seat->drag.active = true;
-       seat_reset_pressed(seat);
+       cursor_context_save(&seat->pressed, NULL);
        if (drag->icon) {
                /* Cleans up automatically on drag->icon->events.destroy */
                wlr_scene_drag_icon_create(seat->drag.icons, drag->icon);
index 500ac08eb9b463c52532803482c6918e42a68de3..5a09bf5090e689a51d6a091367af098a3487cdc3 100644 (file)
@@ -437,8 +437,72 @@ cursor_update_image(struct seat *seat)
                cursor_names[cursor]);
 }
 
+static void
+clear_cursor_context(struct cursor_context_saved *saved_ctx)
+{
+       if (saved_ctx->node_destroy.notify) {
+               wl_list_remove(&saved_ctx->node_destroy.link);
+       }
+       if (saved_ctx->surface_destroy.notify) {
+               wl_list_remove(&saved_ctx->surface_destroy.link);
+       }
+       if (saved_ctx->view_destroy.notify) {
+               wl_list_remove(&saved_ctx->view_destroy.link);
+       }
+       *saved_ctx = (struct cursor_context_saved) {0};
+}
+
+static void
+handle_ctx_node_destroy(struct wl_listener *listener, void *data)
+{
+       struct cursor_context_saved *saved_ctx =
+               wl_container_of(listener, saved_ctx, node_destroy);
+       clear_cursor_context(saved_ctx);
+}
+
+static void
+handle_ctx_surface_destroy(struct wl_listener *listener, void *data)
+{
+       struct cursor_context_saved *saved_ctx =
+               wl_container_of(listener, saved_ctx, surface_destroy);
+       clear_cursor_context(saved_ctx);
+}
+
+static void
+handle_ctx_view_destroy(struct wl_listener *listener, void *data)
+{
+       struct cursor_context_saved *saved_ctx =
+               wl_container_of(listener, saved_ctx, view_destroy);
+       clear_cursor_context(saved_ctx);
+}
+
+void
+cursor_context_save(struct cursor_context_saved *saved_ctx,
+               const struct cursor_context *ctx)
+{
+       assert(saved_ctx);
+
+       clear_cursor_context(saved_ctx);
+       if (!ctx) {
+               return;
+       }
+       saved_ctx->ctx = *ctx;
+       if (ctx->node) {
+               saved_ctx->node_destroy.notify = handle_ctx_node_destroy;
+               wl_signal_add(&ctx->node->events.destroy, &saved_ctx->node_destroy);
+       }
+       if (ctx->surface) {
+               saved_ctx->surface_destroy.notify = handle_ctx_surface_destroy;
+               wl_signal_add(&ctx->surface->events.destroy, &saved_ctx->surface_destroy);
+       }
+       if (ctx->view) {
+               saved_ctx->view_destroy.notify = handle_ctx_view_destroy;
+               wl_signal_add(&ctx->view->events.destroy, &saved_ctx->view_destroy);
+       }
+}
+
 static bool
-update_pressed_surface(struct seat *seat, struct cursor_context *ctx)
+update_pressed_surface(struct seat *seat, const struct cursor_context *ctx)
 {
        /*
         * In most cases, we don't want to leave one surface and enter
@@ -454,10 +518,10 @@ update_pressed_surface(struct seat *seat, struct cursor_context *ctx)
        if (!wlr_seat_pointer_has_grab(seat->seat)) {
                return false;
        }
-       if (seat->pressed.surface && ctx->surface != seat->pressed.surface) {
+       if (seat->pressed.ctx.surface && ctx->surface != seat->pressed.ctx.surface) {
                struct wlr_surface *toplevel = get_toplevel(ctx->surface);
-               if (toplevel && toplevel == get_toplevel(seat->pressed.surface)) {
-                       seat_set_pressed(seat, ctx);
+               if (toplevel && toplevel == get_toplevel(seat->pressed.ctx.surface)) {
+                       cursor_context_save(&seat->pressed, ctx);
                        return true;
                }
        }
@@ -487,7 +551,7 @@ cursor_update_common(struct server *server, struct cursor_context *ctx,
        }
 
        /* TODO: verify drag_icon logic */
-       if (seat->pressed.surface && ctx->surface != seat->pressed.surface
+       if (seat->pressed.ctx.surface && ctx->surface != seat->pressed.ctx.surface
                        && !update_pressed_surface(seat, ctx)
                        && !seat->drag.active) {
                if (cursor_has_moved) {
@@ -499,7 +563,7 @@ cursor_update_common(struct server *server, struct cursor_context *ctx,
                         * if the cursor moves outside of the surface.
                         */
                        int lx, ly;
-                       wlr_scene_node_coords(seat->pressed.node, &lx, &ly);
+                       wlr_scene_node_coords(seat->pressed.ctx.node, &lx, &ly);
                        *sx = server->seat.cursor->x - lx;
                        *sy = server->seat.cursor->y - ly;
                        return true;
@@ -597,8 +661,8 @@ cursor_process_motion(struct server *server, uint32_t time, double *sx, double *
                         * moving/resizing the wrong view
                         */
                        mousebind->pressed_in_context = false;
-                       actions_run(seat->pressed.view, server,
-                               &mousebind->actions, &seat->pressed);
+                       actions_run(seat->pressed.ctx.view, server,
+                               &mousebind->actions, &seat->pressed.ctx);
                }
        }
 
@@ -1073,7 +1137,7 @@ cursor_process_button_press(struct seat *seat, uint32_t button, uint32_t time_ms
 
        if (ctx.view || ctx.surface) {
                /* Store cursor context for later action processing */
-               seat_set_pressed(seat, &ctx);
+               cursor_context_save(&seat->pressed, &ctx);
        }
 
        if (server->input_mode == LAB_INPUT_STATE_MENU) {
@@ -1138,12 +1202,12 @@ cursor_process_button_release(struct seat *seat, uint32_t button,
 {
        struct server *server = seat->server;
        struct cursor_context ctx = get_cursor_context(server);
-       struct wlr_surface *pressed_surface = seat->pressed.surface;
+       struct wlr_surface *pressed_surface = seat->pressed.ctx.surface;
 
        /* Always notify button release event when it's not bound */
        const bool notify = !lab_set_contains(&seat->bound_buttons, button);
 
-       seat_reset_pressed(seat);
+       cursor_context_save(&seat->pressed, NULL);
 
        if (server->input_mode == LAB_INPUT_STATE_MENU) {
                /* TODO: take into account overflow of time_msec */
index 239155f9db1611c650990e9b412d4db4a9abecaa..a5cdf3eeb6a470877c051f5fce0b16c134eb693b 100644 (file)
@@ -848,46 +848,6 @@ seat_set_focus_layer(struct seat *seat, struct wlr_layer_surface_v1 *layer)
        seat->focused_layer = layer;
 }
 
-static void
-pressed_surface_destroy(struct wl_listener *listener, void *data)
-{
-       struct seat *seat = wl_container_of(listener, seat,
-               pressed_surface_destroy);
-
-       /*
-        * Using data directly prevents 'unused variable'
-        * warning when compiling without asserts
-        */
-       assert(data == seat->pressed.surface);
-
-       seat_reset_pressed(seat);
-}
-
-void
-seat_set_pressed(struct seat *seat, struct cursor_context *ctx)
-{
-       assert(ctx);
-       assert(ctx->view || ctx->surface);
-       seat_reset_pressed(seat);
-
-       seat->pressed = *ctx;
-
-       if (ctx->surface) {
-               seat->pressed_surface_destroy.notify = pressed_surface_destroy;
-               wl_signal_add(&ctx->surface->events.destroy,
-                       &seat->pressed_surface_destroy);
-       }
-}
-
-void
-seat_reset_pressed(struct seat *seat)
-{
-       if (seat->pressed.surface) {
-               wl_list_remove(&seat->pressed_surface_destroy.link);
-       }
-       seat->pressed = (struct cursor_context){0};
-}
-
 void
 seat_output_layout_changed(struct seat *seat)
 {
index 662e85fb1c9a20da2d78ddd2c0a91c590824bd3d..473a1b376519fbfc9faec0f7e2ac1814603d6620 100644 (file)
@@ -2612,10 +2612,6 @@ view_destroy(struct view *view)
                server->session_lock_manager->last_active_view = NULL;
        }
 
-       if (server->seat.pressed.view == view) {
-               seat_reset_pressed(&server->seat);
-       }
-
        if (view->tiled_region_evacuate) {
                zfree(view->tiled_region_evacuate);
        }
index f11d522c55beb8e29a987a36a22d364b96f62144..2bb6d660d38a3edbbd23b60db3c41d46690b0ce3 100644 (file)
--- a/src/xdg.c
+++ b/src/xdg.c
@@ -400,7 +400,7 @@ handle_request_move(struct wl_listener *listener, void *data)
         * want.
         */
        struct view *view = wl_container_of(listener, view, request_move);
-       if (view == view->server->seat.pressed.view) {
+       if (view == view->server->seat.pressed.ctx.view) {
                interactive_begin(view, LAB_INPUT_STATE_MOVE, LAB_EDGE_NONE);
        }
 }
@@ -418,7 +418,7 @@ handle_request_resize(struct wl_listener *listener, void *data)
         */
        struct wlr_xdg_toplevel_resize_event *event = data;
        struct view *view = wl_container_of(listener, view, request_resize);
-       if (view == view->server->seat.pressed.view) {
+       if (view == view->server->seat.pressed.ctx.view) {
                interactive_begin(view, LAB_INPUT_STATE_RESIZE, event->edges);
        }
 }
index efd8d8bef58ad1db6d5f9e87ab721ad96dd57c05..91e408972bc46ed68259ec345b8a5a3195ad0da8 100644 (file)
@@ -289,7 +289,7 @@ handle_request_move(struct wl_listener *listener, void *data)
         * want.
         */
        struct view *view = wl_container_of(listener, view, request_move);
-       if (view == view->server->seat.pressed.view) {
+       if (view == view->server->seat.pressed.ctx.view) {
                interactive_begin(view, LAB_INPUT_STATE_MOVE, LAB_EDGE_NONE);
        }
 }
@@ -307,7 +307,7 @@ handle_request_resize(struct wl_listener *listener, void *data)
         */
        struct wlr_xwayland_resize_event *event = data;
        struct view *view = wl_container_of(listener, view, request_resize);
-       if (view == view->server->seat.pressed.view) {
+       if (view == view->server->seat.pressed.ctx.view) {
                interactive_begin(view, LAB_INPUT_STATE_RESIZE, event->edges);
        }
 }