summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Drew DeVault <sir@cmpwn.com>2018-03-28 19:27:52 -0400
committerLibravatar GitHub <noreply@github.com>2018-03-28 19:27:52 -0400
commitca809d25199b229b3da7d69f427eb67539dc7bc0 (patch)
treeb28c55c464feb85c61f314a26487404fd63f4fb3
parentMerge pull request #1638 from swaywm/swaybg-layers (diff)
parentAddress review feedback (diff)
downloadsway-ca809d25199b229b3da7d69f427eb67539dc7bc0.tar.gz
sway-ca809d25199b229b3da7d69f427eb67539dc7bc0.tar.zst
sway-ca809d25199b229b3da7d69f427eb67539dc7bc0.zip
Merge pull request #1642 from swaywm/layer-shell
Implement layer shell (rendering)
-rw-r--r--include/sway/layers.h27
-rw-r--r--include/sway/output.h10
-rw-r--r--include/sway/server.h5
-rw-r--r--protocols/meson.build55
-rw-r--r--sway/commands/output.c2
-rw-r--r--sway/config/output.c31
-rw-r--r--sway/desktop/layer_shell.c320
-rw-r--r--sway/desktop/output.c95
-rw-r--r--sway/desktop/xwayland.c4
-rw-r--r--sway/meson.build10
-rw-r--r--sway/server.c6
-rw-r--r--sway/tree/container.c4
-rw-r--r--sway/tree/layout.c11
-rw-r--r--swaybg/meson.build2
14 files changed, 525 insertions, 57 deletions
diff --git a/include/sway/layers.h b/include/sway/layers.h
new file mode 100644
index 00000000..22054be1
--- /dev/null
+++ b/include/sway/layers.h
@@ -0,0 +1,27 @@
1#ifndef _SWAY_LAYERS_H
2#define _SWAY_LAYERS_H
3#include <stdbool.h>
4#include <wlr/types/wlr_box.h>
5#include <wlr/types/wlr_surface.h>
6#include <wlr/types/wlr_layer_shell.h>
7
8struct sway_layer_surface {
9 struct wlr_layer_surface *layer_surface;
10 struct wl_list link;
11
12 struct wl_listener destroy;
13 struct wl_listener map;
14 struct wl_listener unmap;
15 struct wl_listener surface_commit;
16 struct wl_listener output_destroy;
17 struct wl_listener output_mode;
18 struct wl_listener output_transform;
19
20 bool configured;
21 struct wlr_box geo;
22};
23
24struct sway_output;
25void arrange_layers(struct sway_output *output);
26
27#endif
diff --git a/include/sway/output.h b/include/sway/output.h
index 95d64705..f899230f 100644
--- a/include/sway/output.h
+++ b/include/sway/output.h
@@ -1,7 +1,9 @@
1#ifndef _SWAY_OUTPUT_H 1#ifndef _SWAY_OUTPUT_H
2#define _SWAY_OUTPUT_H 2#define _SWAY_OUTPUT_H
3#include <time.h> 3#include <time.h>
4#include <unistd.h>
4#include <wayland-server.h> 5#include <wayland-server.h>
6#include <wlr/types/wlr_box.h>
5#include <wlr/types/wlr_output.h> 7#include <wlr/types/wlr_output.h>
6 8
7struct sway_server; 9struct sway_server;
@@ -13,8 +15,14 @@ struct sway_output {
13 struct sway_server *server; 15 struct sway_server *server;
14 struct timespec last_frame; 16 struct timespec last_frame;
15 17
18 struct wl_list layers[4]; // sway_layer_surface::link
19 struct wlr_box usable_area;
20
16 struct wl_listener frame; 21 struct wl_listener frame;
17 struct wl_listener output_destroy; 22 struct wl_listener destroy;
23 struct wl_listener mode;
24
25 pid_t bg_pid;
18}; 26};
19 27
20#endif 28#endif
diff --git a/include/sway/server.h b/include/sway/server.h
index eb7fa2ff..25eb64fe 100644
--- a/include/sway/server.h
+++ b/include/sway/server.h
@@ -6,6 +6,7 @@
6#include <wlr/backend/session.h> 6#include <wlr/backend/session.h>
7#include <wlr/types/wlr_compositor.h> 7#include <wlr/types/wlr_compositor.h>
8#include <wlr/types/wlr_data_device.h> 8#include <wlr/types/wlr_data_device.h>
9#include <wlr/types/wlr_layer_shell.h>
9#include <wlr/types/wlr_xdg_shell_v6.h> 10#include <wlr/types/wlr_xdg_shell_v6.h>
10#include <wlr/render/wlr_renderer.h> 11#include <wlr/render/wlr_renderer.h>
11// TODO WLR: make Xwayland optional 12// TODO WLR: make Xwayland optional
@@ -27,6 +28,9 @@ struct sway_server {
27 struct wl_listener new_output; 28 struct wl_listener new_output;
28 struct wl_listener output_frame; 29 struct wl_listener output_frame;
29 30
31 struct wlr_layer_shell *layer_shell;
32 struct wl_listener layer_shell_surface;
33
30 struct wlr_xdg_shell_v6 *xdg_shell_v6; 34 struct wlr_xdg_shell_v6 *xdg_shell_v6;
31 struct wl_listener xdg_shell_v6_surface; 35 struct wl_listener xdg_shell_v6_surface;
32 36
@@ -46,6 +50,7 @@ void server_run(struct sway_server *server);
46 50
47void handle_new_output(struct wl_listener *listener, void *data); 51void handle_new_output(struct wl_listener *listener, void *data);
48 52
53void handle_layer_shell_surface(struct wl_listener *listener, void *data);
49void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data); 54void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data);
50void handle_xwayland_surface(struct wl_listener *listener, void *data); 55void handle_xwayland_surface(struct wl_listener *listener, void *data);
51void handle_wl_shell_surface(struct wl_listener *listener, void *data); 56void handle_wl_shell_surface(struct wl_listener *listener, void *data);
diff --git a/protocols/meson.build b/protocols/meson.build
index 1fda600e..3f79e719 100644
--- a/protocols/meson.build
+++ b/protocols/meson.build
@@ -14,24 +14,57 @@ wayland_scanner_client = generator(
14 arguments: ['client-header', '@INPUT@', '@OUTPUT@'], 14 arguments: ['client-header', '@INPUT@', '@OUTPUT@'],
15) 15)
16 16
17protocols = [ 17wayland_scanner_server = generator(
18 wayland_scanner,
19 output: '@BASENAME@-protocol.h',
20 arguments: ['server-header', '@INPUT@', '@OUTPUT@'],
21)
22
23client_protocols = [
18 [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], 24 [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
19 ['wlr-layer-shell-unstable-v1.xml'] 25 ['wlr-layer-shell-unstable-v1.xml']
20] 26]
21 27
22wl_protos_src = [] 28server_protocols = [
23wl_protos_headers = [] 29 ['wlr-layer-shell-unstable-v1.xml']
30]
31
32client_protos_src = []
33client_protos_headers = []
34
35server_protos_src = []
36server_protos_headers = []
24 37
25foreach p : protocols 38foreach p : client_protocols
26 xml = join_paths(p) 39 xml = join_paths(p)
27 wl_protos_src += wayland_scanner_code.process(xml) 40 client_protos_src += wayland_scanner_code.process(xml)
28 wl_protos_headers += wayland_scanner_client.process(xml) 41 client_protos_headers += wayland_scanner_client.process(xml)
29endforeach 42endforeach
30 43
31lib_wl_protos = static_library('wl_protos', wl_protos_src + wl_protos_headers, 44foreach p : server_protocols
32 dependencies: [wayland_client]) # for the include directory 45 xml = join_paths(p)
46 server_protos_src += wayland_scanner_code.process(xml)
47 server_protos_headers += wayland_scanner_server.process(xml)
48endforeach
49
50lib_client_protos = static_library(
51 'client_protos',
52 client_protos_src + client_protos_headers,
53 dependencies: [wayland_client]
54) # for the include directory
55
56client_protos = declare_dependency(
57 link_with: lib_client_protos,
58 sources: client_protos_headers,
59)
60
61lib_server_protos = static_library(
62 'server_protos',
63 server_protos_src + server_protos_headers,
64 dependencies: [wayland_client]
65) # for the include directory
33 66
34sway_protos = declare_dependency( 67server_protos = declare_dependency(
35 link_with: lib_wl_protos, 68 link_with: lib_server_protos,
36 sources: wl_protos_headers, 69 sources: server_protos_headers,
37) 70)
diff --git a/sway/commands/output.c b/sway/commands/output.c
index e747eb4e..35bc8099 100644
--- a/sway/commands/output.c
+++ b/sway/commands/output.c
@@ -188,7 +188,7 @@ static struct cmd_results *cmd_output_background(struct output_config *output,
188 } 188 }
189 189
190 wordexp_t p; 190 wordexp_t p;
191 char *src = join_args(argv + *i - 1, j); 191 char *src = join_args(argv + *i, j);
192 if (wordexp(src, &p, 0) != 0 || p.we_wordv[0] == NULL) { 192 if (wordexp(src, &p, 0) != 0 || p.we_wordv[0] == NULL) {
193 return cmd_results_new(CMD_INVALID, "output", 193 return cmd_results_new(CMD_INVALID, "output",
194 "Invalid syntax (%s).", src); 194 "Invalid syntax (%s).", src);
diff --git a/sway/config/output.c b/sway/config/output.c
index 69e883f1..9e211861 100644
--- a/sway/config/output.c
+++ b/sway/config/output.c
@@ -1,7 +1,10 @@
1#define _XOPEN_SOURCE 700 1#define _XOPEN_SOURCE 700
2#include <assert.h>
2#include <stdbool.h> 3#include <stdbool.h>
3#include <string.h> 4#include <string.h>
4#include <assert.h> 5#include <signal.h>
6#include <sys/wait.h>
7#include <unistd.h>
5#include <wlr/types/wlr_output.h> 8#include <wlr/types/wlr_output.h>
6#include <wlr/types/wlr_output_layout.h> 9#include <wlr/types/wlr_output_layout.h>
7#include "sway/config.h" 10#include "sway/config.h"
@@ -107,6 +110,16 @@ static void set_mode(struct wlr_output *output, int width, int height,
107 } 110 }
108} 111}
109 112
113void terminate_swaybg(pid_t pid) {
114 int ret = kill(pid, SIGTERM);
115 if (ret != 0) {
116 wlr_log(L_ERROR, "Unable to terminate swaybg [pid: %d]", pid);
117 } else {
118 int status;
119 waitpid(pid, &status, 0);
120 }
121}
122
110void apply_output_config(struct output_config *oc, swayc_t *output) { 123void apply_output_config(struct output_config *oc, swayc_t *output) {
111 assert(output->type == C_OUTPUT); 124 assert(output->type == C_OUTPUT);
112 125
@@ -160,12 +173,12 @@ void apply_output_config(struct output_config *oc, swayc_t *output) {
160 } 173 }
161 174
162 if (oc && oc->background) { 175 if (oc && oc->background) {
163 // TODO swaybg 176 if (output->sway_output->bg_pid != 0) {
164 /*if (output->bg_pid != 0) { 177 terminate_swaybg(output->sway_output->bg_pid);
165 terminate_swaybg(output->bg_pid);
166 } 178 }
167 179
168 wlr_log(L_DEBUG, "Setting background for output %d to %s", output_i, oc->background); 180 wlr_log(L_DEBUG, "Setting background for output %d to %s",
181 output_i, oc->background);
169 182
170 size_t bufsize = 12; 183 size_t bufsize = 12;
171 char output_id[bufsize]; 184 char output_id[bufsize];
@@ -173,17 +186,17 @@ void apply_output_config(struct output_config *oc, swayc_t *output) {
173 output_id[bufsize-1] = 0; 186 output_id[bufsize-1] = 0;
174 187
175 char *const cmd[] = { 188 char *const cmd[] = {
176 "swaybg", 189 "./swaybg/swaybg",
177 output_id, 190 output_id,
178 oc->background, 191 oc->background,
179 oc->background_option, 192 oc->background_option,
180 NULL, 193 NULL,
181 }; 194 };
182 195
183 output->bg_pid = fork(); 196 output->sway_output->bg_pid = fork();
184 if (output->bg_pid == 0) { 197 if (output->sway_output->bg_pid == 0) {
185 execvp(cmd[0], cmd); 198 execvp(cmd[0], cmd);
186 }*/ 199 }
187 } 200 }
188} 201}
189 202
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
14static 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
76static 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
155void 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
192static 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
202static 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
207static 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
212static 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
229static void unmap(struct wlr_layer_surface *layer_surface) {
230 // TODO DAMAGE
231}
232
233static 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
254static void handle_map(struct wl_listener *listener, void *data) {
255 // TODO DAMAGE
256}
257
258static 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
264void 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
143struct render_data {
144 struct sway_output *output;
145 struct timespec *now;
146};
142 147
143static void output_frame_view(swayc_t *view, void *data) { 148static 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
182static 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
180static void output_frame_notify(struct wl_listener *listener, void *data) { 196static 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
221static void handle_output_destroy(struct wl_listener *listener, void *data) { 256static 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
264static 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
229void handle_new_output(struct wl_listener *listener, void *data) { 270void 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
87static void close(struct sway_view *view) { 87static 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;
diff --git a/sway/meson.build b/sway/meson.build
index 26e56ad2..8bddb11b 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -46,6 +46,7 @@ sway_sources = files(
46 'ipc-json.c', 46 'ipc-json.c',
47 'ipc-server.c', 47 'ipc-server.c',
48 'desktop/output.c', 48 'desktop/output.c',
49 'desktop/layer_shell.c',
49 'desktop/wl_shell.c', 50 'desktop/wl_shell.c',
50 'desktop/xdg_shell_v6.c', 51 'desktop/xdg_shell_v6.c',
51 'desktop/xwayland.c', 52 'desktop/xwayland.c',
@@ -57,14 +58,15 @@ sway_sources = files(
57) 58)
58 59
59sway_deps = [ 60sway_deps = [
61 jsonc,
62 libcap,
63 libinput,
64 math,
60 pcre, 65 pcre,
61 pixman, 66 pixman,
67 server_protos,
62 wayland_server, 68 wayland_server,
63 jsonc,
64 wlroots, 69 wlroots,
65 libcap,
66 math,
67 libinput,
68 xkbcommon, 70 xkbcommon,
69] 71]
70 72
diff --git a/sway/server.c b/sway/server.c
index ca08d7fb..92f72f13 100644
--- a/sway/server.c
+++ b/sway/server.c
@@ -7,6 +7,7 @@
7#include <wlr/render/wlr_renderer.h> 7#include <wlr/render/wlr_renderer.h>
8#include <wlr/render/gles2.h> 8#include <wlr/render/gles2.h>
9#include <wlr/types/wlr_compositor.h> 9#include <wlr/types/wlr_compositor.h>
10#include <wlr/types/wlr_layer_shell.h>
10#include <wlr/types/wlr_wl_shell.h> 11#include <wlr/types/wlr_wl_shell.h>
11// TODO WLR: make Xwayland optional 12// TODO WLR: make Xwayland optional
12#include <wlr/xwayland.h> 13#include <wlr/xwayland.h>
@@ -51,6 +52,11 @@ bool server_init(struct sway_server *server) {
51 server->new_output.notify = handle_new_output; 52 server->new_output.notify = handle_new_output;
52 wl_signal_add(&server->backend->events.new_output, &server->new_output); 53 wl_signal_add(&server->backend->events.new_output, &server->new_output);
53 54
55 server->layer_shell = wlr_layer_shell_create(server->wl_display);
56 wl_signal_add(&server->layer_shell->events.new_surface,
57 &server->layer_shell_surface);
58 server->layer_shell_surface.notify = handle_layer_shell_surface;
59
54 server->xdg_shell_v6 = wlr_xdg_shell_v6_create(server->wl_display); 60 server->xdg_shell_v6 = wlr_xdg_shell_v6_create(server->wl_display);
55 wl_signal_add(&server->xdg_shell_v6->events.new_surface, 61 wl_signal_add(&server->xdg_shell_v6->events.new_surface,
56 &server->xdg_shell_v6_surface); 62 &server->xdg_shell_v6_surface);
diff --git a/sway/tree/container.c b/sway/tree/container.c
index 705221d7..bbafe9ec 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -254,7 +254,9 @@ swayc_t *destroy_output(swayc_t *output) {
254 } 254 }
255 } 255 }
256 256
257 wl_list_remove(&output->sway_output->output_destroy.link); 257 wl_list_remove(&output->sway_output->frame.link);
258 wl_list_remove(&output->sway_output->destroy.link);
259 wl_list_remove(&output->sway_output->mode.link);
258 260
259 wlr_log(L_DEBUG, "OUTPUT: Destroying output '%s'", output->name); 261 wlr_log(L_DEBUG, "OUTPUT: Destroying output '%s'", output->name);
260 free_swayc(output); 262 free_swayc(output);
diff --git a/sway/tree/layout.c b/sway/tree/layout.c
index 3d04a1a7..de9e7b58 100644
--- a/sway/tree/layout.c
+++ b/sway/tree/layout.c
@@ -204,10 +204,13 @@ void arrange_windows(swayc_t *container, double width, double height) {
204 case C_WORKSPACE: 204 case C_WORKSPACE:
205 { 205 {
206 swayc_t *output = swayc_parent_by_type(container, C_OUTPUT); 206 swayc_t *output = swayc_parent_by_type(container, C_OUTPUT);
207 container->width = output->width; 207 struct wlr_box *area = &output->sway_output->usable_area;
208 container->height = output->height; 208 wlr_log(L_DEBUG, "Usable area for ws: %dx%d@%d,%d",
209 container->x = x; 209 area->width, area->height, area->x, area->y);
210 container->y = y; 210 container->width = area->width;
211 container->height = area->height;
212 container->x = x = area->x;
213 container->y = y = area->y;
211 wlr_log(L_DEBUG, "Arranging workspace '%s' at %f, %f", 214 wlr_log(L_DEBUG, "Arranging workspace '%s' at %f, %f",
212 container->name, container->x, container->y); 215 container->name, container->x, container->y);
213 } 216 }
diff --git a/swaybg/meson.build b/swaybg/meson.build
index 5e10f3c7..8704de6d 100644
--- a/swaybg/meson.build
+++ b/swaybg/meson.build
@@ -4,12 +4,12 @@ executable(
4 include_directories: [sway_inc], 4 include_directories: [sway_inc],
5 dependencies: [ 5 dependencies: [
6 cairo, 6 cairo,
7 client_protos,
7 gdk_pixbuf, 8 gdk_pixbuf,
8 jsonc, 9 jsonc,
9 math, 10 math,
10 pango, 11 pango,
11 pangocairo, 12 pangocairo,
12 sway_protos,
13 wayland_client, 13 wayland_client,
14 wlroots, 14 wlroots,
15 ], 15 ],