commit ab2e1f5817a8024366fcb02285c978c5fef7dae1
parent 53126cdceb6dbf6ee163ca0db960cf3900870075
Author: Ferdinand Bachmann <ferdinand.bachmann@yrlf.at>
Date: Tue, 18 Feb 2025 23:14:06 +0100
tree/container: remove event listeners on destroy
Change begin_destroy to remove event listeners before the final destroy,
since otherwise event listeners would be removed twice, which crashes.
This fixes a crash in wlroots listener checks. See #8509.
Diffstat:
2 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h
@@ -95,6 +95,7 @@ struct sway_container {
struct wl_listener output_enter;
struct wl_listener output_leave;
+ struct wl_listener output_handler_destroy;
struct sway_container_state current;
struct sway_container_state pending;
diff --git a/sway/tree/container.c b/sway/tree/container.c
@@ -50,6 +50,14 @@ static void handle_output_leave(
}
}
+static void handle_destroy(
+ struct wl_listener *listener, void *data) {
+ struct sway_container *con = wl_container_of(
+ listener, con, output_handler_destroy);
+
+ container_begin_destroy(con);
+}
+
static bool handle_point_accepts_input(
struct wlr_scene_buffer *buffer, double *x, double *y) {
return false;
@@ -135,6 +143,9 @@ struct sway_container *container_create(struct sway_view *view) {
c->output_leave.notify = handle_output_leave;
wl_signal_add(&c->output_handler->events.output_leave,
&c->output_leave);
+ c->output_handler_destroy.notify = handle_destroy;
+ wl_signal_add(&c->output_handler->node.events.destroy,
+ &c->output_handler_destroy);
c->output_handler->point_accepts_input = handle_point_accepts_input;
}
}
@@ -508,8 +519,6 @@ void container_destroy(struct sway_container *con) {
if (con->view && con->view->container == con) {
con->view->container = NULL;
- wl_list_remove(&con->output_enter.link);
- wl_list_remove(&con->output_leave.link);
wlr_scene_node_destroy(&con->output_handler->node);
if (con->view->destroying) {
view_destroy(con->view);
@@ -552,6 +561,12 @@ void container_begin_destroy(struct sway_container *con) {
if (con->pending.parent || con->pending.workspace) {
container_detach(con);
}
+
+ if (con->view && con->view->container == con) {
+ wl_list_remove(&con->output_enter.link);
+ wl_list_remove(&con->output_leave.link);
+ wl_list_remove(&con->output_handler_destroy.link);
+ }
}
void container_reap_empty(struct sway_container *con) {