diff options
Diffstat (limited to '')
-rw-r--r-- | panels/user-accounts/cc-user-panel.c | 1603 |
1 files changed, 1603 insertions, 0 deletions
diff --git a/panels/user-accounts/cc-user-panel.c b/panels/user-accounts/cc-user-panel.c new file mode 100644 index 0000000..4eed0da --- /dev/null +++ b/panels/user-accounts/cc-user-panel.c @@ -0,0 +1,1603 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright 2009-2010 Red Hat, Inc, + * + * 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 <http://www.gnu.org/licenses/>. + * + * Written by: Matthias Clasen <mclasen@redhat.com> + */ + +#include "config.h" + +#include "cc-user-panel.h" + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <locale.h> +#include <errno.h> + +#include <glib.h> +#include <glib/gi18n.h> +#include <gtk/gtk.h> +#include <polkit/polkit.h> +#include <act/act.h> +#include <cairo-gobject.h> + +#define GNOME_DESKTOP_USE_UNSTABLE_API +#include <libgnome-desktop/gnome-languages.h> + +#ifdef HAVE_MALCONTENT +#include <libmalcontent/malcontent.h> +#endif + +#include "cc-add-user-dialog.h" +#include "cc-avatar-chooser.h" +#include "cc-language-chooser.h" +#include "cc-login-history-dialog.h" +#include "cc-password-dialog.h" +#include "cc-realm-manager.h" +#include "cc-user-accounts-resources.h" +#include "cc-fingerprint-manager.h" +#include "cc-fingerprint-dialog.h" +#include "user-utils.h" + +#include "cc-common-language.h" +#include "cc-permission-infobar.h" +#include "cc-util.h" + +#define USER_ACCOUNTS_PERMISSION "org.gnome.controlcenter.user-accounts.administration" + +struct _CcUserPanel { + CcPanel parent_instance; + + ActUserManager *um; + GSettings *login_screen_settings; + + GtkBox *account_settings_box; + GtkListBoxRow *account_type_row; + GtkSwitch *account_type_switch; + GtkWidget *add_user_button; + GtkListBoxRow *autologin_row; + GtkSwitch *autologin_switch; + GtkButton *back_button; + GtkLabel *fingerprint_state_label; + GtkListBoxRow *fingerprint_row; + GtkStack *full_name_stack; + GtkLabel *full_name_label; + GtkToggleButton *full_name_edit_button; + GtkEntry *full_name_entry; + GtkLabel *language_button_label; + GtkListBoxRow *language_row; + GtkLabel *last_login_button_label; + GtkListBoxRow *last_login_row; + GtkWidget *no_users_box; + GtkRevealer *notification_revealer; + AdwPreferencesGroup *other_users; + GtkListBox *other_users_listbox; + AdwPreferencesRow *other_users_row; + GtkLabel *password_button_label; +#ifdef HAVE_MALCONTENT + GtkLabel *parental_controls_button_label; + GtkListBoxRow *parental_controls_row; +#endif + GtkListBoxRow *password_row; + CcPermissionInfobar *permission_infobar; + GtkButton *remove_user_button; + GtkStack *stack; + AdwAvatar *user_avatar; + GtkMenuButton *user_avatar_edit_button; + GtkOverlay *users_overlay; + + ActUser *selected_user; + ActUser *pending_show_user; + GPermission *permission; + CcLanguageChooser *language_chooser; + GListStore *other_users_model; + + CcAvatarChooser *avatar_chooser; + + CcFingerprintManager *fingerprint_manager; +}; + +CC_PANEL_REGISTER (CcUserPanel, cc_user_panel) + +static void show_restart_notification (CcUserPanel *self, const gchar *locale); + +typedef struct { + CcUserPanel *self; + GCancellable *cancellable; + gchar *login; +} AsyncDeleteData; + +static void +async_delete_data_free (AsyncDeleteData *data) +{ + g_clear_object (&data->self); + g_clear_object (&data->cancellable); + g_clear_pointer (&data->login, g_free); + g_slice_free (AsyncDeleteData, data); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (AsyncDeleteData, async_delete_data_free) + +static void +show_error_dialog (CcUserPanel *self, + const gchar *message, + GError *error) +{ + GtkWidget *dialog; + + dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_native (GTK_WIDGET (self))), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_USE_HEADER_BAR, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + "%s", message); + + if (error != NULL) { + g_dbus_error_strip_remote_error (error); + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + "%s", error->message); + } + + g_signal_connect (dialog, "response", G_CALLBACK (gtk_window_destroy), NULL); + gtk_window_present (GTK_WINDOW (dialog)); +} + +static void show_user (ActUser *user, CcUserPanel *self); + +static ActUser * +get_selected_user (CcUserPanel *self) +{ + return self->selected_user; +} + +static void +set_selected_user (CcUserPanel *self, + AdwActionRow *row) +{ + uid_t uid; + + uid = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (row), "uid")); + g_set_object (&self->selected_user, + act_user_manager_get_user_by_id (self->um, uid)); + show_user (self->selected_user, self); +} + +static void +show_current_user (CcUserPanel *self) +{ + ActUser *user; + + user = act_user_manager_get_user_by_id (self->um, getuid ()); + if (user != NULL) + show_user (user, self); +} + + +static void +on_back_button_clicked_cb (CcUserPanel *self) +{ + + if (act_user_get_uid (self->selected_user) == getuid ()) { + gtk_widget_activate_action (GTK_WIDGET (self), + "window.navigate", + "i", + ADW_NAVIGATION_DIRECTION_BACK); + } else { + show_current_user (self); + } +} + +static const gchar * +get_real_or_user_name (ActUser *user) +{ + const gchar *name; + + name = act_user_get_real_name (user); + if (name == NULL) + name = act_user_get_user_name (user); + + return name; +} + +static void +setup_avatar_for_user (AdwAvatar *avatar, ActUser *user) +{ + const gchar *avatar_file; + + adw_avatar_set_custom_image (avatar, NULL); + adw_avatar_set_text (avatar, get_real_or_user_name (user)); + + avatar_file = act_user_get_icon_file (user); + if (avatar_file) { + g_autoptr(GdkPixbuf) pixbuf = NULL; + + pixbuf = gdk_pixbuf_new_from_file_at_size (avatar_file, + adw_avatar_get_size (avatar), + adw_avatar_get_size (avatar), + NULL); + if (pixbuf) { + adw_avatar_set_custom_image (avatar, + GDK_PAINTABLE (gdk_texture_new_for_pixbuf (pixbuf))); + } + } +} + +static GtkWidget * +create_user_row (gpointer item, + gpointer user_data) +{ + ActUser *user = ACT_USER (item); + GtkWidget *row, *user_image; + + row = adw_action_row_new (); + g_object_set_data (G_OBJECT (row), "uid", GINT_TO_POINTER (act_user_get_uid (user))); + gtk_list_box_row_set_activatable (GTK_LIST_BOX_ROW (row), TRUE); + adw_preferences_row_set_title (ADW_PREFERENCES_ROW (row), + get_real_or_user_name (user)); + user_image = adw_avatar_new (48, NULL, TRUE); + setup_avatar_for_user (ADW_AVATAR (user_image), user); + adw_action_row_add_prefix (ADW_ACTION_ROW (row), user_image); + + return row; +} + +static gint +sort_users (gconstpointer a, gconstpointer b, gpointer user_data) +{ + ActUser *ua, *ub; + + ua = ACT_USER (a); + ub = ACT_USER (b); + + /* Make sure the current user is shown first */ + if (act_user_get_uid (ua) == getuid ()) { + return -G_MAXINT32; + } + else if (act_user_get_uid (ub) == getuid ()) { + return G_MAXINT32; + } + else { + g_autofree gchar *name1 = NULL; + g_autofree gchar *name2 = NULL; + + name1 = g_utf8_collate_key (get_real_or_user_name (ua), -1); + name2 = g_utf8_collate_key (get_real_or_user_name (ub), -1); + + return strcmp (name1, name2); + } +} + +static void +user_changed (CcUserPanel *self, ActUser *user) +{ + GSList *user_list, *l; + gboolean show; + + g_list_store_remove_all (self->other_users_model); + user_list = act_user_manager_list_users (self->um); + for (l = user_list; l; l = l->next) { + ActUser *other_user = ACT_USER (l->data); + + if (act_user_is_system_account (other_user)) { + continue; + } + + if (act_user_get_uid (other_user) == getuid ()) { + continue; + } + + g_list_store_insert_sorted (self->other_users_model, + other_user, + sort_users, + self); + } + + if (self->selected_user == user) + show_user (user, self); + + show = g_list_model_get_n_items (G_LIST_MODEL (self->other_users_model)) > 0; + gtk_widget_set_visible (GTK_WIDGET (self->other_users_row), show); +} + +static void +on_add_user_dialog_response (CcUserPanel *self, + gint response, + CcAddUserDialog *dialog) +{ + ActUser *user; + + user = cc_add_user_dialog_get_user (dialog); + if (user != NULL) { + set_default_avatar (user); + show_user (user, self); + } + + gtk_window_destroy (GTK_WINDOW (dialog)); +} + +static void +add_user (CcUserPanel *self) +{ + CcAddUserDialog *dialog; + GtkWindow *toplevel; + + dialog = cc_add_user_dialog_new (self->permission); + toplevel = GTK_WINDOW (gtk_widget_get_native (GTK_WIDGET (self))); + gtk_window_set_transient_for (GTK_WINDOW (dialog), toplevel); + + gtk_window_present (GTK_WINDOW (dialog)); + g_signal_connect_object (dialog, "response", G_CALLBACK (on_add_user_dialog_response), + self, G_CONNECT_SWAPPED); +} + +static void +delete_user_done (ActUserManager *manager, + GAsyncResult *res, + CcUserPanel *self) +{ + g_autoptr(GError) error = NULL; + + if (!act_user_manager_delete_user_finish (manager, res, &error)) { + if (!g_error_matches (error, ACT_USER_MANAGER_ERROR, + ACT_USER_MANAGER_ERROR_PERMISSION_DENIED)) + show_error_dialog (self, _("Failed to delete user"), error); + } + + show_current_user (self); +} + +static void +delete_user_response (CcUserPanel *self, + gint response_id, + GtkWidget *dialog) +{ + ActUser *user; + gboolean remove_files; + + gtk_window_destroy (GTK_WINDOW (dialog)); + + if (response_id == GTK_RESPONSE_CANCEL) { + return; + } + else if (response_id == GTK_RESPONSE_NO) { + remove_files = TRUE; + } + else { + remove_files = FALSE; + } + + user = get_selected_user (self); + + /* remove autologin */ + if (act_user_get_automatic_login (user)) { + act_user_set_automatic_login (user, FALSE); + } + + act_user_manager_delete_user_async (self->um, + user, + remove_files, + NULL, + (GAsyncReadyCallback)delete_user_done, + self); +} + +static void +enterprise_user_revoked (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + g_autoptr(AsyncDeleteData) data = user_data; + CcUserPanel *self = data->self; + CcRealmCommon *common = CC_REALM_COMMON (source); + g_autoptr(GError) error = NULL; + + if (g_cancellable_is_cancelled (data->cancellable)) { + return; + } + + cc_realm_common_call_change_login_policy_finish (common, result, &error); + if (error != NULL) { + show_error_dialog (self, _("Failed to revoke remotely managed user"), error); + } +} + +static CcRealmCommon * +find_matching_realm (CcRealmManager *realm_manager, const gchar *login) +{ + CcRealmCommon *common = NULL; + GList *realms; + + realms = cc_realm_manager_get_realms (realm_manager); + for (GList *l = realms; l != NULL; l = g_list_next (l)) { + const gchar * const *permitted_logins; + gint i; + + common = cc_realm_object_get_common (l->data); + if (common == NULL) + continue; + + permitted_logins = cc_realm_common_get_permitted_logins (common); + for (i = 0; permitted_logins[i] != NULL; i++) { + if (g_strcmp0 (permitted_logins[i], login) == 0) + break; + } + + if (permitted_logins[i] != NULL) + break; + + g_clear_object (&common); + } + g_list_free_full (realms, g_object_unref); + + return common; +} + +static void +realm_manager_found (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + g_autoptr(AsyncDeleteData) data = user_data; + CcUserPanel *self = data->self; + g_autoptr(CcRealmCommon) common = NULL; + CcRealmManager *realm_manager; + const gchar *add[1]; + const gchar *remove[2]; + GVariant *options; + g_autoptr(GError) error = NULL; + + if (g_cancellable_is_cancelled (data->cancellable)) { + return; + } + + realm_manager = cc_realm_manager_new_finish (result, &error); + if (error != NULL) { + show_error_dialog (self, _("Failed to revoke remotely managed user"), error); + return; + } + + /* Find matching realm */ + common = find_matching_realm (realm_manager, data->login); + if (common == NULL) { + /* The realm was probably left */ + return; + } + + /* Remove the user from permitted logins */ + g_debug ("Denying future login for: %s", data->login); + + add[0] = NULL; + remove[0] = data->login; + remove[1] = NULL; + + options = g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0); + cc_realm_common_call_change_login_policy (common, "", + add, remove, options, + data->cancellable, + enterprise_user_revoked, + g_steal_pointer (&data)); +} + +static void +enterprise_user_uncached (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr(AsyncDeleteData) data = user_data; + CcUserPanel *self = data->self; + ActUserManager *manager = ACT_USER_MANAGER (source); + g_autoptr(GError) error = NULL; + + if (g_cancellable_is_cancelled (data->cancellable)) { + return; + } + + act_user_manager_uncache_user_finish (manager, res, &error); + if (error == NULL) { + /* Find realm manager */ + cc_realm_manager_new (cc_panel_get_cancellable (CC_PANEL (self)), realm_manager_found, g_steal_pointer (&data)); + } + else { + show_error_dialog (self, _("Failed to revoke remotely managed user"), error); + } +} + +static void +delete_enterprise_user_response (CcUserPanel *self, + gint response_id, + GtkWidget *dialog) +{ + AsyncDeleteData *data; + ActUser *user; + + gtk_window_destroy (GTK_WINDOW (dialog)); + + if (response_id != GTK_RESPONSE_ACCEPT) { + return; + } + + user = get_selected_user (self); + + data = g_slice_new (AsyncDeleteData); + data->self = g_object_ref (self); + data->cancellable = g_object_ref (cc_panel_get_cancellable (CC_PANEL (self))); + data->login = g_strdup (act_user_get_user_name (user)); + + /* Uncache the user account from the accountsservice */ + g_debug ("Uncaching remote user: %s", data->login); + + act_user_manager_uncache_user_async (self->um, data->login, + data->cancellable, + enterprise_user_uncached, + data); +} + +static void +delete_user (CcUserPanel *self) +{ + ActUser *user; + GtkWidget *dialog; + + user = get_selected_user (self); + if (user == NULL) { + return; + } + else if (act_user_get_uid (user) == getuid ()) { + dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_native (GTK_WIDGET (self))), + 0, + GTK_MESSAGE_INFO, + GTK_BUTTONS_CLOSE, + _("You cannot delete your own account.")); + g_signal_connect (dialog, "response", + G_CALLBACK (gtk_window_destroy), NULL); + } + else if (act_user_is_logged_in_anywhere (user)) { + dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_native (GTK_WIDGET (self))), + 0, + GTK_MESSAGE_INFO, + GTK_BUTTONS_CLOSE, + _("%s is still logged in"), + get_real_or_user_name (user)); + + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + _("Deleting a user while they are logged in can leave the system in an inconsistent state.")); + g_signal_connect (dialog, "response", + G_CALLBACK (gtk_window_destroy), NULL); + } + else if (act_user_is_local_account (user)) { + dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_native (GTK_WIDGET (self))), + 0, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_NONE, + _("Do you want to keep %s’s files?"), + get_real_or_user_name (user)); + + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + _("It is possible to keep the home directory, mail spool and temporary files around when deleting a user account.")); + + gtk_dialog_add_buttons (GTK_DIALOG (dialog), + _("_Delete Files"), GTK_RESPONSE_NO, + _("_Keep Files"), GTK_RESPONSE_YES, + _("_Cancel"), GTK_RESPONSE_CANCEL, + NULL); + + gtk_window_set_icon_name (GTK_WINDOW (dialog), "system-users"); + + g_signal_connect_object (dialog, "response", + G_CALLBACK (delete_user_response), self, G_CONNECT_SWAPPED); + } + else { + dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_native (GTK_WIDGET (self))), + 0, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_NONE, + _("Are you sure you want to revoke remotely managed %s’s account?"), + get_real_or_user_name (user)); + + gtk_dialog_add_buttons (GTK_DIALOG (dialog), + _("_Delete"), GTK_RESPONSE_ACCEPT, + _("_Cancel"), GTK_RESPONSE_CANCEL, + NULL); + + gtk_window_set_icon_name (GTK_WINDOW (dialog), "system-users"); + + g_signal_connect_object (dialog, "response", + G_CALLBACK (delete_enterprise_user_response), self, G_CONNECT_SWAPPED); + } + + g_signal_connect (dialog, "close", + G_CALLBACK (gtk_window_destroy), NULL); + + gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); + + gtk_window_present (GTK_WINDOW (dialog)); +} + +static const gchar * +get_invisible_text (void) +{ + GtkWidget *entry; + gunichar invisible_char; + static gchar invisible_text[40]; + gchar *p; + gint i; + + entry = gtk_entry_new (); + invisible_char = gtk_entry_get_invisible_char (GTK_ENTRY (entry)); + if (invisible_char == 0) + invisible_char = 0x2022; + + g_object_ref_sink (entry); + g_object_unref (entry); + + /* five bullets */ + p = invisible_text; + for (i = 0; i < 5; i++) + p += g_unichar_to_utf8 (invisible_char, p); + *p = 0; + + return invisible_text; +} + +static const gchar * +get_password_mode_text (ActUser *user) +{ + const gchar *text; + + if (act_user_get_locked (user)) { + text = C_("Password mode", "Account disabled"); + } + else { + switch (act_user_get_password_mode (user)) { + case ACT_USER_PASSWORD_MODE_REGULAR: + text = get_invisible_text (); + break; + case ACT_USER_PASSWORD_MODE_SET_AT_LOGIN: + text = C_("Password mode", "To be set at next login"); + break; + case ACT_USER_PASSWORD_MODE_NONE: + text = C_("Password mode", "None"); + break; + default: + g_assert_not_reached (); + } + } + + return text; +} + +static void +autologin_changed (CcUserPanel *self) +{ + gboolean active; + ActUser *user; + + active = gtk_switch_get_active (self->autologin_switch); + user = get_selected_user (self); + + if (active != act_user_get_automatic_login (user)) { + act_user_set_automatic_login (user, active); + if (act_user_get_automatic_login (user)) { + GSList *list; + GSList *l; + list = act_user_manager_list_users (self->um); + for (l = list; l != NULL; l = l->next) { + ActUser *u = l->data; + if (act_user_get_uid (u) != act_user_get_uid (user)) { + act_user_set_automatic_login (user, FALSE); + } + } + g_slist_free (list); + } + } +} + +static gchar * +get_login_time_text (ActUser *user) +{ + gint64 time; + + time = act_user_get_login_time (user); + if (act_user_is_logged_in (user)) { + return g_strdup (_("Logged in")); + } + else if (time > 0) { + g_autoptr(GDateTime) date_time = NULL; + g_autofree gchar *date_str = NULL; + g_autofree gchar *time_str = NULL; + + date_time = g_date_time_new_from_unix_local (time); + date_str = cc_util_get_smart_date (date_time); + + /* Translators: This is a time format string in the style of "22:58". + It indicates a login time which follows a date. */ + time_str = g_date_time_format (date_time, C_("login date-time", "%k:%M")); + + /* Translators: This indicates a login date-time. + The first %s is a date, and the second %s a time. */ + return g_strdup_printf(C_("login date-time", "%s, %s"), date_str, time_str); + } + else { + return g_strdup ("—"); + } +} + +static gboolean +get_autologin_possible (ActUser *user) +{ + gboolean locked; + gboolean set_password_at_login; + + locked = act_user_get_locked (user); + set_password_at_login = (act_user_get_password_mode (user) == ACT_USER_PASSWORD_MODE_SET_AT_LOGIN); + + return !(locked || set_password_at_login); +} + +static void on_permission_changed (CcUserPanel *self); +static void full_name_edit_button_toggled (CcUserPanel *self); + +#ifdef HAVE_MALCONTENT +static gboolean +is_parental_controls_enabled_for_user (ActUser *user) +{ + g_autoptr(MctManager) manager = NULL; + g_autoptr(MctAppFilter) app_filter = NULL; + g_autoptr(GDBusConnection) system_bus = NULL; + g_autoptr(GError) error = NULL; + + /* FIXME: should become asynchronous */ + system_bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error); + if (system_bus == NULL) { + g_warning ("Error getting system bus while trying to show user details: %s", error->message); + return FALSE; + } + + manager = mct_manager_new (system_bus); + app_filter = mct_manager_get_app_filter (manager, + act_user_get_uid (user), + MCT_GET_APP_FILTER_FLAGS_NONE, + NULL, + &error); + if (error) { + if (!g_error_matches (error, MCT_MANAGER_ERROR, MCT_MANAGER_ERROR_DISABLED)) + g_warning ("Error retrieving app filter for user %s: %s", + act_user_get_user_name (user), + error->message); + + return FALSE; + } + + return mct_app_filter_is_enabled (app_filter); +} +#endif + +static void +update_fingerprint_row_state (CcUserPanel *self, GParamSpec *spec, CcFingerprintManager *fingerprint_manager) +{ + CcFingerprintState state = cc_fingerprint_manager_get_state (fingerprint_manager); + + if (state != CC_FINGERPRINT_STATE_UPDATING) { + gtk_widget_set_visible (GTK_WIDGET (self->fingerprint_row), + state != CC_FINGERPRINT_STATE_NONE); + } + + gtk_widget_set_sensitive (GTK_WIDGET (self->fingerprint_row), + state != CC_FINGERPRINT_STATE_UPDATING); + + if (state == CC_FINGERPRINT_STATE_ENABLED) + gtk_label_set_text (self->fingerprint_state_label, _("Enabled")); + else if (state == CC_FINGERPRINT_STATE_DISABLED) + gtk_label_set_text (self->fingerprint_state_label, _("Disabled")); +} + +static void +show_or_hide_back_button (CcUserPanel *self) +{ + gboolean show; + gboolean folded; + + g_object_get(self, "folded", &folded, NULL); + + show = folded || act_user_get_uid (self->selected_user) != getuid(); + + gtk_widget_set_visible (GTK_WIDGET (self->back_button), show); +} + +static void +on_pending_show_user_is_loaded (ActUser *user, + GParamSpec *param, + CcUserPanel *self) +{ + if (!act_user_is_loaded (user)) { + return; + } + + show_user (user, self); +} + +static void +show_user (ActUser *user, CcUserPanel *self) +{ + g_autofree gchar *lang = NULL; + g_autofree gchar *name = NULL; + gboolean show, enable; + ActUser *current; +#ifdef HAVE_MALCONTENT + g_autofree gchar *malcontent_control_path = NULL; +#endif + + if (self->pending_show_user != NULL) { + g_signal_handlers_disconnect_by_func (G_OBJECT (self->pending_show_user), + on_pending_show_user_is_loaded, + self); + g_clear_object (&self->pending_show_user); + } + + if (!act_user_is_loaded (user)) { + g_set_object (&self->pending_show_user, user); + g_signal_connect_object (G_OBJECT (self->pending_show_user), + "notify::is-loaded", + G_CALLBACK (on_pending_show_user_is_loaded), + self, + 0); + return; + } + + g_set_object (&self->selected_user, user); + + setup_avatar_for_user (self->user_avatar, user); + cc_avatar_chooser_set_user (self->avatar_chooser, user); + + gtk_label_set_label (self->full_name_label, get_real_or_user_name (user)); + gtk_editable_set_text (GTK_EDITABLE (self->full_name_entry), gtk_label_get_label (self->full_name_label)); + gtk_widget_set_tooltip_text (GTK_WIDGET (self->full_name_label), get_real_or_user_name (user)); + + g_signal_handlers_block_by_func (self->full_name_edit_button, full_name_edit_button_toggled, self); + gtk_stack_set_visible_child (self->full_name_stack, GTK_WIDGET (self->full_name_label)); + gtk_toggle_button_set_active (self->full_name_edit_button, FALSE); + g_signal_handlers_unblock_by_func (self->full_name_edit_button, full_name_edit_button_toggled, self); + + enable = (act_user_get_account_type (user) == ACT_USER_ACCOUNT_TYPE_ADMINISTRATOR); + gtk_switch_set_active (self->account_type_switch, enable); + + gtk_label_set_label (self->password_button_label, get_password_mode_text (user)); + enable = act_user_is_local_account (user); + gtk_widget_set_sensitive (GTK_WIDGET (self->password_button_label), enable); + + g_signal_handlers_block_by_func (self->autologin_switch, autologin_changed, self); + gtk_switch_set_active (self->autologin_switch, act_user_get_automatic_login (user)); + g_signal_handlers_unblock_by_func (self->autologin_switch, autologin_changed, self); + gtk_widget_set_sensitive (GTK_WIDGET (self->autologin_switch), get_autologin_possible (user)); + + lang = g_strdup (act_user_get_language (user)); + if (lang && *lang != '\0') { + name = gnome_get_language_from_locale (lang, NULL); + } else { + name = g_strdup ("—"); + } + gtk_label_set_label (self->language_button_label, name); + + /* Fingerprint: show when self, local, enabled, and possible */ + show = (act_user_get_uid (user) == getuid() && + act_user_is_local_account (user) && + (self->login_screen_settings && + g_settings_get_boolean (self->login_screen_settings, + "enable-fingerprint-authentication"))); + + if (show) { + if (!self->fingerprint_manager) { + self->fingerprint_manager = cc_fingerprint_manager_new (user); + g_signal_connect_object (self->fingerprint_manager, + "notify::state", + G_CALLBACK (update_fingerprint_row_state), + self, G_CONNECT_SWAPPED); + } + + update_fingerprint_row_state (self, NULL, self->fingerprint_manager); + } else { + gtk_widget_set_visible (GTK_WIDGET (self->fingerprint_row), FALSE); + } + + /* Autologin: show when local account */ + show = act_user_is_local_account (user); + gtk_widget_set_visible (GTK_WIDGET (self->autologin_row), show); + +#ifdef HAVE_MALCONTENT + /* Parental Controls: Unavailable if user is admin or if + * malcontent-control is not available (which can happen if + * libmalcontent is installed but malcontent-control is not). */ + malcontent_control_path = g_find_program_in_path ("malcontent-control"); + + if (act_user_get_account_type (user) == ACT_USER_ACCOUNT_TYPE_ADMINISTRATOR || + malcontent_control_path == NULL) { + gtk_widget_hide (GTK_WIDGET (self->parental_controls_row)); + } else { + GtkStyleContext *context = gtk_widget_get_style_context (GTK_WIDGET (self->parental_controls_button_label)); + + if (is_parental_controls_enabled_for_user (user)) + /* TRANSLATORS: Status of Parental Controls setup */ + gtk_label_set_text (self->parental_controls_button_label, _("Enabled")); + else + /* TRANSLATORS: Status of Parental Controls setup */ + gtk_label_set_text (self->parental_controls_button_label, _("Disabled")); + + gtk_style_context_remove_class (context, "dim-label"); + gtk_widget_show (GTK_WIDGET (self->parental_controls_row)); + } +#endif + + /* Current user */ + show = act_user_get_uid (user) == getuid(); + gtk_widget_set_visible (GTK_WIDGET (self->account_settings_box), !show); + gtk_widget_set_visible (GTK_WIDGET (self->remove_user_button), !show); + gtk_widget_set_visible (GTK_WIDGET (self->back_button), !show); + show_or_hide_back_button(self); + gtk_widget_set_visible (GTK_WIDGET (self->other_users), show); + + /* Last login: show when administrator or current user */ + current = act_user_manager_get_user_by_id (self->um, getuid ()); + show = act_user_get_uid (user) == getuid () || + act_user_get_account_type (current) == ACT_USER_ACCOUNT_TYPE_ADMINISTRATOR; + if (show) { + g_autofree gchar *text = NULL; + + text = get_login_time_text (user); + gtk_label_set_label (self->last_login_button_label, text); + } + gtk_widget_set_visible (GTK_WIDGET (self->last_login_row), show); + + enable = act_user_get_login_history (user) != NULL; + gtk_widget_set_sensitive (GTK_WIDGET (self->last_login_row), enable); + + if (self->permission != NULL) + on_permission_changed (self); +} + +static void +full_name_entry_activate (CcUserPanel *self) +{ + const gchar *text; + ActUser *user; + + user = get_selected_user (self); + text = gtk_editable_get_text (GTK_EDITABLE (self->full_name_entry)); + if (g_strcmp0 (text, act_user_get_real_name (user)) != 0 && + is_valid_name (text)) { + act_user_set_real_name (user, text); + } + + gtk_toggle_button_set_active (self->full_name_edit_button, FALSE); +} + +static void +full_name_edit_button_toggled (CcUserPanel *self) +{ + if (gtk_stack_get_visible_child (self->full_name_stack) == GTK_WIDGET (self->full_name_label)) { + gtk_stack_set_visible_child (self->full_name_stack, GTK_WIDGET (self->full_name_entry)); + + gtk_widget_grab_focus (GTK_WIDGET (self->full_name_entry)); + } else { + gtk_stack_set_visible_child (self->full_name_stack, GTK_WIDGET (self->full_name_label)); + + full_name_entry_activate (self); + } +} + +static gboolean +full_name_entry_key_press_cb (GtkEventController *controller, + guint keyval, + guint keycode, + GdkModifierType state, + CcUserPanel *self) +{ + if (keyval == GDK_KEY_Escape) { + gtk_editable_set_text (GTK_EDITABLE (self->full_name_entry), act_user_get_real_name (self->selected_user)); + + full_name_entry_activate (self); + + return TRUE; + } + + return FALSE; +} + +static void +account_type_changed (CcUserPanel *self) +{ + ActUser *user; + gboolean self_selected; + gboolean is_admin; + ActUserAccountType account_type; + + user = get_selected_user (self); + self_selected = act_user_get_uid (user) == geteuid (); + is_admin = gtk_switch_get_active (self->account_type_switch); + + account_type = is_admin ? ACT_USER_ACCOUNT_TYPE_ADMINISTRATOR : ACT_USER_ACCOUNT_TYPE_STANDARD; + if (account_type != act_user_get_account_type (user)) { + act_user_set_account_type (user, account_type); + + if (self_selected) + show_restart_notification (self, NULL); + } +} + +static void +dismiss_notification (CcUserPanel *self) +{ + gtk_revealer_set_reveal_child (self->notification_revealer, FALSE); +} + +static void +restart_now (CcUserPanel *self) +{ + g_autoptr(GDBusConnection) bus = NULL; + + gtk_revealer_set_reveal_child (self->notification_revealer, FALSE); + + bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL); + g_dbus_connection_call (bus, + "org.gnome.SessionManager", + "/org/gnome/SessionManager", + "org.gnome.SessionManager", + "Logout", + g_variant_new ("(u)", 0), + NULL, 0, G_MAXINT, + NULL, NULL, NULL); +} + +static void +show_restart_notification (CcUserPanel *self, const gchar *locale) +{ + locale_t current_locale; + locale_t new_locale; + + if (locale) { + new_locale = newlocale (LC_MESSAGES_MASK, locale, (locale_t) 0); + if (new_locale == (locale_t) 0) + g_warning ("Failed to create locale %s: %s", locale, g_strerror (errno)); + else + current_locale = uselocale (new_locale); + } + + gtk_revealer_set_reveal_child (self->notification_revealer, TRUE); + + if (locale && new_locale != (locale_t) 0) { + uselocale (current_locale); + freelocale (new_locale); + } +} + +static void +language_response (CcUserPanel *self, + gint response_id, + GtkDialog *dialog) +{ + ActUser *user; + const gchar *lang, *account_language; + + if (response_id != GTK_RESPONSE_OK) { + gtk_widget_hide (GTK_WIDGET (dialog)); + return; + } + + user = get_selected_user (self); + account_language = act_user_get_language (user); + + lang = cc_language_chooser_get_language (CC_LANGUAGE_CHOOSER (dialog)); + if (lang) { + g_autofree gchar *name = NULL; + if (g_strcmp0 (lang, account_language) != 0) { + act_user_set_language (user, lang); + } + + name = gnome_get_language_from_locale (lang, NULL); + gtk_label_set_label (self->language_button_label, name); + } + + gtk_widget_hide (GTK_WIDGET (dialog)); +} + +static void +change_language (CcUserPanel *self) +{ + const gchar *current_language; + ActUser *user; + + user = get_selected_user (self); + current_language = act_user_get_language (user); + + if (self->language_chooser) { + cc_language_chooser_clear_filter (self->language_chooser); + cc_language_chooser_set_language (self->language_chooser, NULL); + } + else { + self->language_chooser = cc_language_chooser_new (); + gtk_window_set_transient_for (GTK_WINDOW (self->language_chooser), + GTK_WINDOW (gtk_widget_get_native (GTK_WIDGET (self)))); + + g_signal_connect_object (self->language_chooser, "response", + G_CALLBACK (language_response), self, G_CONNECT_SWAPPED); + } + + if (current_language && *current_language != '\0') + cc_language_chooser_set_language (self->language_chooser, current_language); + gtk_window_present (GTK_WINDOW (self->language_chooser)); +} + +static void +change_password (CcUserPanel *self) +{ + ActUser *user; + CcPasswordDialog *dialog; + GtkWindow *parent; + + user = get_selected_user (self); + dialog = cc_password_dialog_new (user); + + parent = (GtkWindow *) gtk_widget_get_native (GTK_WIDGET (self)); + gtk_window_set_transient_for (GTK_WINDOW (dialog), parent); + + gtk_window_present (GTK_WINDOW (dialog)); +} + +static void +change_fingerprint (CcUserPanel *self) +{ + ActUser *user; + GtkWindow *parent; + CcFingerprintDialog *dialog; + + user = get_selected_user (self); + parent = (GtkWindow *) gtk_widget_get_native (GTK_WIDGET (self)); + + g_assert (g_strcmp0 (g_get_user_name (), act_user_get_user_name (user)) == 0); + + dialog = cc_fingerprint_dialog_new (self->fingerprint_manager); + gtk_window_set_transient_for (GTK_WINDOW (dialog), parent); + gtk_window_present (GTK_WINDOW (dialog)); +} + +static void +show_history (CcUserPanel *self) +{ + CcLoginHistoryDialog *dialog; + ActUser *user; + GtkWindow *parent; + + user = get_selected_user (self); + dialog = cc_login_history_dialog_new (user); + + parent = (GtkWindow *) gtk_widget_get_native (GTK_WIDGET (self)); + gtk_window_set_transient_for (GTK_WINDOW (dialog), parent); + + gtk_window_present (GTK_WINDOW (dialog)); +} + +#ifdef HAVE_MALCONTENT +static void +spawn_malcontent_control (CcUserPanel *self) +{ + ActUser *user; + + user = get_selected_user (self); + + /* no-op if the user is administrator */ + if (act_user_get_account_type (user) != ACT_USER_ACCOUNT_TYPE_ADMINISTRATOR) { + const gchar *argv[] = { + "malcontent-control", +#ifdef HAVE_MALCONTENT_0_10 + "--user", + act_user_get_user_name (user), +#endif /* HAVE_MALCONTENT_0_10 */ + NULL + }; + g_autoptr(GError) error = NULL; + if (!g_spawn_async (NULL, (char **)argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &error)) + g_debug ("Couldn't launch malcontent-control: %s", error->message); + } else { + g_debug ("Not launching malcontent because selected user is an admin"); + } +} +#endif + +static void +users_loaded (CcUserPanel *self) +{ + GtkWidget *dialog; + + if (act_user_manager_no_service (self->um)) { + GtkWidget *toplevel; + + toplevel = (GtkWidget *)gtk_widget_get_native (GTK_WIDGET (self)); + dialog = gtk_message_dialog_new (GTK_WINDOW (toplevel ), + GTK_DIALOG_MODAL, + GTK_MESSAGE_OTHER, + GTK_BUTTONS_CLOSE, + _("Failed to contact the accounts service")); + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + _("Please make sure that the AccountService is installed and enabled.")); + g_signal_connect (dialog, "response", + G_CALLBACK (gtk_window_destroy), + NULL); + gtk_widget_show (dialog); + + gtk_stack_set_visible_child (self->stack, self->no_users_box); + } else { + gtk_stack_set_visible_child (self->stack, GTK_WIDGET (self->users_overlay)); + show_current_user (self); + } + + g_signal_connect_object (self->um, "user-changed", G_CALLBACK (user_changed), self, G_CONNECT_SWAPPED); + g_signal_connect_object (self->um, "user-is-logged-in-changed", G_CALLBACK (user_changed), self, G_CONNECT_SWAPPED); + g_signal_connect_object (self->um, "user-added", G_CALLBACK (user_changed), self, G_CONNECT_SWAPPED); + g_signal_connect_object (self->um, "user-removed", G_CALLBACK (user_changed), self, G_CONNECT_SWAPPED); +} + +static void +add_unlock_tooltip (GtkWidget *widget) +{ + gtk_widget_set_tooltip_text (widget, + _("This panel must be unlocked to change this setting")); +} + +static void +remove_unlock_tooltip (GtkWidget *widget) +{ + gtk_widget_set_tooltip_text (widget, NULL); +} + +static guint +get_num_active_admin (ActUserManager *um) +{ + GSList *list; + GSList *l; + guint num_admin = 0; + + list = act_user_manager_list_users (um); + for (l = list; l != NULL; l = l->next) { + ActUser *u = l->data; + if (act_user_get_account_type (u) == ACT_USER_ACCOUNT_TYPE_ADMINISTRATOR && !act_user_get_locked (u)) { + num_admin++; + } + } + g_slist_free (list); + + return num_admin; +} + +static gboolean +would_demote_only_admin (ActUser *user) +{ + ActUserManager *um = act_user_manager_get_default (); + + /* Prevent the user from demoting the only admin account. + * Returns TRUE when user is an administrator and there is only + * one enabled administrator. */ + + if (act_user_get_account_type (user) == ACT_USER_ACCOUNT_TYPE_STANDARD || + act_user_get_locked (user)) + return FALSE; + + if (get_num_active_admin (um) > 1) + return FALSE; + + return TRUE; +} + +static void +on_permission_changed (CcUserPanel *self) +{ + gboolean is_authorized; + gboolean self_selected; + ActUser *user; + + is_authorized = g_permission_get_allowed (G_PERMISSION (self->permission)); + + gtk_widget_set_sensitive (self->add_user_button, is_authorized); + + user = get_selected_user (self); + if (!user) { + return; + } + + self_selected = act_user_get_uid (user) == geteuid (); + gtk_widget_set_sensitive (GTK_WIDGET (self->remove_user_button), is_authorized && !self_selected + && !would_demote_only_admin (user)); + if (is_authorized) { + gtk_widget_set_tooltip_text (GTK_WIDGET (self->remove_user_button), _("Delete the selected user account")); + } + else { + gtk_widget_set_tooltip_text (GTK_WIDGET (self->remove_user_button), + _("To delete the selected user account,\nclick the * icon first")); + } + + if (!act_user_is_local_account (user)) { + gtk_widget_set_visible (GTK_WIDGET (self->account_type_row), FALSE); + gtk_widget_set_visible (GTK_WIDGET (self->autologin_row), FALSE); + } else if (is_authorized && act_user_is_local_account (user)) { + if (would_demote_only_admin (user)) { + gtk_widget_set_visible (GTK_WIDGET (self->account_type_row), FALSE); + } else { + gtk_widget_set_visible (GTK_WIDGET (self->account_type_row), TRUE); + } + + if (get_autologin_possible (user)) { + gtk_widget_set_visible (GTK_WIDGET (self->autologin_row), TRUE); + gtk_widget_set_sensitive (GTK_WIDGET (self->autologin_row), TRUE); + } + } + else { + gtk_widget_set_visible (GTK_WIDGET (self->account_type_row), FALSE); + if (would_demote_only_admin (user)) { + gtk_widget_set_visible (GTK_WIDGET (self->account_type_row), FALSE); + } else { + gtk_widget_set_visible (GTK_WIDGET (self->account_type_row), TRUE); + } + gtk_widget_set_sensitive (GTK_WIDGET (self->autologin_row), FALSE); + add_unlock_tooltip (GTK_WIDGET (self->autologin_row)); + } + + /* The full name entry: insensitive if remote or not authorized and not self */ + if (!act_user_is_local_account (user)) { + gtk_widget_set_sensitive (GTK_WIDGET (self->full_name_edit_button), FALSE); + remove_unlock_tooltip (GTK_WIDGET (self->full_name_stack)); + + } else if (is_authorized || self_selected) { + gtk_widget_set_sensitive (GTK_WIDGET (self->full_name_edit_button), TRUE); + remove_unlock_tooltip (GTK_WIDGET (self->full_name_stack)); + + } else { + gtk_widget_set_sensitive (GTK_WIDGET (self->full_name_edit_button), FALSE); + add_unlock_tooltip (GTK_WIDGET (self->full_name_stack)); + } + + if (is_authorized || self_selected) { + CcFingerprintState fingerprint_state = CC_FINGERPRINT_STATE_NONE; + + if (self->fingerprint_manager) + fingerprint_state = cc_fingerprint_manager_get_state (self->fingerprint_manager); + + gtk_widget_set_sensitive (GTK_WIDGET (self->user_avatar_edit_button), TRUE); + remove_unlock_tooltip (GTK_WIDGET (self->user_avatar_edit_button)); + + gtk_widget_set_sensitive (GTK_WIDGET (self->language_row), TRUE); + remove_unlock_tooltip (GTK_WIDGET (self->language_row)); + + gtk_widget_set_sensitive (GTK_WIDGET (self->password_row), TRUE); + remove_unlock_tooltip (GTK_WIDGET (self->password_row)); + + gtk_widget_set_sensitive (GTK_WIDGET (self->fingerprint_row), + fingerprint_state != CC_FINGERPRINT_STATE_UPDATING); + remove_unlock_tooltip (GTK_WIDGET (self->fingerprint_row)); + + gtk_widget_set_sensitive (GTK_WIDGET (self->last_login_row), TRUE); + remove_unlock_tooltip (GTK_WIDGET (self->last_login_row)); + } + else { + gtk_widget_set_sensitive (GTK_WIDGET (self->user_avatar_edit_button), FALSE); + add_unlock_tooltip (GTK_WIDGET (self->user_avatar_edit_button)); + + gtk_widget_set_sensitive (GTK_WIDGET (self->language_row), FALSE); + add_unlock_tooltip (GTK_WIDGET (self->language_row)); + + gtk_widget_set_sensitive (GTK_WIDGET (self->password_row), FALSE); + add_unlock_tooltip (GTK_WIDGET (self->password_row)); + + gtk_widget_set_sensitive (GTK_WIDGET (self->fingerprint_row), FALSE); + add_unlock_tooltip (GTK_WIDGET (self->fingerprint_row)); + + gtk_widget_set_sensitive (GTK_WIDGET (self->last_login_row), FALSE); + add_unlock_tooltip (GTK_WIDGET (self->last_login_row)); + } +} + +static void +setup_main_window (CcUserPanel *self) +{ + g_autoptr(GError) error = NULL; + gboolean loaded; + + self->other_users_model = g_list_store_new (ACT_TYPE_USER); + gtk_list_box_bind_model (self->other_users_listbox, + G_LIST_MODEL (self->other_users_model), + (GtkListBoxCreateWidgetFunc)create_user_row, + self, + NULL); + + add_unlock_tooltip (GTK_WIDGET (self->user_avatar)); + + self->permission = (GPermission *)polkit_permission_new_sync (USER_ACCOUNTS_PERMISSION, NULL, NULL, &error); + if (self->permission != NULL) { + g_signal_connect_object (self->permission, "notify", + G_CALLBACK (on_permission_changed), self, G_CONNECT_SWAPPED); + on_permission_changed (self); + } else { + g_warning ("Cannot create '%s' permission: %s", USER_ACCOUNTS_PERMISSION, error->message); + } + +#ifdef HAVE_MALCONTENT + g_signal_connect_object (self->parental_controls_row, "activated", G_CALLBACK (spawn_malcontent_control), self, G_CONNECT_SWAPPED); +#endif + + gtk_widget_set_tooltip_text (GTK_WIDGET (self->remove_user_button), + _("To delete the selected user account,\nclick the * icon first")); + + self->avatar_chooser = cc_avatar_chooser_new (GTK_WIDGET (self)); + gtk_menu_button_set_popover (self->user_avatar_edit_button, + GTK_WIDGET (self->avatar_chooser)); + + g_object_get (self->um, "is-loaded", &loaded, NULL); + if (loaded) { + users_loaded (self); + user_changed (self, NULL); + } else { + g_signal_connect_object (self->um, "notify::is-loaded", G_CALLBACK (users_loaded), self, G_CONNECT_SWAPPED); + } +} + +static GSettings * +settings_or_null (const gchar *schema) +{ + GSettingsSchemaSource *source = NULL; + gchar **non_relocatable = NULL; + gchar **relocatable = NULL; + GSettings *settings = NULL; + + source = g_settings_schema_source_get_default (); + if (!source) + return NULL; + + g_settings_schema_source_list_schemas (source, TRUE, &non_relocatable, &relocatable); + + if (g_strv_contains ((const gchar * const *)non_relocatable, schema) || + g_strv_contains ((const gchar * const *)relocatable, schema)) + settings = g_settings_new (schema); + + g_strfreev (non_relocatable); + g_strfreev (relocatable); + return settings; +} + +static void +cc_user_panel_constructed (GObject *object) +{ + CcUserPanel *self = CC_USER_PANEL (object); + + G_OBJECT_CLASS (cc_user_panel_parent_class)->constructed (object); + + cc_permission_infobar_set_permission (self->permission_infobar, self->permission); + cc_permission_infobar_set_title (self->permission_infobar, _("Unlock to Add Users and Change Settings")); +} + +static void +cc_user_panel_init (CcUserPanel *self) +{ + volatile GType type G_GNUC_UNUSED; + g_autoptr(GtkCssProvider) provider = NULL; + + g_resources_register (cc_user_accounts_get_resource ()); + + /* register types that the builder might need */ + type = cc_permission_infobar_get_type (); + + gtk_widget_init_template (GTK_WIDGET (self)); + + self->um = act_user_manager_get_default (); + + provider = gtk_css_provider_new (); + gtk_css_provider_load_from_resource (provider, "/org/gnome/control-center/user-accounts/user-accounts-dialog.css"); + gtk_style_context_add_provider_for_display (gdk_display_get_default (), + GTK_STYLE_PROVIDER (provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + + self->login_screen_settings = settings_or_null ("org.gnome.login-screen"); + + setup_main_window (self); + + g_signal_connect_swapped (self, + "notify::folded", + G_CALLBACK (show_or_hide_back_button), + self); +} + +static void +cc_user_panel_dispose (GObject *object) +{ + CcUserPanel *self = CC_USER_PANEL (object); + + g_clear_object (&self->selected_user); + g_clear_object (&self->pending_show_user); + g_clear_object (&self->login_screen_settings); + g_clear_pointer ((GtkWindow **)&self->language_chooser, gtk_window_destroy); + g_clear_object (&self->permission); + + G_OBJECT_CLASS (cc_user_panel_parent_class)->dispose (object); +} + +static const char * +cc_user_panel_get_help_uri (CcPanel *panel) +{ + return "help:gnome-help/user-accounts"; +} + +static void +cc_user_panel_class_init (CcUserPanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + CcPanelClass *panel_class = CC_PANEL_CLASS (klass); + + object_class->dispose = cc_user_panel_dispose; + object_class->constructed = cc_user_panel_constructed; + + panel_class->get_help_uri = cc_user_panel_get_help_uri; + + gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/user-accounts/cc-user-panel.ui"); + + gtk_widget_class_bind_template_child (widget_class, CcUserPanel, account_settings_box); + gtk_widget_class_bind_template_child (widget_class, CcUserPanel, account_type_row); + gtk_widget_class_bind_template_child (widget_class, CcUserPanel, account_type_switch); + gtk_widget_class_bind_template_child (widget_class, CcUserPanel, add_user_button); + gtk_widget_class_bind_template_child (widget_class, CcUserPanel, autologin_row); + gtk_widget_class_bind_template_child (widget_class, CcUserPanel, autologin_switch); + gtk_widget_class_bind_template_child (widget_class, CcUserPanel, back_button); + gtk_widget_class_bind_template_child (widget_class, CcUserPanel, fingerprint_state_label); + gtk_widget_class_bind_template_child (widget_class, CcUserPanel, fingerprint_row); + gtk_widget_class_bind_template_child (widget_class, CcUserPanel, full_name_stack); + gtk_widget_class_bind_template_child (widget_class, CcUserPanel, full_name_label); + gtk_widget_class_bind_template_child (widget_class, CcUserPanel, full_name_edit_button); + gtk_widget_class_bind_template_child (widget_class, CcUserPanel, full_name_entry); + gtk_widget_class_bind_template_child (widget_class, CcUserPanel, language_button_label); + gtk_widget_class_bind_template_child (widget_class, CcUserPanel, language_row); + gtk_widget_class_bind_template_child (widget_class, CcUserPanel, last_login_button_label); + gtk_widget_class_bind_template_child (widget_class, CcUserPanel, last_login_row); + gtk_widget_class_bind_template_child (widget_class, CcUserPanel, no_users_box); + gtk_widget_class_bind_template_child (widget_class, CcUserPanel, notification_revealer); + gtk_widget_class_bind_template_child (widget_class, CcUserPanel, other_users); + gtk_widget_class_bind_template_child (widget_class, CcUserPanel, other_users_row); + gtk_widget_class_bind_template_child (widget_class, CcUserPanel, other_users_listbox); +#ifdef HAVE_MALCONTENT + gtk_widget_class_bind_template_child (widget_class, CcUserPanel, parental_controls_button_label); + gtk_widget_class_bind_template_child (widget_class, CcUserPanel, parental_controls_row); +#endif + gtk_widget_class_bind_template_child (widget_class, CcUserPanel, password_button_label); + gtk_widget_class_bind_template_child (widget_class, CcUserPanel, password_row); + gtk_widget_class_bind_template_child (widget_class, CcUserPanel, permission_infobar); + gtk_widget_class_bind_template_child (widget_class, CcUserPanel, remove_user_button); + gtk_widget_class_bind_template_child (widget_class, CcUserPanel, stack); + gtk_widget_class_bind_template_child (widget_class, CcUserPanel, user_avatar); + gtk_widget_class_bind_template_child (widget_class, CcUserPanel, user_avatar_edit_button); + gtk_widget_class_bind_template_child (widget_class, CcUserPanel, users_overlay); + + gtk_widget_class_bind_template_callback (widget_class, account_type_changed); + gtk_widget_class_bind_template_callback (widget_class, add_user); + gtk_widget_class_bind_template_callback (widget_class, autologin_changed); + gtk_widget_class_bind_template_callback (widget_class, change_fingerprint); + gtk_widget_class_bind_template_callback (widget_class, change_language); + gtk_widget_class_bind_template_callback (widget_class, full_name_edit_button_toggled); + gtk_widget_class_bind_template_callback (widget_class, full_name_entry_activate); + gtk_widget_class_bind_template_callback (widget_class, full_name_entry_key_press_cb); + gtk_widget_class_bind_template_callback (widget_class, change_password); + gtk_widget_class_bind_template_callback (widget_class, delete_user); + gtk_widget_class_bind_template_callback (widget_class, dismiss_notification); + gtk_widget_class_bind_template_callback (widget_class, restart_now); + gtk_widget_class_bind_template_callback (widget_class, set_selected_user); + gtk_widget_class_bind_template_callback (widget_class, on_back_button_clicked_cb); + gtk_widget_class_bind_template_callback (widget_class, show_history); +} |