From e05fb7b3e36c052baf0dd607ddeb22c0a2b5cbde Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:47:04 +0200 Subject: Adding upstream version 43.2. Signed-off-by: Daniel Baumann --- .../pages/account/gis-account-page-local.c | 721 +++++++++++++++++++++ 1 file changed, 721 insertions(+) create mode 100644 gnome-initial-setup/pages/account/gis-account-page-local.c (limited to 'gnome-initial-setup/pages/account/gis-account-page-local.c') diff --git a/gnome-initial-setup/pages/account/gis-account-page-local.c b/gnome-initial-setup/pages/account/gis-account-page-local.c new file mode 100644 index 0000000..21bb597 --- /dev/null +++ b/gnome-initial-setup/pages/account/gis-account-page-local.c @@ -0,0 +1,721 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* + * Copyright (C) 2013 Red Hat + * + * 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, see . + * + * Written by: + * Jasper St. Pierre + */ + +#include "config.h" + +#include "gis-page.h" +#include "gis-account-page-local.h" +#include "gnome-initial-setup.h" + +#include +#include + +#include +#include +#include "um-utils.h" +#include "um-photo-dialog.h" + +#include "gis-page-header.h" + +#define GOA_API_IS_SUBJECT_TO_CHANGE +#include + +#include +#include + +#define VALIDATION_TIMEOUT 600 + +struct _GisAccountPageLocal +{ + AdwBin parent; + + GtkWidget *avatar_button; + GtkWidget *avatar_image; + GtkWidget *header; + GtkWidget *fullname_entry; + GtkWidget *username_combo; + GtkWidget *enable_parental_controls_box; + GtkWidget *enable_parental_controls_check_button; + gboolean has_custom_username; + GtkWidget *username_explanation; + UmPhotoDialog *photo_dialog; + + gint timeout_id; + + GdkPixbuf *avatar_pixbuf; + gchar *avatar_filename; + + ActUserManager *act_client; + + GoaClient *goa_client; + + gboolean valid_name; + gboolean valid_username; + ActUserAccountType account_type; +}; + +G_DEFINE_TYPE (GisAccountPageLocal, gis_account_page_local, ADW_TYPE_BIN); + +enum { + VALIDATION_CHANGED, + MAIN_USER_CREATED, + PARENT_USER_CREATED, + CONFIRM, + LAST_SIGNAL, +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +static void +validation_changed (GisAccountPageLocal *page) +{ + g_signal_emit (page, signals[VALIDATION_CHANGED], 0); +} + +static gboolean +get_profile_sync (const gchar *access_token, + gchar **out_name, + gchar **out_picture, + GCancellable *cancellable, + GError **error) +{ + GError *identity_error; + RestProxy *proxy; + RestProxyCall *call; + JsonParser *parser; + JsonObject *json_object; + gboolean ret; + + ret = FALSE; + + identity_error = NULL; + proxy = NULL; + call = NULL; + parser = NULL; + + /* TODO: cancellable */ + + proxy = rest_proxy_new ("https://www.googleapis.com/oauth2/v2/userinfo", FALSE); + call = rest_proxy_new_call (proxy); + rest_proxy_call_set_method (call, "GET"); + rest_proxy_call_add_param (call, "access_token", access_token); + + if (!rest_proxy_call_sync (call, error)) + goto out; + + if (rest_proxy_call_get_status_code (call) != 200) + { + g_set_error (error, + GOA_ERROR, + GOA_ERROR_FAILED, + "Expected status 200 when requesting your identity, instead got status %d (%s)", + rest_proxy_call_get_status_code (call), + rest_proxy_call_get_status_message (call)); + goto out; + } + + parser = json_parser_new (); + if (!json_parser_load_from_data (parser, + rest_proxy_call_get_payload (call), + rest_proxy_call_get_payload_length (call), + &identity_error)) + { + g_warning ("json_parser_load_from_data() failed: %s (%s, %d)", + identity_error->message, + g_quark_to_string (identity_error->domain), + identity_error->code); + g_set_error (error, + GOA_ERROR, + GOA_ERROR_FAILED, + "Could not parse response"); + goto out; + } + + ret = TRUE; + + json_object = json_node_get_object (json_parser_get_root (parser)); + if (out_name != NULL) + *out_name = g_strdup (json_object_get_string_member (json_object, "name")); + + if (out_picture != NULL) + *out_picture = g_strdup (json_object_get_string_member (json_object, "picture")); + + out: + g_clear_error (&identity_error); + if (call != NULL) + g_object_unref (call); + if (proxy != NULL) + g_object_unref (proxy); + + return ret; +} + +static void +prepopulate_account_page (GisAccountPageLocal *page) +{ + gchar *name = NULL; + gchar *picture = NULL; + GdkPixbuf *pixbuf = NULL; + + if (page->goa_client) { + GList *accounts, *l; + accounts = goa_client_get_accounts (page->goa_client); + for (l = accounts; l != NULL; l = l->next) { + GoaOAuth2Based *oa2; + oa2 = goa_object_get_oauth2_based (GOA_OBJECT (l->data)); + if (oa2) { + gchar *token = NULL; + GError *error = NULL; + if (!goa_oauth2_based_call_get_access_token_sync (oa2, &token, NULL, NULL, &error)) + { + g_warning ("Couldn't get oauth2 token: %s", error->message); + g_error_free (error); + } + else if (!get_profile_sync (token, &name, &picture, NULL, &error)) + { + g_warning ("Couldn't get profile information: %s", error->message); + g_error_free (error); + } + /* FIXME: collect information from more than one account + * and present at least the pictures in the avatar chooser + */ + break; + } + } + g_list_free_full (accounts, (GDestroyNotify) g_object_unref); + } + + if (name) { + g_object_set (page->header, "subtitle", _("Please check the name and username. You can choose a picture too."), NULL); + gtk_editable_set_text (GTK_EDITABLE (page->fullname_entry), name); + } + + if (picture) { + GFile *file; + GFileInputStream *stream; + GError *error = NULL; + file = g_file_new_for_uri (picture); + stream = g_file_read (file, NULL, &error); + if (!stream) + { + g_warning ("Failed to read picture %s: %s", picture, error->message); + g_error_free (error); + } + else + { + pixbuf = gdk_pixbuf_new_from_stream_at_scale (G_INPUT_STREAM (stream), -1, 96, TRUE, NULL, NULL); + g_object_unref (stream); + } + g_object_unref (file); + } + + if (pixbuf) { + GdkPixbuf *rounded = round_image (pixbuf); + + gtk_image_set_from_pixbuf (GTK_IMAGE (page->avatar_image), rounded); + g_object_unref (rounded); + page->avatar_pixbuf = pixbuf; + } + + g_free (name); + g_free (picture); +} + +static void +accounts_changed (GoaClient *client, GoaObject *object, gpointer data) +{ + GisAccountPageLocal *page = data; + + prepopulate_account_page (page); +} + +static gboolean +validate (GisAccountPageLocal *page) +{ + GtkWidget *entry; + const gchar *name, *username; + gboolean parental_controls_enabled; + gchar *tip; + + g_clear_handle_id (&page->timeout_id, g_source_remove); + + entry = gtk_combo_box_get_child (GTK_COMBO_BOX (page->username_combo)); + + name = gtk_editable_get_text (GTK_EDITABLE (page->fullname_entry)); + username = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (page->username_combo)); +#ifdef HAVE_PARENTAL_CONTROLS + parental_controls_enabled = gtk_check_button_get_active (GTK_CHECK_BUTTON (page->enable_parental_controls_check_button)); +#else + parental_controls_enabled = FALSE; +#endif + + page->valid_name = is_valid_name (name); + if (page->valid_name) + set_entry_validation_checkmark (GTK_ENTRY (page->fullname_entry)); + + page->valid_username = is_valid_username (username, parental_controls_enabled, &tip); + if (page->valid_username) + set_entry_validation_checkmark (GTK_ENTRY (entry)); + + gtk_label_set_text (GTK_LABEL (page->username_explanation), tip); + g_free (tip); + + um_photo_dialog_generate_avatar (page->photo_dialog, name); + + validation_changed (page); + + return G_SOURCE_REMOVE; +} + +static gboolean +on_focusout (GisAccountPageLocal *page) +{ + validate (page); + + return FALSE; +} + +static void +fullname_changed (GtkWidget *w, + GParamSpec *pspec, + GisAccountPageLocal *page) +{ + GtkWidget *entry; + GtkTreeModel *model; + const char *name; + + name = gtk_editable_get_text (GTK_EDITABLE (w)); + + entry = gtk_combo_box_get_child (GTK_COMBO_BOX (page->username_combo)); + model = gtk_combo_box_get_model (GTK_COMBO_BOX (page->username_combo)); + + gtk_list_store_clear (GTK_LIST_STORE (model)); + + if ((name == NULL || strlen (name) == 0) && !page->has_custom_username) { + gtk_editable_set_text (GTK_EDITABLE (entry), ""); + } + else if (name != NULL && strlen (name) != 0) { + generate_username_choices (name, GTK_LIST_STORE (model)); + if (!page->has_custom_username) + gtk_combo_box_set_active (GTK_COMBO_BOX (page->username_combo), 0); + } + + clear_entry_validation_error (GTK_ENTRY (w)); + + page->valid_name = FALSE; + + /* username_changed() is called consequently due to changes */ +} + +static void +username_changed (GtkComboBoxText *combo, + GisAccountPageLocal *page) +{ + GtkWidget *entry; + const gchar *username; + + entry = gtk_combo_box_get_child (GTK_COMBO_BOX (combo)); + username = gtk_editable_get_text (GTK_EDITABLE (entry)); + if (*username == '\0') + page->has_custom_username = FALSE; + else if (gtk_widget_has_focus (entry) || + gtk_combo_box_get_active (GTK_COMBO_BOX (page->username_combo)) > 0) + page->has_custom_username = TRUE; + + clear_entry_validation_error (GTK_ENTRY (entry)); + + page->valid_username = FALSE; + validation_changed (page); + + if (page->timeout_id != 0) + g_source_remove (page->timeout_id); + page->timeout_id = g_timeout_add (VALIDATION_TIMEOUT, (GSourceFunc)validate, page); +} + +static void +avatar_callback (GdkPixbuf *pixbuf, + const gchar *filename, + gpointer user_data) +{ + GisAccountPageLocal *page = user_data; + g_autoptr(GdkPixbuf) tmp = NULL; + g_autoptr(GdkPixbuf) rounded = NULL; + + g_clear_object (&page->avatar_pixbuf); + g_clear_pointer (&page->avatar_filename, g_free); + + if (pixbuf) { + page->avatar_pixbuf = g_object_ref (pixbuf); + rounded = round_image (pixbuf); + } + else if (filename) { + page->avatar_filename = g_strdup (filename); + tmp = gdk_pixbuf_new_from_file_at_size (filename, 96, 96, NULL); + + if (tmp != NULL) + rounded = round_image (tmp); + } + + if (rounded != NULL) { + gtk_image_set_from_pixbuf (GTK_IMAGE (page->avatar_image), rounded); + } + else { + /* Fallback. */ + gtk_image_set_pixel_size (GTK_IMAGE (page->avatar_image), 96); + gtk_image_set_from_icon_name (GTK_IMAGE (page->avatar_image), "avatar-default-symbolic"); + } +} + +static void +confirm (GisAccountPageLocal *page) +{ + if (gis_account_page_local_validate (page)) + g_signal_emit (page, signals[CONFIRM], 0); +} + +static void +enable_parental_controls_check_button_toggled_cb (GtkCheckButton *check_button, + gpointer user_data) +{ + GisAccountPageLocal *page = GIS_ACCOUNT_PAGE_LOCAL (user_data); + gboolean parental_controls_enabled = gtk_check_button_get_active (GTK_CHECK_BUTTON (page->enable_parental_controls_check_button)); + + /* This sets the account type of the main user. When we save_data(), we create + * two users if parental controls are enabled: the first user is always an + * admin, and the second user is the main user using this @account_type. */ + page->account_type = parental_controls_enabled ? ACT_USER_ACCOUNT_TYPE_STANDARD : ACT_USER_ACCOUNT_TYPE_ADMINISTRATOR; + + validate (page); +} + +static void +track_focus_out (GisAccountPageLocal *page, + GtkWidget *widget) +{ + GtkEventController *focus_controller; + + focus_controller = gtk_event_controller_focus_new (); + gtk_widget_add_controller (widget, focus_controller); + + g_signal_connect_swapped (focus_controller, "leave", G_CALLBACK (on_focusout), page); +} + + +static void +gis_account_page_local_constructed (GObject *object) +{ + GisAccountPageLocal *page = GIS_ACCOUNT_PAGE_LOCAL (object); + + G_OBJECT_CLASS (gis_account_page_local_parent_class)->constructed (object); + + page->act_client = act_user_manager_get_default (); + + g_signal_connect (page->fullname_entry, "notify::text", + G_CALLBACK (fullname_changed), page); + track_focus_out (page, page->fullname_entry); + + g_signal_connect_swapped (page->fullname_entry, "activate", + G_CALLBACK (validate), page); + g_signal_connect (page->username_combo, "changed", + G_CALLBACK (username_changed), page); + track_focus_out (page, page->username_combo); + + g_signal_connect_swapped (gtk_combo_box_get_child (GTK_COMBO_BOX (page->username_combo)), + "activate", G_CALLBACK (confirm), page); + g_signal_connect_swapped (page->fullname_entry, "activate", + G_CALLBACK (confirm), page); + g_signal_connect (page->enable_parental_controls_check_button, "toggled", + G_CALLBACK (enable_parental_controls_check_button_toggled_cb), page); + + /* Disable parental controls if support is not compiled in. */ +#ifndef HAVE_PARENTAL_CONTROLS + gtk_widget_hide (page->enable_parental_controls_box); +#endif + + page->valid_name = FALSE; + page->valid_username = FALSE; + + /* FIXME: change this for a large deployment scenario; maybe through a GSetting? */ + page->account_type = ACT_USER_ACCOUNT_TYPE_ADMINISTRATOR; + + g_object_set (page->header, "subtitle", _("We need a few details to complete setup."), NULL); + gtk_editable_set_text (GTK_EDITABLE (page->fullname_entry), ""); + gtk_list_store_clear (GTK_LIST_STORE (gtk_combo_box_get_model (GTK_COMBO_BOX (page->username_combo)))); + page->has_custom_username = FALSE; + + gtk_image_set_pixel_size (GTK_IMAGE (page->avatar_image), 96); + gtk_image_set_from_icon_name (GTK_IMAGE (page->avatar_image), "avatar-default-symbolic"); + + page->goa_client = goa_client_new_sync (NULL, NULL); + if (page->goa_client) { + g_signal_connect (page->goa_client, "account-added", + G_CALLBACK (accounts_changed), page); + g_signal_connect (page->goa_client, "account-removed", + G_CALLBACK (accounts_changed), page); + prepopulate_account_page (page); + } + + page->photo_dialog = um_photo_dialog_new (avatar_callback, page); + um_photo_dialog_generate_avatar (page->photo_dialog, ""); + gtk_menu_button_set_popover (GTK_MENU_BUTTON (page->avatar_button), + GTK_WIDGET (page->photo_dialog)); + + validate (page); +} + +static void +gis_account_page_local_dispose (GObject *object) +{ + GisAccountPageLocal *page = GIS_ACCOUNT_PAGE_LOCAL (object); + + g_clear_object (&page->goa_client); + g_clear_object (&page->avatar_pixbuf); + g_clear_pointer (&page->avatar_filename, g_free); + g_clear_handle_id (&page->timeout_id, g_source_remove); + + G_OBJECT_CLASS (gis_account_page_local_parent_class)->dispose (object); +} + +static void +set_user_avatar (GisAccountPageLocal *page, + ActUser *user) +{ + GFile *file = NULL; + GFileIOStream *io_stream = NULL; + GOutputStream *stream = NULL; + GError *error = NULL; + + if (page->avatar_filename != NULL) { + act_user_set_icon_file (user, page->avatar_filename); + return; + } + + if (page->avatar_pixbuf == NULL) { + return; + } + + file = g_file_new_tmp ("usericonXXXXXX", &io_stream, &error); + if (error != NULL) + goto out; + + stream = g_io_stream_get_output_stream (G_IO_STREAM (io_stream)); + if (!gdk_pixbuf_save_to_stream (page->avatar_pixbuf, stream, "png", NULL, &error, NULL)) + goto out; + + act_user_set_icon_file (user, g_file_get_path (file)); + + out: + if (error != NULL) { + g_warning ("failed to save image: %s", error->message); + g_error_free (error); + } + g_clear_object (&io_stream); + g_clear_object (&file); +} + +static gboolean +local_create_user (GisAccountPageLocal *local, + GisPage *page, + GError **error) +{ + const gchar *username; + const gchar *fullname; + gboolean parental_controls_enabled; + g_autoptr(ActUser) main_user = NULL; + g_autoptr(ActUser) parent_user = NULL; + + username = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (local->username_combo)); + fullname = gtk_editable_get_text (GTK_EDITABLE (local->fullname_entry)); + parental_controls_enabled = gis_driver_get_parental_controls_enabled (page->driver); + + /* Always create the admin user first, in case of failure part-way through + * this function, which would leave us with no admin user at all. */ + if (parental_controls_enabled) { + g_autoptr(GError) local_error = NULL; + g_autoptr(GDBusConnection) connection = NULL; + const gchar *parent_username = "administrator"; + const gchar *parent_fullname = _("Administrator"); + + parent_user = act_user_manager_create_user (local->act_client, parent_username, parent_fullname, ACT_USER_ACCOUNT_TYPE_ADMINISTRATOR, error); + if (parent_user == NULL) + { + g_prefix_error (error, + _("Failed to create user '%s': "), + parent_username); + return FALSE; + } + + /* Make the admin account usable in case g-i-s crashes. If all goes + * according to plan a password will be set on it in gis-password-page.c */ + act_user_set_password_mode (parent_user, ACT_USER_PASSWORD_MODE_SET_AT_LOGIN); + + /* Mark it as the parent user account. + * FIXME: This should be async. */ + connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &local_error); + if (connection != NULL) { + g_dbus_connection_call_sync (connection, + "org.freedesktop.Accounts", + act_user_get_object_path (parent_user), + "org.freedesktop.DBus.Properties", + "Set", + g_variant_new ("(ssv)", + "com.endlessm.ParentalControls.AccountInfo", + "IsParent", + g_variant_new_boolean (TRUE)), + NULL, /* reply type */ + G_DBUS_CALL_FLAGS_NONE, + -1, /* default timeout */ + NULL, /* cancellable */ + &local_error); + } + if (local_error != NULL) { + /* Make this non-fatal, since the correct accounts-service interface + * might not be installed, depending on which version of malcontent is installed. */ + g_warning ("Failed to mark user as parent: %s", local_error->message); + g_clear_error (&local_error); + } + + g_signal_emit (local, signals[PARENT_USER_CREATED], 0, parent_user, ""); + } + + /* Now create the main user. */ + main_user = act_user_manager_create_user (local->act_client, username, fullname, local->account_type, error); + if (main_user == NULL) + { + g_prefix_error (error, + _("Failed to create user '%s': "), + username); + /* FIXME: Could we delete the @parent_user at this point to reset the state + * and allow g-i-s to be run again after a reboot? */ + return FALSE; + } + + set_user_avatar (local, main_user); + + g_signal_emit (local, signals[MAIN_USER_CREATED], 0, main_user, ""); + + return TRUE; +} + +static void +gis_account_page_local_class_init (GisAccountPageLocalClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (klass), "/org/gnome/initial-setup/gis-account-page-local.ui"); + + gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GisAccountPageLocal, avatar_button); + gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GisAccountPageLocal, avatar_image); + gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GisAccountPageLocal, header); + gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GisAccountPageLocal, fullname_entry); + gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GisAccountPageLocal, username_combo); + gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GisAccountPageLocal, username_explanation); + gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GisAccountPageLocal, enable_parental_controls_box); + gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GisAccountPageLocal, enable_parental_controls_check_button); + + object_class->constructed = gis_account_page_local_constructed; + object_class->dispose = gis_account_page_local_dispose; + + signals[VALIDATION_CHANGED] = g_signal_new ("validation-changed", GIS_TYPE_ACCOUNT_PAGE_LOCAL, + G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, + G_TYPE_NONE, 0); + + signals[MAIN_USER_CREATED] = g_signal_new ("main-user-created", GIS_TYPE_ACCOUNT_PAGE_LOCAL, + G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, + G_TYPE_NONE, 2, ACT_TYPE_USER, G_TYPE_STRING); + + signals[PARENT_USER_CREATED] = g_signal_new ("parent-user-created", GIS_TYPE_ACCOUNT_PAGE_LOCAL, + G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, + G_TYPE_NONE, 2, ACT_TYPE_USER, G_TYPE_STRING); + + signals[CONFIRM] = g_signal_new ("confirm", GIS_TYPE_ACCOUNT_PAGE_LOCAL, + G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, + G_TYPE_NONE, 0); +} + +static void +gis_account_page_local_init (GisAccountPageLocal *page) +{ + g_type_ensure (GIS_TYPE_PAGE_HEADER); + gtk_widget_init_template (GTK_WIDGET (page)); +} + +gboolean +gis_account_page_local_validate (GisAccountPageLocal *page) +{ + return page->valid_name && page->valid_username; +} + +gboolean +gis_account_page_local_create_user (GisAccountPageLocal *local, + GisPage *page, + GError **error) +{ + return local_create_user (local, page, error); +} + +gboolean +gis_account_page_local_apply (GisAccountPageLocal *local, GisPage *page) +{ + const gchar *username, *full_name; + gboolean parental_controls_enabled; + + username = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (local->username_combo)); + gis_driver_set_username (GIS_PAGE (page)->driver, username); + + full_name = gtk_editable_get_text (GTK_EDITABLE (local->fullname_entry)); + gis_driver_set_full_name (GIS_PAGE (page)->driver, full_name); + + if (local->avatar_pixbuf != NULL) + { + g_autoptr(GdkTexture) texture = NULL; + + texture = gdk_texture_new_for_pixbuf (local->avatar_pixbuf); + gis_driver_set_avatar (GIS_PAGE (page)->driver, GDK_PAINTABLE (texture)); + } + else if (local->avatar_filename != NULL) + { + g_autoptr(GdkTexture) texture = NULL; + g_autoptr(GError) error = NULL; + + texture = gdk_texture_new_from_filename (local->avatar_filename, &error); + + if (!error) + gis_driver_set_avatar (GIS_PAGE (page)->driver, GDK_PAINTABLE (texture)); + else + g_warning ("Error loading avatar: %s", error->message); + } + +#ifdef HAVE_PARENTAL_CONTROLS + parental_controls_enabled = gtk_check_button_get_active (GTK_CHECK_BUTTON (local->enable_parental_controls_check_button)); +#else + parental_controls_enabled = FALSE; +#endif + gis_driver_set_parental_controls_enabled (GIS_PAGE (page)->driver, parental_controls_enabled); + + return FALSE; +} + +void +gis_account_page_local_shown (GisAccountPageLocal *local) +{ + gtk_widget_grab_focus (local->fullname_entry); +} -- cgit v1.2.3