]> git.mdlowis.com Git - proto/labwc.git/commitdiff
cursor: Restore drag icon after the move to scene-graph
authorConsolatis <35009135+Consolatis@users.noreply.github.com>
Sun, 18 Sep 2022 03:40:52 +0000 (05:40 +0200)
committerJohan Malm <johanmalm@users.noreply.github.com>
Mon, 17 Oct 2022 20:22:12 +0000 (21:22 +0100)
Also move everything DnD related to src/dnd.c

include/dnd.h [new file with mode: 0644]
include/labwc.h
src/cursor.c
src/desktop.c
src/dnd.c [new file with mode: 0644]
src/meson.build

diff --git a/include/dnd.h b/include/dnd.h
new file mode 100644 (file)
index 0000000..8212269
--- /dev/null
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __LAB_DND_H
+#define __LAB_DND_H
+
+#include <wayland-server-core.h>
+
+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 */
index c9ff66c960ba2bcde23da605ff40cdf6e6fb6253..950dd31adc4214192afde6d07f0943e594ce0399 100644 (file)
@@ -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;
index 62d89c8dc7d783837662f98efe08d6c93a6f455c..57952cb30fcf92a5e7859b7730d373e31dd12981 100644 (file)
@@ -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);
 }
index e8fa349bcf54882367503414f889c1a7ba4d88dc..aaa719d168f6cc307dfe7eaa160247b4f098b75c 100644 (file)
@@ -3,6 +3,7 @@
 #include <assert.h>
 #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 (file)
index 0000000..8364a73
--- /dev/null
+++ b/src/dnd.c
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <assert.h>
+#include <wlr/types/wlr_data_device.h>
+#include <wlr/types/wlr_scene.h>
+#include <wlr/util/log.h>
+#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);
+}
index 7771fcab5d58b529a0befc4fb307c12bb17ab040..ff4bff8be41cf7d13daab829b0c5865bc846ef7d 100644 (file)
@@ -4,6 +4,7 @@ labwc_sources = files(
   'cursor.c',
   'debug.c',
   'desktop.c',
+  'dnd.c',
   'foreign.c',
   'interactive.c',
   'keyboard.c',