aboutsummaryrefslogtreecommitdiffstats
path: root/swaybg/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'swaybg/main.c')
-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}