When a window is being closed, the frame_done callback often runs after
the output is already destroyed, i.e:

  wayland_output_start_repaint_loop
  input_handle_button
    wayland_output_destroy
  frame_done

To fix this, destroy the output from an idle handler (same as compositor-x11),
and also stop creating new frame_done callbacks.

Signed-off-by: Dima Ryazanov <d...@gmail.com>
---
 libweston/compositor-wayland.c | 59 +++++++++++++++++++++++++++++++++++-------
 1 file changed, 50 insertions(+), 9 deletions(-)

diff --git a/libweston/compositor-wayland.c b/libweston/compositor-wayland.c
index d9cbde5..fc5daf4 100644
--- a/libweston/compositor-wayland.c
+++ b/libweston/compositor-wayland.c
@@ -128,6 +128,13 @@ struct wayland_output {
 
        struct weston_mode mode;
        uint32_t scale;
+
+       bool destroy_pending;
+};
+
+struct output_destroy_data {
+       struct wayland_backend *backend;
+       struct wayland_output *output;
 };
 
 struct wayland_parent_output {
@@ -460,6 +467,9 @@ wayland_output_start_repaint_loop(struct weston_output 
*output_base)
                to_wayland_backend(output->base.compositor);
        struct wl_callback *callback;
 
+       if (output->destroy_pending)
+               return;
+
        /* If this is the initial frame, we need to attach a buffer so that
         * the compositor can map the surface and include it in its render
         * loop. If the surface doesn't end up in the render loop, the frame
@@ -485,6 +495,9 @@ wayland_output_repaint_gl(struct weston_output *output_base,
        struct weston_compositor *ec = output->base.compositor;
        struct wl_callback *callback;
 
+       if (output->destroy_pending)
+               return 0;
+
        callback = wl_surface_frame(output->parent.surface);
        wl_callback_add_listener(callback, &frame_listener, output);
 
@@ -696,6 +709,41 @@ wayland_output_destroy(struct weston_output *base)
        free(output);
 }
 
+static void
+output_destroy_cb(void *data)
+{
+       struct output_destroy_data *dd = data;
+
+       assert(dd->output->destroy_pending);
+
+       wayland_output_destroy(&dd->output->base);
+       if (wl_list_empty(&dd->backend->compositor->output_list))
+               weston_compositor_exit(dd->backend->compositor);
+
+       free(dd);
+}
+
+static void
+handle_window_closed(struct wayland_backend *backend, struct wayland_output 
*output)
+{
+       struct wl_event_loop *loop;
+       struct output_destroy_data *data;
+
+       assert(!output->destroy_pending);
+
+       data = malloc(sizeof *data);
+       if (!data)
+               return;  /* Not much we can do here. */
+
+       data->backend = backend;
+       data->output = output;
+
+       loop = wl_display_get_event_loop(backend->compositor->wl_display);
+       wl_event_loop_add_idle(loop, output_destroy_cb, data);
+
+       output->destroy_pending = true;
+}
+
 static const struct wl_shell_surface_listener shell_surface_listener;
 
 static int
@@ -1600,13 +1648,9 @@ input_handle_button(void *data, struct wl_pointer 
*pointer,
                }
 
                if (frame_status(input->output->frame) & FRAME_STATUS_CLOSE) {
-                       wayland_output_destroy(&input->output->base);
+                       handle_window_closed(input->backend, input->output);
                        input->output = NULL;
                        input->keyboard_focus = NULL;
-
-                       if 
(wl_list_empty(&input->backend->compositor->output_list))
-                               
weston_compositor_exit(input->backend->compositor);
-
                        return;
                }
 
@@ -1964,12 +2008,9 @@ input_handle_touch_up(void *data, struct wl_touch 
*wl_touch,
                frame_touch_up(output->frame, input, id);
 
                if (frame_status(output->frame) & FRAME_STATUS_CLOSE) {
-                       wayland_output_destroy(&output->base);
+                       handle_window_closed(input->backend, output);
                        input->touch_focus = NULL;
                        input->keyboard_focus = NULL;
-                       if 
(wl_list_empty(&input->backend->compositor->output_list))
-                               
weston_compositor_exit(input->backend->compositor);
-
                        return;
                }
                if (frame_status(output->frame) & FRAME_STATUS_REPAINT)
-- 
2.9.3

_______________________________________________
wayland-devel mailing list
wayland-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to