diff --git a/src/screencast.c b/src/screencast.c index 6b0014a..15f6a80 100644 --- a/src/screencast.c +++ b/src/screencast.c @@ -427,16 +427,20 @@ find_best_window_by_app_id_and_title (const char *app_id, const char *title) { ShellIntrospect *shell_introspect = shell_introspect_get (); + GPtrArray *windows; Window *best_match; glong best_match_distance; - GList *l; best_match = NULL; best_match_distance = G_MAXLONG; - for (l = shell_introspect_get_windows (shell_introspect); l; l = l->next) + shell_introspect_ref_listeners (shell_introspect); + shell_introspect_wait_for_windows (shell_introspect); + + windows = shell_introspect_get_windows (shell_introspect); + for (size_t i = 0; windows && i < windows->len; i++) { - Window *window = l->data; + Window *window = g_ptr_array_index (windows, i); glong distance; if (g_strcmp0 (window_get_app_id (window), app_id) != 0) @@ -454,6 +458,8 @@ find_best_window_by_app_id_and_title (const char *app_id, } } + shell_introspect_unref_listeners (shell_introspect); + /* If even the best match's window title is too different, don't * restore it. */ diff --git a/src/screencastwidget.c b/src/screencastwidget.c index 9b30f2d..e95fee2 100644 --- a/src/screencastwidget.c +++ b/src/screencastwidget.c @@ -164,8 +164,7 @@ update_windows_list (ScreenCastWidget *widget) GtkListBox *window_list = GTK_LIST_BOX (widget->window_list); GtkWidget *toplevel; GtkWidget *child; - GList *windows; - GList *l; + GPtrArray *windows; child = gtk_widget_get_first_child (GTK_WIDGET (window_list)); while (child) @@ -181,9 +180,9 @@ update_windows_list (ScreenCastWidget *widget) return; windows = shell_introspect_get_windows (widget->shell_introspect); - for (l = windows; l; l = l->next) + for (size_t i = 0; windows && i < windows->len; i++) { - Window *window = l->data; + Window *window = g_ptr_array_index (windows, i); GtkWidget *window_widget; if (should_skip_window (window, GTK_WINDOW (toplevel))) diff --git a/src/shellintrospect.c b/src/shellintrospect.c index 1fa8b93..c2b288d 100644 --- a/src/shellintrospect.c +++ b/src/shellintrospect.c @@ -22,16 +22,6 @@ #include "shell-dbus.h" #include "shellintrospect.h" -enum -{ - WINDOWS_CHANGED, - ANIMATIONS_ENABLED_CHANGED, - - N_SIGNALS -}; - -static guint signals[N_SIGNALS]; - struct _Window { uint64_t id; @@ -50,7 +40,7 @@ struct _ShellIntrospect unsigned int version; - GList *windows; + GPtrArray *windows; int num_listeners; @@ -60,6 +50,16 @@ struct _ShellIntrospect G_DEFINE_TYPE (ShellIntrospect, shell_introspect, G_TYPE_OBJECT) +enum +{ + WINDOWS_CHANGED, + ANIMATIONS_ENABLED_CHANGED, + + N_SIGNALS +}; + +static guint signals[N_SIGNALS]; + static ShellIntrospect *_shell_introspect; static void @@ -70,50 +70,36 @@ window_free (Window *window) g_free (window); } -const char * -window_get_title (Window *window) -{ - return window->title; -} - -const char * -window_get_app_id (Window *window) -{ - return window->app_id; -} - -const uint64_t -window_get_id (Window *window) -{ - return window->id; -} - static void get_windows_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { ShellIntrospect *shell_introspect = user_data; + g_autoptr(GPtrArray) windows = NULL; g_autoptr(GVariant) windows_variant = NULL; g_autoptr(GError) error = NULL; GVariantIter iter; uint64_t id; GVariant *params = NULL; - GList *windows = NULL; - g_list_free_full (shell_introspect->windows, (GDestroyNotify) window_free); - shell_introspect->windows = NULL; + g_clear_object (&shell_introspect->cancellable); if (!org_gnome_shell_introspect_call_get_windows_finish (shell_introspect->proxy, &windows_variant, res, &error)) { - g_warning ("Failed to get window list: %s", error->message); + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("Failed to get window list: %s", error->message); return; } g_variant_iter_init (&iter, windows_variant); + + windows = g_ptr_array_new_full (g_variant_iter_n_children (&iter), + (GDestroyNotify) window_free); + while (g_variant_iter_loop (&iter, "{t@a{sv}}", &id, ¶ms)) { char *app_id = NULL; @@ -131,64 +117,30 @@ get_windows_cb (GObject *source_object, .title = title, .app_id = app_id }; - windows = g_list_prepend (windows, window); + g_ptr_array_add (windows, window); g_clear_pointer (¶ms, g_variant_unref); } - shell_introspect->windows = windows; + shell_introspect->windows = g_steal_pointer (&windows); g_signal_emit (shell_introspect, signals[WINDOWS_CHANGED], 0); } static void sync_state (ShellIntrospect *shell_introspect) { + g_clear_pointer (&shell_introspect->windows, g_ptr_array_unref); + + g_cancellable_cancel (shell_introspect->cancellable); + g_clear_object (&shell_introspect->cancellable); + shell_introspect->cancellable = g_cancellable_new (); + org_gnome_shell_introspect_call_get_windows (shell_introspect->proxy, shell_introspect->cancellable, get_windows_cb, shell_introspect); } -GList * -shell_introspect_get_windows (ShellIntrospect *shell_introspect) -{ - return shell_introspect->windows; -} - -void -shell_introspect_ref_listeners (ShellIntrospect *shell_introspect) -{ - shell_introspect->num_listeners++; - - if (shell_introspect->proxy) - sync_state (shell_introspect); -} - -void -shell_introspect_unref_listeners (ShellIntrospect *shell_introspect) -{ - g_return_if_fail (shell_introspect->num_listeners > 0); - - shell_introspect->num_listeners--; - if (shell_introspect->num_listeners == 0) - { - g_list_free_full (shell_introspect->windows, - (GDestroyNotify) window_free); - shell_introspect->windows = NULL; - } -} - -gboolean -shell_introspect_are_animations_enabled (ShellIntrospect *shell_introspect, - gboolean *out_animations_enabled) -{ - if (!shell_introspect->animations_enabled_valid) - return FALSE; - - *out_animations_enabled = shell_introspect->animations_enabled; - return TRUE; -} - static void on_windows_changed_cb (GDBusProxy *proxy, ShellIntrospect *shell_introspect) @@ -291,6 +243,29 @@ on_shell_introspect_name_vanished (GDBusConnection *connection, } } +static void +shell_introspect_class_init (ShellIntrospectClass *klass) +{ + signals[WINDOWS_CHANGED] = g_signal_new ("windows-changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 0); + signals[ANIMATIONS_ENABLED_CHANGED] = + g_signal_new ("animations-enabled-changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 0); +} + +static void +shell_introspect_init (ShellIntrospect *shell_introspect) +{ +} + ShellIntrospect * shell_introspect_get (void) { @@ -311,25 +286,67 @@ shell_introspect_get (void) return shell_introspect; } -static void -shell_introspect_init (ShellIntrospect *shell_introspect) +GPtrArray * +shell_introspect_get_windows (ShellIntrospect *shell_introspect) { + return shell_introspect->windows; } -static void -shell_introspect_class_init (ShellIntrospectClass *klass) +void +shell_introspect_ref_listeners (ShellIntrospect *shell_introspect) { - signals[WINDOWS_CHANGED] = g_signal_new ("windows-changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 0); - signals[ANIMATIONS_ENABLED_CHANGED] = - g_signal_new ("animations-enabled-changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 0); + shell_introspect->num_listeners++; + + if (shell_introspect->proxy) + sync_state (shell_introspect); +} + +void +shell_introspect_unref_listeners (ShellIntrospect *shell_introspect) +{ + g_return_if_fail (shell_introspect->num_listeners > 0); + + shell_introspect->num_listeners--; + if (shell_introspect->num_listeners == 0) + g_clear_pointer (&shell_introspect->windows, g_ptr_array_unref); +} + +const char * +window_get_title (Window *window) +{ + return window->title; +} + +const char * +window_get_app_id (Window *window) +{ + return window->app_id; +} + +const uint64_t +window_get_id (Window *window) +{ + return window->id; +} + +gboolean +shell_introspect_are_animations_enabled (ShellIntrospect *shell_introspect, + gboolean *out_animations_enabled) +{ + if (!shell_introspect->animations_enabled_valid) + return FALSE; + + *out_animations_enabled = shell_introspect->animations_enabled; + return TRUE; +} + +void +shell_introspect_wait_for_windows (ShellIntrospect *shell_introspect) +{ + g_assert (shell_introspect->num_listeners > 0); + + sync_state (shell_introspect); + + while (!shell_introspect->windows) + g_main_context_iteration (NULL, TRUE); } diff --git a/src/shellintrospect.h b/src/shellintrospect.h index b187c4d..f63ecee 100644 --- a/src/shellintrospect.h +++ b/src/shellintrospect.h @@ -28,19 +28,21 @@ typedef struct _Window Window; G_DECLARE_FINAL_TYPE (ShellIntrospect, shell_introspect, SHELL, INTROSPECT, GObject) +ShellIntrospect * shell_introspect_get (void); + +void shell_introspect_ref_listeners (ShellIntrospect *shell_introspect); + +void shell_introspect_unref_listeners (ShellIntrospect *shell_introspect); + const char * window_get_app_id (Window *window); const char * window_get_title (Window *window); const uint64_t window_get_id (Window *window); -GList * shell_introspect_get_windows (ShellIntrospect *shell_introspect); +GPtrArray * shell_introspect_get_windows (ShellIntrospect *shell_introspect); -gboolean shell_introspect_are_animations_enabled (ShellIntrospect *introspect, +gboolean shell_introspect_are_animations_enabled (ShellIntrospect *shell_introspect, gboolean *enable_animations); -void shell_introspect_ref_listeners (ShellIntrospect *shell_introspect); - -void shell_introspect_unref_listeners (ShellIntrospect *shell_introspect); - -ShellIntrospect * shell_introspect_get (void); +void shell_introspect_wait_for_windows (ShellIntrospect *shell_introspect);