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
*
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)
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.
*
* 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;
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;
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);
/*
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);
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
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;
}
}
}
/* 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) {
* 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;
* 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);
}
}
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) {
{
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 */
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)
{
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);
}
* 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);
}
}
*/
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);
}
}
* 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);
}
}
*/
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);
}
}