diff options
author | 2018-03-28 19:27:52 -0400 | |
---|---|---|
committer | 2018-03-28 19:27:52 -0400 | |
commit | ca809d25199b229b3da7d69f427eb67539dc7bc0 (patch) | |
tree | b28c55c464feb85c61f314a26487404fd63f4fb3 /sway/desktop | |
parent | Merge pull request #1638 from swaywm/swaybg-layers (diff) | |
parent | Address review feedback (diff) | |
download | sway-ca809d25199b229b3da7d69f427eb67539dc7bc0.tar.gz sway-ca809d25199b229b3da7d69f427eb67539dc7bc0.tar.zst sway-ca809d25199b229b3da7d69f427eb67539dc7bc0.zip |
Merge pull request #1642 from swaywm/layer-shell
Implement layer shell (rendering)
Diffstat (limited to 'sway/desktop')
-rw-r--r-- | sway/desktop/layer_shell.c | 320 | ||||
-rw-r--r-- | sway/desktop/output.c | 95 | ||||
-rw-r--r-- | sway/desktop/xwayland.c | 4 |
3 files changed, 394 insertions, 25 deletions
diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c new file mode 100644 index 00000000..bd62f84a --- /dev/null +++ b/sway/desktop/layer_shell.c | |||
@@ -0,0 +1,320 @@ | |||
1 | #include <stdbool.h> | ||
2 | #include <stdlib.h> | ||
3 | #include <string.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> | ||
8 | #include <wlr/util/log.h> | ||
9 | #include "sway/layers.h" | ||
10 | #include "sway/layout.h" | ||
11 | #include "sway/output.h" | ||
12 | #include "sway/server.h" | ||
13 | |||
14 | static void apply_exclusive(struct wlr_box *usable_area, | ||
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); | ||
190 | } | ||
191 | |||
192 | static void handle_output_destroy(struct wl_listener *listener, void *data) { | ||
193 | struct sway_layer_surface *sway_layer = | ||
194 | wl_container_of(listener, sway_layer, output_destroy); | ||
195 | wl_list_remove(&sway_layer->output_destroy.link); | ||
196 | wl_list_remove(&sway_layer->output_mode.link); | ||
197 | wl_list_remove(&sway_layer->output_transform.link); | ||
198 | sway_layer->layer_surface->output = NULL; | ||
199 | wlr_layer_surface_close(sway_layer->layer_surface); | ||
200 | } | ||
201 | |||
202 | static void handle_output_mode(struct wl_listener *listener, void *data) { | ||
203 | struct wlr_output *output = data; | ||
204 | arrange_layers((struct sway_output *)output->data); | ||
205 | } | ||
206 | |||
207 | static void handle_output_transform(struct wl_listener *listener, void *data) { | ||
208 | struct wlr_output *output = data; | ||
209 | arrange_layers((struct sway_output *)output->data); | ||
210 | } | ||
211 | |||
212 | static void handle_surface_commit(struct wl_listener *listener, void *data) { | ||
213 | struct sway_layer_surface *layer = | ||
214 | wl_container_of(listener, layer, surface_commit); | ||
215 | struct wlr_layer_surface *layer_surface = layer->layer_surface; | ||
216 | struct wlr_output *wlr_output = layer_surface->output; | ||
217 | if (wlr_output != NULL) { | ||
218 | struct sway_output *output = wlr_output->data; | ||
219 | struct wlr_box old_geo = layer->geo; | ||
220 | arrange_layers(output); | ||
221 | if (memcmp(&old_geo, &layer->geo, sizeof(struct wlr_box)) != 0) { | ||
222 | // TODO DAMAGE apply whole surface from previous and new geos | ||
223 | } else { | ||
224 | // TODO DAMAGE from surface damage | ||
225 | } | ||
226 | } | ||
227 | } | ||
228 | |||
229 | static void unmap(struct wlr_layer_surface *layer_surface) { | ||
230 | // TODO DAMAGE | ||
231 | } | ||
232 | |||
233 | static void handle_destroy(struct wl_listener *listener, void *data) { | ||
234 | struct sway_layer_surface *sway_layer = wl_container_of( | ||
235 | listener, sway_layer, destroy); | ||
236 | if (sway_layer->layer_surface->mapped) { | ||
237 | unmap(sway_layer->layer_surface); | ||
238 | } | ||
239 | wl_list_remove(&sway_layer->link); | ||
240 | wl_list_remove(&sway_layer->destroy.link); | ||
241 | wl_list_remove(&sway_layer->map.link); | ||
242 | wl_list_remove(&sway_layer->unmap.link); | ||
243 | wl_list_remove(&sway_layer->surface_commit.link); | ||
244 | if (sway_layer->layer_surface->output != NULL) { | ||
245 | wl_list_remove(&sway_layer->output_destroy.link); | ||
246 | wl_list_remove(&sway_layer->output_mode.link); | ||
247 | wl_list_remove(&sway_layer->output_transform.link); | ||
248 | } | ||
249 | struct sway_output *output = sway_layer->layer_surface->output->data; | ||
250 | arrange_layers(output); | ||
251 | free(sway_layer); | ||
252 | } | ||
253 | |||
254 | static void handle_map(struct wl_listener *listener, void *data) { | ||
255 | // TODO DAMAGE | ||
256 | } | ||
257 | |||
258 | static void handle_unmap(struct wl_listener *listener, void *data) { | ||
259 | struct sway_layer_surface *sway_layer = wl_container_of( | ||
260 | listener, sway_layer, unmap); | ||
261 | unmap(sway_layer->layer_surface); | ||
262 | } | ||
263 | |||
264 | void handle_layer_shell_surface(struct wl_listener *listener, void *data) { | ||
265 | struct wlr_layer_surface *layer_surface = data; | ||
266 | struct sway_server *server = | ||
267 | wl_container_of(listener, server, layer_shell_surface); | ||
268 | wlr_log(L_DEBUG, "new layer surface: namespace %s layer %d anchor %d " | ||
269 | "size %dx%d margin %d,%d,%d,%d", | ||
270 | layer_surface->namespace, layer_surface->layer, layer_surface->layer, | ||
271 | layer_surface->client_pending.desired_width, | ||
272 | layer_surface->client_pending.desired_height, | ||
273 | layer_surface->client_pending.margin.top, | ||
274 | layer_surface->client_pending.margin.right, | ||
275 | layer_surface->client_pending.margin.bottom, | ||
276 | layer_surface->client_pending.margin.left); | ||
277 | |||
278 | struct sway_layer_surface *sway_layer = | ||
279 | calloc(1, sizeof(struct sway_layer_surface)); | ||
280 | if (!sway_layer) { | ||
281 | return; | ||
282 | } | ||
283 | |||
284 | sway_layer->surface_commit.notify = handle_surface_commit; | ||
285 | wl_signal_add(&layer_surface->surface->events.commit, | ||
286 | &sway_layer->surface_commit); | ||
287 | |||
288 | sway_layer->output_destroy.notify = handle_output_destroy; | ||
289 | wl_signal_add(&layer_surface->output->events.destroy, | ||
290 | &sway_layer->output_destroy); | ||
291 | |||
292 | sway_layer->output_mode.notify = handle_output_mode; | ||
293 | wl_signal_add(&layer_surface->output->events.mode, | ||
294 | &sway_layer->output_mode); | ||
295 | |||
296 | sway_layer->output_transform.notify = handle_output_transform; | ||
297 | wl_signal_add(&layer_surface->output->events.transform, | ||
298 | &sway_layer->output_transform); | ||
299 | |||
300 | sway_layer->destroy.notify = handle_destroy; | ||
301 | wl_signal_add(&layer_surface->events.destroy, &sway_layer->destroy); | ||
302 | sway_layer->map.notify = handle_map; | ||
303 | wl_signal_add(&layer_surface->events.map, &sway_layer->map); | ||
304 | sway_layer->unmap.notify = handle_unmap; | ||
305 | wl_signal_add(&layer_surface->events.unmap, &sway_layer->unmap); | ||
306 | // TODO: Listen for subsurfaces | ||
307 | |||
308 | sway_layer->layer_surface = layer_surface; | ||
309 | layer_surface->data = sway_layer; | ||
310 | |||
311 | struct sway_output *output = layer_surface->output->data; | ||
312 | wl_list_insert(&output->layers[layer_surface->layer], &sway_layer->link); | ||
313 | |||
314 | // Temporarily set the layer's current state to client_pending | ||
315 | // So that we can easily arrange it | ||
316 | struct wlr_layer_surface_state old_state = layer_surface->current; | ||
317 | layer_surface->current = layer_surface->client_pending; | ||
318 | arrange_layers(output); | ||
319 | layer_surface->current = old_state; | ||
320 | } | ||
diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 6c990c47..9e7fbcc6 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c | |||
@@ -4,14 +4,17 @@ | |||
4 | #include <time.h> | 4 | #include <time.h> |
5 | #include <wayland-server.h> | 5 | #include <wayland-server.h> |
6 | #include <wlr/render/wlr_renderer.h> | 6 | #include <wlr/render/wlr_renderer.h> |
7 | #include <wlr/types/wlr_box.h> | ||
7 | #include <wlr/types/wlr_matrix.h> | 8 | #include <wlr/types/wlr_matrix.h> |
8 | #include <wlr/types/wlr_output.h> | 9 | #include <wlr/types/wlr_output.h> |
10 | #include <wlr/types/wlr_output_layout.h> | ||
9 | #include <wlr/types/wlr_surface.h> | 11 | #include <wlr/types/wlr_surface.h> |
10 | #include <wlr/types/wlr_wl_shell.h> | 12 | #include <wlr/types/wlr_wl_shell.h> |
11 | #include "log.h" | 13 | #include "log.h" |
12 | #include "sway/container.h" | 14 | #include "sway/container.h" |
13 | #include "sway/input/input-manager.h" | 15 | #include "sway/input/input-manager.h" |
14 | #include "sway/input/seat.h" | 16 | #include "sway/input/seat.h" |
17 | #include "sway/layers.h" | ||
15 | #include "sway/layout.h" | 18 | #include "sway/layout.h" |
16 | #include "sway/output.h" | 19 | #include "sway/output.h" |
17 | #include "sway/server.h" | 20 | #include "sway/server.h" |
@@ -78,9 +81,7 @@ static void render_surface(struct wlr_surface *surface, | |||
78 | rotate_child_position(&sx, &sy, sw, sh, width, height, rotation); | 81 | rotate_child_position(&sx, &sy, sw, sh, width, height, rotation); |
79 | 82 | ||
80 | render_surface(subsurface->surface, wlr_output, when, | 83 | render_surface(subsurface->surface, wlr_output, when, |
81 | lx + sx, | 84 | lx + sx, ly + sy, rotation); |
82 | ly + sy, | ||
83 | rotation); | ||
84 | } | 85 | } |
85 | } | 86 | } |
86 | 87 | ||
@@ -139,9 +140,15 @@ static void render_wl_shell_surface(struct wlr_wl_shell_surface *surface, | |||
139 | } | 140 | } |
140 | } | 141 | } |
141 | 142 | ||
143 | struct render_data { | ||
144 | struct sway_output *output; | ||
145 | struct timespec *now; | ||
146 | }; | ||
142 | 147 | ||
143 | static void output_frame_view(swayc_t *view, void *data) { | 148 | static void output_frame_view(swayc_t *view, void *data) { |
144 | struct sway_output *output = data; | 149 | struct render_data *rdata = data; |
150 | struct sway_output *output = rdata->output; | ||
151 | struct timespec *now = rdata->now; | ||
145 | struct wlr_output *wlr_output = output->wlr_output; | 152 | struct wlr_output *wlr_output = output->wlr_output; |
146 | struct sway_view *sway_view = view->sway_view; | 153 | struct sway_view *sway_view = view->sway_view; |
147 | struct wlr_surface *surface = sway_view->surface; | 154 | struct wlr_surface *surface = sway_view->surface; |
@@ -154,29 +161,38 @@ static void output_frame_view(swayc_t *view, void *data) { | |||
154 | case SWAY_XDG_SHELL_V6_VIEW: { | 161 | case SWAY_XDG_SHELL_V6_VIEW: { |
155 | int window_offset_x = view->sway_view->wlr_xdg_surface_v6->geometry.x; | 162 | int window_offset_x = view->sway_view->wlr_xdg_surface_v6->geometry.x; |
156 | int window_offset_y = view->sway_view->wlr_xdg_surface_v6->geometry.y; | 163 | int window_offset_y = view->sway_view->wlr_xdg_surface_v6->geometry.y; |
157 | render_surface(surface, wlr_output, &output->last_frame, | 164 | render_surface(surface, wlr_output, now, |
158 | view->x - window_offset_x, | 165 | view->x - window_offset_x, view->y - window_offset_y, 0); |
159 | view->y - window_offset_y, | ||
160 | 0); | ||
161 | render_xdg_v6_popups(sway_view->wlr_xdg_surface_v6, wlr_output, | 166 | render_xdg_v6_popups(sway_view->wlr_xdg_surface_v6, wlr_output, |
162 | &output->last_frame, | 167 | now, view->x - window_offset_x, view->y - window_offset_y, 0); |
163 | view->x - window_offset_x, view->y - window_offset_y, | ||
164 | 0); | ||
165 | break; | 168 | break; |
166 | } | 169 | } |
167 | case SWAY_WL_SHELL_VIEW: | 170 | case SWAY_WL_SHELL_VIEW: |
168 | render_wl_shell_surface(sway_view->wlr_wl_shell_surface, wlr_output, | 171 | render_wl_shell_surface(sway_view->wlr_wl_shell_surface, wlr_output, |
169 | &output->last_frame, view->x, view->y, 0, false); | 172 | now, view->x, view->y, 0, false); |
170 | break; | 173 | break; |
171 | case SWAY_XWAYLAND_VIEW: | 174 | case SWAY_XWAYLAND_VIEW: |
172 | render_surface(surface, wlr_output, &output->last_frame, view->x, | 175 | render_surface(surface, wlr_output, now, view->x, view->y, 0); |
173 | view->y, 0); | ||
174 | break; | 176 | break; |
175 | default: | 177 | default: |
176 | break; | 178 | break; |
177 | } | 179 | } |
178 | } | 180 | } |
179 | 181 | ||
182 | static void render_layer(struct sway_output *output, | ||
183 | const struct wlr_box *output_layout_box, | ||
184 | struct timespec *when, | ||
185 | struct wl_list *layer) { | ||
186 | struct sway_layer_surface *sway_layer; | ||
187 | wl_list_for_each(sway_layer, layer, link) { | ||
188 | struct wlr_layer_surface *layer = sway_layer->layer_surface; | ||
189 | render_surface(layer->surface, output->wlr_output, when, | ||
190 | sway_layer->geo.x + output_layout_box->x, | ||
191 | sway_layer->geo.y + output_layout_box->y, 0); | ||
192 | wlr_surface_send_frame_done(layer->surface, when); | ||
193 | } | ||
194 | } | ||
195 | |||
180 | static void output_frame_notify(struct wl_listener *listener, void *data) { | 196 | static void output_frame_notify(struct wl_listener *listener, void *data) { |
181 | struct sway_output *soutput = wl_container_of(listener, soutput, frame); | 197 | struct sway_output *soutput = wl_container_of(listener, soutput, frame); |
182 | struct wlr_output *wlr_output = data; | 198 | struct wlr_output *wlr_output = data; |
@@ -189,13 +205,29 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { | |||
189 | wlr_output_make_current(wlr_output, &buffer_age); | 205 | wlr_output_make_current(wlr_output, &buffer_age); |
190 | wlr_renderer_begin(server->renderer, wlr_output->width, wlr_output->height); | 206 | wlr_renderer_begin(server->renderer, wlr_output->width, wlr_output->height); |
191 | 207 | ||
208 | struct timespec now; | ||
209 | clock_gettime(CLOCK_MONOTONIC, &now); | ||
210 | |||
211 | struct wlr_output_layout *layout = root_container.sway_root->output_layout; | ||
212 | const struct wlr_box *output_box = wlr_output_layout_get_box( | ||
213 | layout, wlr_output); | ||
214 | |||
215 | render_layer(soutput, output_box, &now, | ||
216 | &soutput->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); | ||
217 | render_layer(soutput, output_box, &now, | ||
218 | &soutput->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); | ||
219 | |||
192 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 220 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
193 | swayc_t *focus = sway_seat_get_focus_inactive(seat, soutput->swayc); | 221 | swayc_t *focus = sway_seat_get_focus_inactive(seat, soutput->swayc); |
194 | swayc_t *workspace = (focus->type == C_WORKSPACE ? | 222 | swayc_t *workspace = (focus->type == C_WORKSPACE ? |
195 | focus : | 223 | focus : |
196 | swayc_parent_by_type(focus, C_WORKSPACE)); | 224 | swayc_parent_by_type(focus, C_WORKSPACE)); |
197 | 225 | ||
198 | swayc_descendants_of_type(workspace, C_VIEW, output_frame_view, soutput); | 226 | struct render_data rdata = { |
227 | .output = soutput, | ||
228 | .now = &now, | ||
229 | }; | ||
230 | swayc_descendants_of_type(workspace, C_VIEW, output_frame_view, &rdata); | ||
199 | 231 | ||
200 | // render unmanaged views on top | 232 | // render unmanaged views on top |
201 | struct sway_view *view; | 233 | struct sway_view *view; |
@@ -210,22 +242,31 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { | |||
210 | } | 242 | } |
211 | } | 243 | } |
212 | 244 | ||
213 | wlr_renderer_end(server->renderer); | 245 | // TODO: Consider revising this when fullscreen windows are supported |
214 | wlr_output_swap_buffers(wlr_output, &soutput->last_frame, NULL); | 246 | render_layer(soutput, output_box, &now, |
247 | &soutput->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); | ||
248 | render_layer(soutput, output_box, &now, | ||
249 | &soutput->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); | ||
215 | 250 | ||
216 | struct timespec now; | 251 | wlr_renderer_end(server->renderer); |
217 | clock_gettime(CLOCK_MONOTONIC, &now); | 252 | wlr_output_swap_buffers(wlr_output, &now, NULL); |
218 | soutput->last_frame = now; | 253 | soutput->last_frame = now; |
219 | } | 254 | } |
220 | 255 | ||
221 | static void handle_output_destroy(struct wl_listener *listener, void *data) { | 256 | static void handle_output_destroy(struct wl_listener *listener, void *data) { |
222 | struct sway_output *output = wl_container_of(listener, output, output_destroy); | 257 | struct sway_output *output = wl_container_of(listener, output, destroy); |
223 | struct wlr_output *wlr_output = data; | 258 | struct wlr_output *wlr_output = data; |
224 | wlr_log(L_DEBUG, "Output %p %s removed", wlr_output, wlr_output->name); | 259 | wlr_log(L_DEBUG, "Output %p %s removed", wlr_output, wlr_output->name); |
225 | 260 | ||
226 | destroy_output(output->swayc); | 261 | destroy_output(output->swayc); |
227 | } | 262 | } |
228 | 263 | ||
264 | static void handle_output_mode(struct wl_listener *listener, void *data) { | ||
265 | struct sway_output *output = wl_container_of(listener, output, mode); | ||
266 | arrange_layers(output); | ||
267 | arrange_windows(output->swayc, -1, -1); | ||
268 | } | ||
269 | |||
229 | void handle_new_output(struct wl_listener *listener, void *data) { | 270 | void handle_new_output(struct wl_listener *listener, void *data) { |
230 | struct sway_server *server = wl_container_of(listener, server, new_output); | 271 | struct sway_server *server = wl_container_of(listener, server, new_output); |
231 | struct wlr_output *wlr_output = data; | 272 | struct wlr_output *wlr_output = data; |
@@ -236,6 +277,7 @@ void handle_new_output(struct wl_listener *listener, void *data) { | |||
236 | return; | 277 | return; |
237 | } | 278 | } |
238 | output->wlr_output = wlr_output; | 279 | output->wlr_output = wlr_output; |
280 | wlr_output->data = output; | ||
239 | output->server = server; | 281 | output->server = server; |
240 | 282 | ||
241 | if (!wl_list_empty(&wlr_output->modes)) { | 283 | if (!wl_list_empty(&wlr_output->modes)) { |
@@ -250,13 +292,20 @@ void handle_new_output(struct wl_listener *listener, void *data) { | |||
250 | return; | 292 | return; |
251 | } | 293 | } |
252 | 294 | ||
295 | size_t len = sizeof(output->layers) / sizeof(output->layers[0]); | ||
296 | for (size_t i = 0; i < len; ++i) { | ||
297 | wl_list_init(&output->layers[i]); | ||
298 | } | ||
299 | |||
253 | sway_input_manager_configure_xcursor(input_manager); | 300 | sway_input_manager_configure_xcursor(input_manager); |
254 | 301 | ||
255 | wl_signal_add(&wlr_output->events.frame, &output->frame); | 302 | wl_signal_add(&wlr_output->events.frame, &output->frame); |
256 | output->frame.notify = output_frame_notify; | 303 | output->frame.notify = output_frame_notify; |
304 | wl_signal_add(&wlr_output->events.destroy, &output->destroy); | ||
305 | output->destroy.notify = handle_output_destroy; | ||
306 | wl_signal_add(&wlr_output->events.mode, &output->mode); | ||
307 | output->mode.notify = handle_output_mode; | ||
257 | 308 | ||
258 | wl_signal_add(&wlr_output->events.destroy, &output->output_destroy); | 309 | arrange_layers(output); |
259 | output->output_destroy.notify = handle_output_destroy; | ||
260 | |||
261 | arrange_windows(&root_container, -1, -1); | 310 | arrange_windows(&root_container, -1, -1); |
262 | } | 311 | } |
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 6b5e03f9..f9b5242b 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c | |||
@@ -84,7 +84,7 @@ static void set_activated(struct sway_view *view, bool activated) { | |||
84 | wlr_xwayland_surface_activate(surface, activated); | 84 | wlr_xwayland_surface_activate(surface, activated); |
85 | } | 85 | } |
86 | 86 | ||
87 | static void close(struct sway_view *view) { | 87 | static void close_view(struct sway_view *view) { |
88 | if (!assert_xwayland(view)) { | 88 | if (!assert_xwayland(view)) { |
89 | return; | 89 | return; |
90 | } | 90 | } |
@@ -203,7 +203,7 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) { | |||
203 | sway_view->iface.set_size = set_size; | 203 | sway_view->iface.set_size = set_size; |
204 | sway_view->iface.set_position = set_position; | 204 | sway_view->iface.set_position = set_position; |
205 | sway_view->iface.set_activated = set_activated; | 205 | sway_view->iface.set_activated = set_activated; |
206 | sway_view->iface.close = close; | 206 | sway_view->iface.close = close_view; |
207 | sway_view->wlr_xwayland_surface = xsurface; | 207 | sway_view->wlr_xwayland_surface = xsurface; |
208 | sway_view->sway_xwayland_surface = sway_surface; | 208 | sway_view->sway_xwayland_surface = sway_surface; |
209 | sway_view->surface = xsurface->surface; | 209 | sway_view->surface = xsurface->surface; |