aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Orzechowski <alex@ozal.ski>2022-11-12 19:31:55 -0500
committerAlexander Orzechowski <alex@ozal.ski>2022-11-14 15:44:43 +0000
commitc8a5dfcc878b855253d7b5fa2691c850c8430ff7 (patch)
tree382f020ea673ec55ac9e11ea22cdb226d601b207
parent9f793d350379872aeee56ea5c476adfeedc8bc88 (diff)
wlr_scene: Add drag icon helper
-rw-r--r--include/wlr/types/wlr_scene.h8
-rw-r--r--types/meson.build1
-rw-r--r--types/scene/drag_icon.c93
3 files changed, 102 insertions, 0 deletions
diff --git a/include/wlr/types/wlr_scene.h b/include/wlr/types/wlr_scene.h
index 47dd26da..e45a3ee0 100644
--- a/include/wlr/types/wlr_scene.h
+++ b/include/wlr/types/wlr_scene.h
@@ -28,6 +28,7 @@ struct wlr_output;
struct wlr_output_layout;
struct wlr_xdg_surface;
struct wlr_layer_surface_v1;
+struct wlr_drag_icon;
struct wlr_scene_node;
struct wlr_scene_buffer;
@@ -472,4 +473,11 @@ void wlr_scene_layer_surface_v1_configure(
struct wlr_scene_layer_surface_v1 *scene_layer_surface,
const struct wlr_box *full_area, struct wlr_box *usable_area);
+/**
+ * Add a node displaying a drag icon and all its sub-surfaces to the
+ * scene-graph.
+ */
+struct wlr_scene_tree *wlr_scene_drag_icon_create(
+ struct wlr_scene_tree *parent, struct wlr_drag_icon *drag_icon);
+
#endif
diff --git a/types/meson.build b/types/meson.build
index 853d31c7..e558f5d3 100644
--- a/types/meson.build
+++ b/types/meson.build
@@ -8,6 +8,7 @@ wlr_files += files(
'output/render.c',
'output/state.c',
'output/transform.c',
+ 'scene/drag_icon.c',
'scene/subsurface_tree.c',
'scene/surface.c',
'scene/wlr_scene.c',
diff --git a/types/scene/drag_icon.c b/types/scene/drag_icon.c
new file mode 100644
index 00000000..8c28e1a0
--- /dev/null
+++ b/types/scene/drag_icon.c
@@ -0,0 +1,93 @@
+#include <stdlib.h>
+#include <wlr/types/wlr_scene.h>
+#include <wlr/types/wlr_data_device.h>
+
+struct wlr_scene_drag_icon {
+ struct wlr_scene_tree *tree;
+ struct wlr_scene_tree *surface_tree;
+ struct wlr_drag_icon *drag_icon;
+
+ struct wl_listener tree_destroy;
+ struct wl_listener drag_icon_surface_commit;
+ struct wl_listener drag_icon_map;
+ struct wl_listener drag_icon_unmap;
+ struct wl_listener drag_icon_destroy;
+};
+
+static void drag_icon_handle_surface_commit(struct wl_listener *listener, void *data) {
+ struct wlr_scene_drag_icon *icon =
+ wl_container_of(listener, icon, drag_icon_surface_commit);
+ struct wlr_surface *surface = icon->drag_icon->surface;
+ wlr_scene_node_set_position(&icon->surface_tree->node,
+ surface->sx, surface->sy);
+}
+
+static void drag_icon_handle_map(struct wl_listener *listener, void *data) {
+ struct wlr_scene_drag_icon *icon =
+ wl_container_of(listener, icon, drag_icon_map);
+ wlr_scene_node_set_enabled(&icon->tree->node, true);
+}
+
+static void drag_icon_handle_unmap(struct wl_listener *listener, void *data) {
+ struct wlr_scene_drag_icon *icon =
+ wl_container_of(listener, icon, drag_icon_unmap);
+ wlr_scene_node_set_enabled(&icon->tree->node, false);
+}
+
+static void drag_icon_handle_tree_destroy(struct wl_listener *listener, void *data) {
+ struct wlr_scene_drag_icon *icon =
+ wl_container_of(listener, icon, tree_destroy);
+ wl_list_remove(&icon->tree_destroy.link);
+ wl_list_remove(&icon->drag_icon_surface_commit.link);
+ wl_list_remove(&icon->drag_icon_map.link);
+ wl_list_remove(&icon->drag_icon_unmap.link);
+ wl_list_remove(&icon->drag_icon_destroy.link);
+ free(icon);
+}
+
+static void drag_icon_handle_destroy(struct wl_listener *listener, void *data) {
+ struct wlr_scene_drag_icon *icon =
+ wl_container_of(listener, icon, drag_icon_destroy);
+ wlr_scene_node_destroy(&icon->tree->node);
+}
+
+struct wlr_scene_tree *wlr_scene_drag_icon_create(
+ struct wlr_scene_tree *parent, struct wlr_drag_icon *drag_icon) {
+ struct wlr_scene_drag_icon *icon = calloc(1, sizeof(*icon));
+ if (!icon) {
+ return NULL;
+ }
+
+ icon->drag_icon = drag_icon;
+
+ icon->tree = wlr_scene_tree_create(parent);
+ if (!icon->tree) {
+ free(icon);
+ return NULL;
+ }
+
+ icon->surface_tree = wlr_scene_subsurface_tree_create(
+ icon->tree, drag_icon->surface);
+ if (!icon->surface_tree) {
+ wlr_scene_node_destroy(&icon->tree->node);
+ free(icon);
+ return NULL;
+ }
+
+ wlr_scene_node_set_position(&icon->surface_tree->node,
+ drag_icon->surface->sx, drag_icon->surface->sy);
+ wlr_scene_node_set_enabled(&icon->tree->node, drag_icon->mapped);
+
+ icon->tree_destroy.notify = drag_icon_handle_tree_destroy;
+ wl_signal_add(&icon->tree->node.events.destroy, &icon->tree_destroy);
+ icon->drag_icon_surface_commit.notify = drag_icon_handle_surface_commit;
+ wl_signal_add(&drag_icon->surface->events.commit, &icon->drag_icon_surface_commit);
+ icon->drag_icon_map.notify = drag_icon_handle_map;
+ wl_signal_add(&drag_icon->events.map, &icon->drag_icon_map);
+ icon->drag_icon_unmap.notify = drag_icon_handle_unmap;
+ wl_signal_add(&drag_icon->events.unmap, &icon->drag_icon_unmap);
+ icon->drag_icon_destroy.notify = drag_icon_handle_destroy;
+ wl_signal_add(&drag_icon->events.destroy, &icon->drag_icon_destroy);
+
+ return icon->tree;
+}