From deb658b672fbf4810de33fb66c973aec20a3ebc6 Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Sun, 18 Sep 2022 05:40:52 +0200 Subject: [PATCH] cursor: Restore drag icon after the move to scene-graph Also move everything DnD related to src/dnd.c --- include/dnd.h | 27 ++++++++ include/labwc.h | 14 ++-- src/cursor.c | 64 ++++------------- src/desktop.c | 11 +++ src/dnd.c | 179 ++++++++++++++++++++++++++++++++++++++++++++++++ src/meson.build | 1 + 6 files changed, 241 insertions(+), 55 deletions(-) create mode 100644 include/dnd.h create mode 100644 src/dnd.c diff --git a/include/dnd.h b/include/dnd.h new file mode 100644 index 00000000..82122691 --- /dev/null +++ b/include/dnd.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __LAB_DND_H +#define __LAB_DND_H + +#include + +struct seat; +struct wlr_drag_icon; +struct wlr_scene_tree; + +struct drag_icon { + struct wlr_scene_tree *icon_tree; + struct wlr_drag_icon *icon; + struct { + struct wl_listener map; + struct wl_listener commit; + struct wl_listener unmap; + struct wl_listener destroy; + } events; +}; + +void dnd_init(struct seat *seat); +void dnd_icons_show(struct seat *seat, bool show); +void dnd_icons_move(struct seat *seat, double x, double y); +void dnd_finish(struct seat *seat); + +#endif /* __LAB_DND_H */ diff --git a/include/labwc.h b/include/labwc.h index c9ff66c9..950dd31a 100644 --- a/include/labwc.h +++ b/include/labwc.h @@ -104,7 +104,6 @@ struct seat { struct wlr_cursor *cursor; struct wlr_xcursor_manager *xcursor_manager; - struct wlr_drag_icon *drag_icon; struct wlr_pointer_constraint_v1 *current_constraint; struct wlr_idle *wlr_idle; struct wlr_idle_inhibit_manager_v1 *wlr_idle_inhibit_manager; @@ -136,6 +135,16 @@ struct seat { uint32_t resize_edges; } pressed; + struct { + bool active; + struct { + struct wl_listener request; + struct wl_listener start; + struct wl_listener destroy; + } events; + struct wlr_scene_tree *icons; + } drag; + struct wl_client *active_client_while_inhibited; struct wl_list inputs; struct wl_listener new_input; @@ -163,9 +172,6 @@ struct seat { struct wl_listener touch_motion; struct wl_listener touch_frame; - struct wl_listener request_start_drag; - struct wl_listener start_drag; - struct wl_listener destroy_drag; struct wl_listener constraint_commit; struct wl_listener idle_inhibitor_create; struct wl_listener pressed_surface_destroy; diff --git a/src/cursor.c b/src/cursor.c index 62d89c8d..57952cb3 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -9,6 +9,7 @@ #include "common/mem.h" #include "common/scene-helpers.h" #include "config/mousebind.h" +#include "dnd.h" #include "labwc.h" #include "menu/menu.h" #include "resistance.h" @@ -172,21 +173,6 @@ request_set_primary_selection_notify(struct wl_listener *listener, void *data) event->serial); } -static void -request_start_drag_notify(struct wl_listener *listener, void *data) -{ - struct seat *seat = wl_container_of( - listener, seat, request_start_drag); - struct wlr_seat_request_start_drag_event *event = data; - if (wlr_seat_validate_pointer_grab_serial(seat->seat, event->origin, - event->serial)) { - wlr_seat_start_pointer_drag(seat->seat, event->drag, - event->serial); - } else { - wlr_data_source_destroy(event->drag->source); - } -} - static void process_cursor_move(struct server *server, uint32_t time) { @@ -348,7 +334,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 && !update_pressed_surface(seat, ctx) - && !seat->drag_icon) { + && !seat->drag.active) { if (cursor_has_moved) { /* * Button has been pressed while over another @@ -403,7 +389,7 @@ cursor_update_common(struct server *server, struct cursor_context *ctx, * a drag operation. */ wlr_seat_pointer_notify_clear_focus(wlr_seat); - if (!seat->drag_icon) { + if (!seat->drag.active) { cursor_set(seat, cursor_get_from_ssd(ctx->type)); } } @@ -446,6 +432,10 @@ process_cursor_motion(struct server *server, uint32_t time) return; } + if (seat->drag.active) { + dnd_icons_move(seat, seat->cursor->x, seat->cursor->y); + } + if (ctx.view && rc.focus_follow_mouse) { desktop_focus_and_activate_view(seat, ctx.view); if (rc.raise_on_focus) { @@ -490,21 +480,6 @@ cursor_update_focus(struct server *server) /*cursor_has_moved*/ false); } -void -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_reset_pressed(seat); - seat->drag_icon = wlr_drag->icon; - if (!seat->drag_icon) { - wlr_log(WLR_ERROR, - "Started drag but application did not set a drag icon"); - return; - } - wl_signal_add(&seat->drag_icon->events.destroy, &seat->destroy_drag); -} - void handle_constraint_commit(struct wl_listener *listener, void *data) { @@ -611,18 +586,6 @@ cursor_motion(struct wl_listener *listener, void *data) process_cursor_motion(seat->server, event->time_msec); } -void -destroy_drag(struct wl_listener *listener, void *data) -{ - struct seat *seat = wl_container_of(listener, seat, destroy_drag); - - if (!seat->drag_icon) { - return; - } - seat->drag_icon = NULL; - desktop_focus_topmost_mapped_view(seat->server); -} - void cursor_motion_absolute(struct wl_listener *listener, void *data) { @@ -1022,6 +985,8 @@ cursor_init(struct seat *seat) cursor_names = cursors_x11; } + dnd_init(seat); + seat->cursor_motion.notify = cursor_motion; wl_signal_add(&seat->cursor->events.motion, &seat->cursor_motion); seat->cursor_motion_absolute.notify = cursor_motion_absolute; @@ -1054,13 +1019,6 @@ cursor_init(struct seat *seat) seat->request_set_selection.notify = request_set_selection_notify; wl_signal_add(&seat->seat->events.request_set_selection, &seat->request_set_selection); - seat->request_start_drag.notify = request_start_drag_notify; - wl_signal_add(&seat->seat->events.request_start_drag, - &seat->request_start_drag); - seat->start_drag.notify = start_drag; - wl_signal_add(&seat->seat->events.start_drag, - &seat->start_drag); - seat->destroy_drag.notify = destroy_drag; seat->request_set_primary_selection.notify = request_set_primary_selection_notify; @@ -1070,6 +1028,8 @@ cursor_init(struct seat *seat) void cursor_finish(struct seat *seat) { + /* TODO: either clean up all the listeners or none of them */ + wl_list_remove(&seat->cursor_motion.link); wl_list_remove(&seat->cursor_motion_absolute.link); wl_list_remove(&seat->cursor_button.link); @@ -1088,4 +1048,6 @@ void cursor_finish(struct seat *seat) wlr_xcursor_manager_destroy(seat->xcursor_manager); wlr_cursor_destroy(seat->cursor); + + dnd_finish(seat); } diff --git a/src/desktop.c b/src/desktop.c index e8fa349b..aaa719d1 100644 --- a/src/desktop.c +++ b/src/desktop.c @@ -3,6 +3,7 @@ #include #include "common/list.h" #include "common/scene-helpers.h" +#include "dnd.h" #include "labwc.h" #include "layers.h" #include "node.h" @@ -295,10 +296,20 @@ get_cursor_context(struct server *server) { struct cursor_context ret = {.type = LAB_SSD_NONE}; struct wlr_cursor *cursor = server->seat.cursor; + + /* Prevent drag icons to be on top of the hitbox detection */ + if (server->seat.drag.active) { + dnd_icons_show(&server->seat, false); + } + struct wlr_scene_node *node = wlr_scene_node_at(&server->scene->tree.node, cursor->x, cursor->y, &ret.sx, &ret.sy); + if (server->seat.drag.active) { + dnd_icons_show(&server->seat, true); + } + ret.node = node; if (!node) { ret.type = LAB_SSD_ROOT; diff --git a/src/dnd.c b/src/dnd.c new file mode 100644 index 00000000..8364a73f --- /dev/null +++ b/src/dnd.c @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include +#include +#include +#include "common/mem.h" +#include "dnd.h" +#include "labwc.h" /* for struct seat */ + +/* Internal DnD icon handlers */ +static void +handle_icon_map(struct wl_listener *listener, void *data) +{ + struct drag_icon *self = wl_container_of(listener, self, events.map); + struct wlr_drag_icon *icon = data; + if (icon->data) { + struct wlr_scene_tree *surface_tree = icon->data; + wlr_scene_node_set_enabled(&surface_tree->node, true); + } else { + icon->data = wlr_scene_subsurface_tree_create( + self->icon_tree, icon->surface); + } +} + +static void +handle_surface_commit(struct wl_listener *listener, void *data) +{ + struct drag_icon *self = wl_container_of(listener, self, events.commit); + struct wlr_surface *surface = data; + struct wlr_scene_tree *surface_tree = self->icon->data; + if (surface_tree) { + wlr_scene_node_set_position(&surface_tree->node, + surface->sx, surface->sy); + } +} + +static void +handle_icon_unmap(struct wl_listener *listener, void *data) +{ + struct drag_icon *self = wl_container_of(listener, self, events.unmap); + struct wlr_drag_icon *icon = data; + struct wlr_scene_tree *surface_tree = icon->data; + if (surface_tree) { + wlr_scene_node_set_enabled(&surface_tree->node, false); + } +} + +static void +handle_icon_destroy(struct wl_listener *listener, void *data) +{ + struct drag_icon *self = wl_container_of(listener, self, events.destroy); + + wl_list_remove(&self->events.map.link); + wl_list_remove(&self->events.commit.link); + wl_list_remove(&self->events.unmap.link); + wl_list_remove(&self->events.destroy.link); + + if (self->icon->data) { + struct wlr_scene_tree *tree = self->icon->data; + wlr_scene_node_destroy(&tree->node); + } + + self->icon = NULL; + self->icon_tree = NULL; + free(self); +} + +static void +drag_icon_create(struct seat *seat, struct wlr_drag_icon *wlr_icon) +{ + assert(seat); + assert(wlr_icon); + struct drag_icon *self = znew(*self); + + self->icon = wlr_icon; + self->icon_tree = seat->drag.icons; + + /* Position will be updated by cursor movement */ + wlr_scene_node_set_position(&self->icon_tree->node, + seat->cursor->x, seat->cursor->y); + wlr_scene_node_raise_to_top(&self->icon_tree->node); + + /* Set up events */ + self->events.map.notify = handle_icon_map; + self->events.commit.notify = handle_surface_commit; + self->events.unmap.notify = handle_icon_unmap; + self->events.destroy.notify = handle_icon_destroy; + + wl_signal_add(&wlr_icon->events.map, &self->events.map); + wl_signal_add(&wlr_icon->surface->events.commit, &self->events.commit); + wl_signal_add(&wlr_icon->events.unmap, &self->events.unmap); + wl_signal_add(&wlr_icon->events.destroy, &self->events.destroy); +} + +/* Internal DnD handlers */ +static void +handle_drag_request(struct wl_listener *listener, void *data) +{ + struct seat *seat = wl_container_of(listener, seat, drag.events.request); + struct wlr_seat_request_start_drag_event *event = data; + + if (wlr_seat_validate_pointer_grab_serial( + seat->seat, event->origin, event->serial)) { + wlr_seat_start_pointer_drag(seat->seat, event->drag, + event->serial); + } else { + wlr_data_source_destroy(event->drag->source); + wlr_log(WLR_ERROR, "wrong source for drag request"); + } +} + +static void +handle_drag_start(struct wl_listener *listener, void *data) +{ + struct seat *seat = wl_container_of(listener, seat, drag.events.start); + assert(!seat->drag.active); + struct wlr_drag *drag = data; + + seat->drag.active = true; + seat_reset_pressed(seat); + if (drag->icon) { + /* Cleans up automatically on drag->icon->events.detroy */ + drag_icon_create(seat, drag->icon); + wlr_scene_node_set_enabled(&seat->drag.icons->node, true); + } + wl_signal_add(&drag->events.destroy, &seat->drag.events.destroy); +} + +static void +handle_drag_destroy(struct wl_listener *listener, void *data) +{ + struct seat *seat = wl_container_of(listener, seat, drag.events.destroy); + assert(seat->drag.active); + + seat->drag.active = false; + wl_list_remove(&seat->drag.events.destroy.link); + wlr_scene_node_set_enabled(&seat->drag.icons->node, false); + /* TODO: Not sure we actually need the following */ + desktop_focus_topmost_mapped_view(seat->server); +} + +/* Public API */ +void +dnd_init(struct seat *seat) +{ + seat->drag.icons = wlr_scene_tree_create(&seat->server->scene->tree); + wlr_scene_node_set_enabled(&seat->drag.icons->node, false); + + seat->drag.events.request.notify = handle_drag_request; + seat->drag.events.start.notify = handle_drag_start; + seat->drag.events.destroy.notify = handle_drag_destroy; + + wl_signal_add(&seat->seat->events.request_start_drag, + &seat->drag.events.request); + wl_signal_add(&seat->seat->events.start_drag, &seat->drag.events.start); + /* + * destroy.notify is listened to in handle_drag_start() and reset in + * handle_drag_destroy() + */ +} + +void +dnd_icons_show(struct seat *seat, bool show) +{ + wlr_scene_node_set_enabled(&seat->drag.icons->node, show); +} + +void +dnd_icons_move(struct seat *seat, double x, double y) +{ + wlr_scene_node_set_position(&seat->drag.icons->node, x, y); +} + +void dnd_finish(struct seat *seat) +{ + wlr_scene_node_destroy(&seat->drag.icons->node); + wl_list_remove(&seat->drag.events.request.link); + wl_list_remove(&seat->drag.events.start.link); +} diff --git a/src/meson.build b/src/meson.build index 7771fcab..ff4bff8b 100644 --- a/src/meson.build +++ b/src/meson.build @@ -4,6 +4,7 @@ labwc_sources = files( 'cursor.c', 'debug.c', 'desktop.c', + 'dnd.c', 'foreign.c', 'interactive.c', 'keyboard.c', -- 2.52.0