xdg-shell: Require proper object tree destruction
authorJonas Ådahl <jadahl@gmail.com>
Wed, 18 Mar 2015 08:20:51 +0000 (16:20 +0800)
committerJonas Ådahl <jadahl@gmail.com>
Tue, 5 May 2015 06:17:01 +0000 (14:17 +0800)
Require all child objects to be destroyed before the parent. In other
words, all popups and surfaces created by one xdg_shell instance needs
to be destroyed before the xdg_shell object, otherwise a protocol error
is raised.

Signed-off-by: Jonas Ådahl <jadahl@gmail.com>
Reviewed-by: Bryce Harrington <bryce@osg.samsung.com>
Acked-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
desktop-shell/shell.c
protocol/xdg-shell.xml

index 5f54dea0c1b9bf65a6f6f6646412ac8a956da838..c903ad74874b040157d05087268feecf063e29f2 100644 (file)
@@ -107,6 +107,7 @@ struct shell_surface {
        struct wl_resource *resource;
        struct wl_signal destroy_signal;
        struct shell_client *owner;
+       struct wl_resource *owner_resource;
 
        struct weston_surface *surface;
        struct weston_view *view;
@@ -239,6 +240,7 @@ struct shell_client {
        struct wl_event_source *ping_timer;
        uint32_t ping_serial;
        int unresponsive;
+       struct wl_list surface_list;
 };
 
 static struct desktop_shell *
@@ -3552,6 +3554,7 @@ shell_destroy_shell_surface(struct wl_resource *resource)
 
        if (!wl_list_empty(&shsurf->popup.grab_link))
                remove_popup_grab(shsurf);
+       wl_list_remove(wl_resource_get_link(shsurf->resource));
        shsurf->resource = NULL;
 }
 
@@ -3723,6 +3726,7 @@ shell_get_shell_surface(struct wl_client *client,
        wl_resource_set_implementation(shsurf->resource,
                                       &shell_surface_implementation,
                                       shsurf, shell_destroy_shell_surface);
+       wl_list_init(wl_resource_get_link(shsurf->resource));
 }
 
 static bool
@@ -3986,6 +3990,21 @@ static void
 xdg_shell_destroy(struct wl_client *client,
                  struct wl_resource *resource)
 {
+       struct shell_client *sc = wl_resource_get_user_data(resource);
+       struct wl_resource *shsurf_resource;
+       struct shell_surface *shsurf;
+
+       wl_resource_for_each(shsurf_resource, &sc->surface_list) {
+               shsurf = wl_resource_get_user_data(shsurf_resource);
+               if (shsurf->owner_resource == resource) {
+                       wl_resource_post_error(
+                               resource,
+                               XDG_SHELL_ERROR_DEFUNCT_SURFACES,
+                               "not all child surface objects destroyed");
+                       return;
+               }
+       }
+
        wl_resource_destroy(resource);
 }
 
@@ -4054,6 +4073,9 @@ xdg_get_xdg_surface(struct wl_client *client,
        wl_resource_set_implementation(shsurf->resource,
                                       &xdg_surface_implementation,
                                       shsurf, shell_destroy_shell_surface);
+       shsurf->owner_resource = resource;
+       wl_list_insert(&sc->surface_list,
+                      wl_resource_get_link(shsurf->resource));
 }
 
 static bool
@@ -4180,6 +4202,9 @@ xdg_get_xdg_popup(struct wl_client *client,
        wl_resource_set_implementation(shsurf->resource,
                                       &xdg_popup_implementation,
                                       shsurf, shell_destroy_shell_surface);
+       shsurf->owner_resource = resource;
+       wl_list_insert(&sc->surface_list,
+                      wl_resource_get_link(shsurf->resource));
 }
 
 static void
@@ -5797,6 +5822,7 @@ shell_client_create(struct wl_client *client, struct desktop_shell *shell,
        sc->shell = shell;
        sc->destroy_listener.notify = handle_shell_client_destroy;
        wl_client_add_destroy_listener(client, &sc->destroy_listener);
+       wl_list_init(&sc->surface_list);
 
        return sc;
 }
index 68cf4699dd6f8b49152c4981a1f5a5d17b52006f..866e3300f1e2cf0f543606d4783281fa55ed4e90 100644 (file)
@@ -49,6 +49,7 @@
 
     <enum name="error">
       <entry name="role" value="0" summary="given wl_surface has another role"/>
+      <entry name="defunct_surfaces" value="1" summary="xdg_shell was destroyed before children"/>
     </enum>
 
     <request name="destroy" type="destructor">
@@ -56,9 +57,8 @@
         Destroy this xdg_shell object.
 
         Destroying a bound xdg_shell object while there are surfaces
-        still alive with roles from this interface is illegal and will
-        result in a protocol error. Make sure to destroy all surfaces
-        before destroying this object.
+        still alive created by this xdg_shell object instance is illegal
+        and will result in a protocol error.
       </description>
     </request>