diff options
author | Georges Basile Stavracas Neto <georges.stavracas@gmail.com> | 2022-01-17 16:05:05 -0300 |
---|---|---|
committer | Georges Basile Stavracas Neto <georges.stavracas@gmail.com> | 2022-01-17 19:42:10 -0300 |
commit | 946417990c23283b9aa013ca2d99eeed2a108c95 (patch) | |
tree | 8c4765ee945d9f9f4169d381b73a8999cc0eb4be | |
parent | fdda3e77f6b979eb335e87f9a5e3bb19e3b646cf (diff) | |
download | gnome-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.build | 2 | ||||
-rw-r--r-- | panels/online-accounts/cc-online-accounts-panel.c | 1330 | ||||
-rw-r--r-- | panels/online-accounts/cc-online-accounts-panel.ui | 111 | ||||
-rw-r--r-- | panels/online-accounts/gnome-control-center-goa-helper.c | 491 | ||||
-rw-r--r-- | panels/online-accounts/meson.build | 35 | ||||
-rw-r--r-- | panels/online-accounts/online-accounts.gresource.xml | 2 | ||||
-rw-r--r-- | panels/online-accounts/online-accounts.ui | 237 | ||||
-rw-r--r-- | po/POTFILES.in | 3 | ||||
-rw-r--r-- | shell/cc-panel-loader.c | 4 |
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), |