Add gdk_toplevel_export_handle
authorMatthias Clasen <mclasen@redhat.com>
Sun, 6 Nov 2022 16:17:02 +0000 (17:17 +0100)
committerMatthias Clasen <mclasen@redhat.com>
Wed, 9 Nov 2022 15:28:29 +0000 (16:28 +0100)
This code is backend-specific, and should not live
in gtkwindow.c.

gdk/gdktoplevel.c
gdk/gdktoplevelprivate.h
gdk/wayland/gdksurface-wayland.c
gdk/x11/gdksurface-x11.c

index 340dba3cf7c5e08c5f788736bd1db41dca8b1509..a7e4e42fcf8664c62708827bf56abe70a8194fb0 100644 (file)
@@ -113,6 +113,32 @@ gdk_toplevel_notify_compute_size (GdkToplevel     *toplevel,
   gdk_toplevel_size_validate (size);
 }
 
+static void
+gdk_toplevel_default_export_handle (GdkToplevel          *toplevel,
+                                    GCancellable         *cancellable,
+                                    GAsyncReadyCallback   callback,
+                                    gpointer              user_data)
+{
+  GTask *task;
+
+  task = g_task_new (toplevel, cancellable, callback, user_data);
+  g_task_return_pointer (task, NULL, NULL);
+  g_object_unref (task);
+}
+
+static char *
+gdk_toplevel_default_export_handle_finish (GdkToplevel   *toplevel,
+                                           GAsyncResult  *result,
+                                           GError       **error)
+{
+  return g_task_propagate_pointer (G_TASK (result), error);
+}
+
+static void
+gdk_toplevel_default_unexport_handle (GdkToplevel *toplevel)
+{
+}
+
 static void
 gdk_toplevel_default_init (GdkToplevelInterface *iface)
 {
@@ -125,6 +151,9 @@ gdk_toplevel_default_init (GdkToplevelInterface *iface)
   iface->inhibit_system_shortcuts = gdk_toplevel_default_inhibit_system_shortcuts;
   iface->restore_system_shortcuts = gdk_toplevel_default_restore_system_shortcuts;
   iface->titlebar_gesture = gdk_toplevel_default_titlebar_gesture;
+  iface->export_handle = gdk_toplevel_default_export_handle;
+  iface->export_handle_finish = gdk_toplevel_default_export_handle_finish;
+  iface->unexport_handle = gdk_toplevel_default_unexport_handle;
 
   /**
    * GdkToplevel:state: (attributes org.gtk.Property.get=gdk_toplevel_get_state)
@@ -724,3 +753,72 @@ gdk_toplevel_titlebar_gesture (GdkToplevel        *toplevel,
   return GDK_TOPLEVEL_GET_IFACE (toplevel)->titlebar_gesture (toplevel,
                                                               gesture);
 }
+
+/*< private >
+ * gdk_toplevel_export_handle:
+ * @toplevel: a `GdkToplevel`
+ * @cancellable: (nullable): a `GCancellable`
+ * @callback: ithe callback to call when the handle has been exported
+ * @user_data: (closure callback): data to pass to @callback
+ *
+ * This function asynchronously obtains a handle for a toplevel surface
+ * that can be passed to other processes.
+ *
+ * When a handle has been obtained, @callback will be called, and can
+ * receive the handle via [method@Gdk.Toplevel.export_handle_finish].
+ *
+ * It is an error to call this function on a surface that is already
+ * exported.
+ *
+ * When the handle is no longer needed, [method@Gdk.Toplevel.unexport_handle]
+ * should be called to clean up resources.
+ *
+ * Since: 4.10
+ */
+void
+gdk_toplevel_export_handle (GdkToplevel         *toplevel,
+                            GCancellable        *cancellable,
+                            GAsyncReadyCallback  callback,
+                            gpointer             user_data)
+{
+  GDK_TOPLEVEL_GET_IFACE (toplevel)->export_handle (toplevel, cancellable, callback, user_data);
+}
+
+/*< private >
+ * gdk_toplevel_export_handle_finish:
+ * @toplevel: a `GdkToplevel`
+ * @result: the `GAsyncResult`
+ * @error: return location for an error
+ *
+ * Finishes the [method@Gdk.Toplevel.export_handle] cal and
+ * returns the resulting handle.
+ *
+ * Returns: (nullable) (transfer full): the exported handle,
+ *   or `NULL` and @error is set
+ *
+ * Since: 4.10
+ */
+char *
+gdk_toplevel_export_handle_finish (GdkToplevel   *toplevel,
+                                   GAsyncResult  *result,
+                                   GError       **error)
+{
+  return GDK_TOPLEVEL_GET_IFACE (toplevel)->export_handle_finish (toplevel, result, error);
+}
+
+/*< private >
+ * gdk_toplevel_unexport_handle:
+ * @toplevel: a `GdkToplevel`
+ *
+ * Destroys the handle that was obtained with [method@Gdk.Toplevel.export_handle].
+ *
+ * It is an error to call this function on a surface that
+ * does not have a handle.
+ *
+ * Since: 4.10
+ */
+void
+gdk_toplevel_unexport_handle (GdkToplevel *toplevel)
+{
+  GDK_TOPLEVEL_GET_IFACE (toplevel)->unexport_handle (toplevel);
+}
index 2d1f0122f36fb98d1cf8b9ef8b8d7bf25ebb0df0..f202b1797fa6562feba4c1392a67dc2b9053c5e7 100644 (file)
@@ -40,6 +40,17 @@ struct _GdkToplevelInterface
                                          guint32            timestamp);
   gboolean      (* titlebar_gesture)    (GdkToplevel       *toplevel,
                                          GdkTitlebarGesture gesture);
+
+  void          (* export_handle)          (GdkToplevel          *toplevel,
+                                            GCancellable         *cancellable,
+                                            GAsyncReadyCallback   callback,
+                                            gpointer              user_data);
+
+  char *        (* export_handle_finish)   (GdkToplevel          *toplevel,
+                                            GAsyncResult         *result,
+                                            GError              **error);
+
+  void          (* unexport_handle)        (GdkToplevel          *toplevel);
 };
 
 typedef enum
@@ -63,6 +74,17 @@ guint gdk_toplevel_install_properties (GObjectClass *object_class,
 void gdk_toplevel_notify_compute_size (GdkToplevel     *toplevel,
                                        GdkToplevelSize *size);
 
+void  gdk_toplevel_export_handle        (GdkToplevel          *toplevel,
+                                         GCancellable         *cancellable,
+                                         GAsyncReadyCallback   callback,
+                                         gpointer              user_data);
+
+char *gdk_toplevel_export_handle_finish (GdkToplevel          *toplevel,
+                                         GAsyncResult         *result,
+                                         GError              **error);
+
+void  gdk_toplevel_unexport_handle      (GdkToplevel          *toplevel);
+
 G_END_DECLS
 
 #endif /* __GDK_TOPLEVEL_PRIVATE_H__ */
index 26eacf7c0c1ede03870c637fa942592c54bd4149..dbb63c84bb6683967801149bf01cd1e6a61f7561 100644 (file)
@@ -5235,6 +5235,72 @@ gdk_wayland_toplevel_restore_system_shortcuts (GdkToplevel *toplevel)
   g_object_notify (G_OBJECT (toplevel), "shortcuts-inhibited");
 }
 
+static void
+xdg_exported_handle2 (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);
+}
+
+static const struct zxdg_exported_v1_listener xdg_exported_listener2 = {
+  xdg_exported_handle2
+};
+
+static void
+gdk_wayland_toplevel_real_export_handle (GdkToplevel          *toplevel,
+                                         GCancellable         *cancellable,
+                                         GAsyncReadyCallback   callback,
+                                         gpointer              user_data)
+{
+  GdkWaylandToplevel *wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
+  GdkSurface *surface = GDK_SURFACE (toplevel);
+  GdkDisplay *display = gdk_surface_get_display (GDK_SURFACE (toplevel));
+  GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
+  struct zxdg_exported_v1 *xdg_exported;
+  GTask *task;
+
+  task = g_task_new (toplevel, cancellable, callback, user_data);
+
+  if (!display_wayland->xdg_exporter)
+    {
+      g_task_return_pointer (task, NULL, NULL);
+      g_object_unref (task);
+      return;
+    }
+
+  xdg_exported =
+    zxdg_exporter_v1_export (display_wayland->xdg_exporter,
+                             gdk_wayland_surface_get_wl_surface (surface));
+
+  zxdg_exported_v1_add_listener (xdg_exported, &xdg_exported_listener2, task);
+  wayland_toplevel->xdg_exported = xdg_exported;
+}
+
+static char *
+gdk_wayland_toplevel_real_export_handle_finish (GdkToplevel   *toplevel,
+                                                GAsyncResult  *result,
+                                                GError       **error)
+{
+  return g_task_propagate_pointer (G_TASK (result), error);
+}
+
+static void
+gdk_wayland_toplevel_real_unexport_handle (GdkToplevel *toplevel)
+{
+  GdkWaylandToplevel *wayland_toplevel;
+
+  g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel));
+
+  wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
+
+  g_return_if_fail (wayland_toplevel->xdg_exported);
+
+  g_clear_pointer (&wayland_toplevel->xdg_exported,
+                   zxdg_exported_v1_destroy);
+}
+
 static void
 gdk_wayland_toplevel_iface_init (GdkToplevelInterface *iface)
 {
@@ -5249,6 +5315,9 @@ gdk_wayland_toplevel_iface_init (GdkToplevelInterface *iface)
   iface->restore_system_shortcuts = gdk_wayland_toplevel_restore_system_shortcuts;
   iface->begin_resize = gdk_wayland_toplevel_begin_resize;
   iface->begin_move = gdk_wayland_toplevel_begin_move;
+  iface->export_handle = gdk_wayland_toplevel_real_export_handle;
+  iface->export_handle_finish = gdk_wayland_toplevel_real_export_handle_finish;
+  iface->unexport_handle = gdk_wayland_toplevel_real_unexport_handle;
 }
 
 static void
index 86c84d3fd4d39e401b086d2a7859dd930e06a924..5aa1a29a5bb0758c62dcf6545610adf717bcb2d7 100644 (file)
@@ -5273,6 +5273,35 @@ gdk_x11_toplevel_event_callback (GdkSurface *surface,
   return FALSE;
 }
 
+static void
+gdk_x11_toplevel_export_handle (GdkToplevel          *toplevel,
+                                GCancellable         *cancellable,
+                                GAsyncReadyCallback   callback,
+                                gpointer              user_data)
+{
+  guint32 xid;
+  GTask *task;
+
+  xid = (guint32) gdk_x11_surface_get_xid (GDK_SURFACE (toplevel));
+
+  task = g_task_new (toplevel, cancellable, callback, user_data);
+  g_task_return_pointer (task, g_strdup_printf ("%x", xid), g_free);
+  g_object_unref (task);
+}
+
+static char *
+gdk_x11_toplevel_export_handle_finish (GdkToplevel   *toplevel,
+                                       GAsyncResult  *result,
+                                       GError       **error)
+{
+  return g_task_propagate_pointer (G_TASK (result), error);
+}
+
+static void
+gdk_x11_toplevel_unexport_handle (GdkToplevel *toplevel)
+{
+}
+
 static void
 gdk_x11_toplevel_iface_init (GdkToplevelInterface *iface)
 {
@@ -5286,6 +5315,9 @@ gdk_x11_toplevel_iface_init (GdkToplevelInterface *iface)
   iface->restore_system_shortcuts = gdk_x11_toplevel_restore_system_shortcuts;
   iface->begin_resize = gdk_x11_toplevel_begin_resize;
   iface->begin_move = gdk_x11_toplevel_begin_move;
+  iface->export_handle = gdk_x11_toplevel_export_handle;
+  iface->export_handle_finish = gdk_x11_toplevel_export_handle_finish;
+  iface->unexport_handle = gdk_x11_toplevel_unexport_handle;
 }
 
 typedef struct {