From a181a37b12c804d658bb82eb542870a0ee54a63d Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 2 Sep 2021 12:47:28 +0200 Subject: [PATCH] scene: add wlr_scene_attach_output_layout This is a helper to integrate wlr_scene with wlr_output_layout. --- include/wlr/types/wlr_scene.h | 10 ++++ types/meson.build | 1 + types/scene/output_layout.c | 105 ++++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+) create mode 100644 types/scene/output_layout.c diff --git a/include/wlr/types/wlr_scene.h b/include/wlr/types/wlr_scene.h index 95d86d83..df3d00e8 100644 --- a/include/wlr/types/wlr_scene.h +++ b/include/wlr/types/wlr_scene.h @@ -24,6 +24,7 @@ #include struct wlr_output; +struct wlr_output_layout; enum wlr_scene_node_type { WLR_SCENE_NODE_ROOT, @@ -203,4 +204,13 @@ void wlr_scene_output_set_position(struct wlr_scene_output *scene_output, */ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output); +/** + * Attach an output layout to a scene. + * + * Outputs in the output layout are automatically added to the scene. Any + * change to the output layout is mirrored to the scene-graph outputs. + */ +bool wlr_scene_attach_output_layout(struct wlr_scene *scene, + struct wlr_output_layout *output_layout); + #endif diff --git a/types/meson.build b/types/meson.build index 19385e3a..fd9ce58c 100644 --- a/types/meson.build +++ b/types/meson.build @@ -4,6 +4,7 @@ wlr_files += files( 'data_device/wlr_data_source.c', 'data_device/wlr_drag.c', 'scene/wlr_scene.c', + 'scene/output_layout.c', 'seat/wlr_seat_keyboard.c', 'seat/wlr_seat_pointer.c', 'seat/wlr_seat_touch.c', diff --git a/types/scene/output_layout.c b/types/scene/output_layout.c new file mode 100644 index 00000000..33dac130 --- /dev/null +++ b/types/scene/output_layout.c @@ -0,0 +1,105 @@ +#include +#include +#include + +struct wlr_scene_output_layout { + struct wlr_output_layout *layout; + struct wlr_scene *scene; + + struct wl_listener layout_add; + struct wl_listener layout_change; + struct wl_listener layout_destroy; + struct wl_listener scene_destroy; +}; + +static void scene_output_layout_destroy(struct wlr_scene_output_layout *sol) { + wl_list_remove(&sol->layout_destroy.link); + wl_list_remove(&sol->layout_add.link); + wl_list_remove(&sol->layout_change.link); + wl_list_remove(&sol->scene_destroy.link); + free(sol); +} + +static void scene_output_layout_handle_layout_destroy( + struct wl_listener *listener, void *data) { + struct wlr_scene_output_layout *sol = + wl_container_of(listener, sol, layout_destroy); + + // Remove all outputs managed by the output layout + struct wlr_scene_output *scene_output, *tmp; + wl_list_for_each_safe(scene_output, tmp, &sol->scene->outputs, link) { + struct wlr_output_layout_output *lo = + wlr_output_layout_get(sol->layout, scene_output->output); + if (lo != NULL) { + wlr_scene_output_destroy(scene_output); + } + } + + scene_output_layout_destroy(sol); +} + +static void scene_output_layout_handle_layout_change( + struct wl_listener *listener, void *data) { + struct wlr_scene_output_layout *sol = + wl_container_of(listener, sol, layout_change); + + struct wlr_scene_output *scene_output, *tmp; + wl_list_for_each_safe(scene_output, tmp, &sol->scene->outputs, link) { + struct wlr_output_layout_output *lo = + wlr_output_layout_get(sol->layout, scene_output->output); + if (lo == NULL) { + // Output has been removed from the layout + wlr_scene_output_destroy(scene_output); + continue; + } + + wlr_scene_output_set_position(scene_output, lo->x, lo->y); + } +} + +static void scene_output_layout_handle_layout_add( + struct wl_listener *listener, void *data) { + struct wlr_scene_output_layout *sol = + wl_container_of(listener, sol, layout_add); + struct wlr_output_layout_output *lo = data; + + struct wlr_scene_output *scene_output = + wlr_scene_output_create(sol->scene, lo->output); + if (scene_output == NULL) { + return; + } + + wlr_scene_output_set_position(scene_output, lo->x, lo->y); +} + +static void scene_output_layout_handle_scene_destroy( + struct wl_listener *listener, void *data) { + struct wlr_scene_output_layout *sol = + wl_container_of(listener, sol, scene_destroy); + scene_output_layout_destroy(sol); +} + +bool wlr_scene_attach_output_layout(struct wlr_scene *scene, + struct wlr_output_layout *output_layout) { + struct wlr_scene_output_layout *sol = calloc(1, sizeof(*sol)); + if (sol == NULL) { + return false; + } + + sol->scene = scene; + sol->layout = output_layout; + + sol->layout_destroy.notify = scene_output_layout_handle_layout_destroy; + wl_signal_add(&output_layout->events.destroy, &sol->layout_destroy); + + sol->layout_change.notify = scene_output_layout_handle_layout_change; + wl_signal_add(&output_layout->events.change, &sol->layout_change); + + sol->layout_add.notify = scene_output_layout_handle_layout_add; + wl_signal_add(&output_layout->events.add, &sol->layout_add); + + sol->scene_destroy.notify = scene_output_layout_handle_scene_destroy; + wl_signal_add(&output_layout->events.destroy, &sol->scene_destroy); + + return true; +}