aboutsummaryrefslogtreecommitdiffstats
path: root/swaybg
diff options
context:
space:
mode:
authorLibravatar Brian Ashworth <bosrsf04@gmail.com>2019-04-03 21:53:43 -0400
committerLibravatar Simon Ser <contact@emersion.fr>2019-04-04 20:08:21 +0300
commit75e7bd24ccb9731065bb7f8313aa53ba11ddc420 (patch)
tree2522f31626a21b42c2496a32266eafd3b7d66f50 /swaybg
parentidle_inhibit: fix crash during view destruction (diff)
downloadsway-75e7bd24ccb9731065bb7f8313aa53ba11ddc420.tar.gz
sway-75e7bd24ccb9731065bb7f8313aa53ba11ddc420.tar.zst
sway-75e7bd24ccb9731065bb7f8313aa53ba11ddc420.zip
swaybg: one instance for all outputs
This makes it so there will only be one swaybg instance running instead of one per output. swaybg's cli has been changed to a xrandr like interface, where you select an output and then change properties for that output and then select another output and repeat. This also makes it so swaybg is only killed and respawned when a background changes or when reloading.
Diffstat (limited to 'swaybg')
-rw-r--r--swaybg/main.c452
1 files changed, 325 insertions, 127 deletions
diff --git a/swaybg/main.c b/swaybg/main.c
index e66221f0..b983dd6a 100644
--- a/swaybg/main.c
+++ b/swaybg/main.c
@@ -1,10 +1,12 @@
1#define _POSIX_C_SOURCE 200809L
1#include <assert.h> 2#include <assert.h>
2#include <ctype.h> 3#include <ctype.h>
4#include <getopt.h>
3#include <stdbool.h> 5#include <stdbool.h>
4#include <stdio.h> 6#include <stdio.h>
5#include <stdlib.h> 7#include <stdlib.h>
6#include <string.h> 8#include <string.h>
7#include <time.h> 9#include <strings.h>
8#include <wayland-client.h> 10#include <wayland-client.h>
9#include "background-image.h" 11#include "background-image.h"
10#include "cairo.h" 12#include "cairo.h"
@@ -14,49 +16,44 @@
14#include "wlr-layer-shell-unstable-v1-client-protocol.h" 16#include "wlr-layer-shell-unstable-v1-client-protocol.h"
15#include "xdg-output-unstable-v1-client-protocol.h" 17#include "xdg-output-unstable-v1-client-protocol.h"
16 18
17struct swaybg_state; 19struct swaybg_state {
18 20 struct wl_display *display;
19struct swaybg_args { 21 struct wl_compositor *compositor;
20 const char *output; 22 struct wl_shm *shm;
21 const char *path; 23 struct zwlr_layer_shell_v1 *layer_shell;
22 enum background_mode mode; 24 struct zxdg_output_manager_v1 *xdg_output_manager;
23 const char *fallback; 25 struct wl_list configs; // struct swaybg_output_config::link
26 struct wl_list outputs; // struct swaybg_output::link
27 bool run_display;
24}; 28};
25 29
26struct swaybg_context { 30struct swaybg_output_config {
27 uint32_t color; 31 char *output;
28 cairo_surface_t *image; 32 cairo_surface_t *image;
33 enum background_mode mode;
34 uint32_t color;
35 struct wl_list link;
29}; 36};
30 37
31struct swaybg_output { 38struct swaybg_output {
39 uint32_t wl_name;
32 struct wl_output *wl_output; 40 struct wl_output *wl_output;
33 struct zxdg_output_v1 *xdg_output; 41 struct zxdg_output_v1 *xdg_output;
34 struct swaybg_state *state; 42 char *name;
35 struct wl_list link; 43 char *identifier;
36 44
37 int32_t scale; 45 struct swaybg_state *state;
38}; 46 struct swaybg_output_config *config;
39
40struct swaybg_state {
41 const struct swaybg_args *args;
42 struct swaybg_context context;
43
44 struct wl_display *display;
45 struct wl_compositor *compositor;
46 struct wl_shm *shm;
47 struct wl_list outputs;
48 struct zwlr_layer_shell_v1 *layer_shell;
49 struct zxdg_output_manager_v1 *xdg_output_manager;
50 47
51 struct swaybg_output *output;
52 struct wl_surface *surface; 48 struct wl_surface *surface;
53 struct wl_region *input_region;
54 struct zwlr_layer_surface_v1 *layer_surface; 49 struct zwlr_layer_surface_v1 *layer_surface;
55
56 bool run_display;
57 uint32_t width, height;
58 struct pool_buffer buffers[2]; 50 struct pool_buffer buffers[2];
59 struct pool_buffer *current_buffer; 51 struct pool_buffer *current_buffer;
52
53 uint32_t width, height;
54 int32_t scale;
55
56 struct wl_list link;
60}; 57};
61 58
62bool is_valid_color(const char *color) { 59bool is_valid_color(const char *color) {
@@ -77,68 +74,82 @@ bool is_valid_color(const char *color) {
77 return true; 74 return true;
78} 75}
79 76
80static void render_frame(struct swaybg_state *state) { 77static void render_frame(struct swaybg_output *output) {
81 int buffer_width = state->width * state->output->scale, 78 int buffer_width = output->width * output->scale,
82 buffer_height = state->height * state->output->scale; 79 buffer_height = output->height * output->scale;
83 state->current_buffer = get_next_buffer(state->shm, 80 output->current_buffer = get_next_buffer(output->state->shm,
84 state->buffers, buffer_width, buffer_height); 81 output->buffers, buffer_width, buffer_height);
85 if (!state->current_buffer) { 82 if (!output->current_buffer) {
86 return; 83 return;
87 } 84 }
88 cairo_t *cairo = state->current_buffer->cairo; 85 cairo_t *cairo = output->current_buffer->cairo;
89 cairo_save(cairo); 86 cairo_save(cairo);
90 cairo_set_operator(cairo, CAIRO_OPERATOR_CLEAR); 87 cairo_set_operator(cairo, CAIRO_OPERATOR_CLEAR);
91 cairo_paint(cairo); 88 cairo_paint(cairo);
92 cairo_restore(cairo); 89 cairo_restore(cairo);
93 if (state->args->mode == BACKGROUND_MODE_SOLID_COLOR) { 90 if (output->config->mode == BACKGROUND_MODE_SOLID_COLOR) {
94 cairo_set_source_u32(cairo, state->context.color); 91 cairo_set_source_u32(cairo, output->config->color);
95 cairo_paint(cairo); 92 cairo_paint(cairo);
96 } else { 93 } else {
97 if (state->args->fallback && state->context.color) { 94 if (output->config->color) {
98 cairo_set_source_u32(cairo, state->context.color); 95 cairo_set_source_u32(cairo, output->config->color);
99 cairo_paint(cairo); 96 cairo_paint(cairo);
100 } 97 }
101 render_background_image(cairo, state->context.image, 98 render_background_image(cairo, output->config->image,
102 state->args->mode, buffer_width, buffer_height); 99 output->config->mode, buffer_width, buffer_height);
103 } 100 }
104 101
105 wl_surface_set_buffer_scale(state->surface, state->output->scale); 102 wl_surface_set_buffer_scale(output->surface, output->scale);
106 wl_surface_attach(state->surface, state->current_buffer->buffer, 0, 0); 103 wl_surface_attach(output->surface, output->current_buffer->buffer, 0, 0);
107 wl_surface_damage_buffer(state->surface, 0, 0, INT32_MAX, INT32_MAX); 104 wl_surface_damage_buffer(output->surface, 0, 0, INT32_MAX, INT32_MAX);
108 wl_surface_commit(state->surface); 105 wl_surface_commit(output->surface);
109} 106}
110 107
111static bool prepare_context(struct swaybg_state *state) { 108static void destroy_swaybg_output_config(struct swaybg_output_config *config) {
112 if (state->args->mode == BACKGROUND_MODE_SOLID_COLOR) { 109 if (!config) {
113 state->context.color = parse_color(state->args->path); 110 return;
114 return is_valid_color(state->args->path);
115 } 111 }
116 if (state->args->fallback && is_valid_color(state->args->fallback)) { 112 wl_list_remove(&config->link);
117 state->context.color = parse_color(state->args->fallback); 113 free(config->output);
114 free(config);
115}
116
117static void destroy_swaybg_output(struct swaybg_output *output) {
118 if (!output) {
119 return;
118 } 120 }
119 if (!(state->context.image = load_background_image(state->args->path))) { 121 wl_list_remove(&output->link);
120 return false; 122 if (output->layer_surface != NULL) {
123 zwlr_layer_surface_v1_destroy(output->layer_surface);
121 } 124 }
122 return true; 125 if (output->surface != NULL) {
126 wl_surface_destroy(output->surface);
127 }
128 zxdg_output_v1_destroy(output->xdg_output);
129 wl_output_destroy(output->wl_output);
130 destroy_buffer(&output->buffers[0]);
131 destroy_buffer(&output->buffers[1]);
132 free(output->name);
133 free(output->identifier);
134 free(output);
123} 135}
124 136
125static void layer_surface_configure(void *data, 137static void layer_surface_configure(void *data,
126 struct zwlr_layer_surface_v1 *surface, 138 struct zwlr_layer_surface_v1 *surface,
127 uint32_t serial, uint32_t width, uint32_t height) { 139 uint32_t serial, uint32_t width, uint32_t height) {
128 struct swaybg_state *state = data; 140 struct swaybg_output *output = data;
129 state->width = width; 141 output->width = width;
130 state->height = height; 142 output->height = height;
131 zwlr_layer_surface_v1_ack_configure(surface, serial); 143 zwlr_layer_surface_v1_ack_configure(surface, serial);
132 render_frame(state); 144 render_frame(output);
133} 145}
134 146
135static void layer_surface_closed(void *data, 147static void layer_surface_closed(void *data,
136 struct zwlr_layer_surface_v1 *surface) { 148 struct zwlr_layer_surface_v1 *surface) {
137 struct swaybg_state *state = data; 149 struct swaybg_output *output = data;
138 zwlr_layer_surface_v1_destroy(state->layer_surface); 150 sway_log(SWAY_DEBUG, "Destroying output %s (%s)",
139 wl_surface_destroy(state->surface); 151 output->name, output->identifier);
140 wl_region_destroy(state->input_region); 152 destroy_swaybg_output(output);
141 state->run_display = false;
142} 153}
143 154
144static const struct zwlr_layer_surface_v1_listener layer_surface_listener = { 155static const struct zwlr_layer_surface_v1_listener layer_surface_listener = {
@@ -164,12 +175,9 @@ static void output_done(void *data, struct wl_output *output) {
164static void output_scale(void *data, struct wl_output *wl_output, 175static void output_scale(void *data, struct wl_output *wl_output,
165 int32_t scale) { 176 int32_t scale) {
166 struct swaybg_output *output = data; 177 struct swaybg_output *output = data;
167 struct swaybg_state *state = output->state;
168
169 output->scale = scale; 178 output->scale = scale;
170 179 if (output->state->run_display && output->width > 0 && output->height > 0) {
171 if (state->output == output && state->run_display) { 180 render_frame(output);
172 render_frame(state);
173 } 181 }
174} 182}
175 183
@@ -190,24 +198,91 @@ static void xdg_output_handle_logical_size(void *data,
190 // Who cares 198 // Who cares
191} 199}
192 200
201static void find_config(struct swaybg_output *output, const char *name) {
202 struct swaybg_output_config *config = NULL;
203 wl_list_for_each(config, &output->state->configs, link) {
204 if (strcmp(config->output, name) == 0) {
205 output->config = config;
206 return;
207 } else if (!output->config && strcmp(config->output, "*") == 0) {
208 output->config = config;
209 }
210 }
211}
212
193static void xdg_output_handle_name(void *data, 213static void xdg_output_handle_name(void *data,
194 struct zxdg_output_v1 *xdg_output, const char *name) { 214 struct zxdg_output_v1 *xdg_output, const char *name) {
195 struct swaybg_output *output = data; 215 struct swaybg_output *output = data;
196 struct swaybg_state *state = output->state; 216 output->name = strdup(name);
197 if (strcmp(name, state->args->output) == 0) { 217
198 assert(state->output == NULL); 218 // If description was sent first, the config may already be populated. If
199 state->output = output; 219 // there is an identifier config set, keep it.
220 if (!output->config || strcmp(output->config->output, "*") == 0) {
221 find_config(output, name);
200 } 222 }
201} 223}
202 224
203static void xdg_output_handle_description(void *data, 225static void xdg_output_handle_description(void *data,
204 struct zxdg_output_v1 *xdg_output, const char *description) { 226 struct zxdg_output_v1 *xdg_output, const char *description) {
205 // Who cares 227 struct swaybg_output *output = data;
228
229 // wlroots currently sets the description to `make model serial (name)`
230 // If this changes in the future, this will need to be modified.
231 char *paren = strrchr(description, '(');
232 if (paren) {
233 size_t length = paren - description;
234 output->identifier = malloc(length);
235 if (!output->identifier) {
236 sway_log(SWAY_ERROR, "Failed to allocate output identifier");
237 return;
238 }
239 strncpy(output->identifier, description, length);
240 output->identifier[length - 1] = '\0';
241
242 find_config(output, output->identifier);
243 }
244}
245
246static void create_layer_surface(struct swaybg_output *output) {
247 output->surface = wl_compositor_create_surface(output->state->compositor);
248 assert(output->surface);
249
250 // Empty input region
251 struct wl_region *input_region =
252 wl_compositor_create_region(output->state->compositor);
253 assert(input_region);
254 wl_surface_set_input_region(output->surface, input_region);
255 wl_region_destroy(input_region);
256
257 output->layer_surface = zwlr_layer_shell_v1_get_layer_surface(
258 output->state->layer_shell, output->surface, output->wl_output,
259 ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND, "wallpaper");
260 assert(output->layer_surface);
261
262 zwlr_layer_surface_v1_set_size(output->layer_surface, 0, 0);
263 zwlr_layer_surface_v1_set_anchor(output->layer_surface,
264 ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
265 ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
266 ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM |
267 ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT);
268 zwlr_layer_surface_v1_set_exclusive_zone(output->layer_surface, -1);
269 zwlr_layer_surface_v1_add_listener(output->layer_surface,
270 &layer_surface_listener, output);
271 wl_surface_commit(output->surface);
206} 272}
207 273
208static void xdg_output_handle_done(void *data, 274static void xdg_output_handle_done(void *data,
209 struct zxdg_output_v1 *xdg_output) { 275 struct zxdg_output_v1 *xdg_output) {
210 // Who cares 276 struct swaybg_output *output = data;
277 if (!output->config) {
278 sway_log(SWAY_DEBUG, "Could not find config for output %s (%s)",
279 output->name, output->identifier);
280 destroy_swaybg_output(output);
281 } else if (!output->layer_surface) {
282 sway_log(SWAY_DEBUG, "Found config %s for output %s (%s)",
283 output->config->output, output->name, output->identifier);
284 create_layer_surface(output);
285 }
211} 286}
212 287
213static const struct zxdg_output_v1_listener xdg_output_listener = { 288static const struct zxdg_output_v1_listener xdg_output_listener = {
@@ -229,10 +304,18 @@ static void handle_global(void *data, struct wl_registry *registry,
229 } else if (strcmp(interface, wl_output_interface.name) == 0) { 304 } else if (strcmp(interface, wl_output_interface.name) == 0) {
230 struct swaybg_output *output = calloc(1, sizeof(struct swaybg_output)); 305 struct swaybg_output *output = calloc(1, sizeof(struct swaybg_output));
231 output->state = state; 306 output->state = state;
307 output->wl_name = name;
232 output->wl_output = 308 output->wl_output =
233 wl_registry_bind(registry, name, &wl_output_interface, 3); 309 wl_registry_bind(registry, name, &wl_output_interface, 3);
234 wl_output_add_listener(output->wl_output, &output_listener, output); 310 wl_output_add_listener(output->wl_output, &output_listener, output);
235 wl_list_insert(&state->outputs, &output->link); 311 wl_list_insert(&state->outputs, &output->link);
312
313 if (state->run_display) {
314 output->xdg_output = zxdg_output_manager_v1_get_xdg_output(
315 state->xdg_output_manager, output->wl_output);
316 zxdg_output_v1_add_listener(output->xdg_output,
317 &xdg_output_listener, output);
318 }
236 } else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) { 319 } else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) {
237 state->layer_shell = 320 state->layer_shell =
238 wl_registry_bind(registry, name, &zwlr_layer_shell_v1_interface, 1); 321 wl_registry_bind(registry, name, &zwlr_layer_shell_v1_interface, 1);
@@ -244,7 +327,16 @@ static void handle_global(void *data, struct wl_registry *registry,
244 327
245static void handle_global_remove(void *data, struct wl_registry *registry, 328static void handle_global_remove(void *data, struct wl_registry *registry,
246 uint32_t name) { 329 uint32_t name) {
247 // who cares 330 struct swaybg_state *state = data;
331 struct swaybg_output *output, *tmp;
332 wl_list_for_each_safe(output, tmp, &state->outputs, link) {
333 if (output->wl_name == name) {
334 sway_log(SWAY_DEBUG, "Destroying output %s (%s)",
335 output->name, output->identifier);
336 destroy_swaybg_output(output);
337 break;
338 }
339 }
248} 340}
249 341
250static const struct wl_registry_listener registry_listener = { 342static const struct wl_registry_listener registry_listener = {
@@ -252,32 +344,159 @@ static const struct wl_registry_listener registry_listener = {
252 .global_remove = handle_global_remove, 344 .global_remove = handle_global_remove,
253}; 345};
254 346
255int main(int argc, const char **argv) { 347static bool store_swaybg_output_config(struct swaybg_state *state,
256 sway_log_init(SWAY_DEBUG, NULL); 348 struct swaybg_output_config *config) {
257 349 struct swaybg_output_config *oc = NULL;
258 struct swaybg_args args = {0}; 350 wl_list_for_each(oc, &state->configs, link) {
259 struct swaybg_state state = { .args = &args }; 351 if (strcmp(config->output, oc->output) == 0) {
260 wl_list_init(&state.outputs); 352 // Merge on top
353 if (config->image) {
354 free(oc->image);
355 oc->image = config->image;
356 config->image = NULL;
357 }
358 if (config->color) {
359 oc->color = config->color;
360 }
361 if (config->mode != BACKGROUND_MODE_INVALID) {
362 oc->mode = config->mode;
363 }
364 return false;
365 }
366 }
367 // New config, just add it
368 wl_list_insert(&state->configs, &config->link);
369 return true;
370}
261 371
262 if (argc < 4 || argc > 5) { 372static void parse_command_line(int argc, char **argv,
263 sway_log(SWAY_ERROR, "Do not run this program manually. " 373 struct swaybg_state *state) {
264 "See `man 5 sway-output` and look for background options."); 374 static struct option long_options[] = {
265 return 1; 375 {"color", required_argument, NULL, 'c'},
376 {"help", no_argument, NULL, 'h'},
377 {"image", required_argument, NULL, 'i'},
378 {"mode", required_argument, NULL, 'm'},
379 {"output", required_argument, NULL, 'o'},
380 {"version", no_argument, NULL, 'v'},
381 {0, 0, 0, 0}
382 };
383
384 const char *usage =
385 "Usage: swaybg <options...>\n"
386 "\n"
387 " -c, --color Set the background color.\n"
388 " -h, --help Show help message and quit.\n"
389 " -i, --image Set the image to display.\n"
390 " -m, --mode Set the mode to use for the image.\n"
391 " -o, --output Set the output to operate on or * for all.\n"
392 " -v, --version Show the version number and quit.\n"
393 "\n"
394 "Background Modes:\n"
395 " stretch, fit, fill, center, tile, or solid_color\n";
396
397 struct swaybg_output_config *config = NULL;
398
399 int c;
400 while (1) {
401 int option_index = 0;
402 c = getopt_long(argc, argv, "c:hi:m:o:v", long_options, &option_index);
403 if (c == -1) {
404 break;
405 }
406 switch (c) {
407 case 'c': // color
408 if (!config) {
409 goto no_output;
410 }
411 if (!is_valid_color(optarg)) {
412 sway_log(SWAY_ERROR, "Invalid color: %s", optarg);
413 continue;
414 }
415 config->color = parse_color(optarg);
416 break;
417 case 'i': // image
418 if (!config) {
419 goto no_output;
420 }
421 free(config->image);
422 config->image = load_background_image(optarg);
423 if (!config->image) {
424 sway_log(SWAY_ERROR, "Failed to load image: %s", optarg);
425 }
426 break;
427 case 'm': // mode
428 if (!config) {
429 goto no_output;
430 }
431 config->mode = parse_background_mode(optarg);
432 if (config->mode == BACKGROUND_MODE_INVALID) {
433 sway_log(SWAY_ERROR, "Invalid mode: %s", optarg);
434 }
435 break;
436 case 'o': // output
437 if (config && !store_swaybg_output_config(state, config)) {
438 // Empty config or merged on top of an existing one
439 destroy_swaybg_output_config(config);
440 }
441 config = calloc(sizeof(struct swaybg_output_config), 1);
442 config->output = strdup(optarg);
443 config->mode = BACKGROUND_MODE_INVALID;
444 wl_list_init(&config->link); // init for safe removal
445 break;
446 case 'v': // version
447 fprintf(stdout, "swaybg version " SWAY_VERSION "\n");
448 exit(EXIT_SUCCESS);
449 break;
450 default:
451 fprintf(c == 'h' ? stdout : stderr, "%s", usage);
452 exit(c == 'h' ? EXIT_SUCCESS : EXIT_FAILURE);
453 }
454 }
455 if (config && !store_swaybg_output_config(state, config)) {
456 // Empty config or merged on top of an existing one
457 destroy_swaybg_output_config(config);
266 } 458 }
267 459
268 args.output = argv[1]; 460 // Check for invalid options
269 args.path = argv[2]; 461 if (optind < argc) {
462 config = NULL;
463 struct swaybg_output_config *tmp = NULL;
464 wl_list_for_each_safe(config, tmp, &state->configs, link) {
465 destroy_swaybg_output_config(config);
466 }
467 // continue into empty list
468 }
469 if (wl_list_empty(&state->configs)) {
470 fprintf(stderr, "%s", usage);
471 exit(EXIT_FAILURE);
472 }
270 473
271 args.mode = parse_background_mode(argv[3]); 474 // Set default mode and remove empties
272 if (args.mode == BACKGROUND_MODE_INVALID) { 475 config = NULL;
273 return 1; 476 struct swaybg_output_config *tmp = NULL;
477 wl_list_for_each_safe(config, tmp, &state->configs, link) {
478 if (!config->image && !config->color) {
479 destroy_swaybg_output_config(config);
480 } else if (config->mode == BACKGROUND_MODE_INVALID) {
481 config->mode = config->image
482 ? BACKGROUND_MODE_STRETCH
483 : BACKGROUND_MODE_SOLID_COLOR;
484 }
274 } 485 }
486 return;
487no_output:
488 fprintf(stderr, "Cannot operate on NULL output config\n");
489 exit(EXIT_FAILURE);
490}
275 491
276 args.fallback = argc == 5 ? argv[4] : NULL; 492int main(int argc, char **argv) {
493 sway_log_init(SWAY_DEBUG, NULL);
277 494
278 if (!prepare_context(&state)) { 495 struct swaybg_state state = {0};
279 return 1; 496 wl_list_init(&state.configs);
280 } 497 wl_list_init(&state.outputs);
498
499 parse_command_line(argc, argv, &state);
281 500
282 state.display = wl_display_connect(NULL); 501 state.display = wl_display_connect(NULL);
283 if (!state.display) { 502 if (!state.display) {
@@ -303,42 +522,21 @@ int main(int argc, const char **argv) {
303 zxdg_output_v1_add_listener(output->xdg_output, 522 zxdg_output_v1_add_listener(output->xdg_output,
304 &xdg_output_listener, output); 523 &xdg_output_listener, output);
305 } 524 }
306 // Second roundtrip to get xdg_output properties
307 wl_display_roundtrip(state.display);
308 if (state.output == NULL) {
309 sway_log(SWAY_ERROR, "Cannot find output '%s'", args.output);
310 return 1;
311 }
312
313 state.surface = wl_compositor_create_surface(state.compositor);
314 assert(state.surface);
315
316 // Empty input region
317 state.input_region = wl_compositor_create_region(state.compositor);
318 assert(state.input_region);
319 wl_surface_set_input_region(state.surface, state.input_region);
320
321 state.layer_surface = zwlr_layer_shell_v1_get_layer_surface(
322 state.layer_shell, state.surface, state.output->wl_output,
323 ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND, "wallpaper");
324 assert(state.layer_surface);
325
326 zwlr_layer_surface_v1_set_size(state.layer_surface, 0, 0);
327 zwlr_layer_surface_v1_set_anchor(state.layer_surface,
328 ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
329 ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
330 ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM |
331 ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT);
332 zwlr_layer_surface_v1_set_exclusive_zone(state.layer_surface, -1);
333 zwlr_layer_surface_v1_add_listener(state.layer_surface,
334 &layer_surface_listener, &state);
335 wl_surface_commit(state.surface);
336 wl_display_roundtrip(state.display);
337 525
338 state.run_display = true; 526 state.run_display = true;
339 while (wl_display_dispatch(state.display) != -1 && state.run_display) { 527 while (wl_display_dispatch(state.display) != -1 && state.run_display) {
340 // This space intentionally left blank 528 // This space intentionally left blank
341 } 529 }
342 530
531 struct swaybg_output *tmp_output;
532 wl_list_for_each_safe(output, tmp_output, &state.outputs, link) {
533 destroy_swaybg_output(output);
534 }
535
536 struct swaybg_output_config *config = NULL, *tmp_config = NULL;
537 wl_list_for_each_safe(config, tmp_config, &state.configs, link) {
538 destroy_swaybg_output_config(config);
539 }
540
343 return 0; 541 return 0;
344} 542}