summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonas Ådahl <jadahl@gmail.com>2015-05-18 14:55:08 +0800
committerJonas Ådahl <jadahl@gmail.com>2015-05-20 11:45:13 +0800
commit4e9be39518edbd1cbaa5959598d43d8415a32195 (patch)
tree8a794f0481b0606e5641d1ec8cd13772b5bea5bc
parent181e4399f6e2588b462eaa5689bdebd4063d8a6f (diff)
downloadgtk+-4e9be39518edbd1cbaa5959598d43d8415a32195.tar.gz
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
-rw-r--r--gdk/wayland/gdkdisplay-wayland.c147
-rw-r--r--gdk/wayland/gdkdisplay-wayland.h7
2 files changed, 149 insertions, 5 deletions
diff --git a/gdk/wayland/gdkdisplay-wayland.c b/gdk/wayland/gdkdisplay-wayland.c
index 8e23afe96b..9918c6df36 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 957a89a774..d6e6b06103 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;