wayland: Reimplement exporting
authorMatthias Clasen <mclasen@redhat.com>
Sun, 14 May 2023 21:38:11 +0000 (17:38 -0400)
committerMatthias Clasen <mclasen@redhat.com>
Mon, 15 May 2023 03:49:44 +0000 (23:49 -0400)
Change things so that every call to export_handle
creates a new handle, and unexport_handle destroys
the handle that it is given.

gdk/wayland/gdktoplevel-wayland.c

index 459462485aabedcb7f15cda62a02572772ef2377..bd3738ff3d5b0d065a708340bfaaf97327130932 100644 (file)
@@ -54,11 +54,16 @@ static void gdk_wayland_toplevel_sync_parent             (GdkWaylandToplevel *to
 static void gdk_wayland_toplevel_sync_parent_of_imported (GdkWaylandToplevel *toplevel);
 static void gdk_wayland_surface_create_xdg_toplevel      (GdkWaylandToplevel *toplevel);
 static void gdk_wayland_toplevel_sync_title              (GdkWaylandToplevel *toplevel);
-static gboolean gdk_wayland_toplevel_is_exported         (GdkWaylandToplevel *toplevel);
 static void unset_transient_for_exported                 (GdkWaylandToplevel *toplevel);
 
 /* {{{ GdkWaylandToplevel definition */
 
+typedef struct {
+  struct zxdg_exported_v1 *xdg_exported;
+  struct zxdg_exported_v2 *xdg_exported_v2;
+  char *handle;
+} GdkWaylandExported;
+
 /**
  * GdkWaylandToplevel:
  *
@@ -83,8 +88,7 @@ struct _GdkWaylandToplevel
   GdkWaylandToplevel *transient_for;
 
   struct org_kde_kwin_server_decoration *server_decoration;
-  struct zxdg_exported_v1 *xdg_exported;
-  struct zxdg_exported_v2 *xdg_exported_v2;
+  GList *exported;
 
   struct {
     int width;
@@ -1274,9 +1278,6 @@ gdk_wayland_toplevel_finalize (GObject *object)
 
   display_wayland->toplevels = g_list_remove (display_wayland->toplevels, self);
 
-  if (gdk_wayland_toplevel_is_exported (self))
-    gdk_wayland_toplevel_unexport_handle (GDK_TOPLEVEL (self));
-
   g_free (self->application.application_id);
   g_free (self->application.app_menu_path);
   g_free (self->application.menubar_path);
@@ -1741,8 +1742,12 @@ xdg_exported_handle_v1 (void                    *data,
                         struct zxdg_exported_v1 *zxdg_exported_v1,
                         const char              *handle)
 {
-  g_task_return_pointer (G_TASK (data), g_strdup (handle), g_free);
-  g_object_unref (data);
+  GTask *task = G_TASK (data);
+  GdkWaylandExported *exported = (GdkWaylandExported *)g_task_get_task_data (task);
+
+  exported->handle = g_strdup (handle);
+  g_task_return_pointer (task, g_strdup (handle), g_free);
+  g_object_unref (task);
 }
 
 static const struct zxdg_exported_v1_listener xdg_exported_listener_v1 = {
@@ -1754,8 +1759,12 @@ xdg_exported_handle_v2 (void                    *data,
                         struct zxdg_exported_v2 *zxdg_exported_v2,
                         const char              *handle)
 {
-  g_task_return_pointer (G_TASK (data), g_strdup (handle), g_free);
-  g_object_unref (data);
+  GTask *task = G_TASK (data);
+  GdkWaylandExported *exported = (GdkWaylandExported *)g_task_get_task_data (task);
+
+  exported->handle = g_strdup (handle);
+  g_task_return_pointer (task, g_strdup (handle), g_free);
+  g_object_unref (task);
 }
 
 static const struct zxdg_exported_v2_listener xdg_exported_listener_v2 = {
@@ -1778,19 +1787,27 @@ gdk_wayland_toplevel_real_export_handle (GdkToplevel          *toplevel,
 
   if (display_wayland->xdg_exporter_v2)
     {
-      wayland_toplevel->xdg_exported_v2 =
+      GdkWaylandExported *exported = g_new0 (GdkWaylandExported, 1);
+      exported->xdg_exported_v2 =
         zxdg_exporter_v2_export_toplevel (display_wayland->xdg_exporter_v2,
                                           gdk_wayland_surface_get_wl_surface (surface));
-      zxdg_exported_v2_add_listener (wayland_toplevel->xdg_exported_v2,
+      zxdg_exported_v2_add_listener (exported->xdg_exported_v2,
                                      &xdg_exported_listener_v2, task);
+
+      wayland_toplevel->exported = g_list_prepend (wayland_toplevel->exported, exported);
+      g_task_set_task_data (task, exported, NULL);
     }
   else if (display_wayland->xdg_exporter)
     {
-      wayland_toplevel->xdg_exported =
+      GdkWaylandExported *exported = g_new0 (GdkWaylandExported, 1);
+      exported->xdg_exported =
         zxdg_exporter_v1_export (display_wayland->xdg_exporter,
                                  gdk_wayland_surface_get_wl_surface (surface));
-      zxdg_exported_v1_add_listener (wayland_toplevel->xdg_exported,
+      zxdg_exported_v1_add_listener (exported->xdg_exported,
                                      &xdg_exported_listener_v1, task);
+
+      wayland_toplevel->exported = g_list_prepend (wayland_toplevel->exported, exported);
+      g_task_set_task_data (task, exported, NULL);
     }
   else
     {
@@ -1808,6 +1825,15 @@ gdk_wayland_toplevel_real_export_handle_finish (GdkToplevel   *toplevel,
   return g_task_propagate_pointer (G_TASK (result), error);
 }
 
+static void
+destroy_exported (GdkWaylandExported *exported)
+{
+  g_clear_pointer (&exported->handle, g_free);
+  g_clear_pointer (&exported->xdg_exported_v2, zxdg_exported_v2_destroy);
+  g_clear_pointer (&exported->xdg_exported, zxdg_exported_v1_destroy);
+  g_free (exported);
+}
+
 static void
 gdk_wayland_toplevel_real_unexport_handle (GdkToplevel *toplevel,
                                            const char  *handle)
@@ -1815,10 +1841,21 @@ gdk_wayland_toplevel_real_unexport_handle (GdkToplevel *toplevel,
   GdkWaylandToplevel *wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
 
   g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel));
-  g_return_if_fail (wayland_toplevel->xdg_exported_v2 || wayland_toplevel->xdg_exported);
+  g_return_if_fail (handle != NULL);
+
+  for (GList *l = wayland_toplevel->exported; l; l = l->next)
+    {
+      GdkWaylandExported *exported = l->data;
 
-  g_clear_pointer (&wayland_toplevel->xdg_exported_v2, zxdg_exported_v2_destroy);
-  g_clear_pointer (&wayland_toplevel->xdg_exported, zxdg_exported_v1_destroy);
+      if (exported->handle && strcmp (exported->handle, handle) == 0)
+        {
+          wayland_toplevel->exported = g_list_delete_link (wayland_toplevel->exported, l);
+          destroy_exported (exported);
+          return;
+        }
+    }
+
+  g_warn_if_reached ();
 }
 
 static gboolean
@@ -2253,6 +2290,27 @@ gdk_wayland_toplevel_set_dbus_properties (GdkToplevel *toplevel,
 void
 gdk_wayland_toplevel_destroy (GdkToplevel *toplevel)
 {
+  GdkWaylandToplevel *self = GDK_WAYLAND_TOPLEVEL (toplevel);
+
+  while (self->exported)
+    {
+      GdkWaylandExported *exported = self->exported->data;
+      self->exported = g_list_delete_link (self->exported, self->exported);
+      if (exported->handle == NULL)
+        {
+          GTask *task;
+
+          if (exported->xdg_exported_v2)
+            task = G_TASK (wl_proxy_get_user_data ((struct wl_proxy *) exported->xdg_exported_v2));
+          else
+            task = G_TASK (wl_proxy_get_user_data ((struct wl_proxy *) exported->xdg_exported));
+
+          g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED, "Surface was destroyed");
+          g_object_unref (task);
+        }
+
+      destroy_exported (exported);
+    }
 }
 
 /* }}} */
@@ -2397,12 +2455,6 @@ gdk_wayland_toplevel_uninhibit_idle (GdkToplevel *toplevel)
  * marking surfaces as transient for out-of-process surfaces.
  */
 
-static gboolean
-gdk_wayland_toplevel_is_exported (GdkWaylandToplevel *toplevel)
-{
-  return toplevel->xdg_exported != NULL || toplevel->xdg_exported_v2 != NULL;
-}
-
 typedef struct {
   GdkWaylandToplevelExported callback;
   gpointer user_data;