[accounts-dialog/control-center-panel: 4/15] Various fixes



commit a2ce590b4937f5f0c1089ce2974c591114b70aee
Author: Matthias Clasen <mclasen redhat com>
Date:   Sat Jun 12 23:31:15 2010 -0400

    Various fixes

 src/um-login-options.c    |    2 +-
 src/um-photo-dialog.c     |   12 +-
 src/um-photo-dialog.h     |    3 +-
 src/um-user-module.c      |   41 ++
 src/um-user-panel.c       | 1695 +++++++++++++++++++++++++++++++++++++++++++++
 src/um-user-panel.h       |   59 ++
 src/user-panel.desktop.in |    9 +
 7 files changed, 1810 insertions(+), 11 deletions(-)
---
diff --git a/src/um-login-options.c b/src/um-login-options.c
index 5330112..9fa74ed 100644
--- a/src/um-login-options.c
+++ b/src/um-login-options.c
@@ -423,7 +423,7 @@ um_login_options_free (UmLoginOptions *um)
   if (um->proxy)
     g_object_unref (um->proxy);
   if (um->connection)
-    g_object_unref (um->connection);
+    dbus_g_connection_unref (um->connection);
 
   g_free (um);
 }
diff --git a/src/um-photo-dialog.c b/src/um-photo-dialog.c
index e97f97d..b2e1677 100644
--- a/src/um-photo-dialog.c
+++ b/src/um-photo-dialog.c
@@ -42,7 +42,6 @@
 #define ROW_SPAN 6
 
 struct _UmPhotoDialog {
-        GtkWidget *parent_window;
         GtkWidget *photo_popup;
         GtkWidget *popup_button;
         GtkWidget *crop_area;
@@ -91,7 +90,7 @@ um_photo_dialog_crop (UmPhotoDialog *um,
         GtkWidget *frame;
 
         dialog = gtk_dialog_new_with_buttons ("",
-                                              GTK_WINDOW (um->parent_window),
+                                              GTK_WINDOW (gtk_widget_get_toplevel (um->popup_button)),
                                               GTK_DIALOG_NO_SEPARATOR,
                                               GTK_STOCK_CANCEL,
                                               GTK_RESPONSE_REJECT,
@@ -211,7 +210,7 @@ um_photo_dialog_select_file (UmPhotoDialog *um)
         GtkWidget *preview;
 
         chooser = gtk_file_chooser_dialog_new (_("Browse for more pictures"),
-                                               GTK_WINDOW (um->parent_window),
+                                               GTK_WINDOW (gtk_widget_get_toplevel (um->popup_button)),
                                                GTK_FILE_CHOOSER_ACTION_OPEN,
                                                GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
                                                GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
@@ -289,7 +288,7 @@ webcam_icon_selected (GtkMenuItem   *menuitem,
 
         window = cheese_avatar_chooser_new ();
         gtk_window_set_transient_for (GTK_WINDOW (window),
-                                      GTK_WINDOW (um->parent_window));
+                                      GTK_WINDOW (gtk_widget_get_toplevel (um->popup_button)));
         gtk_window_set_modal (GTK_WINDOW (window), TRUE);
         g_signal_connect (G_OBJECT (window), "response",
                           G_CALLBACK (webcam_response_cb), um);
@@ -529,7 +528,7 @@ popup_button_focus_changed (GObject       *button,
 }
 
 UmPhotoDialog *
-um_photo_dialog_new (GtkWidget *button, GtkWidget *parent)
+um_photo_dialog_new (GtkWidget *button)
 {
         UmPhotoDialog *um;
 
@@ -552,9 +551,6 @@ um_photo_dialog_new (GtkWidget *button, GtkWidget *parent)
         g_signal_connect (um->photo_popup, "unmap",
                           G_CALLBACK (on_photo_popup_unmap), um);
 
-        /* Parent window */
-        um->parent_window = parent;
-
         return um;
 }
 
diff --git a/src/um-photo-dialog.h b/src/um-photo-dialog.h
index f5a9b5f..3f0c404 100644
--- a/src/um-photo-dialog.h
+++ b/src/um-photo-dialog.h
@@ -29,8 +29,7 @@ G_BEGIN_DECLS
 
 typedef struct _UmPhotoDialog UmPhotoDialog;
 
-UmPhotoDialog *um_photo_dialog_new      (GtkWidget *button,
-                                         GtkWidget *parent);
+UmPhotoDialog *um_photo_dialog_new      (GtkWidget     *button);
 void           um_photo_dialog_free     (UmPhotoDialog *dialog);
 void           um_photo_dialog_set_user (UmPhotoDialog *dialog,
                                          UmUser        *user);
diff --git a/src/um-user-module.c b/src/um-user-module.c
new file mode 100644
index 0000000..d96ed40
--- /dev/null
+++ b/src/um-user-module.c
@@ -0,0 +1,41 @@
+/* -*- 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 3 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.
+ *
+ * Written by: Matthias Clasen <mclasen redhat com>
+ */
+
+#include <config.h>
+
+#include "um-user-panel.h"
+
+#include <glib/gi18n.h>
+
+void
+g_io_module_load (GIOModule *module)
+{
+  bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
+  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+
+  /* register the panel */
+  um_user_panel_register (module);
+}
+
+void
+g_io_module_unload (GIOModule *module)
+{
+}
diff --git a/src/um-user-panel.c b/src/um-user-panel.c
new file mode 100644
index 0000000..4a1ef3b
--- /dev/null
+++ b/src/um-user-panel.c
@@ -0,0 +1,1695 @@
+/* -*- 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 3 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.
+ *
+ * Written by: Matthias Clasen <mclasen redhat com>
+ */
+
+#include "config.h"
+
+#include "um-user-panel.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+#include <libintl.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+#include <unique/unique.h>
+#include <polkit/polkit.h>
+#include <polkitgtk/polkitgtk.h>
+#include <dbus/dbus-glib-bindings.h>
+
+#ifdef HAVE_CHEESE
+#include <gst/gst.h>
+#endif /* HAVE_CHEESE */
+
+#include "marshal.h"
+
+#include "um-user.h"
+#include "um-user-manager.h"
+
+#include "um-account-dialog.h"
+#include "um-language-dialog.h"
+#include "um-login-options.h"
+#include "um-password-dialog.h"
+#include "um-photo-dialog.h"
+#include "um-fingerprint-dialog.h"
+#include "um-utils.h"
+#include "um-strength-bar.h"
+#include "gdm-languages.h"
+
+G_DEFINE_DYNAMIC_TYPE (UmUserPanel, um_user_panel, CC_TYPE_PANEL)
+
+#define UM_USER_PANEL_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), UM_TYPE_USER_PANEL, UmUserPanelPrivate))
+
+struct _UmUserPanelPrivate {
+        UmUserManager *um;
+        GtkBuilder *builder;
+
+        GtkWidget *notebook;
+        GtkWidget *lock_button;
+        GtkWidget *language_chooser;
+
+        UmAccountDialog *account_dialog;
+        UmPasswordDialog *password_dialog;
+        UmPhotoDialog *photo_dialog;
+        UmLoginOptions *login_options;
+
+        PolkitAuthority *authority;
+};
+
+static GtkWidget *
+get_widget (UmUserPanelPrivate *d, const char *name)
+{
+        return (GtkWidget *)gtk_builder_get_object (d->builder, name);
+}
+
+enum {
+        USER_COL,
+        FACE_COL,
+        NAME_COL,
+        USER_ROW_COL,
+        TITLE_COL,
+        HEADING_ROW_COL,
+        SORT_KEY_COL,
+        NUM_USER_LIST_COLS
+};
+
+static UmUser *
+get_selected_user (UmUserPanelPrivate *d)
+{
+        GtkTreeView *tv;
+        GtkListStore *store;
+        GtkTreeIter iter;
+        GtkTreeSelection *selection;
+        GtkTreeModel *model;
+        UmUser *user;
+
+        tv = (GtkTreeView *)get_widget (d, "list-treeview");
+        store = (GtkListStore *)gtk_tree_view_get_model (tv);
+        selection = gtk_tree_view_get_selection (tv);
+
+        if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
+                gtk_tree_model_get (model, &iter, USER_COL, &user, -1);
+                return user;
+        }
+
+        return NULL;
+}
+
+static void
+user_added (UmUserManager *um, UmUser *user, UmUserPanelPrivate *d)
+{
+        GtkWidget *widget;
+        GtkTreeModel *model;
+        GtkListStore *store;
+        GtkTreeIter iter;
+        GtkTreeIter dummy;
+        GdkPixbuf *pixbuf;
+        gchar *text;
+        GtkTreeSelection *selection;
+        gint sort_key;
+
+        g_debug ("user added: %d %s\n", um_user_get_uid (user), um_user_get_real_name (user));
+        widget = get_widget (d, "list-treeview");
+        model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
+        store = GTK_LIST_STORE (model);
+        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
+
+        pixbuf = um_user_render_icon (user, TRUE, 48);
+        text = g_strdup_printf ("<b>%s</b>\n<i>%s</i>",
+                                um_user_get_display_name (user),
+                                um_account_type_get_name (um_user_get_account_type (user)));
+
+        if (um_user_get_uid (user) == getuid ()) {
+                sort_key = 1;
+        }
+        else {
+                sort_key = 3;
+        }
+        gtk_list_store_append (store, &iter);
+
+        gtk_list_store_set (store, &iter,
+                            USER_COL, user,
+                            FACE_COL, pixbuf,
+                            NAME_COL, text,
+                            USER_ROW_COL, TRUE,
+                            TITLE_COL, NULL,
+                            HEADING_ROW_COL, FALSE,
+                            SORT_KEY_COL, sort_key,
+                            -1);
+        g_object_unref (pixbuf);
+        g_free (text);
+
+        if (sort_key == 1 &&
+            !gtk_tree_selection_get_selected (selection, &model, &dummy)) {
+                gtk_tree_selection_select_iter (selection, &iter);
+        }
+}
+
+static void
+get_previous_user_row (GtkTreeModel *model,
+                       GtkTreeIter  *iter,
+                       GtkTreeIter  *prev)
+{
+        GtkTreePath *path;
+        UmUser *user;
+
+        path = gtk_tree_model_get_path (model, iter);
+        while (gtk_tree_path_prev (path)) {
+                gtk_tree_model_get_iter (model, prev, path);
+                gtk_tree_model_get (model, prev, USER_COL, &user, -1);
+                if (user) {
+                        g_object_unref (user);
+                        break;
+                }
+        }
+        gtk_tree_path_free (path);
+}
+
+static gboolean
+get_next_user_row (GtkTreeModel *model,
+                   GtkTreeIter  *iter,
+                   GtkTreeIter  *next)
+{
+        UmUser *user;
+
+        *next = *iter;
+        while (gtk_tree_model_iter_next (model, next)) {
+                gtk_tree_model_get (model, next, USER_COL, &user, -1);
+                if (user) {
+                        g_object_unref (user);
+                        return TRUE;
+                }
+        }
+
+        return FALSE;
+}
+
+static void
+user_removed (UmUserManager *um, UmUser *user, UmUserPanelPrivate *d)
+{
+        GtkTreeView *tv;
+        GtkTreeModel *model;
+        GtkTreeSelection *selection;
+        GtkListStore *store;
+        GtkTreeIter iter, next;
+        UmUser *u;
+
+        g_debug ("user removed: %s\n", um_user_get_user_name (user));
+        tv = (GtkTreeView *)get_widget (d, "list-treeview");
+        selection = gtk_tree_view_get_selection (tv);
+        model = gtk_tree_view_get_model (tv);
+        store = GTK_LIST_STORE (model);
+        if (gtk_tree_model_get_iter_first (model, &iter)) {
+                do {
+                        gtk_tree_model_get (model, &iter, USER_COL, &u, -1);
+
+                        if (u != NULL) {
+                                if (um_user_get_uid (user) == um_user_get_uid (u)) {
+                                        if (!get_next_user_row (model, &iter, &next))
+                                                get_previous_user_row (model, &iter, &next);
+                                        gtk_list_store_remove (store, &iter);
+                                        gtk_tree_selection_select_iter (selection, &next);
+                                        g_object_unref (u);
+                                        break;
+                                }
+                                g_object_unref (u);
+                        }
+                } while (gtk_tree_model_iter_next (model, &iter));
+        }
+}
+
+static void show_user (UmUser *user, UmUserPanelPrivate *d);
+
+static void
+user_changed (UmUserManager *um, UmUser *user, UmUserPanelPrivate *d)
+{
+        GtkTreeView *tv;
+        GtkTreeSelection *selection;
+        GtkTreeModel *model;
+        GtkTreeIter iter;
+        UmUser *current;
+        GdkPixbuf *pixbuf;
+        char *text;
+
+        tv = (GtkTreeView *)get_widget (d, "list-treeview");
+        model = gtk_tree_view_get_model (tv);
+        selection = gtk_tree_view_get_selection (tv);
+
+        gtk_tree_model_get_iter_first (model, &iter);
+        do {
+                gtk_tree_model_get (model, &iter, USER_COL, &current, -1);
+                if (current == user) {
+                        pixbuf = um_user_render_icon (user, TRUE, 48);
+                        text = g_strdup_printf ("<b>%s</b>\n<i>%s</i>",
+                                                um_user_get_display_name (user),
+                                                um_account_type_get_name (um_user_get_account_type (user)));
+
+                        gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+                                            USER_COL, user,
+                                            FACE_COL, pixbuf,
+                                            NAME_COL, text,
+                                            -1);
+                        g_object_unref (pixbuf);
+                        g_free (text);
+                        g_object_unref (current);
+
+                        break;
+                }
+                if (current)
+                        g_object_unref (current);
+
+        } while (gtk_tree_model_iter_next (model, &iter));
+
+        if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
+                gtk_tree_model_get (model, &iter, USER_COL, &current, -1);
+
+                if (current == user) {
+                        show_user (user, d);
+                }
+                if (current)
+                        g_object_unref (current);
+        }
+}
+
+static void
+select_created_user (UmUser *user, UmUserPanelPrivate *d)
+{
+        GtkTreeView *tv;
+        GtkTreeModel *model;
+        GtkTreeSelection *selection;
+        GtkTreeIter iter;
+        UmUser *current;
+        GtkTreePath *path;
+
+        tv = (GtkTreeView *)get_widget (d, "list-treeview");
+        model = gtk_tree_view_get_model (tv);
+        selection = gtk_tree_view_get_selection (tv);
+
+        gtk_tree_model_get_iter_first (model, &iter);
+        do {
+                gtk_tree_model_get (model, &iter, USER_COL, &current, -1);
+                if (user == current) {
+                        path = gtk_tree_model_get_path (model, &iter);
+                        gtk_tree_view_scroll_to_cell (tv, path, NULL, FALSE, 0.0, 0.0);
+                        gtk_tree_selection_select_path (selection, path);
+                        gtk_tree_path_free (path);
+                        break;
+                }
+        } while (gtk_tree_model_iter_next (model, &iter));
+}
+
+static void
+add_user (GtkButton *button, UmUserPanelPrivate *d)
+{
+        um_account_dialog_show (d->account_dialog,
+                                GTK_WINDOW (gtk_widget_get_toplevel (d->notebook)),
+                                (UserCreatedCallback)select_created_user, d);
+}
+
+static void
+delete_user_done (UmUserManager     *manager,
+                  GAsyncResult      *res,
+                  UmUserPanelPrivate *d)
+{
+        GError *error;
+
+        error = NULL;
+        if (!um_user_manager_delete_user_finish (manager, res, &error)) {
+                if (!g_error_matches (error, UM_USER_MANAGER_ERROR, UM_USER_MANAGER_ERROR_PERMISSION_DENIED)) {
+                        GtkWidget *dialog;
+
+                        dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (d->notebook)),
+                                                         GTK_DIALOG_DESTROY_WITH_PARENT,
+                                                         GTK_MESSAGE_ERROR,
+                                                         GTK_BUTTONS_CLOSE,
+                                                         _("Failed to delete user"));
+
+                        gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+                                                                  "%s", error->message);
+
+                        g_signal_connect (G_OBJECT (dialog), "response",
+                                          G_CALLBACK (gtk_widget_destroy), NULL);
+                        gtk_window_present (GTK_WINDOW (dialog));
+                }
+                g_error_free (error);
+        }
+}
+
+static void
+delete_user_response (GtkWidget         *dialog,
+                      gint               response_id,
+                      UmUserPanelPrivate *d)
+{
+        UmUser *user;
+        gboolean remove_files;
+
+        gtk_widget_destroy (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 (d);
+
+        um_user_manager_delete_user (d->um,
+                                     user,
+                                     remove_files,
+                                     (GAsyncReadyCallback)delete_user_done,
+                                     d,
+                                     NULL);
+
+        g_object_unref (user);
+}
+
+static void
+delete_user (GtkButton *button, UmUserPanelPrivate *d)
+{
+        UmUser *user;
+        GtkWidget *dialog;
+
+        user = get_selected_user (d);
+        if (user == NULL) {
+                return;
+        }
+        else if (um_user_get_uid (user) == getuid ()) {
+                dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (d->notebook)),
+                                                 0,
+                                                 GTK_MESSAGE_INFO,
+                                                 GTK_BUTTONS_CLOSE,
+                                                 _("You cannot delete your own account."));
+                g_signal_connect (dialog, "response",
+                                  G_CALLBACK (gtk_widget_destroy), NULL);
+        }
+        else if (um_user_is_logged_in (user)) {
+                dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (d->notebook)),
+                                                 0,
+                                                 GTK_MESSAGE_INFO,
+                                                 GTK_BUTTONS_CLOSE,
+                                                 _("%s is still logged in"),
+                                                um_user_get_real_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_widget_destroy), NULL);
+        }
+        else {
+                dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (d->notebook)),
+                                                 0,
+                                                 GTK_MESSAGE_QUESTION,
+                                                 GTK_BUTTONS_NONE,
+                                                 _("Do you want to keep %s's files?"),
+                                                um_user_get_real_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 (dialog, "response",
+                                  G_CALLBACK (delete_user_response), d);
+        }
+
+        g_signal_connect (dialog, "close",
+                          G_CALLBACK (gtk_widget_destroy), NULL);
+
+        gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
+
+        gtk_window_present (GTK_WINDOW (dialog));
+
+}
+
+static const char *
+nonempty (const char *str)
+{
+        return (str == NULL || str[0] == 0) ? "\xe2\x80\x94" : str;
+}
+
+static void language_changed (GtkComboBox *combo, UmUserPanelPrivate *d);
+
+static void
+show_user (UmUser *user, UmUserPanelPrivate *d)
+{
+        GtkWidget *image;
+        GtkWidget *label;
+        GtkWidget *label2;
+        GtkWidget *label3;
+        GdkPixbuf *pixbuf;
+        const char *text;
+        char *language;
+        GtkWidget *combo;
+        GtkTreeModel *model;
+        GtkTreeIter iter;
+        GtkWidget *widget;
+
+        pixbuf = um_user_render_icon (user, FALSE, 48);
+        image = get_widget (d, "user-icon-image");
+        gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf);
+        image = get_widget (d, "user-icon-image2");
+        gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf);
+        g_object_unref (pixbuf);
+
+        um_photo_dialog_set_user (d->photo_dialog, user);
+
+        label = get_widget (d, "full-name-value-label");
+        gtk_label_set_text (GTK_LABEL (label), um_user_get_real_name (user));
+        gtk_widget_set_tooltip_text (label, um_user_get_user_name (user));
+
+        label = get_widget (d, "full-name-button-label");
+        gtk_label_set_text (GTK_LABEL (label), um_user_get_real_name (user));
+        widget = get_widget (d, "full-name-button");
+        gtk_widget_set_tooltip_text (label, um_user_get_user_name (user));
+        widget = get_widget (d, "full-name-entry");
+        gtk_entry_set_text (GTK_ENTRY (widget), um_user_get_real_name (user));
+
+        label = get_widget (d, "account-type-value-label");
+        gtk_label_set_text (GTK_LABEL (label), um_account_type_get_name (um_user_get_account_type (user)));
+        label = get_widget (d, "account-type-button-label");
+        gtk_label_set_text (GTK_LABEL (label), um_account_type_get_name (um_user_get_account_type (user)));
+        combo = get_widget (d, "account-type-combo");
+        model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
+        gtk_tree_model_get_iter_first (model, &iter);
+        do {
+                gint t;
+                gtk_tree_model_get (model, &iter, 1, &t, -1);
+                if (t == um_user_get_account_type (user)) {
+                        gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo), &iter);
+                }
+        }  while (gtk_tree_model_iter_next (model, &iter));
+
+        if (um_user_get_locked (user)) {
+                text = C_("Password mode", "Account disabled");
+        }
+        else {
+                switch (um_user_get_password_mode (user)) {
+                case UM_PASSWORD_MODE_REGULAR:
+                        text = "\xe2\x80\xa2\xe2\x80\xa2\xe2\x80\xa2\xe2\x80\xa2\xe2\x80\xa2";
+                        break;
+                case UM_PASSWORD_MODE_SET_AT_LOGIN:
+                        text = C_("Password mode", "To be set at next login");
+                        break;
+                case UM_PASSWORD_MODE_NONE:
+                        text = C_("Password mode", "None");
+                        break;
+                default:
+                        g_assert_not_reached ();
+                }
+        }
+        label = get_widget (d, "account-password-value-label");
+        gtk_label_set_text (GTK_LABEL (label), text);
+        label = get_widget (d, "account-password-button-label");
+        gtk_label_set_text (GTK_LABEL (label), text);
+
+        text = um_user_get_email (user);
+        widget = get_widget (d, "account-email-value-label");
+        gtk_label_set_text (GTK_LABEL (widget), nonempty (text));
+        widget = get_widget (d, "account-email-button-label");
+        gtk_label_set_text (GTK_LABEL (widget), nonempty (text));
+        widget = get_widget (d, "account-email-entry");
+        gtk_entry_set_text (GTK_ENTRY (widget), text);
+
+        widget = get_widget (d, "account-language-combo");
+        g_signal_handlers_block_by_func (widget, language_changed, d);
+        um_add_user_languages (widget);
+
+        text = um_user_get_language (user);
+        if (text) {
+                um_select_language (widget, text);
+                language = gdm_get_language_from_name (text, NULL);
+        }
+        else {
+                const gchar *locale;
+                locale = (const gchar *) setlocale (LC_MESSAGES, NULL);
+                if (locale) {
+                        gchar *name;
+                        name = gdm_normalize_language_name (locale);
+                        um_select_language (widget, name);
+                        language = gdm_get_language_from_name (name, NULL);
+                        g_free (name);
+                } else {
+                        language = g_strdup (nonempty (""));
+                }
+        }
+        label = get_widget (d, "account-language-value-label");
+        gtk_label_set_text (GTK_LABEL (label), language);
+        label = get_widget (d, "account-language-button-label");
+        gtk_label_set_text (GTK_LABEL (label), language);
+        g_free (language);
+        g_signal_handlers_unblock_by_func (widget, language_changed, d);
+
+        text = um_user_get_location (user);
+        label = get_widget (d, "account-location-value-label");
+        gtk_label_set_text (GTK_LABEL (label), nonempty (text));
+        label = get_widget (d, "account-location-button-label");
+        gtk_label_set_text (GTK_LABEL (label), nonempty (text));
+        label = get_widget (d, "account-location-entry");
+        gtk_entry_set_text (GTK_ENTRY (label), text);
+
+        widget = get_widget (d, "account-fingerprint-notebook");
+        label = get_widget (d, "account-fingerprint-label");
+        label2 = get_widget (d, "account-fingerprint-value-label");
+        label3 = get_widget (d, "account-fingerprint-button-label");
+        if (um_user_get_uid (user) != getuid() ||
+            !set_fingerprint_label (label2, label3)) {
+                gtk_widget_hide (label);
+                gtk_widget_hide (widget);
+        } else {
+                gtk_widget_show (label);
+                gtk_widget_show (widget);
+        }
+}
+
+static void lockbutton_changed (PolkitLockButton *button, gpointer data);
+
+static void
+selected_user_changed (GtkTreeSelection *selection, UmUserPanelPrivate *d)
+{
+        GtkWidget *widget;
+        GtkTreeModel *model;
+        GtkTreeIter iter;
+        UmUser *user;
+
+        if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
+                gtk_tree_model_get (model, &iter, USER_COL, &user, -1);
+                show_user (user, d);
+
+                lockbutton_changed (POLKIT_LOCK_BUTTON (d->lock_button), d);
+
+                g_object_unref (user);
+        }
+}
+
+static void
+name_style_set (GtkWidget *widget, GtkStyle *previous_style, UmUserPanelPrivate *d)
+{
+        PangoFontDescription *desc;
+        gint size;
+
+        desc = pango_font_description_copy (widget->style->font_desc);
+        size = pango_font_description_get_size (desc);
+        pango_font_description_set_size (desc, 1.2 * size);
+        pango_font_description_set_weight (desc, PANGO_WEIGHT_BOLD);
+
+        g_signal_handlers_block_by_func (widget, name_style_set, d);
+        gtk_widget_modify_font (widget, desc);
+        g_signal_handlers_unblock_by_func (widget, name_style_set, d);
+
+        pango_font_description_free (desc);
+}
+
+static void
+change_name_start (GtkButton *button, UmUserPanelPrivate *d)
+{
+        gtk_notebook_set_current_page (GTK_NOTEBOOK (get_widget (d, "full-name-notebook")), 2);
+}
+
+static void
+change_name_done (GtkWidget         *entry,
+                  UmUserPanelPrivate *d)
+{
+        const gchar *text;
+        UmUser *user;
+
+        user = get_selected_user (d);
+
+        text = gtk_entry_get_text (GTK_ENTRY (entry));
+        if (g_strcmp0 (text, um_user_get_location (user)) != 0) {
+                um_user_set_real_name (user, text);
+        }
+
+        gtk_notebook_set_current_page (GTK_NOTEBOOK (get_widget (d, "full-name-notebook")), 1);
+}
+
+static void
+change_name_canceled (UmUserPanelPrivate *d)
+{
+        UmUser *user;
+        const gchar *text;
+        GtkWidget *widget;
+
+        user = get_selected_user (d);
+        text = um_user_get_real_name (user);
+
+        widget = get_widget (d, "full-name-value-label");
+        gtk_label_set_text (GTK_LABEL (widget), nonempty (text));
+        widget = get_widget (d, "full-name-button-label");
+        gtk_label_set_text (GTK_LABEL (widget), nonempty (text));
+        widget = get_widget (d, "full-name-entry");
+        gtk_entry_set_text (GTK_ENTRY (widget), text);
+
+        gtk_notebook_set_current_page (GTK_NOTEBOOK (get_widget (d, "full-name-notebook")), 1);
+}
+
+static void
+change_name_activate (GtkWidget         *widget,
+                      UmUserPanelPrivate *d)
+{
+        change_name_done (widget, d);
+}
+
+static gboolean
+change_name_focus_out (GtkWidget         *widget,
+                       GdkEventFocus     *event,
+                       UmUserPanelPrivate *d)
+{
+        change_name_done (widget, d);
+
+        return FALSE;
+}
+
+static gboolean
+change_name_key_press (GtkWidget         *widget,
+                       GdkEventKey       *event,
+                       UmUserPanelPrivate *d)
+{
+        if (event->keyval == GDK_Escape) {
+                change_name_canceled (d);
+        }
+
+        return FALSE;
+}
+
+static void
+change_account_type_authorized_cb (GObject           *source,
+                                   GAsyncResult      *res,
+                                   UmUserPanelPrivate *d)
+{
+        GError *error;
+        PolkitAuthorizationResult *result;
+        gboolean is_authorized;
+
+        error = NULL;
+        is_authorized = FALSE;
+        result = polkit_authority_check_authorization_finish (d->authority,
+                                                              res,
+                                                              &error);
+        if (error) {
+                g_warning ("polkit check failed: %s", error->message);
+                g_error_free (error);
+        }
+        else {
+                if (polkit_authorization_result_get_is_authorized (result)) {
+                        is_authorized = TRUE;
+                }
+
+                g_object_unref (result);
+        }
+
+        if (is_authorized) {
+                gtk_notebook_set_current_page (GTK_NOTEBOOK (get_widget (d, "account-type-notebook")), 2);
+        }
+}
+
+static void
+change_account_type_start (GtkButton         *button,
+                           UmUserPanelPrivate *d)
+{
+        PolkitSubject *subject;
+
+        subject = polkit_unix_process_new (getpid ());
+
+        polkit_authority_check_authorization (d->authority,
+                                              subject,
+                                              "org.freedesktop.accounts.user-administration",
+                                              NULL,
+                                              POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
+                                              NULL,
+                                              (GAsyncReadyCallback)change_account_type_authorized_cb,
+                                              d);
+
+        g_object_unref (subject);
+}
+
+static void
+account_type_changed (GtkComboBox       *combo,
+                      UmUserPanelPrivate *d)
+{
+        GtkTreeModel *model;
+        GtkTreeIter iter;
+        gint t;
+        UmUser *user;
+
+        user = get_selected_user (d);
+        model = gtk_combo_box_get_model (combo);
+        gtk_combo_box_get_active_iter (combo, &iter);
+        gtk_tree_model_get (model, &iter, 1, &t, -1);
+
+        if (t != um_user_get_account_type (user)) {
+                um_user_set_account_type (user, t);
+        }
+}
+
+static void
+language_response (GtkDialog         *dialog,
+                   gint               response_id,
+                   UmUserPanelPrivate *d)
+{
+        GtkWidget *widget;
+        UmUser *user;
+        gchar *lang;
+        const gchar *text;
+        gchar *language;
+
+        user = get_selected_user (d);
+        widget = get_widget (d, "account-language-combo");
+        if (response_id == GTK_RESPONSE_OK) {
+                lang = um_language_chooser_get_language (GTK_WIDGET (dialog));
+                um_user_set_language (user, lang);
+                um_select_language (widget, lang);
+                language = g_strdup (nonempty (lang));
+                g_free (lang);
+        }
+        else {
+                text = um_user_get_language (user);
+                if (text) {
+                        um_select_language (widget, text);
+                        language = gdm_get_language_from_name (text, NULL);
+                }
+                else {
+                        const gchar *locale;
+                        locale = (const gchar *) setlocale (LC_MESSAGES, NULL);
+                        if (locale) {
+                                char *name;
+                                name = gdm_normalize_language_name (locale);
+                                um_select_language (widget, name);
+                                language = gdm_get_language_from_name (name, NULL);
+                                g_free (name);
+                        } else {
+                                language = g_strdup (nonempty (""));
+                        }
+                }
+        }
+
+        gtk_label_set_text (GTK_LABEL (get_widget (d, "account-language-value-label")), language);
+        gtk_label_set_text (GTK_LABEL (get_widget (d, "account-language-button-label")), language);
+        g_free (language);
+
+        gtk_widget_hide (GTK_WIDGET (dialog));
+        gtk_widget_set_sensitive (widget, TRUE);
+        gtk_notebook_set_current_page (GTK_NOTEBOOK (get_widget (d, "account-language-notebook")), 1);
+}
+
+static gboolean
+finish_language_chooser (UmUserPanelPrivate *d)
+{
+        GtkWidget *combo;
+
+        combo = get_widget (d, "account-language-combo");
+        d->language_chooser = um_language_chooser_new ();
+        gtk_window_set_transient_for (GTK_WINDOW (d->language_chooser),
+                                      GTK_WINDOW (gtk_widget_get_toplevel (d->notebook)));
+        g_signal_connect (d->language_chooser, "response",
+                          G_CALLBACK (language_response), d);
+        g_signal_connect (d->language_chooser, "delete-event",
+                          G_CALLBACK (gtk_widget_hide_on_delete), NULL);
+
+        gdk_window_set_cursor (gtk_widget_get_window (gtk_widget_get_toplevel (d->notebook)), NULL);
+        gtk_window_present (GTK_WINDOW (d->language_chooser));
+        gtk_widget_set_sensitive (GTK_WIDGET (combo), FALSE);
+
+        return FALSE;
+}
+
+static void
+language_changed (GtkComboBox       *combo,
+                  UmUserPanelPrivate *d)
+{
+        GtkTreeModel *model;
+        GtkTreeIter iter;
+        gchar *lang;
+        UmUser *user;
+        GdkCursor *cursor;
+
+        if (!gtk_combo_box_get_active_iter (combo, &iter))
+                 return;
+
+        user = get_selected_user (d);
+        model = gtk_combo_box_get_model (combo);
+
+        gtk_tree_model_get (model, &iter, 0, &lang, -1);
+        if (lang) {
+                if (g_strcmp0 (lang, um_user_get_language (user)) != 0) {
+                        um_user_set_language (user, lang);
+                }
+                g_free (lang);
+                return;
+        }
+
+        if (d->language_chooser) {
+                gtk_window_present (GTK_WINDOW (d->language_chooser));
+                gtk_widget_set_sensitive (GTK_WIDGET (combo), FALSE);
+                return;
+        }
+
+        cursor = gdk_cursor_new (GDK_WATCH);
+        gdk_window_set_cursor (gtk_widget_get_window (gtk_widget_get_toplevel (d->notebook)),
+                               cursor);
+        gdk_cursor_unref (cursor);
+
+        g_idle_add ((GSourceFunc)finish_language_chooser, d);
+}
+
+static gboolean
+language_key_press (GtkWidget         *combo,
+                    GdkEventKey       *event,
+                    UmUserPanelPrivate *d)
+{
+        GtkWidget *nb;
+
+        if (event->keyval == GDK_Escape) {
+                nb = get_widget (d, "account-language-notebook");
+                gtk_notebook_set_current_page (GTK_NOTEBOOK (nb), 1);
+
+                return TRUE;
+        }
+
+        return FALSE;
+}
+
+static void
+change_password (GtkButton *button, UmUserPanelPrivate *d)
+{
+        UmUser *user;
+
+        user = get_selected_user (d);
+
+        um_password_dialog_set_user (d->password_dialog, user);
+        um_password_dialog_show (d->password_dialog,
+                                  GTK_WINDOW (gtk_widget_get_toplevel (d->notebook)));
+
+        g_object_unref (user);
+}
+
+static void
+change_email_start (GtkButton         *button,
+                    UmUserPanelPrivate *d)
+{
+        gtk_notebook_set_current_page (GTK_NOTEBOOK (get_widget (d, "account-email-notebook")), 2);
+}
+
+static void
+change_email_done (GtkWidget         *entry,
+                   UmUserPanelPrivate *d)
+{
+        const gchar *text;
+        UmUser *user;
+
+        user = get_selected_user (d);
+
+        text = gtk_entry_get_text (GTK_ENTRY (entry));
+        if (g_strcmp0 (text, um_user_get_email (user)) != 0) {
+                um_user_set_email (user, text);
+        }
+
+        gtk_notebook_set_current_page (GTK_NOTEBOOK (get_widget (d, "account-email-notebook")), 1);
+}
+
+static void
+change_email_canceled (UmUserPanelPrivate *d)
+{
+        UmUser *user;
+        const gchar *text;
+        GtkWidget *widget;
+
+        user = get_selected_user (d);
+        text = um_user_get_email (user);
+
+        widget = get_widget (d, "account-email-value-label");
+        gtk_label_set_text (GTK_LABEL (widget), nonempty (text));
+        widget = get_widget (d, "account-email-button-label");
+        gtk_label_set_text (GTK_LABEL (widget), nonempty (text));
+        widget = get_widget (d, "account-email-entry");
+        gtk_entry_set_text (GTK_ENTRY (widget), text);
+
+        gtk_notebook_set_current_page (GTK_NOTEBOOK (get_widget (d, "account-email-notebook")), 1);
+}
+
+static void
+change_email_activate (GtkWidget         *widget,
+                       UmUserPanelPrivate *d)
+{
+        change_email_done (widget, d);
+}
+
+static gboolean
+change_email_focus_out (GtkWidget         *widget,
+                        GdkEventFocus     *event,
+                        UmUserPanelPrivate *d)
+{
+        change_email_done (widget, d);
+
+        return FALSE;
+}
+
+static gboolean
+change_email_key_press (GtkWidget         *widget,
+                        GdkEventKey       *event,
+                        UmUserPanelPrivate *d)
+{
+        if (event->keyval == GDK_Escape) {
+                change_email_canceled (d);
+        }
+
+        return FALSE;
+}
+
+static void
+change_location_start (GtkButton         *button,
+                       UmUserPanelPrivate *d)
+{
+        gtk_notebook_set_current_page (GTK_NOTEBOOK (get_widget (d, "account-location-notebook")), 2);
+}
+
+static void
+change_location_done (GtkWidget         *entry,
+                      UmUserPanelPrivate *d)
+{
+        const gchar *text;
+        UmUser *user;
+
+        user = get_selected_user (d);
+
+        text = gtk_entry_get_text (GTK_ENTRY (entry));
+        if (g_strcmp0 (text, um_user_get_location (user)) != 0) {
+                um_user_set_location (user, text);
+        }
+
+        gtk_notebook_set_current_page (GTK_NOTEBOOK (get_widget (d, "account-location-notebook")), 1);
+}
+
+static void
+change_location_canceled (UmUserPanelPrivate *d)
+{
+        UmUser *user;
+        const gchar *text;
+        GtkWidget *widget;
+
+        user = get_selected_user (d);
+        text = um_user_get_location (user);
+
+        widget = get_widget (d, "account-location-value-label");
+        gtk_label_set_text (GTK_LABEL (widget), nonempty (text));
+        widget = get_widget (d, "account-location-button-label");
+        gtk_label_set_text (GTK_LABEL (widget), nonempty (text));
+        widget = get_widget (d, "account-location-entry");
+        gtk_entry_set_text (GTK_ENTRY (widget), text);
+
+        gtk_notebook_set_current_page (GTK_NOTEBOOK (get_widget (d, "account-location-notebook")), 1);
+}
+
+static void
+change_location_activate (GtkWidget         *widget,
+                          UmUserPanelPrivate *d)
+{
+        change_location_done (widget, d);
+}
+
+static gboolean
+change_location_focus_out (GtkWidget         *widget,
+                           GdkEventFocus     *event,
+                           UmUserPanelPrivate *d)
+{
+        change_location_done (widget, d);
+
+        return FALSE;
+}
+
+static gboolean
+change_location_key_press (GtkWidget         *widget,
+                           GdkEventKey       *event,
+                           UmUserPanelPrivate *d)
+{
+        if (event->keyval == GDK_Escape) {
+                change_location_canceled (d);
+        }
+
+        return FALSE;
+}
+
+static void
+change_language_start (GtkButton         *button,
+                       UmUserPanelPrivate *d)
+{
+        gtk_notebook_set_current_page (GTK_NOTEBOOK (get_widget (d, "account-language-notebook")), 2);
+}
+
+static void
+change_fingerprint (GtkButton *button, UmUserPanelPrivate *d)
+{
+        GtkWidget *label, *label2;
+        UmUser *user;
+
+        user = get_selected_user (d);
+        g_assert (g_strcmp0 (g_get_user_name (), um_user_get_user_name (user)) == 0);
+
+        label = get_widget (d, "account-fingerprint-value-label");
+        label2 = get_widget (d, "account-fingerprint-button-label");
+        fingerprint_button_clicked (GTK_WINDOW (gtk_widget_get_toplevel (d->notebook)), label, label2, user);
+        g_object_unref (user);
+}
+
+static void
+toggle_login_options (GtkButton *button, UmUserPanelPrivate *d)
+{
+        GtkWidget *widget;
+        gboolean active;
+        GtkWidget *list;
+        GtkTreeSelection *selection;
+        GtkTreeModel *model;
+        GtkTreeIter iter;
+
+        active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
+        widget = get_widget (d, "top-level-notebook");
+        list = get_widget (d, "list-treeview");
+        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list));
+        model = gtk_tree_view_get_model (GTK_TREE_VIEW (list));
+        if (active) {
+                gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), 1);
+                gtk_tree_selection_unselect_all (selection);
+        }
+        else {
+                gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), 0);
+                if (!gtk_tree_selection_get_selected (selection, NULL, NULL)) {
+                        gtk_tree_model_get_iter_first (model, &iter);
+                        do {
+                                gint sort_key;
+
+                                gtk_tree_model_get (model, &iter, SORT_KEY_COL, &sort_key, -1);
+
+                                if (sort_key == 1) {
+                                        /* select the current user */
+                                        gtk_tree_selection_select_iter (selection, &iter);
+                                        break;
+                                }
+                        } while (gtk_tree_model_iter_next (model, &iter));
+                }
+        }
+}
+
+static gint
+sort_users (GtkTreeModel *model,
+            GtkTreeIter  *a,
+            GtkTreeIter  *b,
+            gpointer      data)
+{
+        UmUser *ua, *ub;
+        gint sa, sb;
+        gint result;
+
+        gtk_tree_model_get (model, a, USER_COL, &ua, SORT_KEY_COL, &sa, -1);
+        gtk_tree_model_get (model, b, USER_COL, &ub, SORT_KEY_COL, &sb, -1);
+
+        if (sa < sb) {
+                result = -1;
+        }
+        else if (sa > sb) {
+                result = 1;
+        }
+        else {
+                result = um_user_collate (ua, ub);
+        }
+
+        if (ua) {
+                g_object_unref (ua);
+        }
+        if (ub) {
+                g_object_unref (ub);
+        }
+
+        return result;
+}
+
+static gboolean
+dont_select_headings (GtkTreeSelection *selection,
+                      GtkTreeModel     *model,
+                      GtkTreePath      *path,
+                      gboolean          selected,
+                      gpointer          data)
+{
+        GtkTreeIter iter;
+        gboolean is_user;
+
+        gtk_tree_model_get_iter (model, &iter, path);
+        gtk_tree_model_get (model, &iter, USER_ROW_COL, &is_user, -1);
+
+        return is_user;
+}
+
+static void
+users_loaded (UmUserManager     *manager,
+              UmUserPanelPrivate *d)
+{
+        GSList *list, *l;
+        UmUser *user;
+        GtkWidget *dialog;
+
+        if (um_user_manager_no_service (d->um)) {
+                dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (d->notebook)),
+                                                 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_main_quit), NULL);
+                gtk_widget_show (dialog);
+        }
+
+        list = um_user_manager_list_users (d->um);
+        g_debug ("Got %d users\n", g_slist_length (list));
+
+        g_signal_connect (d->um, "user-changed", G_CALLBACK (user_changed), d);
+
+        for (l = list; l; l = l->next) {
+                user = l->data;
+                g_debug ("adding user %s\n", um_user_get_real_name (user));
+                user_added (d->um, user, d);
+        }
+        g_slist_free (list);
+
+        g_signal_connect (d->um, "user-added", G_CALLBACK (user_added), d);
+        g_signal_connect (d->um, "user-removed", G_CALLBACK (user_removed), d);
+}
+
+static void
+lockbutton_changed (PolkitLockButton *button,
+                    gpointer          data)
+{
+        UmUserPanelPrivate *d = data;
+        gboolean is_authorized;
+        gboolean self_selected;
+        UmUser *user;
+        GtkWidget *widget;
+
+        user = get_selected_user (d);
+        if (!user) {
+                return;
+        }
+
+        is_authorized = polkit_lock_button_get_is_authorized (button);
+        self_selected = um_user_get_uid (user) == geteuid ();
+
+        widget = get_widget (d, "add-user-button");
+        gtk_widget_set_sensitive (widget, is_authorized);
+        if (is_authorized) {
+                setup_tooltip_with_embedded_icon (widget, _("Create a user"), NULL, NULL);
+        }
+        else {
+                setup_tooltip_with_embedded_icon (widget,
+                                                  _("To create a user,\nclick the * icon first"),
+                                                  "*",
+                                                  "stock_lock");
+        }
+
+        widget = get_widget (d, "delete-user-button");
+        gtk_widget_set_sensitive (widget, is_authorized && !self_selected);
+        if (is_authorized) {
+                setup_tooltip_with_embedded_icon (widget, _("Delete the selected user"), NULL, NULL);
+        }
+        else {
+                setup_tooltip_with_embedded_icon (widget,
+                                                  _("To delete the selected user,\nclick the * icon first"),
+                                                  "*",
+                                                  "stock_lock");
+        }
+
+        if (is_authorized) {
+                if (gtk_notebook_get_current_page (GTK_NOTEBOOK (get_widget (d, "account-type-notebook"))) == 0) {
+
+                        gtk_notebook_set_current_page (GTK_NOTEBOOK (get_widget (d, "account-type-notebook")), 1);
+                }
+        }
+        else {
+                gtk_notebook_set_current_page (GTK_NOTEBOOK (get_widget (d, "account-type-notebook")), 0);
+        }
+
+        if (is_authorized || self_selected) {
+                gtk_widget_show (get_widget (d, "user-icon-button"));
+                gtk_widget_hide (get_widget (d, "user-icon-nonbutton"));
+
+                gtk_notebook_set_current_page (GTK_NOTEBOOK (get_widget (d, "full-name-notebook")), 1);
+                gtk_notebook_set_current_page (GTK_NOTEBOOK (get_widget (d, "account-email-notebook")), 1);
+                gtk_notebook_set_current_page (GTK_NOTEBOOK (get_widget (d, "account-language-notebook")), 1);
+                gtk_notebook_set_current_page (GTK_NOTEBOOK (get_widget (d, "account-location-notebook")), 1);
+                gtk_notebook_set_current_page (GTK_NOTEBOOK (get_widget (d, "account-password-notebook")), 1);
+                gtk_notebook_set_current_page (GTK_NOTEBOOK (get_widget (d, "account-fingerprint-notebook")), 1);
+        }
+        else {
+                gtk_widget_hide (get_widget (d, "user-icon-button"));
+                gtk_widget_show (get_widget (d, "user-icon-nonbutton"));
+
+                gtk_notebook_set_current_page (GTK_NOTEBOOK (get_widget (d, "full-name-notebook")), 0);
+                gtk_notebook_set_current_page (GTK_NOTEBOOK (get_widget (d, "account-email-notebook")), 0);
+                gtk_notebook_set_current_page (GTK_NOTEBOOK (get_widget (d, "account-language-notebook")), 0);
+                gtk_notebook_set_current_page (GTK_NOTEBOOK (get_widget (d, "account-location-notebook")), 0);
+                gtk_notebook_set_current_page (GTK_NOTEBOOK (get_widget (d, "account-password-notebook")), 0);
+                gtk_notebook_set_current_page (GTK_NOTEBOOK (get_widget (d, "account-fingerprint-notebook")), 0);
+        }
+
+        um_password_dialog_set_privileged (d->password_dialog, is_authorized);
+}
+
+static void
+focus_moved (GtkWindow         *window,
+             GtkWidget         *widget,
+             UmUserPanelPrivate *d)
+{
+        GtkWidget *nb;
+
+        nb = get_widget (d, "account-type-notebook");
+
+        if (gtk_notebook_get_current_page (GTK_NOTEBOOK (nb)) == 2 &&
+            (!widget || !gtk_widget_is_ancestor (widget, nb))) {
+                gtk_notebook_set_current_page (GTK_NOTEBOOK (nb), 1);
+        }
+
+        nb = get_widget (d, "account-language-notebook");
+
+        if (gtk_notebook_get_current_page (GTK_NOTEBOOK (nb)) == 2 &&
+            (!widget || !gtk_widget_is_ancestor (widget, nb))) {
+                gtk_notebook_set_current_page (GTK_NOTEBOOK (nb), 1);
+        }
+}
+
+static gboolean
+match_user (GtkTreeModel *model,
+            gint          column,
+            const gchar  *key,
+            GtkTreeIter  *iter,
+            gpointer      search_data)
+{
+        UmUser *user;
+        const gchar *name;
+        gchar *normalized_key = NULL;
+        gchar *normalized_name = NULL;
+        gchar *case_normalized_key = NULL;
+        gchar *case_normalized_name = NULL;
+        gchar *p;
+        gboolean result = TRUE;
+        gint i;
+
+        gtk_tree_model_get (model, iter, USER_COL, &user, -1);
+
+        if (!user) {
+                goto out;
+        }
+
+        normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
+        if (!normalized_key) {
+                goto out;
+        }
+
+        case_normalized_key = g_utf8_casefold (normalized_key, -1);
+
+        for (i = 0; i < 2; i++) {
+                if (i == 0)
+                        name = um_user_get_real_name (user);
+                else
+                        name = um_user_get_user_name (user);
+
+                g_free (normalized_name);
+                normalized_name = g_utf8_normalize (name, -1, G_NORMALIZE_ALL);
+                if (normalized_name) {
+                        g_free (case_normalized_name);
+                        case_normalized_name = g_utf8_casefold (normalized_name, -1);
+                        p = strstr (case_normalized_name, case_normalized_key);
+
+                        /* poor man's \b */
+                        if (p == case_normalized_name || (p && p[-1] == ' ')) {
+                                result = FALSE;
+                                break;
+                        }
+                }
+        }
+
+ out:
+        if (user) {
+                g_object_unref (user);
+        }
+        g_free (normalized_key);
+        g_free (case_normalized_key);
+        g_free (normalized_name);
+        g_free (case_normalized_name);
+
+        return result;
+}
+
+static void
+setup_main_window (UmUserPanelPrivate *d)
+{
+        GtkWidget *window;
+        GtkWidget *userlist;
+        GtkTreeModel *model;
+        GtkListStore *store;
+        GtkTreeViewColumn *column;
+        GtkCellRenderer *cell;
+        GtkTreeSelection *selection;
+        GtkWidget *button;
+        GtkTreeIter iter;
+        gint expander_size;
+        GtkWidget *box;
+
+        window = get_widget (d, "user-account-window");
+        g_signal_connect (window, "delete-event", G_CALLBACK (gtk_main_quit), NULL);
+
+        userlist = get_widget (d, "list-treeview");
+        store = gtk_list_store_new (NUM_USER_LIST_COLS,
+                                    UM_TYPE_USER,
+                                    GDK_TYPE_PIXBUF,
+                                    G_TYPE_STRING,
+                                    G_TYPE_BOOLEAN,
+                                    G_TYPE_STRING,
+                                    G_TYPE_BOOLEAN,
+                                    G_TYPE_INT);
+        model = (GtkTreeModel *)store;
+        gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (model), sort_users, NULL, NULL);
+        gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, GTK_SORT_ASCENDING);
+        gtk_tree_view_set_model (GTK_TREE_VIEW (userlist), model);
+        gtk_tree_view_set_search_column (GTK_TREE_VIEW (userlist), USER_COL);
+        gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (userlist),
+                                             match_user, NULL, NULL);
+
+        g_signal_connect (d->um, "users-loaded", G_CALLBACK (users_loaded), d);
+
+        gtk_widget_style_get (userlist, "expander-size", &expander_size, NULL);
+        gtk_tree_view_set_level_indentation (GTK_TREE_VIEW (userlist), - (expander_size + 6));
+
+        gtk_list_store_append (store, &iter);
+        gtk_list_store_set (store, &iter,
+                            TITLE_COL, "<small><span foreground=\"#555555\">My Account</span></small>",
+                            HEADING_ROW_COL, TRUE,
+                            SORT_KEY_COL, 0,
+                            -1);
+        gtk_list_store_append (store, &iter);
+        gtk_list_store_set (store, &iter,
+                            TITLE_COL, "<small><span foreground=\"#555555\">Other Accounts</span></small>",
+                            HEADING_ROW_COL, TRUE,
+                            SORT_KEY_COL, 2,
+                            -1);
+
+        column = gtk_tree_view_column_new ();
+        cell = gtk_cell_renderer_pixbuf_new ();
+        gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (column), cell, FALSE);
+        gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (column), cell, "pixbuf", FACE_COL);
+        gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (column), cell, "visible", USER_ROW_COL);
+        cell = gtk_cell_renderer_text_new ();
+        g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, "width-chars", 18, NULL);
+        gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (column), cell, TRUE);
+        gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (column), cell, "markup", NAME_COL);
+        gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (column), cell, "visible", USER_ROW_COL);
+        cell = gtk_cell_renderer_text_new ();
+        gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (column), cell, TRUE);
+        gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (column), cell, "markup", TITLE_COL);
+        gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (column), cell, "visible", HEADING_ROW_COL);
+
+        gtk_tree_view_append_column (GTK_TREE_VIEW (userlist), column);
+
+        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (userlist));
+        gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
+        g_signal_connect (selection, "changed", G_CALLBACK (selected_user_changed), d);
+        gtk_tree_selection_set_select_function (selection, dont_select_headings, NULL, NULL);
+
+        button = get_widget (d, "add-user-button");
+        g_signal_connect (button, "clicked", G_CALLBACK (add_user), d);
+
+        button = get_widget (d, "delete-user-button");
+        g_signal_connect (button, "clicked", G_CALLBACK (delete_user), d);
+
+        button = get_widget (d, "user-icon-nonbutton");
+        setup_tooltip_with_embedded_icon (button,
+                                          _("To make changes,\nclick the * icon first"),
+                                          "*",
+                                          "stock_lock");
+        g_signal_connect (button, "button-release-event",
+                           G_CALLBACK (show_tooltip_now), NULL);
+
+        button = get_widget (d, "full-name-value-label");
+        setup_tooltip_with_embedded_icon (button,
+                                          _("To make changes,\nclick the * icon first"),
+                                          "*",
+                                          "stock_lock");
+        g_signal_connect (button, "button-release-event",
+                           G_CALLBACK (show_tooltip_now), NULL);
+
+        button = get_widget (d, "full-name-button");
+        g_signal_connect (button, "clicked", G_CALLBACK (change_name_start), d);
+        button = get_widget (d, "full-name-entry");
+        g_signal_connect (button, "style-set", G_CALLBACK (name_style_set), d);
+        g_signal_connect (button, "activate", G_CALLBACK (change_name_activate), d);
+        g_signal_connect (button, "focus-out-event", G_CALLBACK (change_name_focus_out), d);
+        g_signal_connect (button, "key-press-event", G_CALLBACK (change_name_key_press), d);
+
+        button = get_widget (d, "account-type-value-label");
+        setup_tooltip_with_embedded_icon (button,
+                                          _("To change the account type,\nclick the * icon first"),
+                                          "*",
+                                          "stock_lock");
+        g_signal_connect (button, "button-release-event",
+                           G_CALLBACK (show_tooltip_now), NULL);
+
+        button = get_widget (d, "account-type-button");
+        g_signal_connect (button, "clicked", G_CALLBACK (change_account_type_start), d);
+        button = get_widget (d, "account-type-combo");
+        g_signal_connect (button, "changed", G_CALLBACK (account_type_changed), d);
+
+        button = get_widget (d, "account-password-value-label");
+        setup_tooltip_with_embedded_icon (button,
+                                          _("To make changes,\nclick the * icon first"),
+                                          "*",
+                                          "stock_lock");
+        g_signal_connect (button, "button-release-event",
+                           G_CALLBACK (show_tooltip_now), NULL);
+
+        button = get_widget (d, "account-password-button");
+        g_signal_connect (button, "clicked", G_CALLBACK (change_password), d);
+
+        button = get_widget (d, "account-email-value-label");
+        setup_tooltip_with_embedded_icon (button,
+                                          _("To make changes,\nclick the * icon first"),
+                                          "*",
+                                          "stock_lock");
+        g_signal_connect (button, "button-release-event",
+                           G_CALLBACK (show_tooltip_now), NULL);
+
+        button = get_widget (d, "account-email-button");
+        g_signal_connect (button, "clicked", G_CALLBACK (change_email_start), d);
+        button = get_widget (d, "account-email-entry");
+        g_signal_connect (button, "activate", G_CALLBACK (change_email_activate), d);
+        g_signal_connect (button, "focus-out-event", G_CALLBACK (change_email_focus_out), d);
+        g_signal_connect (button, "key-press-event", G_CALLBACK (change_email_key_press), d);
+
+        button = get_widget (d, "account-language-value-label");
+        setup_tooltip_with_embedded_icon (button,
+                                          _("To make changes,\nclick the * icon first"),
+                                          "*",
+                                          "stock_lock");
+        g_signal_connect (button, "button-release-event",
+                           G_CALLBACK (show_tooltip_now), NULL);
+
+        button = get_widget (d, "account-language-button");
+        g_signal_connect (button, "clicked", G_CALLBACK (change_language_start), d);
+        button = get_widget (d, "account-language-combo");
+        g_signal_connect (button, "changed", G_CALLBACK (language_changed), d);
+        g_signal_connect (button, "key-press-event", G_CALLBACK (language_key_press), d);
+
+        /* ugly hack to catch the combo boxes losing focus */
+        g_signal_connect (window, "set-focus", G_CALLBACK (focus_moved), d);
+
+        button = get_widget (d, "account-location-value-label");
+        setup_tooltip_with_embedded_icon (button,
+                                          _("To make changes,\nclick the * icon first"),
+                                          "*",
+                                          "stock_lock");
+        g_signal_connect (button, "button-release-event",
+                           G_CALLBACK (show_tooltip_now), NULL);
+
+        button = get_widget (d, "account-location-button");
+        g_signal_connect (button, "clicked", G_CALLBACK (change_location_start), d);
+        button = get_widget (d, "account-location-entry");
+        g_signal_connect (button, "activate", G_CALLBACK (change_location_activate), d);
+        g_signal_connect (button, "focus-out-event", G_CALLBACK (change_location_focus_out), d);
+        g_signal_connect (button, "key-press-event", G_CALLBACK (change_location_key_press), d);
+
+        button = get_widget (d, "account-fingerprint-button");
+        g_signal_connect (button, "clicked",
+                          G_CALLBACK (change_fingerprint), d);
+
+        button = polkit_lock_button_new ("org.freedesktop.accounts.user-administration");
+        gtk_widget_show (button);
+        box = get_widget (d, "userlist-vbox");
+        gtk_box_pack_end (GTK_BOX (box), button, FALSE, FALSE, 0);
+        g_signal_connect (button, "changed",
+                          G_CALLBACK (lockbutton_changed), d);
+        lockbutton_changed (POLKIT_LOCK_BUTTON (button), d);
+        d->lock_button = button;
+
+        button = get_widget (d, "add-user-button");
+        setup_tooltip_with_embedded_icon (button,
+                                          _("To create a user,\nclick the * icon first"),
+                                          "*",
+                                          "stock_lock");
+        button = get_widget (d, "delete-user-button");
+        setup_tooltip_with_embedded_icon (button,
+                                          _("To delete the selected user,\nclick the * icon first"),
+                                          "*",
+                                          "stock_lock");
+}
+
+static void
+um_user_panel_init (UmUserPanel *self)
+{
+        UmUserPanelPrivate *d;
+        GError *error;
+        volatile GType type;
+        const gchar *filename;
+        GtkWidget *button;
+
+        dbus_g_object_register_marshaller (fprintd_marshal_VOID__STRING_BOOLEAN,
+                                           G_TYPE_NONE, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_INVALID);
+
+        d = self->priv = UM_USER_PANEL_PRIVATE (self);
+
+        /* register types that the builder might need */
+        type = um_strength_bar_get_type ();
+
+        d->builder = gtk_builder_new ();
+        d->um = um_user_manager_ref_default ();
+
+        filename = UIDIR "/user-accounts-dialog.ui";
+        if (!g_file_test (filename, G_FILE_TEST_EXISTS))
+                filename = "../data/user-accounts-dialog.ui";
+        error = NULL;
+        if (!gtk_builder_add_from_file (d->builder, filename, &error)) {
+                g_error ("%s", error->message);
+                g_error_free (error);
+                exit (1);
+        }
+
+        d->authority = polkit_authority_get ();
+
+        setup_main_window (d);
+        d->login_options = um_login_options_new (d->builder);
+        d->account_dialog = um_account_dialog_new ();
+        d->password_dialog = um_password_dialog_new ();
+        button = get_widget (d, "user-icon-button");
+        d->notebook = get_widget (d, "top-level-notebook");
+        d->photo_dialog = um_photo_dialog_new (button);
+        gtk_widget_reparent (d->notebook, GTK_WIDGET (self));
+}
+
+static void
+um_user_panel_dispose (GObject *object)
+{
+  UmUserPanelPrivate *priv = UM_USER_PANEL (object)->priv;
+
+  if (priv->um)
+    {
+      g_object_unref (priv->um);
+      priv->um = NULL;
+    }
+
+  if (priv->builder)
+    {
+      g_object_unref (priv->builder);
+      priv->builder = NULL;
+    }
+
+  if (priv->account_dialog)
+    {
+      um_account_dialog_free (priv->account_dialog);
+      priv->account_dialog = NULL;
+    }
+
+  if (priv->password_dialog)
+    {
+      um_password_dialog_free (priv->password_dialog);
+      priv->password_dialog = NULL;
+    }
+
+  if (priv->photo_dialog)
+    {
+      um_photo_dialog_free (priv->photo_dialog);
+      priv->photo_dialog = NULL;
+    }
+
+  if (priv->login_options)
+    {
+      um_login_options_free (priv->login_options);
+      priv->login_options = NULL;
+    }
+
+  if (priv->authority)
+    {
+      g_object_unref (priv->authority);
+      priv->authority = NULL;
+    }
+
+  G_OBJECT_CLASS (um_user_panel_parent_class)->dispose (object);
+}
+
+static void
+um_user_panel_finalize (GObject *object)
+{
+  G_OBJECT_CLASS (um_user_panel_parent_class)->finalize (object);
+}
+
+static void
+um_user_panel_class_init (UmUserPanelClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (UmUserPanelPrivate));
+
+  object_class->dispose = um_user_panel_dispose;
+  object_class->finalize = um_user_panel_finalize;
+}
+
+static void
+um_user_panel_class_finalize (UmUserPanelClass *klass)
+{
+}
+
+void
+um_user_panel_register (GIOModule *module)
+{
+  um_user_panel_register_type (G_TYPE_MODULE (module));
+  g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT,
+                                  UM_TYPE_USER_PANEL,
+                                  "users", 0);
+}
diff --git a/src/um-user-panel.h b/src/um-user-panel.h
new file mode 100644
index 0000000..4f5aec0
--- /dev/null
+++ b/src/um-user-panel.h
@@ -0,0 +1,59 @@
+/* -*- 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 3 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.
+ *
+ * Written by: Matthias Clasen <mclasen redhat com>
+ */
+
+#ifndef _UM_USER_PANEL_H
+#define _UM_USER_PANEL_H
+
+#include <libgnome-control-center/cc-panel.h>
+
+G_BEGIN_DECLS
+
+#define UM_TYPE_USER_PANEL um_user_panel_get_type()
+
+#define UM_USER_PANEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), UM_TYPE_USER_PANEL, UmUserPanel))
+#define UM_USER_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UM_TYPE_USER_PANEL, UmUserPanelClass))
+#define UM_IS_USER_PANEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UM_TYPE_USER_PANEL))
+#define UM_IS_USER_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UM_TYPE_USER_PANEL))
+#define UM_USER_PANEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), UM_TYPE_USER_PANEL, UmUserPanelClass))
+
+typedef struct _UmUserPanel UmUserPanel;
+typedef struct _UmUserPanelClass UmUserPanelClass;
+typedef struct _UmUserPanelPrivate UmUserPanelPrivate;
+
+struct _UmUserPanel
+{
+  CcPanel parent;
+
+  UmUserPanelPrivate *priv;
+};
+
+struct _UmUserPanelClass
+{
+  CcPanelClass parent_class;
+};
+
+GType um_user_panel_get_type (void) G_GNUC_CONST;
+
+void  um_user_panel_register (GIOModule *module);
+
+G_END_DECLS
+
+#endif /* _UM_USER_PANEL_H */
diff --git a/src/user-panel.desktop.in b/src/user-panel.desktop.in
new file mode 100644
index 0000000..f2ece0d
--- /dev/null
+++ b/src/user-panel.desktop.in
@@ -0,0 +1,9 @@
+[Desktop Entry]
+Name=Users
+Comment=Add or remove users
+Categories=System;Settings;
+Icon=system-users
+Exec=gnome-control-center users
+Type=Application
+Terminal=false
+X-GNOME-Settings-Panel=users



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]