diff options
Diffstat (limited to 'sway/desktop/layer_shell.c')
-rw-r--r-- | sway/desktop/layer_shell.c | 239 |
1 files changed, 230 insertions, 9 deletions
diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index 3cf171bd..a2506d21 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c | |||
@@ -1,40 +1,261 @@ | |||
1 | #include <stdbool.h> | ||
1 | #include <stdlib.h> | 2 | #include <stdlib.h> |
3 | #include <string.h> | ||
2 | #include <wayland-server.h> | 4 | #include <wayland-server.h> |
5 | #include <wlr/types/wlr_box.h> | ||
6 | #include <wlr/types/wlr_layer_shell.h> | ||
7 | #include <wlr/types/wlr_output.h> | ||
3 | #include <wlr/util/log.h> | 8 | #include <wlr/util/log.h> |
4 | #include "sway/layers.h" | 9 | #include "sway/layers.h" |
10 | #include "sway/layout.h" | ||
5 | #include "sway/output.h" | 11 | #include "sway/output.h" |
6 | #include "sway/server.h" | 12 | #include "sway/server.h" |
7 | 13 | ||
8 | static void arrange_layers(struct sway_output *output) { | 14 | static void apply_exclusive(struct wlr_box *usable_area, |
9 | // TODO | 15 | uint32_t anchor, int32_t exclusive, |
16 | int32_t margin_top, int32_t margin_right, | ||
17 | int32_t margin_bottom, int32_t margin_left) { | ||
18 | if (exclusive <= 0) { | ||
19 | return; | ||
20 | } | ||
21 | struct { | ||
22 | uint32_t anchors; | ||
23 | int *positive_axis; | ||
24 | int *negative_axis; | ||
25 | int margin; | ||
26 | } edges[] = { | ||
27 | { | ||
28 | .anchors = | ||
29 | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | | ||
30 | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | | ||
31 | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP, | ||
32 | .positive_axis = &usable_area->y, | ||
33 | .negative_axis = &usable_area->height, | ||
34 | .margin = margin_top, | ||
35 | }, | ||
36 | { | ||
37 | .anchors = | ||
38 | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | | ||
39 | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | | ||
40 | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, | ||
41 | .positive_axis = NULL, | ||
42 | .negative_axis = &usable_area->height, | ||
43 | .margin = margin_bottom, | ||
44 | }, | ||
45 | { | ||
46 | .anchors = | ||
47 | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | | ||
48 | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | | ||
49 | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, | ||
50 | .positive_axis = &usable_area->x, | ||
51 | .negative_axis = &usable_area->width, | ||
52 | .margin = margin_left, | ||
53 | }, | ||
54 | { | ||
55 | .anchors = | ||
56 | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | | ||
57 | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | | ||
58 | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, | ||
59 | .positive_axis = NULL, | ||
60 | .negative_axis = &usable_area->width, | ||
61 | .margin = margin_right, | ||
62 | }, | ||
63 | }; | ||
64 | for (size_t i = 0; i < sizeof(edges) / sizeof(edges[0]); ++i) { | ||
65 | if ((anchor & edges[i].anchors) == edges[i].anchors) { | ||
66 | if (edges[i].positive_axis) { | ||
67 | *edges[i].positive_axis += exclusive + edges[i].margin; | ||
68 | } | ||
69 | if (edges[i].negative_axis) { | ||
70 | *edges[i].negative_axis -= exclusive + edges[i].margin; | ||
71 | } | ||
72 | } | ||
73 | } | ||
74 | } | ||
75 | |||
76 | static void arrange_layer(struct sway_output *output, struct wl_list *list, | ||
77 | struct wlr_box *usable_area, bool exclusive) { | ||
78 | struct sway_layer_surface *sway_layer; | ||
79 | struct wlr_box full_area = { 0 }; | ||
80 | wlr_output_effective_resolution(output->wlr_output, | ||
81 | &full_area.width, &full_area.height); | ||
82 | wl_list_for_each(sway_layer, list, link) { | ||
83 | struct wlr_layer_surface *layer = sway_layer->layer_surface; | ||
84 | struct wlr_layer_surface_state *state = &layer->current; | ||
85 | if (exclusive != (state->exclusive_zone > 0)) { | ||
86 | continue; | ||
87 | } | ||
88 | struct wlr_box bounds; | ||
89 | if (state->exclusive_zone == -1) { | ||
90 | bounds = full_area; | ||
91 | } else { | ||
92 | bounds = *usable_area; | ||
93 | } | ||
94 | struct wlr_box box = { | ||
95 | .width = state->desired_width, | ||
96 | .height = state->desired_height | ||
97 | }; | ||
98 | // Horizontal axis | ||
99 | const uint32_t both_horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ||
100 | | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; | ||
101 | if ((state->anchor & both_horiz) && box.width == 0) { | ||
102 | box.x = bounds.x; | ||
103 | box.width = bounds.width; | ||
104 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) { | ||
105 | box.x = bounds.x; | ||
106 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) { | ||
107 | box.x = bounds.x + (bounds.width - box.width); | ||
108 | } else { | ||
109 | box.x = bounds.x + ((bounds.width / 2) - (box.width / 2)); | ||
110 | } | ||
111 | // Vertical axis | ||
112 | const uint32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ||
113 | | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; | ||
114 | if ((state->anchor & both_vert) && box.height == 0) { | ||
115 | box.y = bounds.y; | ||
116 | box.height = bounds.height; | ||
117 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) { | ||
118 | box.y = bounds.y; | ||
119 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) { | ||
120 | box.y = bounds.y + (bounds.height - box.height); | ||
121 | } else { | ||
122 | box.y = bounds.y + ((bounds.height / 2) - (box.height / 2)); | ||
123 | } | ||
124 | // Margin | ||
125 | if ((state->anchor & both_horiz) == both_horiz) { | ||
126 | box.x += state->margin.left; | ||
127 | box.width -= state->margin.left + state->margin.right; | ||
128 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) { | ||
129 | box.x += state->margin.left; | ||
130 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) { | ||
131 | box.x -= state->margin.right; | ||
132 | } | ||
133 | if ((state->anchor & both_vert) == both_vert) { | ||
134 | box.y += state->margin.top; | ||
135 | box.height -= state->margin.top + state->margin.bottom; | ||
136 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) { | ||
137 | box.y += state->margin.top; | ||
138 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) { | ||
139 | box.y -= state->margin.bottom; | ||
140 | } | ||
141 | if (box.width < 0 || box.height < 0) { | ||
142 | // TODO: Bubble up a protocol error? | ||
143 | wlr_layer_surface_close(layer); | ||
144 | continue; | ||
145 | } | ||
146 | // Apply | ||
147 | sway_layer->geo = box; | ||
148 | apply_exclusive(usable_area, state->anchor, state->exclusive_zone, | ||
149 | state->margin.top, state->margin.right, | ||
150 | state->margin.bottom, state->margin.left); | ||
151 | wlr_layer_surface_configure(layer, box.width, box.height); | ||
152 | } | ||
153 | } | ||
154 | |||
155 | void arrange_layers(struct sway_output *output) { | ||
156 | struct wlr_box usable_area = { 0 }; | ||
157 | wlr_output_effective_resolution(output->wlr_output, | ||
158 | &usable_area.width, &usable_area.height); | ||
159 | struct wlr_box usable_area_before = output->usable_area; | ||
160 | |||
161 | // Arrange exclusive surfaces from top->bottom | ||
162 | arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], | ||
163 | &usable_area, true); | ||
164 | arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], | ||
165 | &usable_area, true); | ||
166 | arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], | ||
167 | &usable_area, true); | ||
168 | arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], | ||
169 | &usable_area, true); | ||
170 | memcpy(&output->usable_area, &usable_area, sizeof(struct wlr_box)); | ||
171 | |||
172 | if (memcmp(&usable_area_before, | ||
173 | &usable_area, sizeof(struct wlr_box)) != 0) { | ||
174 | wlr_log(L_DEBUG, "arrange"); | ||
175 | arrange_windows(output->swayc, -1, -1); | ||
176 | } | ||
177 | |||
178 | // Arrange non-exlusive surfaces from top->bottom | ||
179 | usable_area.x = usable_area.y = 0; | ||
180 | wlr_output_effective_resolution(output->wlr_output, | ||
181 | &usable_area.width, &usable_area.height); | ||
182 | arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], | ||
183 | &usable_area, false); | ||
184 | arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], | ||
185 | &usable_area, false); | ||
186 | arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], | ||
187 | &usable_area, false); | ||
188 | arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], | ||
189 | &usable_area, false); | ||
10 | } | 190 | } |
11 | 191 | ||
12 | static void handle_output_destroy(struct wl_listener *listener, void *data) { | 192 | static void handle_output_destroy(struct wl_listener *listener, void *data) { |
13 | // TODO | 193 | struct sway_layer_surface *sway_layer = |
194 | wl_container_of(listener, sway_layer, output_destroy); | ||
195 | sway_layer->layer_surface->output = NULL; | ||
196 | wl_list_remove(&sway_layer->output_destroy.link); | ||
197 | wl_list_remove(&sway_layer->output_mode.link); | ||
198 | wlr_layer_surface_close(sway_layer->layer_surface); | ||
14 | } | 199 | } |
15 | 200 | ||
16 | static void handle_output_mode(struct wl_listener *listener, void *data) { | 201 | static void handle_output_mode(struct wl_listener *listener, void *data) { |
17 | // TODO | 202 | struct wlr_output *output = data; |
203 | arrange_layers((struct sway_output *)output->data); | ||
18 | } | 204 | } |
19 | 205 | ||
20 | static void handle_output_transform(struct wl_listener *listener, void *data) { | 206 | static void handle_output_transform(struct wl_listener *listener, void *data) { |
21 | // TODO | 207 | struct wlr_output *output = data; |
208 | arrange_layers((struct sway_output *)output->data); | ||
22 | } | 209 | } |
23 | 210 | ||
24 | static void handle_surface_commit(struct wl_listener *listener, void *data) { | 211 | static void handle_surface_commit(struct wl_listener *listener, void *data) { |
25 | // TODO | 212 | struct sway_layer_surface *layer = |
213 | wl_container_of(listener, layer, surface_commit); | ||
214 | struct wlr_layer_surface *layer_surface = layer->layer_surface; | ||
215 | struct wlr_output *wlr_output = layer_surface->output; | ||
216 | if (wlr_output != NULL) { | ||
217 | struct sway_output *output = wlr_output->data; | ||
218 | struct wlr_box old_geo = layer->geo; | ||
219 | arrange_layers(output); | ||
220 | if (memcmp(&old_geo, &layer->geo, sizeof(struct wlr_box)) != 0) { | ||
221 | // TODO DAMAGE apply whole surface from previous and new geos | ||
222 | } else { | ||
223 | // TODO DAMAGE from surface damage | ||
224 | } | ||
225 | } | ||
226 | } | ||
227 | |||
228 | static void unmap(struct wlr_layer_surface *layer_surface) { | ||
229 | // TODO DAMAGE | ||
26 | } | 230 | } |
27 | 231 | ||
28 | static void handle_destroy(struct wl_listener *listener, void *data) { | 232 | static void handle_destroy(struct wl_listener *listener, void *data) { |
29 | // TODO | 233 | struct sway_layer_surface *sway_layer = wl_container_of( |
234 | listener, sway_layer, destroy); | ||
235 | if (sway_layer->layer_surface->mapped) { | ||
236 | unmap(sway_layer->layer_surface); | ||
237 | } | ||
238 | wl_list_remove(&sway_layer->link); | ||
239 | wl_list_remove(&sway_layer->destroy.link); | ||
240 | wl_list_remove(&sway_layer->map.link); | ||
241 | wl_list_remove(&sway_layer->unmap.link); | ||
242 | wl_list_remove(&sway_layer->surface_commit.link); | ||
243 | wl_list_remove(&sway_layer->output_destroy.link); | ||
244 | wl_list_remove(&sway_layer->output_mode.link); | ||
245 | wl_list_remove(&sway_layer->output_transform.link); | ||
246 | struct sway_output *output = sway_layer->layer_surface->output->data; | ||
247 | arrange_layers(output); | ||
248 | free(sway_layer); | ||
30 | } | 249 | } |
31 | 250 | ||
32 | static void handle_map(struct wl_listener *listener, void *data) { | 251 | static void handle_map(struct wl_listener *listener, void *data) { |
33 | // TODO | 252 | // TODO DAMAGE |
34 | } | 253 | } |
35 | 254 | ||
36 | static void handle_unmap(struct wl_listener *listener, void *data) { | 255 | static void handle_unmap(struct wl_listener *listener, void *data) { |
37 | // TODO | 256 | struct sway_layer_surface *sway_layer = wl_container_of( |
257 | listener, sway_layer, unmap); | ||
258 | unmap(sway_layer->layer_surface); | ||
38 | } | 259 | } |
39 | 260 | ||
40 | void handle_layer_shell_surface(struct wl_listener *listener, void *data) { | 261 | void handle_layer_shell_surface(struct wl_listener *listener, void *data) { |