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 +#include +#include + +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; +}