[gtk+/gtk-3-22] GdkWaylandWindow: Allow calling export() multiple time



commit dba57db1f3a9c1568d7a3c9ae479491dcfcee152
Author: Jonas Ådahl <jadahl gmail com>
Date:   Mon May 8 18:35:50 2017 +0800

    GdkWaylandWindow: Allow calling export() multiple time
    
    Allow getting the same export handle multiple times by calling
    gdk_wayland_window_export_handle() multiple times. For each time
    export() is called, a unexport() must be called to unexport.
    
    When the window is already exported, the exported callback is called
    via a idle handler. If there are multiple export() calls, they are
    invoked in order either when the handle is received by the display
    server, or when the idle callback is invoked.
    
    Calling unexport() will not affect future invokations of the exported
    callback, unless all export() calls have their unexport() call count
    matched.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=782325

 gdk/wayland/gdkwindow-wayland.c |  135 ++++++++++++++++++++++++++++++++-------
 1 files changed, 111 insertions(+), 24 deletions(-)
---
diff --git a/gdk/wayland/gdkwindow-wayland.c b/gdk/wayland/gdkwindow-wayland.c
index 7a33771..6ac9c04 100644
--- a/gdk/wayland/gdkwindow-wayland.c
+++ b/gdk/wayland/gdkwindow-wayland.c
@@ -100,6 +100,13 @@ typedef enum _PositionMethod
   POSITION_METHOD_MOVE_TO_RECT
 } PositionMethod;
 
+typedef struct _ExportedClosure
+{
+  GdkWaylandWindowExported callback;
+  gpointer user_data;
+  GDestroyNotify destroy_func;
+} ExportedClosure;
+
 struct _GdkWindowImplWayland
 {
   GdkWindowImpl parent_instance;
@@ -200,9 +207,10 @@ struct _GdkWindowImplWayland
   } pending;
 
   struct {
-    GdkWaylandWindowExported callback;
-    gpointer user_data;
-    GDestroyNotify destroy_func;
+    char *handle;
+    int export_count;
+    GList *closures;
+    guint idle_source_id;
   } exported;
 
   struct zxdg_imported_v1 *imported_transient_for;
@@ -240,6 +248,7 @@ static void calculate_moved_to_rect_result (GdkWindow    *window,
                                             gboolean     *flipped_y);
 
 static gboolean gdk_wayland_window_is_exported (GdkWindow *window);
+static void gdk_wayland_window_unexport (GdkWindow *window);
 
 GType _gdk_window_impl_wayland_get_type (void);
 
@@ -4019,6 +4028,26 @@ _gdk_wayland_window_offset_next_wl_buffer (GdkWindow *window,
 }
 
 static void
+invoke_exported_closures (GdkWindow *window)
+{
+  GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
+  GList *l;
+
+  for (l = impl->exported.closures; l; l = l->next)
+    {
+      ExportedClosure *closure = l->data;
+
+      closure->callback (window, impl->exported.handle, closure->user_data);
+
+      if (closure->destroy_func)
+        closure->destroy_func (closure->user_data);
+    }
+
+  g_list_free_full (impl->exported.closures, g_free);
+  impl->exported.closures = NULL;
+}
+
+static void
 xdg_exported_handle (void                    *data,
                      struct zxdg_exported_v1 *zxdg_exported_v1,
                      const char              *handle)
@@ -4026,9 +4055,9 @@ xdg_exported_handle (void                    *data,
   GdkWindow *window = data;
   GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
 
-  impl->exported.callback (window, handle, impl->exported.user_data);
-  g_clear_pointer (&impl->exported.user_data,
-                   impl->exported.destroy_func);
+  impl->exported.handle = g_strdup (handle);
+
+  invoke_exported_closures (window);
 }
 
 static const struct zxdg_exported_v1_listener xdg_exported_listener = {
@@ -4057,6 +4086,19 @@ gdk_wayland_window_is_exported (GdkWindow *window)
   return !!impl->display_server.xdg_exported;
 }
 
+static gboolean
+exported_idle (gpointer user_data)
+{
+  GdkWindow *window = user_data;
+  GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
+
+  invoke_exported_closures (window);
+
+  impl->exported.idle_source_id = 0;
+
+  return G_SOURCE_REMOVE;
+}
+
 /**
  * gdk_wayland_window_export_handle:
  * @window: the #GdkWindow to obtain a handle for
@@ -4068,11 +4110,16 @@ gdk_wayland_window_is_exported (GdkWindow *window)
  * to other processes. When the handle has been obtained, @callback
  * will be called.
  *
- * It is an error to call this function on a window that is already
- * exported.
+ * Up until 3.22.12 it was an error to call this function on a window that is
+ * already exported. When the handle is no longer needed,
+ * gdk_wayland_window_unexport_handle() should be called to clean up resources.
  *
- * When the handle is no longer needed, gdk_wayland_window_unexport_handle()
- * should be called to clean up resources.
+ * Starting with 3.22.13, calling this function on an already exported window
+ * will cause the callback to be invoked with the same handle as was already
+ * invoked, from an idle callback. To unexport the window,
+ * gdk_wayland_window_unexport_handle() must be called the same number of times
+ * as gdk_wayland_window_export_handle() was called. Any 'exported' callback
+ * may still be invoked until the window is unexported or destroyed.
  *
  * The main purpose for obtaining a handle is to mark a surface
  * from another window as transient for this one, see
@@ -4095,7 +4142,7 @@ gdk_wayland_window_export_handle (GdkWindow                *window,
   GdkWindowImplWayland *impl;
   GdkWaylandDisplay *display_wayland;
   GdkDisplay *display = gdk_window_get_display (window);
-  struct zxdg_exported_v1 *xdg_exported;
+  ExportedClosure *closure;
 
   g_return_val_if_fail (GDK_IS_WAYLAND_WINDOW (window), FALSE);
   g_return_val_if_fail (GDK_IS_WAYLAND_DISPLAY (display), FALSE);
@@ -4103,26 +4150,67 @@ gdk_wayland_window_export_handle (GdkWindow                *window,
   impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
   display_wayland = GDK_WAYLAND_DISPLAY (display);
 
-  g_return_val_if_fail (!impl->display_server.xdg_exported, FALSE);
-
   if (!display_wayland->xdg_exporter)
     {
       g_warning ("Server is missing xdg_foreign support");
       return FALSE;
     }
 
-  xdg_exported = zxdg_exporter_v1_export (display_wayland->xdg_exporter,
-                                          impl->display_server.wl_surface);
-  zxdg_exported_v1_add_listener (xdg_exported,  &xdg_exported_listener, window);
+  if (!impl->display_server.xdg_exported)
+    {
+      struct zxdg_exported_v1 *xdg_exported;
 
-  impl->display_server.xdg_exported = xdg_exported;
-  impl->exported.callback = callback;
-  impl->exported.user_data = user_data;
-  impl->exported.destroy_func = destroy_func;
+      xdg_exported = zxdg_exporter_v1_export (display_wayland->xdg_exporter,
+                                              impl->display_server.wl_surface);
+      zxdg_exported_v1_add_listener (xdg_exported,
+                                     &xdg_exported_listener,
+                                     window);
+
+      impl->display_server.xdg_exported = xdg_exported;
+    }
+
+  closure = g_new0 (ExportedClosure, 1);
+  closure->callback = callback;
+  closure->user_data = user_data;
+  closure->destroy_func = destroy_func;
+
+  impl->exported.closures = g_list_append (impl->exported.closures, closure);
+  impl->exported.export_count++;
+
+  if (impl->exported.handle && !impl->exported.idle_source_id)
+    impl->exported.idle_source_id = g_idle_add (exported_idle, window);
 
   return TRUE;
 }
 
+static void
+gdk_wayland_window_unexport (GdkWindow *window)
+{
+  GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
+  GList *l;
+
+  g_clear_pointer (&impl->display_server.xdg_exported,
+                   zxdg_exported_v1_destroy);
+
+  for (l = impl->exported.closures; l; l = l->next)
+    {
+      ExportedClosure *closure = l->data;
+
+      if (closure->destroy_func)
+        closure->destroy_func (closure->user_data);
+    }
+
+  g_list_free_full (impl->exported.closures, g_free);
+  impl->exported.closures = NULL;
+  g_clear_pointer (&impl->exported.handle, g_free);
+
+  if (impl->exported.idle_source_id)
+    {
+      g_source_remove (impl->exported.idle_source_id);
+      impl->exported.idle_source_id = 0;
+    }
+}
+
 /**
  * gdk_wayland_window_unexport_handle:
  * @window: the #GdkWindow to unexport
@@ -4149,10 +4237,9 @@ gdk_wayland_window_unexport_handle (GdkWindow *window)
 
   g_return_if_fail (impl->display_server.xdg_exported);
 
-  g_clear_pointer (&impl->display_server.xdg_exported,
-                   zxdg_exported_v1_destroy);
-  g_clear_pointer (&impl->exported.user_data,
-                   impl->exported.destroy_func);
+  impl->exported.export_count--;
+  if (impl->exported.export_count == 0)
+    gdk_wayland_window_unexport (window);
 }
 
 static void


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