desktop-shell: Unset the shell surface owner when it goes away
authorJonas Ådahl <jadahl@gmail.com>
Fri, 26 Feb 2016 06:02:06 +0000 (14:02 +0800)
committerJonas Ådahl <jadahl@gmail.com>
Fri, 22 Apr 2016 02:31:21 +0000 (10:31 +0800)
On client destruction, the shell object may be destroyed before the
shell surface objects. If this happens to two surfaces of the same
client, and one surface being destroyed results in the focus being
switched to the other, this would trigger a ping event.

The ping event sending function relies on having a valid owner, and if
the shell would be destoryed prior to the shell surface, we'd crash in
this function.

Solve this by unsetting the owner pointer when the shell client goes
away and early out in the ping event sending function if the owner is
gone.

Signed-off-by: Jonas Ådahl <jadahl@gmail.com>
Reviewed-by: Mike Blumenkrantz <zmike@osg.samsung.com>
desktop-shell/shell.c

index 24437d8de84e164585c8f61cfeb465773e0b6a01..f705c99413ace4ed7014660ae3fa6fb1d5517118 100644 (file)
@@ -2149,6 +2149,8 @@ ping_handler(struct weston_surface *surface, uint32_t serial)
                return;
        if (shsurf->surface == shsurf->shell->grab_surface)
                return;
+       if (!shsurf->owner)
+               return;
 
        handle_xdg_ping(shsurf, serial);
 }
@@ -3778,7 +3780,8 @@ 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));
+       wl_list_insert(&sc->surface_list,
+                      wl_resource_get_link(shsurf->resource));
 }
 
 static bool
@@ -5864,6 +5867,8 @@ handle_shell_client_destroy(struct wl_listener *listener, void *data)
 {
        struct shell_client *sc =
                container_of(listener, struct shell_client, destroy_listener);
+       struct wl_resource *shsurf_resource;
+       struct shell_surface *shsurf;
 
        if (sc->ping_timer)
                wl_event_source_remove(sc->ping_timer);
@@ -5872,6 +5877,10 @@ handle_shell_client_destroy(struct wl_listener *listener, void *data)
         * head of the surface list so we don't use that freed list node
         * during surface clean up later on.
         */
+       wl_resource_for_each(shsurf_resource, &sc->surface_list) {
+               shsurf = wl_resource_get_user_data(shsurf_resource);
+               shsurf->owner = NULL;
+       }
        wl_list_remove(&sc->surface_list);
 
        free(sc);