diff options
author | 2022-02-06 12:21:27 -0800 | |
---|---|---|
committer | 2022-04-13 10:05:24 +0200 | |
commit | d726e50643d6e54bdb5882008e13bf5d20a1c3ba (patch) | |
tree | 459f4f106efd258093af96dbe53cfd00276fbf44 | |
parent | Shuffle variables to satisfy -Werror=restrict (diff) | |
download | sway-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.c | 53 |
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 | ||
391 | static void handle_map(struct wl_listener *listener, void *data) { | 378 | static 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 | } |