aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Thomas Hebb <tommyhebb@gmail.com>2022-02-06 12:21:27 -0800
committerLibravatar Simon Ser <contact@emersion.fr>2022-04-13 10:05:24 +0200
commitd726e50643d6e54bdb5882008e13bf5d20a1c3ba (patch)
tree459f4f106efd258093af96dbe53cfd00276fbf44
parentShuffle variables to satisfy -Werror=restrict (diff)
downloadsway-d726e50643d6e54bdb5882008e13bf5d20a1c3ba.tar.gz
sway-d726e50643d6e54bdb5882008e13bf5d20a1c3ba.tar.zst
sway-d726e50643d6e54bdb5882008e13bf5d20a1c3ba.zip
layer_shell: keep output non-NULL wherever possible
Our layer shell implementation assigns every layer surface to an output on creation. It tracks this output using the output field on the underlying wlr_layer_surface_v1 structure. As such, much of the existing code assumes that output is always non-NULL and omits NULL checks accordingly. However, there are currently two cases where we destroy a sway_layer_surface and output is NULL. The first is when we can't find an output to assign the surface to and destroy it immediately after creation. The second is when we destroy a surface in response to its output getting destroyed, as we set output to NULL in handle_output_destroy() before we call wlr_layer_surface_v1_destroy(), which is what calls the appropriate unmap and destroy callbacks. The former case doesn't cause any problems, since we haven't even allocated a sway_layer_surface at that point or registered any callbacks. The latter case, however, currently triggers a crash (#6120) if a popup is visible, since our popup_handle_unmap() implementation can't handle a NULL output. To fix this issue, keep output set until right before we free the sway_layer_surface. All we need to do is remove some of the cleanup logic from handle_output_destroy(), since as of commit c9060bcc12d0 ("layer-shell: replace close() with destroy()") that same logic is guaranteed to be happen later when wlroots calls handle_destroy() as part of wlr_layer_surface_v1_destroy(). This lets us remove some NULL checks from other unmap/destroy callbacks, which is nice. We also don't need to check that the wlr_output points to a valid sway_output anymore, since we unset that pointer after disabling the output as of commit a0bbe67076b8 ("Address emersions comments on output re-enabling") Just to be safe, I've added assertions that the wlr_output is non-NULL wherever we use it. Fixes #6120.
-rw-r--r--sway/desktop/layer_shell.c53
1 files changed, 24 insertions, 29 deletions
diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c
index 1250415e..159f3336 100644
--- a/sway/desktop/layer_shell.c
+++ b/sway/desktop/layer_shell.c
@@ -271,10 +271,6 @@ static void handle_output_destroy(struct wl_listener *listener, void *data) {
271 wl_resource_get_client(sway_layer->layer_surface->resource); 271 wl_resource_get_client(sway_layer->layer_surface->resource);
272 bool set_focus = seat->exclusive_client == client; 272 bool set_focus = seat->exclusive_client == client;
273 273
274 wl_list_remove(&sway_layer->output_destroy.link);
275 wl_list_remove(&sway_layer->link);
276 wl_list_init(&sway_layer->link);
277
278 if (set_focus) { 274 if (set_focus) {
279 struct sway_layer_surface *layer = 275 struct sway_layer_surface *layer =
280 find_mapped_layer_by_client(client, sway_layer->layer_surface->output); 276 find_mapped_layer_by_client(client, sway_layer->layer_surface->output);
@@ -283,7 +279,6 @@ static void handle_output_destroy(struct wl_listener *listener, void *data) {
283 } 279 }
284 } 280 }
285 281
286 sway_layer->layer_surface->output = NULL;
287 wlr_layer_surface_v1_destroy(sway_layer->layer_surface); 282 wlr_layer_surface_v1_destroy(sway_layer->layer_surface);
288} 283}
289 284
@@ -292,10 +287,7 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) {
292 wl_container_of(listener, layer, surface_commit); 287 wl_container_of(listener, layer, surface_commit);
293 struct wlr_layer_surface_v1 *layer_surface = layer->layer_surface; 288 struct wlr_layer_surface_v1 *layer_surface = layer->layer_surface;
294 struct wlr_output *wlr_output = layer_surface->output; 289 struct wlr_output *wlr_output = layer_surface->output;
295 if (wlr_output == NULL) { 290 sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
296 return;
297 }
298
299 struct sway_output *output = wlr_output->data; 291 struct sway_output *output = wlr_output->data;
300 struct wlr_box old_extent = layer->extent; 292 struct wlr_box old_extent = layer->extent;
301 293
@@ -342,13 +334,8 @@ static void unmap(struct sway_layer_surface *sway_layer) {
342 cursor_rebase_all(); 334 cursor_rebase_all();
343 335
344 struct wlr_output *wlr_output = sway_layer->layer_surface->output; 336 struct wlr_output *wlr_output = sway_layer->layer_surface->output;
345 if (wlr_output == NULL) { 337 sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
346 return;
347 }
348 struct sway_output *output = wlr_output->data; 338 struct sway_output *output = wlr_output->data;
349 if (output == NULL) {
350 return;
351 }
352 output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y, 339 output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y,
353 sway_layer->layer_surface->surface, true); 340 sway_layer->layer_surface->surface, true);
354} 341}
@@ -376,22 +363,24 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
376 wl_list_remove(&sway_layer->surface_commit.link); 363 wl_list_remove(&sway_layer->surface_commit.link);
377 wl_list_remove(&sway_layer->new_popup.link); 364 wl_list_remove(&sway_layer->new_popup.link);
378 wl_list_remove(&sway_layer->new_subsurface.link); 365 wl_list_remove(&sway_layer->new_subsurface.link);
379 if (sway_layer->layer_surface->output != NULL) { 366
380 struct sway_output *output = sway_layer->layer_surface->output->data; 367 struct wlr_output *wlr_output = sway_layer->layer_surface->output;
381 if (output != NULL) { 368 sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
382 arrange_layers(output); 369 struct sway_output *output = wlr_output->data;
383 transaction_commit_dirty(); 370 arrange_layers(output);
384 } 371 transaction_commit_dirty();
385 wl_list_remove(&sway_layer->output_destroy.link); 372 wl_list_remove(&sway_layer->output_destroy.link);
386 sway_layer->layer_surface->output = NULL; 373 sway_layer->layer_surface->output = NULL;
387 } 374
388 free(sway_layer); 375 free(sway_layer);
389} 376}
390 377
391static void handle_map(struct wl_listener *listener, void *data) { 378static void handle_map(struct wl_listener *listener, void *data) {
392 struct sway_layer_surface *sway_layer = wl_container_of(listener, 379 struct sway_layer_surface *sway_layer = wl_container_of(listener,
393 sway_layer, map); 380 sway_layer, map);
394 struct sway_output *output = sway_layer->layer_surface->output->data; 381 struct wlr_output *wlr_output = sway_layer->layer_surface->output;
382 sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
383 struct sway_output *output = wlr_output->data;
395 output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y, 384 output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y,
396 sway_layer->layer_surface->surface, true); 385 sway_layer->layer_surface->surface, true);
397 wlr_surface_send_enter(sway_layer->layer_surface->surface, 386 wlr_surface_send_enter(sway_layer->layer_surface->surface,
@@ -409,9 +398,7 @@ static void subsurface_damage(struct sway_layer_subsurface *subsurface,
409 bool whole) { 398 bool whole) {
410 struct sway_layer_surface *layer = subsurface->layer_surface; 399 struct sway_layer_surface *layer = subsurface->layer_surface;
411 struct wlr_output *wlr_output = layer->layer_surface->output; 400 struct wlr_output *wlr_output = layer->layer_surface->output;
412 if (!wlr_output) { 401 sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
413 return;
414 }
415 struct sway_output *output = wlr_output->data; 402 struct sway_output *output = wlr_output->data;
416 int ox = subsurface->wlr_subsurface->current.x + layer->geo.x; 403 int ox = subsurface->wlr_subsurface->current.x + layer->geo.x;
417 int oy = subsurface->wlr_subsurface->current.y + layer->geo.y; 404 int oy = subsurface->wlr_subsurface->current.y + layer->geo.y;
@@ -514,6 +501,7 @@ static void popup_damage(struct sway_layer_popup *layer_popup, bool whole) {
514 } 501 }
515 } 502 }
516 struct wlr_output *wlr_output = layer->layer_surface->output; 503 struct wlr_output *wlr_output = layer->layer_surface->output;
504 sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
517 struct sway_output *output = wlr_output->data; 505 struct sway_output *output = wlr_output->data;
518 output_damage_surface(output, ox, oy, surface, whole); 506 output_damage_surface(output, ox, oy, surface, whole);
519} 507}
@@ -522,6 +510,7 @@ static void popup_handle_map(struct wl_listener *listener, void *data) {
522 struct sway_layer_popup *popup = wl_container_of(listener, popup, map); 510 struct sway_layer_popup *popup = wl_container_of(listener, popup, map);
523 struct sway_layer_surface *layer = popup_get_layer(popup); 511 struct sway_layer_surface *layer = popup_get_layer(popup);
524 struct wlr_output *wlr_output = layer->layer_surface->output; 512 struct wlr_output *wlr_output = layer->layer_surface->output;
513 sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
525 wlr_surface_send_enter(popup->wlr_popup->base->surface, wlr_output); 514 wlr_surface_send_enter(popup->wlr_popup->base->surface, wlr_output);
526 popup_damage(popup, true); 515 popup_damage(popup, true);
527} 516}
@@ -551,7 +540,9 @@ static void popup_unconstrain(struct sway_layer_popup *popup) {
551 struct sway_layer_surface *layer = popup_get_layer(popup); 540 struct sway_layer_surface *layer = popup_get_layer(popup);
552 struct wlr_xdg_popup *wlr_popup = popup->wlr_popup; 541 struct wlr_xdg_popup *wlr_popup = popup->wlr_popup;
553 542
554 struct sway_output *output = layer->layer_surface->output->data; 543 struct wlr_output *wlr_output = layer->layer_surface->output;
544 sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
545 struct sway_output *output = wlr_output->data;
555 546
556 // the output box expressed in the coordinate system of the toplevel parent 547 // the output box expressed in the coordinate system of the toplevel parent
557 // of the popup 548 // of the popup
@@ -643,6 +634,10 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
643 sway_log(SWAY_ERROR, 634 sway_log(SWAY_ERROR,
644 "no output to auto-assign layer surface '%s' to", 635 "no output to auto-assign layer surface '%s' to",
645 layer_surface->namespace); 636 layer_surface->namespace);
637 // Note that layer_surface->output can be NULL
638 // here, but none of our destroy callbacks are
639 // registered yet so we don't have to make them
640 // handle that case.
646 wlr_layer_surface_v1_destroy(layer_surface); 641 wlr_layer_surface_v1_destroy(layer_surface);
647 return; 642 return;
648 } 643 }