online-accounts: remove goa-helper

Remove the GOA subprocess helper and use GoaClient directly.

The GoaClient is loaded asynchronously, with the panel being marked
insensitive until ready. Any `CcPanel::parameters` passed while loading
are deferred until the client is ready.
This commit is contained in:
Andy Holmes 2023-12-11 13:09:32 -08:00 committed by Felipe Borges
parent 9f5580832f
commit 08c51127ac
5 changed files with 243 additions and 939 deletions

View file

@ -19,6 +19,10 @@
#include <config.h>
#include <glib/gi18n.h>
#define GOA_API_IS_SUBJECT_TO_CHANGE
#define GOA_BACKEND_API_IS_SUBJECT_TO_CHANGE
#include <goabackend/goabackend.h>
#include "cc-online-account-provider-row.h"
#include "cc-online-accounts-resources.h"
@ -28,7 +32,7 @@ struct _CcOnlineAccountProviderRow
GtkImage *icon_image;
GVariant *provider;
GoaProvider *provider;
};
G_DEFINE_TYPE (CcOnlineAccountProviderRow, cc_online_account_provider_row, ADW_TYPE_ACTION_ROW)
@ -56,7 +60,7 @@ cc_online_account_provider_row_dispose (GObject *object)
{
CcOnlineAccountProviderRow *self = CC_ONLINE_ACCOUNT_PROVIDER_ROW (object);
g_clear_pointer (&self->provider, g_variant_unref);
g_clear_object (&self->provider);
G_OBJECT_CLASS (cc_online_account_provider_row_parent_class)->dispose (object);
}
@ -81,7 +85,7 @@ cc_online_account_provider_row_init (CcOnlineAccountProviderRow *self)
}
CcOnlineAccountProviderRow *
cc_online_account_provider_row_new (GVariant *provider)
cc_online_account_provider_row_new (GoaProvider *provider)
{
CcOnlineAccountProviderRow *self;
g_autoptr(GIcon) icon = NULL;
@ -96,18 +100,9 @@ cc_online_account_provider_row_new (GVariant *provider)
}
else
{
g_autoptr(GVariant) icon_variant = NULL;
self->provider = g_variant_ref (provider);
g_variant_get (provider, "(ssviu)",
NULL,
&name,
&icon_variant,
NULL,
NULL);
icon = g_icon_deserialize (icon_variant);
self->provider = g_object_ref (provider);
icon = goa_provider_get_provider_icon (provider, NULL);
name = goa_provider_get_provider_name (provider, NULL);
}
gtk_image_set_from_gicon (self->icon_image, icon);
@ -127,7 +122,7 @@ cc_online_account_provider_row_new (GVariant *provider)
return self;
}
GVariant *
GoaProvider *
cc_online_account_provider_row_get_provider (CcOnlineAccountProviderRow *self)
{
g_return_val_if_fail (CC_IS_ONLINE_ACCOUNT_PROVIDER_ROW (self), NULL);

View file

@ -21,12 +21,16 @@
#include <gtk/gtk.h>
#include <adwaita.h>
#define GOA_API_IS_SUBJECT_TO_CHANGE
#define GOA_BACKEND_API_IS_SUBJECT_TO_CHANGE
#include <goabackend/goabackend.h>
G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (CcOnlineAccountProviderRow, cc_online_account_provider_row, CC, ONLINE_ACCOUNT_PROVIDER_ROW, AdwActionRow)
CcOnlineAccountProviderRow *cc_online_account_provider_row_new (GVariant *provider);
CcOnlineAccountProviderRow *cc_online_account_provider_row_new (GoaProvider *provider);
GVariant *cc_online_account_provider_row_get_provider (CcOnlineAccountProviderRow *row);
GoaProvider *cc_online_account_provider_row_get_provider (CcOnlineAccountProviderRow *row);
G_END_DECLS

View file

@ -32,12 +32,9 @@
#include "cc-online-account-row.h"
#include "cc-online-accounts-resources.h"
#ifdef GDK_WINDOWING_X11
#include <gdk/x11/gdkx.h>
#endif
#ifdef GDK_WINDOWING_WAYLAND
#include <gdk/wayland/gdkwayland.h>
#endif
#define GOA_API_IS_SUBJECT_TO_CHANGE
#define GOA_BACKEND_API_IS_SUBJECT_TO_CHANGE
#include <goabackend/goabackend.h>
struct _CcOnlineAccountsPanel
{
@ -59,9 +56,9 @@ struct _CcOnlineAccountsPanel
GoaClient *client;
GoaObject *active_object;
GoaObject *removed_object;
GVariant *parameters;
guint remove_account_timeout_id;
gchar *window_export_handle;
};
static gboolean remove_account_timeout_cb (gpointer user_data);
@ -141,115 +138,6 @@ modify_row_for_account (CcOnlineAccountsPanel *self,
g_list_free (children);
}
/* Auxiliary methods */
G_GNUC_NULL_TERMINATED
static char *
run_goa_helper_sync (const char *command,
...)
{
g_autoptr(GPtrArray) argv = NULL;
g_autofree char *output = NULL;
g_autoptr(GError) error = NULL;
const char *param;
va_list args;
int status;
argv = g_ptr_array_new_with_free_func (g_free);
g_ptr_array_add (argv, g_strdup (LIBEXECDIR "/gnome-control-center-goa-helper"));
g_ptr_array_add (argv, g_strdup (command));
va_start (args, command);
while ((param = va_arg (args, const char*)) != NULL)
g_ptr_array_add (argv, g_strdup (param));
va_end (args);
g_ptr_array_add (argv, NULL);
if (!g_spawn_sync (NULL,
(char **) argv->pdata,
NULL,
0,
NULL,
NULL,
&output,
NULL,
&status,
&error))
{
g_warning ("Failed to run online accounts helper: %s", error->message);
return NULL;
}
if (!g_spawn_check_wait_status (status, NULL))
return NULL;
if (output == NULL || *output == '\0')
return NULL;
return g_steal_pointer (&output);
}
static void
run_goa_helper_in_thread_func (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
{
g_autofree char *output = NULL;
g_autoptr(GError) error = NULL;
GPtrArray *argv = task_data;
int status;
g_spawn_sync (NULL,
(char **) argv->pdata,
NULL, 0, NULL, NULL,
&output,
NULL,
&status,
&error);
if (error)
{
g_task_return_error (task, g_steal_pointer (&error));
return;
}
if (!g_spawn_check_wait_status (status, &error))
{
g_task_return_error (task, g_steal_pointer (&error));
return;
}
g_task_return_pointer (task, g_steal_pointer (&output), g_free);
}
static void
run_goa_helper_async (const gchar *command,
const gchar *param,
const gchar *window_handle,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
g_autoptr(GPtrArray) argv = NULL;
g_autoptr(GTask) task = NULL;
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
argv = g_ptr_array_new_with_free_func (g_free);
g_ptr_array_add (argv, g_strdup (LIBEXECDIR "/gnome-control-center-goa-helper"));
g_ptr_array_add (argv, g_strdup (command));
g_ptr_array_add (argv, g_strdup (param));
g_ptr_array_add (argv, g_strdup (window_handle));
g_ptr_array_add (argv, NULL);
task = g_task_new (NULL, cancellable, callback, user_data);
g_task_set_source_tag (task, run_goa_helper_async);
g_task_set_task_data (task, g_steal_pointer (&argv), (GDestroyNotify) g_ptr_array_unref);
g_task_run_in_thread (task, run_goa_helper_in_thread_func);
}
static void
cancel_notification_timeout (CcOnlineAccountsPanel *self)
{
@ -286,220 +174,127 @@ start_remove_account_timeout (CcOnlineAccountsPanel *self)
}
static void
on_show_account_finish_cb (GObject *source_object,
GAsyncResult *result,
gpointer user_data)
on_remove_button_clicked_cb (CcOnlineAccountsPanel *self,
GtkButton *button)
{
CcOnlineAccountsPanel *self = CC_ONLINE_ACCOUNTS_PANEL (user_data);
g_autofree char *output = NULL;
g_autoptr(GError) error = NULL;
output = g_task_propagate_pointer (G_TASK (result), &error);
if (error)
{
g_warning ("Error showing account: %s", error->message);
return;
}
if (g_strcmp0 (output, "remove") == 0)
start_remove_account_timeout (self);
GtkRoot *root;
start_remove_account_timeout (self);
self->active_object = NULL;
root = gtk_widget_get_root (GTK_WIDGET (button));
if (root != NULL)
gtk_window_destroy (GTK_WINDOW (root));
}
static void
show_account (CcOnlineAccountsPanel *self,
GoaObject *object)
{
g_autoptr(GoaProvider) provider = NULL;
g_autofree char *title = NULL;
GoaAccount *account;
GtkWidget *content_area;
GtkWidget *button;
GtkWidget *dialog;
GtkWidget *box;
const char *provider_type;
if (!self->window_export_handle)
return;
self->active_object = g_object_ref (object);
g_set_object (&self->active_object, object);
account = goa_object_peek_account (object);
run_goa_helper_async ("show-account",
goa_account_get_id (account),
self->window_export_handle,
cc_panel_get_cancellable (CC_PANEL (self)),
on_show_account_finish_cb,
self);
}
static void
on_create_account_finish_cb (GObject *source_object,
GAsyncResult *result,
gpointer user_data)
{
CcOnlineAccountsPanel *self = CC_ONLINE_ACCOUNTS_PANEL (user_data);
g_autofree char *new_account_id = NULL;
g_autoptr(GoaObject) object = NULL;
g_autoptr(GError) error = NULL;
new_account_id = g_task_propagate_pointer (G_TASK (result), &error);
if (error)
/* Find the provider with a matching type */
account = goa_object_get_account (object);
provider_type = goa_account_get_provider_type (account);
provider = goa_provider_get_for_provider_type (provider_type);
if (provider == NULL)
{
g_warning ("Error showing account: %s", error->message);
g_warning ("Error showing account: Unsupported provider");
return;
}
if (new_account_id)
object = goa_client_lookup_by_id (self->client, new_account_id);
dialog = g_object_new (GTK_TYPE_DIALOG,
"use-header-bar", 1,
"modal", TRUE,
"transient-for", gtk_widget_get_root (GTK_WIDGET (self)),
NULL);
/* Keep account alive so that the switches are still bound to it */
g_object_set_data_full (G_OBJECT (dialog), "goa-account", account, g_object_unref);
if (object)
show_account (self, object);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 42);
gtk_widget_set_margin_bottom (box, 24);
content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
g_object_set (content_area,
"margin-top", 6,
"margin-end", 6,
"margin-bottom", 6,
"margin-start", 6,
NULL);
gtk_box_append (GTK_BOX (content_area), box);
goa_provider_show_account (provider,
self->client,
object,
GTK_BOX (box),
NULL,
NULL);
/* translators: This is the title of the "Show Account" dialog. The
* %s is the name of the provider. e.g., 'Google'. */
title = g_strdup_printf (_("%s Account"), goa_account_get_provider_name (account));
gtk_window_set_title (GTK_WINDOW (dialog), title);
button = gtk_button_new_with_label (_("Remove Account"));
gtk_widget_set_margin_start (box, 24);
gtk_widget_set_margin_end (box, 24);
gtk_widget_set_halign (button, GTK_ALIGN_END);
gtk_widget_set_valign (button, GTK_ALIGN_END);
gtk_widget_set_visible (button, !goa_account_get_is_locked (account));
gtk_widget_add_css_class (button, "destructive-action");
gtk_box_append (GTK_BOX (box), button);
g_signal_connect_swapped (button,
"clicked",
G_CALLBACK (on_remove_button_clicked_cb),
self);
gtk_window_present (GTK_WINDOW (dialog));
}
static void
create_account (CcOnlineAccountsPanel *self,
GVariant *provider)
GoaProvider *provider)
{
g_autofree char *provider_type = NULL;
if (!self->window_export_handle)
return;
g_variant_get (provider, "(ssviu)", &provider_type, NULL, NULL, NULL, NULL);
run_goa_helper_async ("create-account",
provider_type,
self->window_export_handle,
cc_panel_get_cancellable (CC_PANEL (self)),
on_create_account_finish_cb,
self);
}
static void
add_provider_row (CcOnlineAccountsPanel *self,
GVariant *provider)
{
CcOnlineAccountProviderRow *row;
row = cc_online_account_provider_row_new (provider);
gtk_list_box_append (self->providers_listbox, GTK_WIDGET (row));
}
static void
list_providers (CcOnlineAccountsPanel *self)
{
g_autoptr(GVariant) providers_variant = NULL;
g_autoptr(GError) error = NULL;
g_autofree char *providers = NULL;
GVariantIter iter;
GVariant *provider;
GtkWidget *dialog;
GtkWidget *content;
GoaObject *object;
providers = run_goa_helper_sync ("list-providers", NULL);
g_return_if_fail (GOA_IS_PROVIDER (provider));
if (!providers)
return;
dialog = g_object_new (GTK_TYPE_DIALOG,
"use-header-bar", 1,
"default-width", 500,
"default-height", 350,
"modal", TRUE,
"transient-for", gtk_widget_get_root (GTK_WIDGET (self)),
NULL);
providers_variant = g_variant_parse (G_VARIANT_TYPE ("a(ssviu)"),
providers,
NULL,
NULL,
&error);
content = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
object = goa_provider_add_account (provider,
self->client,
GTK_DIALOG (dialog),
GTK_BOX (content),
&error);
gtk_window_destroy (GTK_WINDOW (dialog));
if (error)
{
g_warning ("Error listing providers: %s", error->message);
g_warning ("Error creating account: %s", error->message);
return;
}
g_variant_iter_init (&iter, providers_variant);
while ((provider = g_variant_iter_next_value (&iter)))
{
add_provider_row (self, provider);
g_variant_unref (provider);
}
}
static void
add_account (CcOnlineAccountsPanel *self,
GoaObject *object)
{
CcOnlineAccountRow *row;
row = cc_online_account_row_new (object);
/* Add to the listbox */
gtk_list_box_append (self->accounts_listbox, GTK_WIDGET (row));
gtk_widget_set_visible (GTK_WIDGET (self->accounts_frame), TRUE);
}
static void
fill_accounts_listbox (CcOnlineAccountsPanel *self)
{
g_autolist(GoaAccount) accounts = NULL;
GList *l;
accounts = goa_client_get_accounts (self->client);
for (l = accounts; l != NULL; l = l->next)
add_account (self, l->data);
}
#ifdef GDK_WINDOWING_WAYLAND
static void
wayland_window_exported_cb (GdkToplevel *toplevel,
const char *handle,
gpointer data)
{
CcOnlineAccountsPanel *self = data;
self->window_export_handle = g_strdup_printf ("wayland:%s", handle);
}
#endif
static void
export_window_handle (CcOnlineAccountsPanel *self)
{
GtkNative *native = gtk_widget_get_native (GTK_WIDGET (self));
#ifdef GDK_WINDOWING_X11
if (GDK_IS_X11_DISPLAY (gtk_widget_get_display (GTK_WIDGET (native))))
{
GdkSurface *surface = gtk_native_get_surface (native);
guint32 xid = (guint32) gdk_x11_surface_get_xid (surface);
self->window_export_handle = g_strdup_printf ("x11:%x", xid);
}
#endif
#ifdef GDK_WINDOWING_WAYLAND
if (GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (GTK_WIDGET (native))))
{
GdkSurface *surface = gtk_native_get_surface (native);
gdk_wayland_toplevel_export_handle (GDK_TOPLEVEL (surface),
wayland_window_exported_cb,
self,
NULL);
}
#endif
}
static void
unexport_window_handle (CcOnlineAccountsPanel *self)
{
if (!self->window_export_handle)
return;
#ifdef GDK_WINDOWING_WAYLAND
GtkNative *native = gtk_widget_get_native (GTK_WIDGET (self));
if (GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (GTK_WIDGET (native))))
{
GdkSurface *surface = gtk_native_get_surface (native);
gdk_wayland_toplevel_unexport_handle (GDK_TOPLEVEL (surface));
}
#endif
g_clear_pointer (&self->window_export_handle, g_free);
show_account (self, object);
}
static void
@ -555,16 +350,16 @@ command_add (CcOnlineAccountsPanel *self,
if (provider_name != NULL)
{
GtkWidget *child;
GVariant *provider;
GoaProvider *provider;
for (child = gtk_widget_get_first_child (GTK_WIDGET (self->providers_listbox));
child;
child = gtk_widget_get_next_sibling (child))
{
g_autofree gchar *provider_type = NULL;
const char *provider_type = NULL;
provider = cc_online_account_provider_row_get_provider (CC_ONLINE_ACCOUNT_PROVIDER_ROW (child));
g_variant_get (provider, "(ssviu)", &provider_type, NULL, NULL, NULL, NULL);
provider_type = goa_provider_get_provider_type (provider);
if (g_strcmp0 (provider_type, provider_name) == 0)
break;
@ -616,35 +411,45 @@ sort_providers_func (GtkListBoxRow *a,
GtkListBoxRow *b,
gpointer user_data)
{
GVariant *a_provider, *b_provider;
GoaProvider *a_provider, *b_provider;
gboolean a_branded, b_branded;
gint a_features, b_features;
GoaProviderFeatures a_features, b_features;
a_provider = cc_online_account_provider_row_get_provider (CC_ONLINE_ACCOUNT_PROVIDER_ROW (a));
a_features = goa_provider_get_provider_features (a_provider);
a_branded = (a_features & GOA_PROVIDER_FEATURE_BRANDED) != 0;
b_provider = cc_online_account_provider_row_get_provider (CC_ONLINE_ACCOUNT_PROVIDER_ROW (b));
g_variant_get (a_provider, "(ssviu)", NULL, NULL, NULL, &a_features, NULL);
g_variant_get (b_provider, "(ssviu)", NULL, NULL, NULL, &b_features, NULL);
/* FIXME: this needs to go away once libgoa-backend is ported to GTK4 */
#define FEATURE_BRANDED (1 << 1)
a_branded = (a_features & FEATURE_BRANDED) != 0;
b_branded = (a_features & FEATURE_BRANDED) != 0;
#undef FEATURE_BRANDED
b_features = goa_provider_get_provider_features (b_provider);
b_branded = (b_features & GOA_PROVIDER_FEATURE_BRANDED) != 0;
if (a_branded != b_branded)
{
if (a_branded)
return -1;
else
return 1;
}
return a_branded ? -1 : 1;
return gtk_list_box_row_get_index (b) - gtk_list_box_row_get_index (a);
}
static void
add_account (CcOnlineAccountsPanel *self,
GoaObject *object)
{
CcOnlineAccountRow *row;
row = cc_online_account_row_new (object);
gtk_list_box_append (self->accounts_listbox, GTK_WIDGET (row));
gtk_widget_set_visible (GTK_WIDGET (self->accounts_frame), TRUE);
}
static void
add_provider (CcOnlineAccountsPanel *self,
GoaProvider *provider)
{
CcOnlineAccountProviderRow *row;
row = cc_online_account_provider_row_new (provider);
gtk_list_box_append (self->providers_listbox, GTK_WIDGET (row));
}
static void
on_account_added_cb (CcOnlineAccountsPanel *self,
GoaObject *object)
@ -733,7 +538,7 @@ static void
on_provider_row_activated_cb (CcOnlineAccountsPanel *self,
GtkListBoxRow *activated_row)
{
GVariant *provider = cc_online_account_provider_row_get_provider (CC_ONLINE_ACCOUNT_PROVIDER_ROW (activated_row));
GoaProvider *provider = cc_online_account_provider_row_get_provider (CC_ONLINE_ACCOUNT_PROVIDER_ROW (activated_row));
create_account (self, provider);
}
@ -744,10 +549,88 @@ remove_account_timeout_cb (gpointer user_data)
CcOnlineAccountsPanel *self = CC_ONLINE_ACCOUNTS_PANEL (user_data);
gtk_widget_activate (self->close_notification_button);
self->remove_account_timeout_id = 0;
return G_SOURCE_REMOVE;
}
static void
goa_provider_get_all_cb (GObject *object,
GAsyncResult *res,
gpointer user_data)
{
g_autoptr (CcOnlineAccountsPanel) self = CC_ONLINE_ACCOUNTS_PANEL (user_data);
g_autolist(GoaProvider) providers = NULL;
g_autolist(GoaAccount) accounts = NULL;
g_autoptr (GError) error = NULL;
/* goa_provider_get_all() doesn't have a cancellable argument, so check if
* the panel cancellable was triggered.
*/
if (g_cancellable_is_cancelled (cc_panel_get_cancellable (CC_PANEL (self))))
return;
if (!goa_provider_get_all_finish (&providers, res, &error))
{
g_warning ("Error listing providers: %s", error->message);
return;
}
for (const GList *iter = providers; iter != NULL; iter = iter->next)
add_provider (self, GOA_PROVIDER (iter->data));
/* Load existing accounts */
accounts = goa_client_get_accounts (self->client);
for (const GList *iter = accounts; iter != NULL; iter = iter->next)
add_account (self, GOA_OBJECT (iter->data));
g_signal_connect_swapped (self->client,
"account-added",
G_CALLBACK (on_account_added_cb),
self);
g_signal_connect_swapped (self->client,
"account-changed",
G_CALLBACK (on_account_changed_cb),
self);
g_signal_connect_swapped (self->client,
"account-removed",
G_CALLBACK (on_account_removed_cb),
self);
/* With the client ready, check if we have a pending command */
gtk_widget_set_sensitive (GTK_WIDGET (self), TRUE);
if (self->parameters != NULL)
{
g_autoptr (GVariant) parameters = NULL;
parameters = g_steal_pointer (&self->parameters);
g_object_set (self, "parameters", parameters, NULL);
}
}
static void
goa_client_new_cb (GObject *object,
GAsyncResult *res,
gpointer user_data)
{
g_autoptr (CcOnlineAccountsPanel) self = CC_ONLINE_ACCOUNTS_PANEL (user_data);
g_autoptr (GError) error = NULL;
self->client = goa_client_new_finish (res, &error);
if (self->client == NULL)
{
g_warning ("Error connect to service: %s", error->message);
gtk_widget_set_sensitive (GTK_WIDGET (self), FALSE);
return;
}
goa_provider_get_all (goa_provider_get_all_cb, g_object_ref (self));
}
/* CcPanel overrides */
static const char *
@ -756,24 +639,6 @@ cc_online_accounts_panel_get_help_uri (CcPanel *panel)
return "help:gnome-help/accounts";
}
/* GtkWidget overrides */
static void
cc_online_accounts_panel_realize (GtkWidget *widget)
{
GTK_WIDGET_CLASS (cc_online_accounts_panel_parent_class)->realize (widget);
export_window_handle (CC_ONLINE_ACCOUNTS_PANEL (widget));
}
static void
cc_online_accounts_panel_unrealize (GtkWidget *widget)
{
unexport_window_handle (CC_ONLINE_ACCOUNTS_PANEL (widget));
GTK_WIDGET_CLASS (cc_online_accounts_panel_parent_class)->unrealize (widget);
}
/* GObject overrides */
static void
@ -782,6 +647,8 @@ cc_online_accounts_panel_set_property (GObject *object,
const GValue *value,
GParamSpec *pspec)
{
CcOnlineAccountsPanel *self = CC_ONLINE_ACCOUNTS_PANEL (object);
switch (property_id)
{
case PROP_PARAMETERS:
@ -804,10 +671,20 @@ cc_online_accounts_panel_set_property (GObject *object,
(gchar *)g_variant_get_type (v));
}
if (g_strcmp0 (first_arg, "add") == 0)
command_add (CC_ONLINE_ACCOUNTS_PANEL (object), parameters);
/* Waiting for the client to load */
if (!gtk_widget_get_sensitive (GTK_WIDGET (self)))
{
g_clear_pointer (&self->parameters, g_variant_unref);
self->parameters = g_value_dup_variant (value);
}
else if (g_strcmp0 (first_arg, "add") == 0)
{
command_add (CC_ONLINE_ACCOUNTS_PANEL (object), self->parameters);
}
else if (first_arg != NULL)
select_account_by_id (CC_ONLINE_ACCOUNTS_PANEL (object), first_arg);
{
select_account_by_id (CC_ONLINE_ACCOUNTS_PANEL (object), first_arg);
}
return;
}
@ -816,16 +693,6 @@ cc_online_accounts_panel_set_property (GObject *object,
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
static void
cc_online_accounts_panel_constructed (GObject *object)
{
CcOnlineAccountsPanel *self = CC_ONLINE_ACCOUNTS_PANEL (object);
G_OBJECT_CLASS (cc_online_accounts_panel_parent_class)->constructed (object);
list_providers (self);
}
static void
cc_online_accounts_panel_finalize (GObject *object)
{
@ -848,6 +715,7 @@ cc_online_accounts_panel_finalize (GObject *object)
}
g_clear_object (&self->client);
g_clear_pointer (&self->parameters, g_variant_unref);
G_OBJECT_CLASS (cc_online_accounts_panel_parent_class)->finalize (object);
}
@ -863,10 +731,6 @@ cc_online_accounts_panel_class_init (CcOnlineAccountsPanelClass *klass)
object_class->set_property = cc_online_accounts_panel_set_property;
object_class->finalize = cc_online_accounts_panel_finalize;
object_class->constructed = cc_online_accounts_panel_constructed;
widget_class->realize = cc_online_accounts_panel_realize;
widget_class->unrealize = cc_online_accounts_panel_unrealize;
g_object_class_override_property (object_class, PROP_PARAMETERS, "parameters");
@ -889,7 +753,6 @@ cc_online_accounts_panel_class_init (CcOnlineAccountsPanelClass *klass)
static void
cc_online_accounts_panel_init (CcOnlineAccountsPanel *self)
{
g_autoptr(GError) error = NULL;
GNetworkMonitor *monitor;
g_resources_register (cc_online_accounts_get_resource ());
@ -919,31 +782,11 @@ cc_online_accounts_panel_init (CcOnlineAccountsPanel *self)
"sensitive",
G_BINDING_SYNC_CREATE);
/* TODO: probably want to avoid _sync() ... */
self->client = goa_client_new_sync (cc_panel_get_cancellable (CC_PANEL (self)), &error);
if (self->client == NULL)
{
g_warning ("Error getting a GoaClient: %s (%s, %d)",
error->message, g_quark_to_string (error->domain), error->code);
gtk_widget_set_sensitive (GTK_WIDGET (self), FALSE);
return;
}
g_signal_connect_swapped (self->client,
"account-added",
G_CALLBACK (on_account_added_cb),
self);
g_signal_connect_swapped (self->client,
"account-changed",
G_CALLBACK (on_account_changed_cb),
self);
g_signal_connect_swapped (self->client,
"account-removed",
G_CALLBACK (on_account_removed_cb),
self);
fill_accounts_listbox (self);
load_custom_css ();
/* Disable the panel while we wait for the client */
gtk_widget_set_sensitive (GTK_WIDGET (self), FALSE);
goa_client_new (cc_panel_get_cancellable (CC_PANEL (self)),
goa_client_new_cb,
g_object_ref (self));
}

View file

@ -1,511 +0,0 @@
/*
* Copyright (C) 2022 Endless OS Foundation, LLC
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author:
* Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
*/
#include "config.h"
#include <gtk/gtk.h>
#include <glib/gi18n.h>
#define GOA_API_IS_SUBJECT_TO_CHANGE
#define GOA_BACKEND_API_IS_SUBJECT_TO_CHANGE
#include <goabackend/goabackend.h>
#ifdef HAVE_GTK_X11
#include <gdk/gdkx.h>
#endif
#ifdef HAVE_GTK_WAYLAND
#include <gdk/gdkwayland.h>
#endif
static GdkDisplay *
get_wayland_display (void)
{
static GdkDisplay *wayland_display = NULL;
if (wayland_display)
return wayland_display;
gdk_set_allowed_backends ("wayland");
wayland_display = gdk_display_open (NULL);
gdk_set_allowed_backends (NULL);
if (!wayland_display)
g_warning ("Failed to open Wayland display");
return wayland_display;
}
static GdkDisplay *
get_x11_display (void)
{
static GdkDisplay *x11_display = NULL;
if (x11_display)
return x11_display;
gdk_set_allowed_backends ("x11");
x11_display = gdk_display_open (NULL);
gdk_set_allowed_backends (NULL);
if (!x11_display)
g_warning ("Failed to open X11 display");
return x11_display;
}
static void
set_external_parent_from_handle (GtkApplication *application,
GtkWindow *dialog,
const char *handle_str)
{
GdkDisplay *display;
GtkWindow *fake_parent;
GdkScreen *screen;
#ifdef HAVE_GTK_X11
{
const char *x11_prefix = "x11:";
if (g_str_has_prefix (handle_str, x11_prefix))
{
display = get_x11_display ();
if (!display)
{
g_warning ("No X display connection, ignoring X11 parent");
return;
}
}
}
#endif
#ifdef HAVE_GTK_WAYLAND
{
const char *wayland_prefix = "wayland:";
if (g_str_has_prefix (handle_str, wayland_prefix))
{
display = get_wayland_display ();
if (!display)
{
g_warning ("No Wayland display connection, ignoring Wayland parent");
return;
}
}
}
#endif
screen = gdk_display_get_default_screen (gdk_display_get_default ());
fake_parent = g_object_new (GTK_TYPE_APPLICATION_WINDOW,
"application", application,
"type", GTK_WINDOW_TOPLEVEL,
"screen", screen,
NULL);
g_object_ref_sink (fake_parent);
gtk_window_set_transient_for (dialog, GTK_WINDOW (fake_parent));
gtk_window_set_modal (dialog, TRUE);
gtk_widget_realize (GTK_WIDGET (dialog));
#ifdef HAVE_GTK_X11
{
const char *x11_prefix = "x11:";
if (g_str_has_prefix (handle_str, x11_prefix))
{
GdkWindow *foreign_gdk_window;
int xid;
errno = 0;
xid = strtol (handle_str + strlen (x11_prefix), NULL, 16);
if (errno != 0)
{
g_warning ("Failed to reference external X11 window, invalid XID %s", handle_str);
return;
}
foreign_gdk_window = gdk_x11_window_foreign_new_for_display (display, xid);
if (!foreign_gdk_window)
{
g_warning ("Failed to create foreign window for XID %d", xid);
return;
}
gdk_window_set_transient_for (gtk_widget_get_window (GTK_WIDGET (dialog)),
foreign_gdk_window);
}
}
#endif
#ifdef HAVE_GTK_WAYLAND
{
const char *wayland_prefix = "wayland:";
if (g_str_has_prefix (handle_str, wayland_prefix))
{
const char *wayland_handle_str = handle_str + strlen (wayland_prefix);
if (!gdk_wayland_window_set_transient_for_exported (gtk_widget_get_window (GTK_WIDGET (dialog)),
(char *) wayland_handle_str))
{
g_warning ("Failed to set window transient for external parent");
return;
}
}
}
#endif
gtk_window_present (dialog);
}
/* create-account */
static void
on_application_activate_create_account_cb (GtkApplication *application,
char **argv)
{
g_autoptr(GoaProvider) provider = NULL;
g_autoptr(GoaClient) client = NULL;
g_autoptr(GError) error = NULL;
GoaAccount *account;
GtkWidget *content_area;
GtkWidget *dialog;
GoaObject *object;
client = goa_client_new_sync (NULL, &error);
if (error)
{
g_printerr ("Error retrieving online accounts client");
exit (EXIT_FAILURE);
return;
}
/* Find the provider with a matching type */
provider = goa_provider_get_for_provider_type (argv[2]);
if (!provider)
{
g_printerr ("Provider type not supported");
exit (EXIT_FAILURE);
return;
}
dialog = g_object_new (GTK_TYPE_DIALOG,
"use-header-bar", 1,
"default-width", 500,
"default-height", 350,
NULL);
g_signal_connect_swapped (dialog, "response", G_CALLBACK (g_application_quit), application);
set_external_parent_from_handle (application, GTK_WINDOW (dialog), argv[3]);
content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
gtk_container_set_border_width (GTK_CONTAINER (content_area), 0);
object = goa_provider_add_account (provider,
client,
GTK_DIALOG (dialog),
GTK_BOX (content_area),
&error);
if (error)
{
g_printerr ("Failed to create account: %s", error->message);
exit (EXIT_FAILURE);
return;
}
account = goa_object_peek_account (object);
g_print ("%s", goa_account_get_id (account));
}
static int
create_account (int argc,
char **argv)
{
g_autoptr(GtkApplication) application = NULL;
gtk_init (&argc, &argv);
if (argc != 4)
{
g_printerr ("Not enough arguments");
return EXIT_FAILURE;
}
application = gtk_application_new ("org.gnome.Settings.GoaHelper",
G_APPLICATION_FLAGS_NONE);
g_signal_connect (application, "activate", G_CALLBACK (on_application_activate_create_account_cb), argv);
return g_application_run (G_APPLICATION (application), 0, NULL);
}
/* list-providers */
typedef struct {
GMainLoop *mainloop;
GList *providers;
GError *error;
} GetAllProvidersData;
static void
get_all_providers_cb (GObject *source,
GAsyncResult *res,
gpointer user_data)
{
g_autolist(GoaProvider) providers = NULL;
GetAllProvidersData *data;
data = user_data;
goa_provider_get_all_finish (&providers, res, &data->error);
if (data->error)
goto out;
data->providers = g_steal_pointer (&providers);
out:
g_main_loop_quit (data->mainloop);
}
static GList *
get_all_providers (GError **error)
{
GetAllProvidersData data = (GetAllProvidersData) {
.mainloop = g_main_loop_new (NULL, FALSE),
.providers = NULL,
.error = NULL,
};
goa_provider_get_all (get_all_providers_cb, &data);
g_main_loop_run (data.mainloop);
g_main_loop_unref (data.mainloop);
if (data.error)
g_propagate_error (error, data.error);
return data.providers;
}
static int
list_providers (int argc,
char **argv)
{
g_autofree char *serialized_result = NULL;
g_autolist(GoaProvider) providers = NULL;
g_autoptr(GVariant) result = NULL;
g_autoptr(GError) error = NULL;
GVariantBuilder b;
GList *l;
providers = get_all_providers (&error);
if (error)
{
g_printerr ("%s", error->message);
return EXIT_FAILURE;
}
g_variant_builder_init (&b, G_VARIANT_TYPE ("a(ssviu)"));
for (l = providers; l; l = l->next)
{
GoaProvider *provider = l->data;
g_autofree char *name = NULL;
g_autoptr(GVariant) icon_variant = NULL;
g_autoptr(GIcon) icon = NULL;
name = goa_provider_get_provider_name (provider, NULL);
icon = goa_provider_get_provider_icon (provider, NULL);
icon_variant = g_icon_serialize (icon);
g_variant_builder_add (&b, "(ssviu)",
goa_provider_get_provider_type (provider),
name,
icon_variant,
goa_provider_get_provider_features (provider),
goa_provider_get_credentials_generation (provider));
}
result = g_variant_builder_end (&b);
serialized_result = g_variant_print (result, TRUE);
g_print ("%s", serialized_result);
return EXIT_SUCCESS;
}
/* show-account */
static void
on_remove_button_clicked_cb (GApplication *application)
{
g_print ("remove");
g_application_quit (application);
}
static void
on_application_activate_show_account_cb (GtkApplication *application,
char **argv)
{
g_autoptr(GoaProvider) provider = NULL;
g_autoptr(GoaObject) object = NULL;
g_autoptr(GoaClient) client = NULL;
g_autoptr(GError) error = NULL;
g_autofree char *title = NULL;
GoaAccount *account;
GtkWidget *content_area;
GtkWidget *button;
GtkWidget *dialog;
GtkWidget *box;
const char *provider_type;
client = goa_client_new_sync (NULL, &error);
if (error)
{
g_printerr ("Error retrieving online accounts client");
exit (EXIT_FAILURE);
return;
}
object = goa_client_lookup_by_id (client, argv[2]);
if (!object)
{
g_printerr ("Online account does not exist");
exit (EXIT_FAILURE);
return;
}
/* Find the provider with a matching type */
account = goa_object_get_account (object);
provider_type = goa_account_get_provider_type (account);
provider = goa_provider_get_for_provider_type (provider_type);
if (!provider)
{
g_printerr ("Provider type not supported");
exit (EXIT_FAILURE);
return;
}
dialog = g_object_new (GTK_TYPE_DIALOG,
"use-header-bar", 1,
NULL);
/* Keep account alive so that the switches are still bound to it */
g_object_set_data_full (G_OBJECT (dialog), "goa-account", account, g_object_unref);
g_signal_connect_swapped (dialog, "response", G_CALLBACK (g_application_quit), application);
set_external_parent_from_handle (application, GTK_WINDOW (dialog), argv[3]);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 42);
gtk_widget_set_margin_bottom (box, 24);
content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
gtk_container_set_border_width (GTK_CONTAINER (content_area), 0);
gtk_container_add (GTK_CONTAINER (content_area), box);
goa_provider_show_account (provider,
client,
object,
GTK_BOX (box),
NULL,
NULL);
/*
* The above call doesn't set any widgets to visible, so we have to do that.
* https://gitlab.gnome.org/GNOME/gnome-online-accounts/issues/56
*/
gtk_widget_show_all (box);
/* translators: This is the title of the "Show Account" dialog. The
* %s is the name of the provider. e.g., 'Google'. */
title = g_strdup_printf (_("%s Account"), goa_account_get_provider_name (account));
gtk_window_set_title (GTK_WINDOW (dialog), title);
button = gtk_button_new_with_label (_("Remove Account"));
gtk_widget_set_margin_start (box, 24);
gtk_widget_set_margin_end (box, 24);
gtk_widget_set_halign (button, GTK_ALIGN_END);
gtk_widget_set_valign (button, GTK_ALIGN_END);
gtk_widget_set_visible (button, !goa_account_get_is_locked (account));
gtk_style_context_add_class (gtk_widget_get_style_context (button), "destructive-action");
gtk_container_add (GTK_CONTAINER (box), button);
g_signal_connect_swapped (button, "clicked", G_CALLBACK (on_remove_button_clicked_cb), application);
}
static int
show_account (int argc,
char **argv)
{
g_autoptr(GtkApplication) application = NULL;
gtk_init (&argc, &argv);
if (argc != 4)
{
g_printerr ("Not enough arguments");
return EXIT_FAILURE;
}
application = gtk_application_new ("org.gnome.Settings.GoaHelper",
G_APPLICATION_FLAGS_NONE);
g_signal_connect (application, "activate", G_CALLBACK (on_application_activate_show_account_cb), argv);
return g_application_run (G_APPLICATION (application), 0, NULL);
}
struct {
const char *command_name;
int (*command_func) (int argc,
char **argv);
} commands[] = {
{ "create-account", create_account, },
{ "list-providers", list_providers, },
{ "show-account", show_account, },
};
static void
log_handler (const gchar *domain,
GLogLevelFlags log_level,
const gchar *message,
gpointer user_data)
{
g_printerr ("%s: %s\n", domain, message);
}
int
main (int argc,
char **argv)
{
gsize i;
bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
textdomain (GETTEXT_PACKAGE);
if (argc < 2)
return EXIT_FAILURE;
/*
* This helper currently communicates to the gnome-control-center parent process
* by writing information to stdout using g_print. Therefore we need
* a custom logging handler, so to not write logs into stdout,
* which would confuse the parent process.
*/
g_log_set_default_handler (log_handler, NULL);
for (i = 0; i < G_N_ELEMENTS (commands); i++)
{
if (g_strcmp0 (commands[i].command_name, argv[1]) == 0)
return commands[i].command_func (argc, argv);
}
return EXIT_SUCCESS;
}

View file

@ -29,6 +29,7 @@ sources += gnome.compile_resources(
deps = common_deps + [
goa_dep,
dependency('goa-backend-1.0', version: goa_req_version),
]
panels_libs += static_library(
@ -39,32 +40,4 @@ panels_libs += static_library(
c_args: cflags
)
goa_helper_deps = [
dependency('goa-backend-1.0', version: goa_req_version),
]
goa_helper_cflags = cflags + [
'-DGNOMELOCALEDIR="@0@"'.format(control_center_localedir),
]
gtk_x11_dep = dependency('gtk+-x11-3.0', required: false)
if gtk_x11_dep.found()
goa_helper_cflags += ['-DHAVE_GTK_X11']
endif
gtk_wayland_dep = dependency('gtk+-wayland-3.0', required: false)
if gtk_wayland_dep.found()
goa_helper_cflags += ['-DHAVE_GTK_WAYLAND']
endif
executable(
'gnome-control-center-goa-helper',
'gnome-control-center-goa-helper.c',
include_directories: [ top_inc ],
dependencies: goa_helper_deps,
c_args: goa_helper_cflags,
install: true,
install_dir: control_center_libexecdir,
)
subdir('icons')