summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorges Basile Stavracas Neto <georges.stavracas@gmail.com>2022-01-17 16:05:05 -0300
committerGeorges Basile Stavracas Neto <georges.stavracas@gmail.com>2022-01-17 19:42:10 -0300
commit946417990c23283b9aa013ca2d99eeed2a108c95 (patch)
tree8c4765ee945d9f9f4169d381b73a8999cc0eb4be
parentfdda3e77f6b979eb335e87f9a5e3bb19e3b646cf (diff)
downloadgnome-control-center-946417990c23283b9aa013ca2d99eeed2a108c95.tar.gz
online-accounts: Port to GTK4
This is a massive rewrite of the panel. Because we can't have nice things and WebKit2GTK for GTK4 won't be ready in time, rework the panel to spawn a new subprocess with a dialog that handles online accounts - both creation and editing.
-rw-r--r--panels/meson.build2
-rw-r--r--panels/online-accounts/cc-online-accounts-panel.c1330
-rw-r--r--panels/online-accounts/cc-online-accounts-panel.ui111
-rw-r--r--panels/online-accounts/gnome-control-center-goa-helper.c491
-rw-r--r--panels/online-accounts/meson.build35
-rw-r--r--panels/online-accounts/online-accounts.gresource.xml2
-rw-r--r--panels/online-accounts/online-accounts.ui237
-rw-r--r--po/POTFILES.in3
-rw-r--r--shell/cc-panel-loader.c4
9 files changed, 1336 insertions, 879 deletions
diff --git a/panels/meson.build b/panels/meson.build
index d379a9fb1..4498f198a 100644
--- a/panels/meson.build
+++ b/panels/meson.build
@@ -17,7 +17,7 @@ panels = [
'mouse',
'multitasking',
'notifications',
-# 'online-accounts',
+ 'online-accounts',
'power',
'printers',
'region',
diff --git a/panels/online-accounts/cc-online-accounts-panel.c b/panels/online-accounts/cc-online-accounts-panel.c
index a696b4b8c..06071aabc 100644
--- a/panels/online-accounts/cc-online-accounts-panel.c
+++ b/panels/online-accounts/cc-online-accounts-panel.c
@@ -26,13 +26,16 @@
#define GOA_API_IS_SUBJECT_TO_CHANGE
#include <goa/goa.h>
-#define GOA_BACKEND_API_IS_SUBJECT_TO_CHANGE
-#include <goabackend/goabackend.h>
#include "cc-online-accounts-panel.h"
#include "cc-online-accounts-resources.h"
-#include "list-box-helper.h"
+#ifdef GDK_WINDOWING_X11
+#include <gdk/x11/gdkx.h>
+#endif
+#ifdef GDK_WINDOWING_WAYLAND
+#include <gdk/wayland/gdkwayland.h>
+#endif
struct _CcGoaPanel
{
@@ -40,16 +43,15 @@ struct _CcGoaPanel
GtkFrame *accounts_frame;
GtkListBox *accounts_listbox;
+ GtkWidget *close_notification_button;
GtkDialog *edit_account_dialog;
GtkHeaderBar *edit_account_headerbar;
GtkBox *editor_box;
- GtkBox *new_account_vbox;
GtkLabel *notification_label;
GtkRevealer *notification_revealer;
GtkLabel *offline_label;
GtkListBox *providers_listbox;
GtkButton *remove_account_button;
- GtkStack *stack;
GtkBox *accounts_vbox;
GoaClient *client;
@@ -57,44 +59,10 @@ struct _CcGoaPanel
GoaObject *removed_object;
guint remove_account_timeout_id;
+ gchar *window_export_handle;
};
-static gboolean on_edit_account_dialog_delete_event (CcGoaPanel *self);
-
-static void on_listbox_row_activated (CcGoaPanel *self,
- GtkListBoxRow *activated_row);
-
-static void fill_accounts_listbox (CcGoaPanel *self);
-
-static void on_account_added (GoaClient *client,
- GoaObject *object,
- gpointer user_data);
-
-static void on_account_changed (GoaClient *client,
- GoaObject *object,
- gpointer user_data);
-
-static void on_account_removed (GoaClient *client,
- GoaObject *object,
- gpointer user_data);
-
-static void select_account_by_id (CcGoaPanel *panel,
- const gchar *account_id);
-
-static void get_all_providers_cb (GObject *source,
- GAsyncResult *res,
- gpointer user_data);
-
-static void show_page_account (CcGoaPanel *panel,
- GoaObject *object);
-
-static void on_remove_button_clicked (CcGoaPanel *self);
-
-static void on_notification_closed (GtkButton *button,
- CcGoaPanel *self);
-
-static void on_undo_button_clicked (GtkButton *button,
- CcGoaPanel *self);
+static gboolean remove_account_timeout_cb (gpointer user_data);
CC_PANEL_REGISTER (CcGoaPanel, cc_goa_panel);
@@ -103,842 +71,934 @@ enum {
PROP_PARAMETERS
};
-/* ---------------------------------------------------------------------------------------------------- */
+/* Rows methods */
+
+typedef void (*RowForAccountCallback) (CcGoaPanel *self, GtkWidget *row, GList *other_rows);
static void
-reset_headerbar (CcGoaPanel *self)
+hide_row_for_account_cb (CcGoaPanel *self,
+ GtkWidget *row,
+ GList *other_rows)
{
- gtk_header_bar_set_title (self->edit_account_headerbar, NULL);
- gtk_header_bar_set_subtitle (self->edit_account_headerbar, NULL);
- gtk_header_bar_set_show_close_button (self->edit_account_headerbar, TRUE);
-
- /* Remove any leftover widgets */
- gtk_container_foreach (GTK_CONTAINER (self->edit_account_headerbar),
- (GtkCallback) gtk_widget_destroy,
- NULL);
-
+ gtk_widget_hide (row);
+ gtk_widget_set_visible (GTK_WIDGET (self->accounts_frame), other_rows != NULL);
}
-/* ---------------------------------------------------------------------------------------------------- */
-
static void
-add_provider_row (CcGoaPanel *self,
- GoaProvider *provider)
+remove_row_for_account_cb (CcGoaPanel *self,
+ GtkWidget *row,
+ GList *other_rows)
{
- GIcon *icon;
- GtkWidget *image;
- GtkWidget *label;
- GtkWidget *row;
- GtkWidget *row_grid;
- gchar *markup;
- gchar *name;
+ gtk_list_box_remove (self->accounts_listbox, row);
+ gtk_widget_set_visible (GTK_WIDGET (self->accounts_frame), other_rows != NULL);
+}
- row = gtk_list_box_row_new ();
+static void
+show_row_for_account_cb (CcGoaPanel *self,
+ GtkWidget *row,
+ GList *other_rows)
+{
+ gtk_widget_show (row);
+ gtk_widget_show (GTK_WIDGET (self->accounts_frame));
+}
- row_grid = gtk_grid_new ();
- gtk_widget_show (row_grid);
- gtk_orientable_set_orientation (GTK_ORIENTABLE (row_grid), GTK_ORIENTATION_HORIZONTAL);
- gtk_grid_set_column_spacing (GTK_GRID (row_grid), 6);
- gtk_container_add (GTK_CONTAINER (row), row_grid);
+static void
+modify_row_for_account (CcGoaPanel *self,
+ GoaObject *object,
+ RowForAccountCallback callback)
+{
+ GtkWidget *child;
+ GList *children = NULL;
+ GList *l;
- if (provider == NULL)
+ for (child = gtk_widget_get_first_child (GTK_WIDGET (self->accounts_listbox));
+ child;
+ child = gtk_widget_get_next_sibling (child))
{
- g_object_set_data (G_OBJECT (row), "goa-provider", NULL);
- icon = g_themed_icon_new_with_default_fallbacks ("goa-account");
- name = g_strdup (C_("Online Account", "Other"));
+ children = g_list_prepend (children, child);
}
- else
- {
- g_object_set_data_full (G_OBJECT (row), "goa-provider", g_object_ref (provider), g_object_unref);
- icon = goa_provider_get_provider_icon (provider, NULL);
- name = goa_provider_get_provider_name (provider, NULL);
- }
-
- image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_DIALOG);
- gtk_style_context_add_class (gtk_widget_get_style_context (image), "lowres-icon");
- gtk_widget_show (image);
- gtk_container_add (GTK_CONTAINER (row_grid), image);
- g_object_set (image, "margin", 6, NULL);
- markup = g_strdup_printf ("<b>%s</b>", name);
- label = gtk_label_new (NULL);
- gtk_widget_show (label);
- gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
- gtk_label_set_xalign (GTK_LABEL (label), 0.0f);
- gtk_label_set_markup (GTK_LABEL (label), markup);
- gtk_container_add (GTK_CONTAINER (row_grid), label);
+ children = g_list_reverse (children);
- gtk_widget_show (row);
- gtk_container_add (GTK_CONTAINER (self->providers_listbox), row);
+ for (l = children; l != NULL; l = l->next)
+ {
+ GoaObject *row_object;
- g_free (markup);
- g_free (name);
- g_object_unref (icon);
-}
+ row_object = g_object_get_data (G_OBJECT (l->data), "goa-object");
+ if (row_object == object)
+ {
+ GtkWidget *row = GTK_WIDGET (l->data);
-static gint
-sort_providers_func (GtkListBoxRow *a,
- GtkListBoxRow *b,
- gpointer user_data)
-{
- GoaProvider *a_provider, *b_provider;
- gboolean a_branded, b_branded;
+ children = g_list_remove_link (children, l);
+ callback (self, row, children);
+ g_list_free (l);
+ break;
+ }
+ }
- a_provider = g_object_get_data (G_OBJECT (a), "goa-provider");
- b_provider = g_object_get_data (G_OBJECT (b), "goa-provider");
+ g_list_free (children);
+}
- a_branded = (goa_provider_get_provider_features (a_provider) & GOA_PROVIDER_FEATURE_BRANDED) != 0;
- b_branded = (goa_provider_get_provider_features (b_provider) & GOA_PROVIDER_FEATURE_BRANDED) != 0;
+/* Auxiliary methods */
- if (a_branded != b_branded)
+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))
{
- if (a_branded)
- return -1;
- else
- return 1;
+ g_warning ("Failed to run online accounts helper: %s", error->message);
+ return NULL;
}
- return gtk_list_box_row_get_index (b) - gtk_list_box_row_get_index (a);
+ if (!g_spawn_check_wait_status (status, NULL))
+ return NULL;
+
+ if (output == NULL || *output == '\0')
+ return NULL;
+
+ return g_steal_pointer (&output);
}
static void
-add_account (CcGoaPanel *self,
- GoaProvider *provider)
+run_goa_helper_in_thread_func (GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable)
{
- GoaObject *object;
+ 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;
+ }
- gtk_container_foreach (GTK_CONTAINER (self->new_account_vbox),
- (GtkCallback) gtk_widget_destroy,
- NULL);
-
- reset_headerbar (self);
-
- /* Move to the new account page */
- gtk_stack_set_visible_child (self->stack, GTK_WIDGET (self->new_account_vbox));
-
- /* Reset the dialog size */
- gtk_window_resize (GTK_WINDOW (self->edit_account_dialog), 1, 1);
-
- /* This spins gtk_dialog_run() */
- object = goa_provider_add_account (provider,
- self->client,
- self->edit_account_dialog,
- self->new_account_vbox,
- &error);
+ if (!g_spawn_check_wait_status (status, &error))
+ {
+ g_task_return_error (task, g_steal_pointer (&error));
+ return;
+ }
- if (object == NULL)
- gtk_widget_hide (GTK_WIDGET (self->edit_account_dialog));
- else
- show_page_account (self, object);
+ g_task_return_pointer (task, g_steal_pointer (&output), g_free);
}
static void
-on_provider_row_activated (CcGoaPanel *self,
- GtkListBoxRow *activated_row)
+run_goa_helper_async (const gchar *command,
+ const gchar *param,
+ const gchar *window_handle,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
- GoaProvider *provider;
+ g_autoptr(GPtrArray) argv = NULL;
+ g_autoptr(GTask) task = NULL;
- provider = g_object_get_data (G_OBJECT (activated_row), "goa-provider");
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
- add_account (self, provider);
-}
+ 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 gint
-sort_func (GtkListBoxRow *a,
- GtkListBoxRow *b,
- gpointer user_data)
+static void
+cancel_notification_timeout (CcGoaPanel *self)
{
- GoaObject *a_obj, *b_obj;
- GoaAccount *a_account, *b_account;
-
- a_obj = g_object_get_data (G_OBJECT (a), "goa-object");
- a_account = goa_object_peek_account (a_obj);
-
- b_obj = g_object_get_data (G_OBJECT (b), "goa-object");
- b_account = goa_object_peek_account (b_obj);
-
- return g_strcmp0 (goa_account_get_id (a_account), goa_account_get_id (b_account));
+ g_clear_handle_id (&self->remove_account_timeout_id, g_source_remove);
+ self->removed_object = NULL;
}
static void
-command_add (CcGoaPanel *panel,
- GVariant *parameters)
+start_remove_account_timeout (CcGoaPanel *self)
{
- GVariant *v = NULL;
- GoaProvider *provider = NULL;
- const gchar *provider_name = NULL;
+ GoaAccount *account;
+ g_autofree gchar *id = NULL;
+ g_autofree gchar *label = NULL;
- g_assert (panel != NULL);
- g_assert (parameters != NULL);
+ if (self->active_object == NULL)
+ return;
- switch (g_variant_n_children (parameters))
- {
- case 2:
- g_variant_get_child (parameters, 1, "v", &v);
- if (g_variant_is_of_type (v, G_VARIANT_TYPE_STRING))
- provider_name = g_variant_get_string (v, NULL);
- else
- g_warning ("Wrong type for the second argument (provider name) GVariant, expected 's' but got '%s'",
- (gchar *)g_variant_get_type (v));
- g_variant_unref (v);
- break;
- default:
- g_warning ("Unexpected parameters found, ignore request");
- goto out;
- }
+ if (self->removed_object != NULL)
+ gtk_widget_activate (self->close_notification_button);
- if (provider_name != NULL)
- {
- provider = goa_provider_get_for_provider_type (provider_name);
- if (provider == NULL)
- {
- g_warning ("Unable to get a provider for type '%s'", provider_name);
- goto out;
- }
+ self->removed_object = g_steal_pointer (&self->active_object);
- add_account (panel, provider);
- }
+ account = goa_object_peek_account (self->removed_object);
+ id = g_strdup_printf ("<b>%s</b>", goa_account_get_presentation_identity (account));
+ /* Translators: The %s is the username (eg., debarshi.ray@gmail.com
+ * or rishi).
+ */
+ label = g_strdup_printf (_("%s removed"), id);
+ gtk_label_set_markup (self->notification_label, label);
+ gtk_revealer_set_reveal_child (self->notification_revealer, TRUE);
-out:
- g_clear_object (&provider);
+ modify_row_for_account (self, self->removed_object, hide_row_for_account_cb);
+ self->remove_account_timeout_id = g_timeout_add_seconds (10, remove_account_timeout_cb, self);
}
static void
-cc_goa_panel_set_property (GObject *object,
- guint property_id,
- const GValue *value,
- GParamSpec *pspec)
+on_show_account_finish_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- switch (property_id)
- {
- case PROP_PARAMETERS:
- {
- GVariant *parameters, *v;
- const gchar *first_arg = NULL;
-
- parameters = g_value_get_variant (value);
- if (parameters == NULL)
- return;
-
- if (g_variant_n_children (parameters) > 0)
- {
- g_variant_get_child (parameters, 0, "v", &v);
- if (g_variant_is_of_type (v, G_VARIANT_TYPE_STRING))
- first_arg = g_variant_get_string (v, NULL);
- else
- g_warning ("Wrong type for the second argument GVariant, expected 's' but got '%s'",
- (gchar *)g_variant_get_type (v));
- g_variant_unref (v);
- }
+ CcGoaPanel *self = CC_GOA_PANEL (user_data);
+ g_autofree char *output = NULL;
+ g_autoptr(GError) error = NULL;
- if (g_strcmp0 (first_arg, "add") == 0)
- command_add (CC_GOA_PANEL (object), parameters);
- else if (first_arg != NULL)
- select_account_by_id (CC_GOA_PANEL (object), first_arg);
+ output = g_task_propagate_pointer (G_TASK (result), &error);
- return;
- }
+ if (error)
+ {
+ g_warning ("Error showing account: %s", error->message);
+ return;
}
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ if (g_strcmp0 (output, "remove") == 0)
+ start_remove_account_timeout (self);
+
+ self->active_object = NULL;
}
static void
-cc_goa_panel_dispose (GObject *object)
+show_account (CcGoaPanel *self,
+ GoaObject *object)
{
- CcGoaPanel *panel = CC_GOA_PANEL (object);
+ GoaAccount *account;
- /* Must be destroyed in dispose, not finalize. */
- g_clear_pointer ((GtkWidget **) &panel->edit_account_dialog, gtk_widget_destroy);
+ if (!self->window_export_handle)
+ return;
- G_OBJECT_CLASS (cc_goa_panel_parent_class)->dispose (object);
+ self->active_object = g_object_ref (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
-cc_goa_panel_finalize (GObject *object)
+on_create_account_finish_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- CcGoaPanel *panel = CC_GOA_PANEL (object);
+ CcGoaPanel *self = CC_GOA_PANEL (user_data);
+ g_autofree char *new_account_id = NULL;
+ g_autoptr(GoaObject) object = NULL;
+ g_autoptr(GError) error = NULL;
- if (panel->removed_object != NULL)
- {
- g_autoptr(GError) error = NULL;
- goa_account_call_remove_sync (goa_object_peek_account (panel->removed_object),
- NULL, /* GCancellable */
- &error);
+ new_account_id = g_task_propagate_pointer (G_TASK (result), &error);
- if (error != NULL)
- {
- g_warning ("Error removing account: %s (%s, %d)",
- error->message,
- g_quark_to_string (error->domain),
- error->code);
- }
+ if (error)
+ {
+ g_warning ("Error showing account: %s", error->message);
+ return;
}
- g_clear_object (&panel->client);
+ if (new_account_id)
+ object = goa_client_lookup_by_id (self->client, new_account_id);
- G_OBJECT_CLASS (cc_goa_panel_parent_class)->finalize (object);
+ if (object)
+ show_account (self, object);
}
static void
-cc_goa_panel_init (CcGoaPanel *panel)
+create_account (CcGoaPanel *self,
+ GVariant *provider)
{
- GNetworkMonitor *monitor;
- g_autoptr(GError) error = NULL;
-
- g_resources_register (cc_online_accounts_get_resource ());
+ g_autofree char *provider_type = NULL;
- gtk_widget_init_template (GTK_WIDGET (panel));
-
- gtk_list_box_set_header_func (panel->accounts_listbox,
- cc_list_box_update_header_func,
- NULL,
- NULL);
- gtk_list_box_set_sort_func (panel->accounts_listbox,
- sort_func,
- panel,
- NULL);
+ if (!self->window_export_handle)
+ return;
- gtk_list_box_set_header_func (panel->providers_listbox,
- cc_list_box_update_header_func,
- NULL,
- NULL);
- gtk_list_box_set_sort_func (panel->providers_listbox,
- sort_providers_func,
- panel,
- NULL);
+ g_variant_get (provider, "(ssviu)", &provider_type, NULL, NULL, NULL, NULL);
- monitor = g_network_monitor_get_default();
+ 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);
+}
- g_object_bind_property (monitor, "network-available",
- panel->offline_label, "visible",
- G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN);
+static void
+add_provider_row (CcGoaPanel *self,
+ GVariant *provider)
+{
+ g_autofree char *name = NULL;
+ g_autoptr(GIcon) icon = NULL;
+ GtkWidget *image;
+ GtkWidget *row;
- g_object_bind_property (monitor, "network-available",
- panel->providers_listbox, "sensitive",
- G_BINDING_SYNC_CREATE);
+ row = adw_action_row_new ();
+ gtk_list_box_row_set_activatable (GTK_LIST_BOX_ROW (row), TRUE);
- /* TODO: probably want to avoid _sync() ... */
- panel->client = goa_client_new_sync (cc_panel_get_cancellable (CC_PANEL (panel)), &error);
- if (panel->client == NULL)
+ if (provider == 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 (panel), FALSE);
- return;
+ g_object_set_data (G_OBJECT (row), "goa-provider", NULL);
+ icon = g_themed_icon_new_with_default_fallbacks ("goa-account");
+ name = g_strdup (C_("Online Account", "Other"));
}
+ else
+ {
+ g_autoptr(GVariant) icon_variant = NULL;
- g_signal_connect (panel->client,
- "account-added",
- G_CALLBACK (on_account_added),
- panel);
+ g_object_set_data_full (G_OBJECT (row),
+ "goa-provider",
+ g_variant_ref (provider),
+ (GDestroyNotify) g_variant_unref);
- g_signal_connect (panel->client,
- "account-changed",
- G_CALLBACK (on_account_changed),
- panel);
+ g_variant_get (provider, "(ssviu)",
+ NULL,
+ &name,
+ &icon_variant,
+ NULL,
+ NULL);
- g_signal_connect (panel->client,
- "account-removed",
- G_CALLBACK (on_account_removed),
- panel);
+ icon = g_icon_deserialize (icon_variant);
+ }
- fill_accounts_listbox (panel);
+ image = gtk_image_new_from_gicon (icon);
+ gtk_image_set_icon_size (GTK_IMAGE (image), GTK_ICON_SIZE_LARGE);
+ gtk_widget_add_css_class (image, "lowres-icon");
+ adw_action_row_add_prefix (ADW_ACTION_ROW (row), image);
- gtk_widget_show (GTK_WIDGET (panel));
-}
+ adw_preferences_row_set_title (ADW_PREFERENCES_ROW (row), name);
-static const char *
-cc_goa_panel_get_help_uri (CcPanel *panel)
-{
- return "help:gnome-help/accounts";
+ gtk_list_box_append (self->providers_listbox, row);
}
static void
-cc_goa_panel_constructed (GObject *object)
+list_providers (CcGoaPanel *self)
{
- CcGoaPanel *self = CC_GOA_PANEL (object);
- GtkWindow *parent;
-
- /* Setup account editor dialog */
- parent = GTK_WINDOW (cc_shell_get_toplevel (cc_panel_get_shell (CC_PANEL (self))));
-
- gtk_window_set_transient_for (GTK_WINDOW (self->edit_account_dialog), parent);
+ g_autoptr(GVariant) providers_variant = NULL;
+ g_autoptr(GError) error = NULL;
+ g_autofree char *providers = NULL;
+ GVariantIter iter;
+ GVariant *provider;
+
+ providers = run_goa_helper_sync ("list-providers", NULL);
+ providers_variant = g_variant_parse (G_VARIANT_TYPE ("a(ssviu)"),
+ providers,
+ NULL,
+ NULL,
+ &error);
+
+ if (error)
+ {
+ g_warning ("Error listing providers: %s", error->message);
+ return;
+ }
- goa_provider_get_all (get_all_providers_cb, g_object_ref_sink (self));
+ g_variant_iter_init (&iter, providers_variant);
- G_OBJECT_CLASS (cc_goa_panel_parent_class)->constructed (object);
+ while ((provider = g_variant_iter_next_value (&iter)))
+ add_provider_row (self, provider);
}
static void
-cc_goa_panel_class_init (CcGoaPanelClass *klass)
+add_account (CcGoaPanel *self,
+ GoaObject *object)
{
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- CcPanelClass *panel_class = CC_PANEL_CLASS (klass);
-
- panel_class->get_help_uri = cc_goa_panel_get_help_uri;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GIcon) gicon = NULL;
+ GoaAccount *account;
+ GtkWidget *row, *icon;
- object_class->set_property = cc_goa_panel_set_property;
- object_class->finalize = cc_goa_panel_finalize;
- object_class->constructed = cc_goa_panel_constructed;
- object_class->dispose = cc_goa_panel_dispose;
+ account = goa_object_peek_account (object);
- g_object_class_override_property (object_class, PROP_PARAMETERS, "parameters");
+ row = adw_action_row_new ();
+ g_object_set_data (G_OBJECT (row), "goa-object", object);
+ gtk_list_box_row_set_activatable (GTK_LIST_BOX_ROW (row), TRUE);
- gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/online-accounts/online-accounts.ui");
+ adw_preferences_row_set_title (ADW_PREFERENCES_ROW (row),
+ goa_account_get_provider_name (account));
+ adw_action_row_set_subtitle (ADW_ACTION_ROW (row),
+ goa_account_get_presentation_identity (account));
- gtk_widget_class_bind_template_child (widget_class, CcGoaPanel, accounts_frame);
- gtk_widget_class_bind_template_child (widget_class, CcGoaPanel, accounts_listbox);
- gtk_widget_class_bind_template_child (widget_class, CcGoaPanel, accounts_vbox);
- gtk_widget_class_bind_template_child (widget_class, CcGoaPanel, edit_account_dialog);
- gtk_widget_class_bind_template_child (widget_class, CcGoaPanel, edit_account_headerbar);
- gtk_widget_class_bind_template_child (widget_class, CcGoaPanel, editor_box);
- gtk_widget_class_bind_template_child (widget_class, CcGoaPanel, new_account_vbox);
- gtk_widget_class_bind_template_child (widget_class, CcGoaPanel, notification_label);
- gtk_widget_class_bind_template_child (widget_class, CcGoaPanel, notification_revealer);
- gtk_widget_class_bind_template_child (widget_class, CcGoaPanel, offline_label);
- gtk_widget_class_bind_template_child (widget_class, CcGoaPanel, providers_listbox);
- gtk_widget_class_bind_template_child (widget_class, CcGoaPanel, remove_account_button);
- gtk_widget_class_bind_template_child (widget_class, CcGoaPanel, stack);
+ /* The provider icon */
+ icon = gtk_image_new ();
+ gtk_widget_add_css_class (icon, "lowres-icon");
+ gtk_image_set_icon_size (GTK_IMAGE (icon), GTK_ICON_SIZE_LARGE);
- gtk_widget_class_bind_template_callback (widget_class, on_edit_account_dialog_delete_event);
- gtk_widget_class_bind_template_callback (widget_class, on_listbox_row_activated);
- gtk_widget_class_bind_template_callback (widget_class, on_notification_closed);
- gtk_widget_class_bind_template_callback (widget_class, on_provider_row_activated);
- gtk_widget_class_bind_template_callback (widget_class, on_remove_button_clicked);
- gtk_widget_class_bind_template_callback (widget_class, on_undo_button_clicked);
-}
+ gicon = g_icon_new_for_string (goa_account_get_provider_icon (account), &error);
+ if (error != NULL)
+ {
+ g_warning ("Error creating GIcon for account: %s (%s, %d)",
+ error->message,
+ g_quark_to_string (error->domain),
+ error->code);
+ }
+ else
+ {
+ gtk_image_set_from_gicon (GTK_IMAGE (icon), gicon);
+ }
+ adw_action_row_add_prefix (ADW_ACTION_ROW (row), icon);
-/* ---------------------------------------------------------------------------------------------------- */
+ /* "Needs attention" icon */
+ icon = gtk_image_new_from_icon_name ("dialog-warning-symbolic");
+ g_object_bind_property (account,
+ "attention-needed",
+ icon,
+ "visible",
+ G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
+ adw_action_row_add_suffix (ADW_ACTION_ROW (row), icon);
-static void
-show_page_nothing_selected (CcGoaPanel *panel)
-{
+ /* Add to the listbox */
+ gtk_list_box_append (self->accounts_listbox, row);
+ gtk_widget_show (GTK_WIDGET (self->accounts_frame));
}
static void
-show_page_account (CcGoaPanel *panel,
- GoaObject *object)
+fill_accounts_listbox (CcGoaPanel *self)
{
- GList *children;
+ g_autolist(GoaAccount) accounts = NULL;
GList *l;
- GoaProvider *provider;
- GoaAccount *account;
- gboolean is_locked;
- const gchar *provider_name;
- const gchar *provider_type;
- gchar *title;
- provider = NULL;
-
- panel->active_object = object;
- reset_headerbar (panel);
+ accounts = goa_client_get_accounts (self->client);
- /* Move to the account editor page */
- gtk_stack_set_visible_child (panel->stack, GTK_WIDGET (panel->editor_box));
+ for (l = accounts; l != NULL; l = l->next)
+ add_account (self, l->data);
+}
- /* Out with the old */
- children = gtk_container_get_children (GTK_CONTAINER (panel->accounts_vbox));
- for (l = children; l != NULL; l = l->next)
- gtk_container_remove (GTK_CONTAINER (panel->accounts_vbox), GTK_WIDGET (l->data));
- g_list_free (children);
+#ifdef GDK_WINDOWING_WAYLAND
+static void
+wayland_window_exported_cb (GdkToplevel *toplevel,
+ const char *handle,
+ gpointer data)
- account = goa_object_peek_account (object);
+{
+ CcGoaPanel *self = data;
- is_locked = goa_account_get_is_locked (account);
- gtk_widget_set_visible (GTK_WIDGET (panel->remove_account_button), !is_locked);
+ self->window_export_handle = g_strdup_printf ("wayland:%s", handle);
+}
+#endif
- provider_type = goa_account_get_provider_type (account);
- provider = goa_provider_get_for_provider_type (provider_type);
+static void
+export_window_handle (CcGoaPanel *self)
+{
+ GtkNative *native = gtk_widget_get_native (GTK_WIDGET (self));
- if (provider != NULL)
+#ifdef GDK_WINDOWING_X11
+ if (GDK_IS_X11_DISPLAY (gtk_widget_get_display (GTK_WIDGET (native))))
{
- goa_provider_show_account (provider,
- panel->client,
- object,
- panel->accounts_vbox,
- 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 (GTK_WIDGET (panel->accounts_vbox));
+ 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);
- provider_name = goa_account_get_provider_name (account);
- /* 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"), provider_name);
- gtk_header_bar_set_title (panel->edit_account_headerbar, title);
- g_free (title);
+ gdk_wayland_toplevel_export_handle (GDK_TOPLEVEL (surface),
+ wayland_window_exported_cb,
+ self,
+ NULL);
+ }
+#endif
+}
- /* Reset the dialog size */
- gtk_window_resize (GTK_WINDOW (panel->edit_account_dialog), 1, 1);
+static void
+unexport_window_handle (CcGoaPanel *self)
+{
+ if (!self->window_export_handle)
+ return;
- gtk_widget_show (GTK_WIDGET (panel->accounts_vbox));
- gtk_widget_show (GTK_WIDGET (panel->edit_account_dialog));
+#ifdef GDK_WINDOWING_WAYLAND
+ GtkNative *native = gtk_widget_get_native (GTK_WIDGET (self));
- g_clear_object (&provider);
+ 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
}
-/* ---------------------------------------------------------------------------------------------------- */
-
static void
-select_account_by_id (CcGoaPanel *panel,
+select_account_by_id (CcGoaPanel *self,
const gchar *account_id)
{
- GList *children, *l;
-
- children = gtk_container_get_children (GTK_CONTAINER (panel->accounts_listbox));
+ GtkWidget *child;
- for (l = children; l != NULL; l = l->next)
+ for (child = gtk_widget_get_first_child (GTK_WIDGET (self->accounts_listbox));
+ child;
+ child = gtk_widget_get_next_sibling (child))
{
GoaAccount *account;
GoaObject *row_object;
- row_object = g_object_get_data (l->data, "goa-object");
+ row_object = g_object_get_data (G_OBJECT (child), "goa-object");
account = goa_object_peek_account (row_object);
if (g_strcmp0 (goa_account_get_id (account), account_id) == 0)
{
- show_page_account (panel, row_object);
+ show_account (self, row_object);
break;
}
}
-
- g_list_free (children);
}
-static gboolean
-on_edit_account_dialog_delete_event (CcGoaPanel *self)
+static void
+command_add (CcGoaPanel *self,
+ GVariant *parameters)
{
- self->active_object = NULL;
- gtk_widget_hide (GTK_WIDGET (self->edit_account_dialog));
- return TRUE;
+ const gchar *provider_name = NULL;
+ GVariant *v = NULL;
+
+ g_assert (self != NULL);
+ g_assert (parameters != NULL);
+
+ switch (g_variant_n_children (parameters))
+ {
+ case 2:
+ g_variant_get_child (parameters, 1, "v", &v);
+ if (g_variant_is_of_type (v, G_VARIANT_TYPE_STRING))
+ provider_name = g_variant_get_string (v, NULL);
+ else
+ g_warning ("Wrong type for the second argument (provider name) GVariant, expected 's' but got '%s'",
+ (gchar *)g_variant_get_type (v));
+ g_variant_unref (v);
+ break;
+
+ default:
+ g_warning ("Unexpected parameters found, ignore request");
+ return;
+ }
+
+ if (provider_name != NULL)
+ {
+ GtkWidget *child;
+ GVariant *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;
+
+ provider = g_object_get_data (G_OBJECT (child), "goa-provider");
+ g_variant_get (provider, "(ssviu)", &provider_type, NULL, NULL, NULL, NULL);
+
+ if (g_strcmp0 (provider_type, provider_name) == 0)
+ break;
+ }
+
+ if (child == NULL)
+ {
+ g_warning ("Unable to get a provider for type '%s'", provider_name);
+ return;
+ }
+
+ create_account (self, provider);
+ }
}
-static void
-on_listbox_row_activated (CcGoaPanel *self,
- GtkListBoxRow *activated_row)
+/* Callbacks */
+
+static gint
+sort_accounts_func (GtkListBoxRow *a,
+ GtkListBoxRow *b,
+ gpointer user_data)
{
- GoaObject *object;
+ GoaAccount *a_account, *b_account;
+ GoaObject *a_object, *b_object;
+
+ a_object = g_object_get_data (G_OBJECT (a), "goa-object");
+ a_account = goa_object_peek_account (a_object);
+
+ b_object = g_object_get_data (G_OBJECT (b), "goa-object");
+ b_account = goa_object_peek_account (b_object);
- object = g_object_get_data (G_OBJECT (activated_row), "goa-object");
- show_page_account (self, object);
+ return g_strcmp0 (goa_account_get_id (a_account), goa_account_get_id (b_account));
}
-static void
-fill_accounts_listbox (CcGoaPanel *self)
+static gint
+sort_providers_func (GtkListBoxRow *a,
+ GtkListBoxRow *b,
+ gpointer user_data)
{
- GList *accounts, *l;
+ GVariant *a_provider, *b_provider;
+ gboolean a_branded, b_branded;
+ gint a_features, b_features;
- accounts = goa_client_get_accounts (self->client);
+ a_provider = g_object_get_data (G_OBJECT (a), "goa-provider");
+ b_provider = g_object_get_data (G_OBJECT (b), "goa-provider");
- if (accounts == NULL)
- {
- show_page_nothing_selected (self);
- }
- else
+ 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
+
+ if (a_branded != b_branded)
{
- for (l = accounts; l != NULL; l = l->next)
- on_account_added (self->client, l->data, self);
+ if (a_branded)
+ return -1;
+ else
+ return 1;
}
- g_list_free_full (accounts, g_object_unref);
+ return gtk_list_box_row_get_index (b) - gtk_list_box_row_get_index (a);
}
-/* ---------------------------------------------------------------------------------------------------- */
-
-typedef void (*RowForAccountCallback) (CcGoaPanel *self, GtkWidget *row, GList *other_rows);
-
static void
-hide_row_for_account (CcGoaPanel *self, GtkWidget *row, GList *other_rows)
+on_account_added_cb (GoaClient *client,
+ GoaObject *object,
+ CcGoaPanel *self)
{
- gtk_widget_hide (row);
- gtk_widget_set_visible (GTK_WIDGET (self->accounts_frame), other_rows != NULL);
+ add_account (self, object);
}
static void
-remove_row_for_account (CcGoaPanel *self, GtkWidget *row, GList *other_rows)
+on_account_changed_cb (GoaClient *client,
+ GoaObject *object,
+ CcGoaPanel *self)
{
- gtk_widget_destroy (row);
- gtk_widget_set_visible (GTK_WIDGET (self->accounts_frame), other_rows != NULL);
+ if (self->active_object == object)
+ show_account (self, self->active_object);
}
static void
-show_row_for_account (CcGoaPanel *self, GtkWidget *row, GList *other_rows)
+on_account_removed_cb (GoaClient *client,
+ GoaObject *object,
+ CcGoaPanel *self)
{
- gtk_widget_show (row);
- gtk_widget_show (GTK_WIDGET (self->accounts_frame));
+ modify_row_for_account (self, object, remove_row_for_account_cb);
}
static void
-modify_row_for_account (CcGoaPanel *self,
- GoaObject *object,
- RowForAccountCallback callback)
+on_accounts_listbox_row_activated (CcGoaPanel *self,
+ GtkListBoxRow *activated_row)
{
- GList *children, *l;
+ GoaObject *object = g_object_get_data (G_OBJECT (activated_row), "goa-object");
- children = gtk_container_get_children (GTK_CONTAINER (self->accounts_listbox));
+ show_account (self, object);
+}
- for (l = children; l != NULL; l = l->next)
- {
- GoaObject *row_object;
+static void
+on_client_remove_account_finish_cb (GoaAccount *account,
+ GAsyncResult *res,
+ CcGoaPanel *self)
+{
+ g_autoptr(GError) error = NULL;
- row_object = g_object_get_data (G_OBJECT (l->data), "goa-object");
- if (row_object == object)
- {
- GtkWidget *row = GTK_WIDGET (l->data);
+ goa_account_call_remove_finish (account, res, &error);
- children = g_list_remove_link (children, l);
- callback (self, row, children);
- g_list_free (l);
- break;
- }
+ if (error)
+ {
+ GtkWidget *dialog;
+ dialog = gtk_message_dialog_new (GTK_WINDOW (cc_shell_get_toplevel (cc_panel_get_shell (CC_PANEL (self)))),
+ GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ _("Error removing account"));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ "%s",
+ error->message);
+ gtk_window_present (GTK_WINDOW (dialog));
}
- g_list_free (children);
+ g_object_unref (self);
}
-/* ---------------------------------------------------------------------------------------------------- */
-
static void
-on_account_added (GoaClient *client,
- GoaObject *object,
- gpointer user_data)
+on_notification_closed_cb (GtkButton *button,
+ CcGoaPanel *self)
{
- CcGoaPanel *self = user_data;
- GtkWidget *row, *icon, *label, *box;
- GoaAccount *account;
- GIcon *gicon;
- gchar* title = NULL;
- g_autoptr(GError) error = NULL;
-
- account = goa_object_peek_account (object);
+ goa_account_call_remove (goa_object_peek_account (self->removed_object),
+ cc_panel_get_cancellable (CC_PANEL (self)),
+ (GAsyncReadyCallback) on_client_remove_account_finish_cb,
+ g_object_ref (self));
- /* The main grid */
- box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
- gtk_widget_show (box);
+ gtk_revealer_set_reveal_child (self->notification_revealer, FALSE);
- /* The provider icon */
- icon = gtk_image_new ();
- gtk_widget_show (icon);
+ cancel_notification_timeout (self);
+ self->removed_object = NULL;
+}
- gicon = g_icon_new_for_string (goa_account_get_provider_icon (account), &error);
- if (error != NULL)
- {
- g_warning ("Error creating GIcon for account: %s (%s, %d)",
- error->message,
- g_quark_to_string (error->domain),
- error->code);
- }
- else
- {
- gtk_image_set_from_gicon (GTK_IMAGE (icon), gicon, GTK_ICON_SIZE_DIALOG);
- }
+static void
+on_undo_button_clicked_cb (GtkButton *button,
+ CcGoaPanel *self)
+{
+ /* Simply show the account row and hide the notification */
+ modify_row_for_account (self, self->removed_object, show_row_for_account_cb);
+ gtk_revealer_set_reveal_child (self->notification_revealer, FALSE);
- g_object_set (icon, "margin", 6, NULL);
+ cancel_notification_timeout (self);
+ self->removed_object = NULL;
+}
- gtk_container_add (GTK_CONTAINER (box), icon);
+static void
+on_provider_row_activated_cb (CcGoaPanel *self,
+ GtkListBoxRow *activated_row)
+{
+ GVariant *provider = g_object_get_data (G_OBJECT (activated_row), "goa-provider");
- /* The name of the provider */
- title = g_strdup_printf ("<b>%s</b>\n<small>%s</small>",
- goa_account_get_provider_name (account),
- goa_account_get_presentation_identity (account));
+ create_account (self, provider);
+}
- label = gtk_label_new (NULL);
- gtk_label_set_markup (GTK_LABEL (label), title);
- gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
- gtk_label_set_xalign (GTK_LABEL (label), 0.0);
- gtk_widget_set_hexpand (label, TRUE);
- gtk_widget_show (label);
- gtk_container_add (GTK_CONTAINER (box), label);
+static gboolean
+remove_account_timeout_cb (gpointer user_data)
+{
+ CcGoaPanel *self = CC_GOA_PANEL (user_data);
- /* "Needs attention" icon */
- icon = gtk_image_new_from_icon_name ("dialog-warning-symbolic", GTK_ICON_SIZE_BUTTON);
- gtk_widget_hide (icon);
- g_object_set (icon, "margin_end", 30, NULL);
- g_object_bind_property (goa_object_peek_account (object),
- "attention-needed",
- icon,
- "visible",
- G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
- gtk_container_add (GTK_CONTAINER (box), icon);
+ gtk_widget_activate (self->close_notification_button);
- /* The row */
- row = gtk_list_box_row_new ();
- gtk_widget_show (row);
- g_object_set_data (G_OBJECT (row), "goa-object", object);
- gtk_container_add (GTK_CONTAINER (row), box);
+ return G_SOURCE_REMOVE;
+}
- /* Add to the listbox */
- gtk_container_add (GTK_CONTAINER (self->accounts_listbox), row);
- gtk_widget_show (GTK_WIDGET (self->accounts_frame));
+/* CcPanel overrides */
- g_clear_pointer (&title, g_free);
- g_clear_object (&gicon);
+static const char *
+cc_goa_panel_get_help_uri (CcPanel *panel)
+{
+ return "help:gnome-help/accounts";
}
+/* GtkWidget overrides */
+
static void
-on_account_changed (GoaClient *client,
- GoaObject *object,
- gpointer user_data)
+cc_goa_panel_realize (GtkWidget *widget)
{
- CcGoaPanel *panel = CC_GOA_PANEL (user_data);
+ GTK_WIDGET_CLASS (cc_goa_panel_parent_class)->realize (widget);
- if (panel->active_object != object)
- return;
-
- show_page_account (panel, panel->active_object);
+ export_window_handle (CC_GOA_PANEL (widget));
}
static void
-on_account_removed (GoaClient *client,
- GoaObject *object,
- gpointer user_data)
+cc_goa_panel_unrealize (GtkWidget *widget)
{
- CcGoaPanel *self = user_data;
- modify_row_for_account (self, object, remove_row_for_account);
+ unexport_window_handle (CC_GOA_PANEL (widget));
+
+ GTK_WIDGET_CLASS (cc_goa_panel_parent_class)->unrealize (widget);
}
-/* ---------------------------------------------------------------------------------------------------- */
+/* GObject overrides */
static void
-get_all_providers_cb (GObject *source,
- GAsyncResult *res,
- gpointer user_data)
+cc_goa_panel_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
{
- g_autoptr(CcGoaPanel) self = user_data;
- GList *providers;
- GList *l;
- g_autoptr(GError) error = NULL;
-
- providers = NULL;
- if (!goa_provider_get_all_finish (&providers, res, &error))
+ switch (property_id)
{
- if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
- g_warning ("Failed to get GOA providers: %s", error->message);
+ case PROP_PARAMETERS:
+ {
+ GVariant *parameters, *v;
+ const gchar *first_arg = NULL;
- return;
- }
+ parameters = g_value_get_variant (value);
+ if (parameters == NULL)
+ return;
- for (l = providers; l != NULL; l = l->next)
- {
- GoaProvider *provider;
- provider = GOA_PROVIDER (l->data);
+ if (g_variant_n_children (parameters) > 0)
+ {
+ g_variant_get_child (parameters, 0, "v", &v);
+ if (g_variant_is_of_type (v, G_VARIANT_TYPE_STRING))
+ first_arg = g_variant_get_string (v, NULL);
+ else
+ g_warning ("Wrong type for the second argument GVariant, expected 's' but got '%s'",
+ (gchar *)g_variant_get_type (v));
+ g_variant_unref (v);
+ }
- add_provider_row (self, provider);
+ if (g_strcmp0 (first_arg, "add") == 0)
+ command_add (CC_GOA_PANEL (object), parameters);
+ else if (first_arg != NULL)
+ select_account_by_id (CC_GOA_PANEL (object), first_arg);
+
+ return;
+ }
}
- g_list_free_full (providers, g_object_unref);
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
static void
-cancel_notification_timeout (CcGoaPanel *self)
+cc_goa_panel_constructed (GObject *object)
{
- if (self->remove_account_timeout_id == 0)
- return;
+ CcGoaPanel *self = CC_GOA_PANEL (object);
- g_source_remove (self->remove_account_timeout_id);
+ G_OBJECT_CLASS (cc_goa_panel_parent_class)->constructed (object);
- self->remove_account_timeout_id = 0;
+ list_providers (self);
}
static void
-remove_account_cb (GoaAccount *account,
- GAsyncResult *res,
- gpointer user_data)
+cc_goa_panel_finalize (GObject *object)
{
- CcGoaPanel *panel = CC_GOA_PANEL (user_data);
- g_autoptr(GError) error = NULL;
+ CcGoaPanel *panel = CC_GOA_PANEL (object);
- if (!goa_account_call_remove_finish (account, res, &error))
+ if (panel->removed_object != NULL)
{
- GtkWidget *dialog;
- dialog = gtk_message_dialog_new (GTK_WINDOW (cc_shell_get_toplevel (cc_panel_get_shell (CC_PANEL (panel)))),
- GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
- GTK_MESSAGE_ERROR,
- GTK_BUTTONS_CLOSE,
- _("Error removing account"));
- gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
- "%s",
- error->message);
- gtk_widget_show (dialog);
- gtk_dialog_run (GTK_DIALOG (dialog));
- gtk_widget_destroy (dialog);
+ g_autoptr(GError) error = NULL;
+ goa_account_call_remove_sync (goa_object_peek_account (panel->removed_object),
+ NULL, /* GCancellable */
+ &error);
+
+ if (error != NULL)
+ {
+ g_warning ("Error removing account: %s (%s, %d)",
+ error->message,
+ g_quark_to_string (error->domain),
+ error->code);
+ }
}
- g_object_unref (panel);
+
+ g_clear_object (&panel->client);
+
+ G_OBJECT_CLASS (cc_goa_panel_parent_class)->finalize (object);
}
static void
-on_notification_closed (GtkButton *button,
- CcGoaPanel *self)
+cc_goa_panel_class_init (CcGoaPanelClass *klass)
{
- goa_account_call_remove (goa_object_peek_account (self->removed_object),
- cc_panel_get_cancellable (CC_PANEL (self)),
- (GAsyncReadyCallback) remove_account_cb,
- g_object_ref (self));
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ CcPanelClass *panel_class = CC_PANEL_CLASS (klass);
- gtk_revealer_set_reveal_child (self->notification_revealer, FALSE);
+ panel_class->get_help_uri = cc_goa_panel_get_help_uri;
- cancel_notification_timeout (self);
- self->removed_object = NULL;
-}
+ object_class->set_property = cc_goa_panel_set_property;
+ object_class->finalize = cc_goa_panel_finalize;
+ object_class->constructed = cc_goa_panel_constructed;
-static void
-on_undo_button_clicked (GtkButton *button,
- CcGoaPanel *self)
-{
- /* Simply show the account row and hide the notification */
- modify_row_for_account (self, self->removed_object, show_row_for_account);
- gtk_revealer_set_reveal_child (self->notification_revealer, FALSE);
+ widget_class->realize = cc_goa_panel_realize;
+ widget_class->unrealize = cc_goa_panel_unrealize;
- cancel_notification_timeout (self);
- self->removed_object = NULL;
-}
+ g_object_class_override_property (object_class, PROP_PARAMETERS, "parameters");
-static gboolean
-on_remove_account_timeout (gpointer user_data)
-{
- on_notification_closed (NULL, user_data);
- return G_SOURCE_REMOVE;
+ gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/online-accounts/cc-online-accounts-panel.ui");
+
+ gtk_widget_class_bind_template_child (widget_class, CcGoaPanel, accounts_frame);
+ gtk_widget_class_bind_template_child (widget_class, CcGoaPanel, accounts_listbox);
+ gtk_widget_class_bind_template_child (widget_class, CcGoaPanel, close_notification_button);
+ gtk_widget_class_bind_template_child (widget_class, CcGoaPanel, notification_label);
+ gtk_widget_class_bind_template_child (widget_class, CcGoaPanel, notification_revealer);
+ gtk_widget_class_bind_template_child (widget_class, CcGoaPanel, offline_label);
+ gtk_widget_class_bind_template_child (widget_class, CcGoaPanel, providers_listbox);
+
+ gtk_widget_class_bind_template_callback (widget_class, on_accounts_listbox_row_activated);
+ gtk_widget_class_bind_template_callback (widget_class, on_notification_closed_cb);
+ gtk_widget_class_bind_template_callback (widget_class, on_provider_row_activated_cb);
+ gtk_widget_class_bind_template_callback (widget_class, on_undo_button_clicked_cb);
}
static void
-on_remove_button_clicked (CcGoaPanel *panel)
+cc_goa_panel_init (CcGoaPanel *self)
{
- GoaAccount *account;
- g_autofree gchar *id = NULL;
- g_autofree gchar *label = NULL;
+ g_autoptr(GError) error = NULL;
+ GNetworkMonitor *monitor;
- if (panel->active_object == NULL)
- return;
+ g_resources_register (cc_online_accounts_get_resource ());
- if (panel->removed_object != NULL)
- on_notification_closed (NULL, panel);
+ gtk_widget_init_template (GTK_WIDGET (self));
- panel->removed_object = panel->active_object;
- panel->active_object = NULL;
+ gtk_list_box_set_sort_func (self->accounts_listbox,
+ sort_accounts_func,
+ self,
+ NULL);
- account = goa_object_peek_account (panel->removed_object);
- id = g_strdup_printf ("<b>%s</b>", goa_account_get_presentation_identity (account));
- /* Translators: The %s is the username (eg., debarshi.ray@gmail.com
- * or rishi).
- */
- label = g_strdup_printf (_("%s removed"), id);
- gtk_label_set_markup (panel->notification_label, label);
- gtk_revealer_set_reveal_child (panel->notification_revealer, TRUE);
+ gtk_list_box_set_sort_func (self->providers_listbox,
+ sort_providers_func,
+ self,
+ NULL);
- modify_row_for_account (panel, panel->removed_object, hide_row_for_account);
- gtk_widget_hide (GTK_WIDGET (panel->edit_account_dialog));
+ monitor = g_network_monitor_get_default();
+ g_object_bind_property (monitor,
+ "network-available",
+ self->offline_label,
+ "visible",
+ G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN);
+
+ g_object_bind_property (monitor,
+ "network-available",
+ self->providers_listbox,
+ "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 (self->client,
+ "account-added",
+ G_CALLBACK (on_account_added_cb),
+ self);
+
+ g_signal_connect (self->client,
+ "account-changed",
+ G_CALLBACK (on_account_changed_cb),
+ self);
+
+ g_signal_connect (self->client,
+ "account-removed",
+ G_CALLBACK (on_account_removed_cb),
+ self);
- panel->remove_account_timeout_id = g_timeout_add_seconds (10, on_remove_account_timeout, panel);
+ fill_accounts_listbox (self);
}
diff --git a/panels/online-accounts/cc-online-accounts-panel.ui b/panels/online-accounts/cc-online-accounts-panel.ui
new file mode 100644
index 000000000..a248db96d
--- /dev/null
+++ b/panels/online-accounts/cc-online-accounts-panel.ui
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="CcGoaPanel" parent="CcPanel">
+ <child>
+ <object class="GtkOverlay">
+ <child type="overlay">
+ <object class="GtkRevealer" id="notification_revealer">
+ <property name="halign">center</property>
+ <property name="valign">start</property>
+ <property name="transition_type">slide-down</property>
+ <child>
+ <object class="GtkFrame">
+ <child>
+ <object class="GtkBox">
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="notification_label">
+ <property name="use_markup">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="undo_button">
+ <property name="label" translatable="yes">Undo</property>
+ <signal name="clicked" handler="on_undo_button_clicked_cb" object="CcGoaPanel" swapped="no" />
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="close_notification_button">
+ <property name="icon-name">window-close-symbolic</property>
+ <signal name="clicked" handler="on_notification_closed_cb" object="CcGoaPanel" swapped="no" />
+ <style>
+ <class name="flat" />
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ <style>
+ <class name="app-notification" />
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+
+ <child>
+ <object class="AdwPreferencesPage">
+
+ <child>
+ <object class="AdwPreferencesGroup">
+ <child>
+ <object class="GtkLabel" id="accounts_label">
+ <property name="wrap">True</property>
+ <property name="justify">center</property>
+ <property name="label" translatable="yes">Connect to your data in the cloud</property>
+ <style>
+ <class name="title-1" />
+ </style>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkLabel" id="offline_label">
+ <property name="margin-top">24</property>
+ <property name="wrap">True</property>
+ <property name="label" translatable="yes">No internet connection — connect to set up new online accounts</property>
+ </object>
+ </child>
+ </object>
+ </child>
+
+ <child>
+ <object class="AdwPreferencesGroup" id="accounts_frame">
+ <child>
+ <object class="GtkListBox" id="accounts_listbox">
+ <property name="hexpand">True</property>
+ <property name="selection_mode">none</property>
+ <signal name="row-activated" handler="on_accounts_listbox_row_activated" object="CcGoaPanel" swapped="yes" />
+ <style>
+ <class name="boxed-list" />
+ </style>
+ <accessibility>
+ <relation name="labelled-by">accounts_label</relation>
+ </accessibility>
+ </object>
+ </child>
+ </object>
+ </child>
+
+ <child>
+ <object class="AdwPreferencesGroup">
+ <property name="title" translatable="yes">Add an account</property>
+ <child>
+ <object class="GtkListBox" id="providers_listbox">
+ <property name="selection_mode">none</property>
+ <signal name="row-activated" handler="on_provider_row_activated_cb" object="CcGoaPanel" swapped="yes" />
+ <style>
+ <class name="boxed-list" />
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+
+</interface>
diff --git a/panels/online-accounts/gnome-control-center-goa-helper.c b/panels/online-accounts/gnome-control-center-goa-helper.c
new file mode 100644
index 000000000..d37f4ff90
--- /dev/null
+++ b/panels/online-accounts/gnome-control-center-goa-helper.c
@@ -0,0 +1,491 @@
+/*
+ * 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, 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.ControlCenter.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);
+
+ 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 (GtkButton *button,
+ 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_peek_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);
+ 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 (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.ControlCenter.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, },
+};
+
+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;
+
+ 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;
+}
diff --git a/panels/online-accounts/meson.build b/panels/online-accounts/meson.build
index 687097724..bf2c302fb 100644
--- a/panels/online-accounts/meson.build
+++ b/panels/online-accounts/meson.build
@@ -16,9 +16,13 @@ i18n.merge_file(
install_dir: control_center_desktopdir
)
+cflags += [
+ '-DLIBEXECDIR="@0@"'.format(control_center_libexecdir),
+]
+
sources = files('cc-online-accounts-panel.c')
-resource_data = files('online-accounts.ui')
+resource_data = files('cc-online-accounts-panel.ui')
sources += gnome.compile_resources(
'cc-' + cappletname + '-resources',
@@ -30,7 +34,6 @@ sources += gnome.compile_resources(
deps = common_deps + [
goa_dep,
- dependency('goa-backend-1.0', version: goa_req_version)
]
panels_libs += static_library(
@@ -41,4 +44,32 @@ 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')
diff --git a/panels/online-accounts/online-accounts.gresource.xml b/panels/online-accounts/online-accounts.gresource.xml
index b428394d2..a82edbec7 100644
--- a/panels/online-accounts/online-accounts.gresource.xml
+++ b/panels/online-accounts/online-accounts.gresource.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/gnome/control-center/online-accounts">
- <file preprocess="xml-stripblanks">online-accounts.ui</file>
+ <file preprocess="xml-stripblanks">cc-online-accounts-panel.ui</file>
</gresource>
</gresources>
diff --git a/panels/online-accounts/online-accounts.ui b/panels/online-accounts/online-accounts.ui
deleted file mode 100644
index c0dfb54c9..000000000
--- a/panels/online-accounts/online-accounts.ui
+++ /dev/null
@@ -1,237 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<interface>
- <!-- interface-requires gtk+ 3.0 -->
- <template class="CcGoaPanel" parent="CcPanel">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <child>
- <object class="GtkOverlay">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <child type="overlay">
- <object class="GtkRevealer" id="notification_revealer">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">center</property>
- <property name="valign">start</property>
- <property name="transition_type">slide-down</property>
- <child>
- <object class="GtkFrame">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <child>
- <object class="GtkBox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="spacing">12</property>
- <child>
- <object class="GtkLabel" id="notification_label">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="use_markup">True</property>
- </object>
- </child>
- <child>
- <object class="GtkButton" id="undo_button">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Undo</property>
- <signal name="clicked" handler="on_undo_button_clicked" object="CcGoaPanel" swapped="no" />
- </object>
- </child>
- <child>
- <object class="GtkButton">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="relief">none</property>
- <signal name="clicked" handler="on_notification_closed" object="CcGoaPanel" swapped="no" />
- <child>
- <object class="GtkImage">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="icon-name">window-close-symbolic</property>
- </object>
- </child>
- </object>
- </child>
- </object>
- </child>
- <style>
- <class name="app-notification" />
- </style>
- </object>
- </child>
- </object>
- </child>
- <child>
- <object class="GtkScrolledWindow">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="hscrollbar_policy">never</property>
- <property name="min_content_height">500</property>
- <child>
- <object class="HdyClamp">
- <property name="visible">True</property>
- <property name="margin_top">32</property>
- <property name="margin_bottom">32</property>
- <property name="margin_start">12</property>
- <property name="margin_end">12</property>
-
- <child>
- <object class="GtkBox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="spacing">12</property>
- <property name="orientation">vertical</property>
- <property name="hexpand">True</property>
-
- <child>
- <object class="GtkLabel" id="accounts_label">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="wrap">True</property>
- <property name="justify">center</property>
- <property name="label" translatable="yes">Connect to your data in the cloud</property>
- <property name="margin_bottom">20</property>
- <attributes>
- <attribute name="scale" value="1.66" />
- </attributes>
- <accessibility>
- <relation target="accounts_listbox" type="label-for"/>
- </accessibility>
- </object>
- </child>
- <child>
- <object class="GtkLabel" id="offline_label">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="wrap">True</property>
- <property name="label" translatable="yes">No internet connection — connect to set up new online accounts</property>
- </object>
- </child>
- <child>
- <object class="GtkFrame" id="accounts_frame">
- <property name="can_focus">False</property>
- <child>
- <object class="GtkListBox" id="accounts_listbox">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="selection_mode">none</property>
- <signal name="row-activated" handler="on_listbox_row_activated" object="CcGoaPanel" swapped="yes" />
- <accessibility>
- <relation target="accounts_label" type="labelled-by"/>
- </accessibility>
- </object>
- </child>
- </object>
- </child>
- <child>
- <object class="GtkLabel" id="providers_label">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin-top">20</property>
- <property name="xalign">0</property>
- <property name="label" translatable="yes">Add an account</property>
- <attributes>
- <attribute name="weight" value="bold" />
- </attributes>
- <accessibility>
- <relation target="providers_listbox" type="label-for"/>
- </accessibility>
- </object>
- </child>
- <child>
- <object class="GtkFrame">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <child>
- <object class="GtkListBox" id="providers_listbox">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="selection_mode">none</property>
- <signal name="row-activated" handler="on_provider_row_activated" object="CcGoaPanel" swapped="yes" />
- <accessibility>
- <relation target="providers_label" type="labelled-by"/>
- </accessibility>
- </object>
- </child>
- </object>
- </child>
- </object>
- </child>
- </object>
- </child>
- </object>
- </child>
- </object>
- </child>
- </template>
- <object class="GtkDialog" id="edit_account_dialog">
- <property name="can_focus">False</property>
- <property name="type_hint">dialog</property>
- <property name="use_header_bar">1</property>
- <property name="resizable">False</property>
- <property name="modal">True</property>
- <signal name="delete-event" handler="on_edit_account_dialog_delete_event" object="CcGoaPanel" swapped="yes" />
- <child type="titlebar">
- <object class="GtkHeaderBar" id="edit_account_headerbar">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="show_close_button">True</property>
- </object>
- </child>
- <child internal-child="vbox">
- <object class="GtkBox">
- <property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- <property name="border_width">0</property>
- <child>
- <object class="GtkStack" id="stack">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="transition_type">crossfade</property>
- <property name="homogeneous">False</property>
- <child>
- <object class="GtkBox" id="new_account_vbox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- </object>
- </child>
- <child>
- <object class="GtkBox" id="editor_box">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin-bottom">24</property>
- <property name="spacing">42</property>
- <property name="orientation">vertical</property>
- <child>
- <object class="GtkBox" id="accounts_vbox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="vexpand">True</property>
- <property name="orientation">vertical</property>
- </object>
- </child>
- <child>
- <object class="GtkButton" id="remove_account_button">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="margin-start">24</property>
- <property name="margin-end">24</property>
- <property name="valign">end</property>
- <property name="halign">end</property>
- <property name="label" translatable="yes">Remove Account</property>
- <signal name="clicked" handler="on_remove_button_clicked" object="CcGoaPanel" swapped="yes" />
- <style>
- <class name="destructive-action" />
- </style>
- </object>
- </child>
- </object>
- </child>
- </object>
- </child>
- </object>
- </child>
- </object>
-</interface>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index e48012cbc..15696c19b 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -156,8 +156,9 @@ panels/notifications/cc-notifications-panel.c
panels/notifications/cc-notifications-panel.ui
panels/notifications/gnome-notifications-panel.desktop.in.in
panels/online-accounts/cc-online-accounts-panel.c
+panels/online-accounts/cc-online-accounts-panel.ui
+panels/online-accounts/gnome-control-center-goa-helper.c
panels/online-accounts/gnome-online-accounts-panel.desktop.in.in
-panels/online-accounts/online-accounts.ui
panels/power/cc-battery-row.c
panels/power/cc-power-panel.c
panels/power/cc-power-panel.ui
diff --git a/shell/cc-panel-loader.c b/shell/cc-panel-loader.c
index 403a44267..ee1c1fd72 100644
--- a/shell/cc-panel-loader.c
+++ b/shell/cc-panel-loader.c
@@ -49,7 +49,7 @@ extern GType cc_network_panel_get_type (void);
extern GType cc_wifi_panel_get_type (void);
#endif /* BUILD_NETWORK */
extern GType cc_notifications_panel_get_type (void);
-//extern GType cc_goa_panel_get_type (void);
+extern GType cc_goa_panel_get_type (void);
extern GType cc_power_panel_get_type (void);
extern GType cc_printers_panel_get_type (void);
extern GType cc_region_panel_get_type (void);
@@ -120,7 +120,7 @@ static CcPanelLoaderVtable default_panels[] =
PANEL_TYPE("wifi", cc_wifi_panel_get_type, cc_wifi_panel_static_init_func),
#endif
PANEL_TYPE("notifications", cc_notifications_panel_get_type, NULL),
- //PANEL_TYPE("online-accounts", cc_goa_panel_get_type, NULL),
+ PANEL_TYPE("online-accounts", cc_goa_panel_get_type, NULL),
PANEL_TYPE("power", cc_power_panel_get_type, NULL),
PANEL_TYPE("printers", cc_printers_panel_get_type, NULL),
PANEL_TYPE("region", cc_region_panel_get_type, NULL),