summaryrefslogtreecommitdiff
path: root/output_layout.c
blob: 33dac1303b0cfee2c186dac235ed7f49f2ec048e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
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;
}