aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/wlr/types/wlr_scene.h10
-rw-r--r--types/meson.build1
-rw-r--r--types/scene/output_layout.c105
3 files changed, 116 insertions, 0 deletions
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 <wlr/types/wlr_surface.h>
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 <stdlib.h>
+#include <wlr/types/wlr_output_layout.h>
+#include <wlr/types/wlr_scene.h>
+
+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;
+}