[gtk+] wayland: Add global object depedency tracking



commit 4e9be39518edbd1cbaa5959598d43d8415a32195
Author: Jonas Ådahl <jadahl gmail com>
Date:   Mon May 18 14:55:08 2015 +0800

    wayland: Add global object depedency tracking
    
    Some features need certain globals to initialize. In order to deal with
    these dependencies, add a way to postpone closures that depend on a
    certain set of globals, that later will be invoked when required
    globals are all received.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=719819

 gdk/wayland/gdkdisplay-wayland.c |  147 ++++++++++++++++++++++++++++++++++++--
 gdk/wayland/gdkdisplay-wayland.h |    7 ++
 2 files changed, 149 insertions(+), 5 deletions(-)
---
diff --git a/gdk/wayland/gdkdisplay-wayland.c b/gdk/wayland/gdkdisplay-wayland.c
index 8e23afe..9918c6d 100644
--- a/gdk/wayland/gdkdisplay-wayland.c
+++ b/gdk/wayland/gdkdisplay-wayland.c
@@ -171,6 +171,110 @@ static const struct xdg_shell_listener xdg_shell_listener = {
   xdg_shell_ping,
 };
 
+static gboolean
+is_known_global (gpointer key, gpointer value, gpointer user_data)
+{
+  const char *required_global = user_data;
+  const char *known_global = value;
+
+  return g_strcmp0 (required_global, known_global) == 0;
+}
+
+static gboolean
+has_required_globals (GdkWaylandDisplay *display_wayland,
+                      const char *required_globals[])
+{
+  int i = 0;
+
+  while (required_globals[i])
+    {
+      if (g_hash_table_find (display_wayland->known_globals,
+                             is_known_global,
+                             (gpointer)required_globals[i]) == NULL)
+        return FALSE;
+
+      i++;
+    }
+
+  return TRUE;
+}
+
+typedef struct _OnHasGlobalsClosure OnHasGlobalsClosure;
+
+typedef void (*HasGlobalsCallback) (GdkWaylandDisplay *display_wayland,
+                                    OnHasGlobalsClosure *closure);
+
+struct _OnHasGlobalsClosure
+{
+  HasGlobalsCallback handler;
+  const char **required_globals;
+};
+
+static void
+process_on_globals_closures (GdkWaylandDisplay *display_wayland)
+{
+  GList *iter;
+
+  iter = display_wayland->on_has_globals_closures;
+  while (iter != NULL)
+    {
+      GList *next = iter->next;
+      OnHasGlobalsClosure *closure = iter->data;
+
+      if (has_required_globals (display_wayland,
+                                closure->required_globals))
+        {
+          closure->handler (display_wayland, closure);
+          g_free (closure);
+          display_wayland->on_has_globals_closures =
+            g_list_delete_link (display_wayland->on_has_globals_closures, iter);
+        }
+
+      iter = next;
+    }
+}
+
+typedef struct
+{
+  OnHasGlobalsClosure base;
+  uint32_t id;
+  uint32_t version;
+} SeatAddedClosure;
+
+static void
+_gdk_wayland_display_add_seat (GdkWaylandDisplay *display_wayland,
+                               uint32_t id,
+                               uint32_t version)
+{
+  GdkDisplay *gdk_display = GDK_DISPLAY_OBJECT (display_wayland);
+  struct wl_seat *seat;
+
+  seat = wl_registry_bind (display_wayland->wl_registry,
+                           id, &wl_seat_interface, MIN (version, 4));
+  _gdk_wayland_device_manager_add_seat (gdk_display->device_manager,
+                                        id, seat);
+  _gdk_wayland_display_async_roundtrip (display_wayland);
+}
+
+static void
+seat_added_closure_run (GdkWaylandDisplay *display_wayland,
+                        OnHasGlobalsClosure *closure)
+{
+  SeatAddedClosure *seat_added_closure = (SeatAddedClosure*)closure;
+
+  _gdk_wayland_display_add_seat (display_wayland,
+                                 seat_added_closure->id,
+                                 seat_added_closure->version);
+}
+
+static void
+postpone_on_globals_closure (GdkWaylandDisplay *display_wayland,
+                             OnHasGlobalsClosure *closure)
+{
+  display_wayland->on_has_globals_closures =
+    g_list_append (display_wayland->on_has_globals_closures, closure);
+}
+
 static void
 gdk_registry_handle_global (void               *data,
                             struct wl_registry *registry,
@@ -179,9 +283,8 @@ gdk_registry_handle_global (void               *data,
                             uint32_t            version)
 {
   GdkWaylandDisplay *display_wayland = data;
-  GdkDisplay *gdk_display = GDK_DISPLAY_OBJECT (data);
-  struct wl_seat *seat;
   struct wl_output *output;
+  gboolean handled = TRUE;
 
   GDK_NOTE (MISC,
             g_message ("add global %u, interface %s, version %u", id, interface, version));
@@ -226,9 +329,26 @@ gdk_registry_handle_global (void               *data,
     }
   else if (strcmp (interface, "wl_seat") == 0)
     {
-      seat = wl_registry_bind (display_wayland->wl_registry, id, &wl_seat_interface, MIN (version, 4));
-      _gdk_wayland_device_manager_add_seat (gdk_display->device_manager, id, seat);
-      _gdk_wayland_display_async_roundtrip (display_wayland);
+      static const char *required_device_manager_globals[] = {
+        "wl_compositor",
+        "wl_data_device_manager",
+        NULL
+      };
+
+      if (has_required_globals (display_wayland,
+                                required_device_manager_globals))
+        _gdk_wayland_display_add_seat (display_wayland, id, version);
+      else
+        {
+          SeatAddedClosure *closure;
+
+          closure = g_new0 (SeatAddedClosure, 1);
+          closure->base.handler = seat_added_closure_run;
+          closure->base.required_globals = required_device_manager_globals;
+          closure->id = id;
+          closure->version = version;
+          postpone_on_globals_closure (display_wayland, &closure->base);
+        }
     }
   else if (strcmp (interface, "wl_data_device_manager") == 0)
     {
@@ -240,6 +360,14 @@ gdk_registry_handle_global (void               *data,
       display_wayland->subcompositor =
         wl_registry_bind (display_wayland->wl_registry, id, &wl_subcompositor_interface, 1);
     }
+  else
+    handled = FALSE;
+
+  if (handled)
+    g_hash_table_insert (display_wayland->known_globals,
+                         GUINT_TO_POINTER (id), g_strdup (interface));
+
+  process_on_globals_closures (display_wayland);
 }
 
 static void
@@ -254,6 +382,8 @@ gdk_registry_handle_global_remove (void               *data,
   _gdk_wayland_device_manager_remove_seat (display->device_manager, id);
   _gdk_wayland_screen_remove_output (display_wayland->screen, id);
 
+  g_hash_table_remove (display_wayland->known_globals, GUINT_TO_POINTER (id));
+
   /* FIXME: the object needs to be destroyed here, we're leaking */
 }
 
@@ -297,6 +427,10 @@ _gdk_wayland_display_open (const gchar *display_name)
   display_wayland->wl_display = wl_display;
   display_wayland->screen = _gdk_wayland_screen_new (display);
   display_wayland->event_source = _gdk_wayland_display_event_source_new (display);
+
+  display_wayland->known_globals =
+    g_hash_table_new_full (NULL, NULL, NULL, g_free);
+
   _gdk_wayland_display_init_cursors (display_wayland);
 
   display_wayland->wl_registry = wl_display_get_registry (display_wayland->wl_display);
@@ -350,6 +484,9 @@ gdk_wayland_display_dispose (GObject *object)
   g_list_foreach (display_wayland->async_roundtrips,
                   (GFunc) wl_callback_destroy, NULL);
 
+  g_hash_table_destroy (display_wayland->known_globals);
+  g_list_free_full (display_wayland->on_has_globals_closures, g_free);
+
   G_OBJECT_CLASS (gdk_wayland_display_parent_class)->dispose (object);
 }
 
diff --git a/gdk/wayland/gdkdisplay-wayland.h b/gdk/wayland/gdkdisplay-wayland.h
index 957a89a..d6e6b06 100644
--- a/gdk/wayland/gdkdisplay-wayland.h
+++ b/gdk/wayland/gdkdisplay-wayland.h
@@ -74,6 +74,13 @@ struct _GdkWaylandDisplay
 
   GList *async_roundtrips;
 
+  /* Keep track of the ID's of the known globals and their corresponding
+   * names. This way we can check whether an interface is known, and
+   * remove globals given its ID. This table is not expected to be very
+   * large, meaning the lookup by interface name time is insignificant. */
+  GHashTable *known_globals;
+  GList *on_has_globals_closures;
+
   struct wl_cursor_theme *scaled_cursor_themes[GDK_WAYLAND_THEME_SCALES_COUNT];
   gchar *cursor_theme_name;
   int cursor_theme_size;


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