aboutsummaryrefslogtreecommitdiffstats
path: root/sway/desktop/layer_shell.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/desktop/layer_shell.c')
-rw-r--r--sway/desktop/layer_shell.c78
1 files changed, 45 insertions, 33 deletions
diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c
index d4ca4fb4..2b4b2027 100644
--- a/sway/desktop/layer_shell.c
+++ b/sway/desktop/layer_shell.c
@@ -2,7 +2,6 @@
2#include <stdlib.h> 2#include <stdlib.h>
3#include <string.h> 3#include <string.h>
4#include <wayland-server-core.h> 4#include <wayland-server-core.h>
5#include <wlr/types/wlr_box.h>
6#include <wlr/types/wlr_layer_shell_v1.h> 5#include <wlr/types/wlr_layer_shell_v1.h>
7#include <wlr/types/wlr_output_damage.h> 6#include <wlr/types/wlr_output_damage.h>
8#include <wlr/types/wlr_output.h> 7#include <wlr/types/wlr_output.h>
@@ -115,9 +114,10 @@ static void arrange_layer(struct sway_output *output, struct wl_list *list,
115 // Horizontal axis 114 // Horizontal axis
116 const uint32_t both_horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT 115 const uint32_t both_horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT
117 | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; 116 | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
118 if ((state->anchor & both_horiz) && box.width == 0) { 117 if (box.width == 0) {
119 box.x = bounds.x; 118 box.x = bounds.x;
120 box.width = bounds.width; 119 } else if ((state->anchor & both_horiz) == both_horiz) {
120 box.x = bounds.x + ((bounds.width / 2) - (box.width / 2));
121 } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) { 121 } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) {
122 box.x = bounds.x; 122 box.x = bounds.x;
123 } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) { 123 } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) {
@@ -128,9 +128,10 @@ static void arrange_layer(struct sway_output *output, struct wl_list *list,
128 // Vertical axis 128 // Vertical axis
129 const uint32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP 129 const uint32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP
130 | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; 130 | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
131 if ((state->anchor & both_vert) && box.height == 0) { 131 if (box.height == 0) {
132 box.y = bounds.y; 132 box.y = bounds.y;
133 box.height = bounds.height; 133 } else if ((state->anchor & both_vert) == both_vert) {
134 box.y = bounds.y + ((bounds.height / 2) - (box.height / 2));
134 } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) { 135 } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) {
135 box.y = bounds.y; 136 box.y = bounds.y;
136 } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) { 137 } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) {
@@ -139,29 +140,37 @@ static void arrange_layer(struct sway_output *output, struct wl_list *list,
139 box.y = bounds.y + ((bounds.height / 2) - (box.height / 2)); 140 box.y = bounds.y + ((bounds.height / 2) - (box.height / 2));
140 } 141 }
141 // Margin 142 // Margin
142 if ((state->anchor & both_horiz) == both_horiz) { 143 if (box.width == 0) {
143 box.x += state->margin.left; 144 box.x += state->margin.left;
144 box.width -= state->margin.left + state->margin.right; 145 box.width = bounds.width -
146 (state->margin.left + state->margin.right);
147 } else if ((state->anchor & both_horiz) == both_horiz) {
148 // don't apply margins
145 } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) { 149 } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) {
146 box.x += state->margin.left; 150 box.x += state->margin.left;
147 } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) { 151 } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) {
148 box.x -= state->margin.right; 152 box.x -= state->margin.right;
149 } 153 }
150 if ((state->anchor & both_vert) == both_vert) { 154 if (box.height == 0) {
151 box.y += state->margin.top; 155 box.y += state->margin.top;
152 box.height -= state->margin.top + state->margin.bottom; 156 box.height = bounds.height -
157 (state->margin.top + state->margin.bottom);
158 } else if ((state->anchor & both_vert) == both_vert) {
159 // don't apply margins
153 } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) { 160 } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) {
154 box.y += state->margin.top; 161 box.y += state->margin.top;
155 } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) { 162 } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) {
156 box.y -= state->margin.bottom; 163 box.y -= state->margin.bottom;
157 } 164 }
158 if (box.width < 0 || box.height < 0) { 165 if (!sway_assert(box.width >= 0 && box.height >= 0,
159 // TODO: Bubble up a protocol error? 166 "Expected layer surface to have positive size")) {
160 wlr_layer_surface_v1_close(layer);
161 continue; 167 continue;
162 } 168 }
163 // Apply 169 // Apply
164 sway_layer->geo = box; 170 sway_layer->geo = box;
171 wlr_surface_get_extends(layer->surface, &sway_layer->extent);
172 sway_layer->extent.x += box.x;
173 sway_layer->extent.y += box.y;
165 apply_exclusive(usable_area, state->anchor, state->exclusive_zone, 174 apply_exclusive(usable_area, state->anchor, state->exclusive_zone,
166 state->margin.top, state->margin.right, 175 state->margin.top, state->margin.right,
167 state->margin.bottom, state->margin.left); 176 state->margin.bottom, state->margin.left);
@@ -191,7 +200,7 @@ void arrange_layers(struct sway_output *output) {
191 arrange_output(output); 200 arrange_output(output);
192 } 201 }
193 202
194 // Arrange non-exlusive surfaces from top->bottom 203 // Arrange non-exclusive surfaces from top->bottom
195 arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], 204 arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],
196 &usable_area, false); 205 &usable_area, false);
197 arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], 206 arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
@@ -277,7 +286,7 @@ static void handle_output_destroy(struct wl_listener *listener, void *data) {
277 } 286 }
278 287
279 sway_layer->layer_surface->output = NULL; 288 sway_layer->layer_surface->output = NULL;
280 wlr_layer_surface_v1_close(sway_layer->layer_surface); 289 wlr_layer_surface_v1_destroy(sway_layer->layer_surface);
281} 290}
282 291
283static void handle_surface_commit(struct wl_listener *listener, void *data) { 292static void handle_surface_commit(struct wl_listener *listener, void *data) {
@@ -288,13 +297,17 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) {
288 if (wlr_output == NULL) { 297 if (wlr_output == NULL) {
289 return; 298 return;
290 } 299 }
300 if (layer_surface->current.committed == 0) {
301 // The layer surface state didn't change
302 return;
303 }
291 304
292 struct sway_output *output = wlr_output->data; 305 struct sway_output *output = wlr_output->data;
293 struct wlr_box old_geo = layer->geo; 306 struct wlr_box old_extent = layer->extent;
294 arrange_layers(output); 307 arrange_layers(output);
295 308
296 bool geo_changed = 309 bool extent_changed =
297 memcmp(&old_geo, &layer->geo, sizeof(struct wlr_box)) != 0; 310 memcmp(&old_extent, &layer->extent, sizeof(struct wlr_box)) != 0;
298 bool layer_changed = layer->layer != layer_surface->current.layer; 311 bool layer_changed = layer->layer != layer_surface->current.layer;
299 if (layer_changed) { 312 if (layer_changed) {
300 wl_list_remove(&layer->link); 313 wl_list_remove(&layer->link);
@@ -302,9 +315,8 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) {
302 &layer->link); 315 &layer->link);
303 layer->layer = layer_surface->current.layer; 316 layer->layer = layer_surface->current.layer;
304 } 317 }
305 if (geo_changed || layer_changed) { 318 if (extent_changed || layer_changed) {
306 output_damage_surface(output, old_geo.x, old_geo.y, 319 output_damage_box(output, &old_extent);
307 layer_surface->surface, true);
308 output_damage_surface(output, layer->geo.x, layer->geo.y, 320 output_damage_surface(output, layer->geo.x, layer->geo.y,
309 layer_surface->surface, true); 321 layer_surface->surface, true);
310 } else { 322 } else {
@@ -429,7 +441,7 @@ static struct sway_layer_subsurface *create_subsurface(
429 struct wlr_subsurface *wlr_subsurface, 441 struct wlr_subsurface *wlr_subsurface,
430 struct sway_layer_surface *layer_surface) { 442 struct sway_layer_surface *layer_surface) {
431 struct sway_layer_subsurface *subsurface = 443 struct sway_layer_subsurface *subsurface =
432 calloc(1, sizeof(struct sway_layer_surface)); 444 calloc(1, sizeof(struct sway_layer_subsurface));
433 if (subsurface == NULL) { 445 if (subsurface == NULL) {
434 return NULL; 446 return NULL;
435 } 447 }
@@ -590,14 +602,14 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
590 sway_log(SWAY_DEBUG, "new layer surface: namespace %s layer %d anchor %" PRIu32 602 sway_log(SWAY_DEBUG, "new layer surface: namespace %s layer %d anchor %" PRIu32
591 " size %" PRIu32 "x%" PRIu32 " margin %" PRIu32 ",%" PRIu32 ",%" PRIu32 ",%" PRIu32 ",", 603 " size %" PRIu32 "x%" PRIu32 " margin %" PRIu32 ",%" PRIu32 ",%" PRIu32 ",%" PRIu32 ",",
592 layer_surface->namespace, 604 layer_surface->namespace,
593 layer_surface->client_pending.layer, 605 layer_surface->pending.layer,
594 layer_surface->client_pending.anchor, 606 layer_surface->pending.anchor,
595 layer_surface->client_pending.desired_width, 607 layer_surface->pending.desired_width,
596 layer_surface->client_pending.desired_height, 608 layer_surface->pending.desired_height,
597 layer_surface->client_pending.margin.top, 609 layer_surface->pending.margin.top,
598 layer_surface->client_pending.margin.right, 610 layer_surface->pending.margin.right,
599 layer_surface->client_pending.margin.bottom, 611 layer_surface->pending.margin.bottom,
600 layer_surface->client_pending.margin.left); 612 layer_surface->pending.margin.left);
601 613
602 if (!layer_surface->output) { 614 if (!layer_surface->output) {
603 // Assign last active output 615 // Assign last active output
@@ -614,7 +626,7 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
614 sway_log(SWAY_ERROR, 626 sway_log(SWAY_ERROR,
615 "no output to auto-assign layer surface '%s' to", 627 "no output to auto-assign layer surface '%s' to",
616 layer_surface->namespace); 628 layer_surface->namespace);
617 wlr_layer_surface_v1_close(layer_surface); 629 wlr_layer_surface_v1_destroy(layer_surface);
618 return; 630 return;
619 } 631 }
620 output = root->outputs->items[0]; 632 output = root->outputs->items[0];
@@ -651,13 +663,13 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
651 sway_layer->output_destroy.notify = handle_output_destroy; 663 sway_layer->output_destroy.notify = handle_output_destroy;
652 wl_signal_add(&output->events.destroy, &sway_layer->output_destroy); 664 wl_signal_add(&output->events.destroy, &sway_layer->output_destroy);
653 665
654 wl_list_insert(&output->layers[layer_surface->client_pending.layer], 666 wl_list_insert(&output->layers[layer_surface->pending.layer],
655 &sway_layer->link); 667 &sway_layer->link);
656 668
657 // Temporarily set the layer's current state to client_pending 669 // Temporarily set the layer's current state to pending
658 // So that we can easily arrange it 670 // So that we can easily arrange it
659 struct wlr_layer_surface_v1_state old_state = layer_surface->current; 671 struct wlr_layer_surface_v1_state old_state = layer_surface->current;
660 layer_surface->current = layer_surface->client_pending; 672 layer_surface->current = layer_surface->pending;
661 arrange_layers(output); 673 arrange_layers(output);
662 layer_surface->current = old_state; 674 layer_surface->current = old_state;
663} 675}