[mutter/wayland] wayland: Rework how surface destruction works



commit 2a145262c7af22bf379fba69916597f5769d4c1a
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Tue Feb 18 16:39:23 2014 -0500

    wayland: Rework how surface destruction works
    
    To prevent the MetaSurfaceActor from being destroyed, we normally
    unparent it before we unmanage the window. However, this doesn't
    work for XWayland windows, which we unmanage when we get UnmapNotify
    or DestroyNotify, not when we get the wl_surface_destroy.
    
    To solve this, add an early hook in meta_window_unmanage that
    unparents the surface actor if we have one. At the same time, clean
    up the destruction code to remove old comments and assumptions about
    how wl_shell behaves.

 src/core/window.c                  |    3 ++
 src/wayland/meta-wayland-surface.c |   65 ++++++++++++++---------------------
 src/wayland/meta-wayland-surface.h |    3 ++
 3 files changed, 32 insertions(+), 39 deletions(-)
---
diff --git a/src/core/window.c b/src/core/window.c
index ccd1749..79b7cb3 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -1498,6 +1498,9 @@ meta_window_unmanage (MetaWindow  *window,
 
   meta_verbose ("Unmanaging 0x%lx\n", window->xwindow);
 
+  if (window->surface)
+    meta_wayland_surface_window_unmanaged (window->surface);
+
   if (window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
     {
       MetaStackWindow stack_window;
diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c
index 496a6bf..b8fc0e7 100644
--- a/src/wayland/meta-wayland-surface.c
+++ b/src/wayland/meta-wayland-surface.c
@@ -574,23 +574,6 @@ const struct wl_surface_interface meta_wayland_surface_interface = {
 };
 
 static void
-meta_wayland_surface_free (MetaWaylandSurface *surface)
-{
-  MetaWaylandCompositor *compositor = surface->compositor;
-
-  compositor->surfaces = g_list_remove (compositor->surfaces, surface);
-
-  surface_set_buffer (surface, NULL);
-  double_buffered_state_destroy (&surface->pending);
-  g_object_unref (surface->surface_actor);
-  if (surface->resource)
-    wl_resource_set_user_data (surface->resource, NULL);
-  g_slice_free (MetaWaylandSurface, surface);
-
-  meta_wayland_compositor_repick (compositor);
-}
-
-static void
 unparent_actor (MetaWaylandSurface *surface)
 {
   ClutterActor *parent_actor;
@@ -599,46 +582,50 @@ unparent_actor (MetaWaylandSurface *surface)
   clutter_actor_remove_child (parent_actor, CLUTTER_ACTOR (surface->surface_actor));
 }
 
+void
+meta_wayland_surface_window_unmanaged (MetaWaylandSurface *surface)
+{
+  /* The window is being unmanaged. Unparent our surface actor
+   * before the window actor is destroyed, as we need to hold
+   * onto it... */
+  unparent_actor (surface);
+
+  surface->window = NULL;
+}
+
 static void
 destroy_window (MetaWaylandSurface *surface)
 {
   MetaDisplay *display = meta_get_display ();
   guint32 timestamp = meta_display_get_current_time_roundtrip (display);
 
-  /* Remove our actor from the parent, so it doesn't get destroyed when
-   * the MetaWindowActor is destroyed. */
-  unparent_actor (surface);
-
   g_assert (surface->window != NULL);
   meta_window_unmanage (surface->window, timestamp);
-  surface->window = NULL;
+  g_assert (surface->window == NULL);
 }
 
 static void
 wl_surface_destructor (struct wl_resource *resource)
 {
   MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
+  MetaWaylandCompositor *compositor = surface->compositor;
 
-  /* There are four cases here:
-     - An X11 unmanaged window -> surface is NULL, nothing to do
-     - An X11 unmanaged window, but we got the wayland event first ->
-       just clear the resource pointer
-     - A wayland surface without window (destroyed before set_toplevel) ->
-       need to free the surface itself
-     - A wayland window -> need to unmanage
-  */
+  /* At the time when the wl_surface is destroyed, we should
+   * no longer have a window, unless we're an XWayland window
+   * in which case we received the wl_surface.destroy before
+   * the UnmapNotify/DestroyNotify. */
+  g_assert (surface->window == NULL || surface->window->client_type == META_WINDOW_CLIENT_TYPE_X11);
 
-  if (surface)
-    {
-      surface->resource = NULL;
+  compositor->surfaces = g_list_remove (compositor->surfaces, surface);
 
-      /* NB: If the surface corresponds to an X window then we will be
-       * sure to free the MetaWindow according to some X event. */
-      if (surface->window && surface->window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
-        destroy_window (surface);
+  surface_set_buffer (surface, NULL);
+  double_buffered_state_destroy (&surface->pending);
+  g_object_unref (surface->surface_actor);
+  if (surface->resource)
+    wl_resource_set_user_data (surface->resource, NULL);
+  g_slice_free (MetaWaylandSurface, surface);
 
-      meta_wayland_surface_free (surface);
-    }
+  meta_wayland_compositor_repick (compositor);
 }
 
 MetaWaylandSurface *
diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h
index df725db..0fafb8c 100644
--- a/src/wayland/meta-wayland-surface.h
+++ b/src/wayland/meta-wayland-surface.h
@@ -118,6 +118,9 @@ MetaWaylandSurface *meta_wayland_surface_create (MetaWaylandCompositor *composit
                                                 struct wl_client      *client,
                                                 guint32                id,
                                                 guint32                version);
+
+void                meta_wayland_surface_window_unmanaged (MetaWaylandSurface *surface);
+
 void                meta_wayland_surface_configure_notify (MetaWaylandSurface *surface,
                                                           int                 width,
                                                           int                 height);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]