[gnome-control-center] Add user-accounts dialog



commit bf5cb4401669f4881bb7191ecbbcc957ef456950
Author: William Jon McCann <jmccann redhat com>
Date:   Sat Oct 30 16:14:30 2010 -0400

    Add user-accounts dialog
    
    Copied from the accounts-dialog git module.

 configure.ac                                       |   16 +-
 panels/Makefile.am                                 |    1 +
 panels/user-accounts/Makefile.am                   |  102 ++
 panels/user-accounts/data/Makefile.am              |   29 +
 panels/user-accounts/data/account-dialog.ui        |  268 ++++
 panels/user-accounts/data/account-fingerprint.ui   |  278 +++++
 .../data/gnome-user-accounts-panel.desktop.in.in   |   15 +
 panels/user-accounts/data/icons/Makefile.am        |   31 +
 .../data/icons/gnome-about-me-lock-open.png        |  Bin 0 -> 2913 bytes
 .../data/icons/gnome-about-me-lock.png             |  Bin 0 -> 2978 bytes
 .../user-accounts/data/icons/left-index-finger.png |  Bin 0 -> 1515 bytes
 .../user-accounts/data/icons/left-index-finger.svg |  177 +++
 .../data/icons/left-little-finger.png              |  Bin 0 -> 1500 bytes
 .../data/icons/left-little-finger.svg              |  180 +++
 .../data/icons/left-middle-finger.png              |  Bin 0 -> 1483 bytes
 .../data/icons/left-middle-finger.svg              |  180 +++
 .../user-accounts/data/icons/left-ring-finger.png  |  Bin 0 -> 1512 bytes
 .../user-accounts/data/icons/left-ring-finger.svg  |  180 +++
 panels/user-accounts/data/icons/left-thumb.png     |  Bin 0 -> 1512 bytes
 panels/user-accounts/data/icons/left-thumb.svg     |  180 +++
 panels/user-accounts/data/icons/print_error.png    |  Bin 0 -> 4160 bytes
 panels/user-accounts/data/icons/print_error.svg    |  525 ++++++++
 panels/user-accounts/data/icons/print_ok.png       |  Bin 0 -> 3677 bytes
 panels/user-accounts/data/icons/print_ok.svg       |  310 +++++
 .../data/icons/right-index-finger.png              |  Bin 0 -> 1506 bytes
 .../data/icons/right-index-finger.svg              |  179 +++
 .../data/icons/right-little-finger.png             |  Bin 0 -> 1479 bytes
 .../data/icons/right-little-finger.svg             |  182 +++
 .../data/icons/right-middle-finger.png             |  Bin 0 -> 1468 bytes
 .../data/icons/right-middle-finger.svg             |  182 +++
 .../user-accounts/data/icons/right-ring-finger.png |  Bin 0 -> 1506 bytes
 .../user-accounts/data/icons/right-ring-finger.svg |  182 +++
 panels/user-accounts/data/icons/right-thumb.png    |  Bin 0 -> 1486 bytes
 panels/user-accounts/data/icons/right-thumb.svg    |  182 +++
 panels/user-accounts/data/language-chooser.ui      |   90 ++
 panels/user-accounts/data/password-dialog.ui       |  531 ++++++++
 panels/user-accounts/data/photo-dialog.ui          |  304 +++++
 panels/user-accounts/data/user-accounts-dialog.ui  |  726 +++++++++++
 panels/user-accounts/fingerprint-strings.h         |  111 ++
 panels/user-accounts/fprintd-marshal.list          |    1 +
 panels/user-accounts/gdm-languages.c               | 1003 +++++++++++++++
 panels/user-accounts/gdm-languages.h               |   41 +
 panels/user-accounts/locarchive.h                  |   97 ++
 panels/user-accounts/run-passwd.c                  |  772 ++++++++++++
 panels/user-accounts/run-passwd.h                  |   58 +
 panels/user-accounts/um-account-dialog.c           |  493 ++++++++
 panels/user-accounts/um-account-dialog.h           |   43 +
 panels/user-accounts/um-account-type.c             |   43 +
 panels/user-accounts/um-account-type.h             |   37 +
 panels/user-accounts/um-crop-area.c                |  817 +++++++++++++
 panels/user-accounts/um-crop-area.h                |   65 +
 panels/user-accounts/um-editable-button.c          |  403 ++++++
 panels/user-accounts/um-editable-button.h          |   72 ++
 panels/user-accounts/um-editable-combo.c           |  439 +++++++
 panels/user-accounts/um-editable-combo.h           |   76 ++
 panels/user-accounts/um-editable-entry.c           |  489 ++++++++
 panels/user-accounts/um-editable-entry.h           |   72 ++
 panels/user-accounts/um-fingerprint-dialog.c       |  674 ++++++++++
 panels/user-accounts/um-fingerprint-dialog.h       |   28 +
 panels/user-accounts/um-language-dialog.c          |  555 +++++++++
 panels/user-accounts/um-language-dialog.h          |   49 +
 panels/user-accounts/um-lockbutton.c               |  637 ++++++++++
 panels/user-accounts/um-lockbutton.h               |   70 ++
 panels/user-accounts/um-login-options.c            |  433 +++++++
 panels/user-accounts/um-login-options.h            |   34 +
 panels/user-accounts/um-password-dialog.c          |  834 +++++++++++++
 panels/user-accounts/um-password-dialog.h          |   43 +
 panels/user-accounts/um-photo-dialog.c             |  693 +++++++++++
 panels/user-accounts/um-photo-dialog.h             |   39 +
 panels/user-accounts/um-strength-bar.c             |  261 ++++
 panels/user-accounts/um-strength-bar.h             |   62 +
 panels/user-accounts/um-user-manager.c             |  624 ++++++++++
 panels/user-accounts/um-user-manager.h             |  112 ++
 panels/user-accounts/um-user-module.c              |   41 +
 panels/user-accounts/um-user-panel.c               | 1286 ++++++++++++++++++++
 panels/user-accounts/um-user-panel.h               |   59 +
 panels/user-accounts/um-user.c                     | 1093 +++++++++++++++++
 panels/user-accounts/um-user.h                     |  107 ++
 panels/user-accounts/um-utils.c                    |  382 ++++++
 panels/user-accounts/um-utils.h                    |   56 +
 po/POTFILES.in                                     |   19 +
 po/POTFILES.skip                                   |    2 +
 82 files changed, 18354 insertions(+), 1 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 72f60a1..867f15c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -94,7 +94,7 @@ PKG_CHECK_MODULES(DBUS, dbus-1 dbus-glib-1)
 PKG_CHECK_MODULES(GNOME_DESKTOP, gnome-desktop-3.0)
 PKG_CHECK_MODULES(DEFAULT_APPLICATIONS_CAPPLET, libxml-2.0)
 PKG_CHECK_MODULES(GSD_DBUS, gnome-settings-daemon)
-PKG_CHECK_MODULES(GIO, gio-2.0)
+PKG_CHECK_MODULES(GIO, gio-2.0 gio-unix-2.0)
 PKG_CHECK_MODULES(XML, libxml-2.0)
 PKG_CHECK_MODULES(CANBERRA, libcanberra-gtk3 >= $CANBERRA_REQUIRED_VERSION)
 AC_SUBST(CANBERRA_CFLAGS)
@@ -112,6 +112,16 @@ AC_SUBST(GTK_ENGINE_DIR)
 
 PKG_CHECK_MODULES(GLIB, glib-2.0)
 
+PKG_CHECK_MODULES(POLKIT, polkit-gobject-1)
+PKG_CHECK_MODULES(CHEESE, gstreamer-0.10 cheese-gtk >= 2.29.90, have_cheese=yes, have_cheese=no)
+
+if test x$have_cheese = xyes ; then
+        AC_DEFINE(HAVE_CHEESE, 1, [Define to 1 to enable cheese webcam support])
+fi
+
+AC_DEFINE_UNQUOTED([ISO_CODES_PREFIX],["`$PKG_CONFIG --variable=prefix iso-codes`"],[ISO codes prefix])
+ISO_CODES=iso-codes
+
 dnl
 dnl Check for Xft version 2; we build in extra functionality to the font capplet
 dnl when we have it.
@@ -361,6 +371,10 @@ panels/sound/data/icons/scalable/devices/Makefile
 panels/sound/data/sounds/Makefile
 panels/universal-access/Makefile
 panels/universal-access/gnome-universal-access-panel.desktop.in
+panels/user-accounts/Makefile
+panels/user-accounts/data/Makefile
+panels/user-accounts/data/gnome-user-accounts-panel.desktop.in
+panels/user-accounts/data/icons/Makefile
 po/Makefile.in
 shell/Makefile
 shell/gnome-control-center.desktop.in
diff --git a/panels/Makefile.am b/panels/Makefile.am
index 225fcbc..945270e 100644
--- a/panels/Makefile.am
+++ b/panels/Makefile.am
@@ -8,6 +8,7 @@ SUBDIRS= \
 	default-applications \
 	keybindings \
 	universal-access \
+	user-accounts \
 	datetime
 
 -include $(top_srcdir)/git.mk
diff --git a/panels/user-accounts/Makefile.am b/panels/user-accounts/Makefile.am
new file mode 100644
index 0000000..8cebc10
--- /dev/null
+++ b/panels/user-accounts/Makefile.am
@@ -0,0 +1,102 @@
+SUBDIRS = data
+
+# This is used in GNOMECC_CAPPLETS_CFLAGS
+cappletname = user-accounts
+NULL =
+
+ccpanelsdir = $(PANELS_DIR)
+ccpanels_LTLIBRARIES = libuser-accounts.la
+
+AM_CPPFLAGS =						\
+	$(GNOMECC_CAPPLETS_CFLAGS)			\
+	-DDATADIR=\""$(datadir)"\"			\
+	-DUIDIR=\""$(pkgdatadir)/ui/user-accounts"\"	\
+	-DLIBLOCALEDIR=\""$(prefix)/lib/locale"\"       \
+	-DGNOMELOCALEDIR=\""$(datadir)/locale"\"        \
+	-DUM_PIXMAP_DIR=\""$(pkgdatadir)/pixmaps"\"	\
+	$(PANEL_CFLAGS)					\
+	$(GNOME_DESKTOP_CFLAGS) 			\
+	$(POLKIT_CFLAGS)				\
+	$(CHEESE_CFLAGS)				\
+	$(DBUS_CFLAGS)					\
+	$(GIO_CFLAGS)					\
+	$(WARN_CFLAGS)
+
+MARSHALFILES = marshal.c marshal.h
+BUILT_SOURCES = $(MARSHALFILES)
+
+marshal.h: fprintd-marshal.list
+	@GLIB_GENMARSHAL@ --prefix=fprintd_marshal $< --header > $@
+marshal.c: fprintd-marshal.list
+	@GLIB_GENMARSHAL@ --prefix=fprintd_marshal $< --body --header > $@
+
+libuser_accounts_la_CFLAGS = 		\
+	$(PANEL_CFLAGS)
+
+libuser_accounts_la_SOURCES =		\
+	gdm-languages.h 		\
+	gdm-languages.c 		\
+	um-account-type.h		\
+	um-account-type.c 		\
+	um-user.h 			\
+	um-user.c 			\
+	um-user-manager.h 		\
+	um-user-manager.c 		\
+	um-account-dialog.h		\
+	um-account-dialog.c		\
+	um-language-dialog.h 		\
+	um-language-dialog.c		\
+	um-lockbutton.h			\
+	um-lockbutton.c			\
+	um-login-options.h		\
+	um-login-options.c		\
+	um-password-dialog.h		\
+	um-password-dialog.c		\
+	um-photo-dialog.h		\
+	um-photo-dialog.c		\
+	um-crop-area.h			\
+	um-crop-area.c			\
+	um-fingerprint-dialog.h		\
+	um-fingerprint-dialog.c		\
+	um-utils.h			\
+	um-utils.c			\
+	fingerprint-strings.h		\
+	um-strength-bar.h		\
+	um-strength-bar.c		\
+	run-passwd.h			\
+	run-passwd.c			\
+	$(MARSHALFILES)			\
+	um-editable-button.h		\
+	um-editable-button.c		\
+	um-editable-entry.h		\
+	um-editable-entry.c		\
+	um-editable-combo.h		\
+	um-editable-combo.c		\
+	um-user-panel.h 		\
+	um-user-panel.c			\
+	um-user-module.c
+
+libuser_accounts_la_LIBADD = 		\
+	$(PANEL_LIBS)			\
+	$(GNOME_DESKTOP_LIBS)		\
+	$(POLKIT_LIBS)			\
+	$(CHEESE_LIBS)			\
+	$(DBUS_LIBS)			\
+	$(GIO_LIBS)			\
+	-lcrypt
+
+libuser_accounts_la_LDFLAGS = $(PANEL_LDFLAGS)
+
+EXTRA_DIST = \
+	locarchive.h \
+	fprintd-marshal.list
+
+CLEANFILES =				\
+	$(BUILT_SOURCES)		\
+	$(NULL)
+
+MAINTAINERCLEANFILES =                  \
+        *~                              \
+        Makefile.in
+
+-include $(top_srcdir)/git.mk
diff --git a/panels/user-accounts/data/Makefile.am b/panels/user-accounts/data/Makefile.am
new file mode 100644
index 0000000..fbc3825
--- /dev/null
+++ b/panels/user-accounts/data/Makefile.am
@@ -0,0 +1,29 @@
+SUBDIRS = icons
+
+uidir = $(pkgdatadir)/ui/user-accounts
+ui_DATA = \
+	account-dialog.ui	\
+	language-chooser.ui	\
+	password-dialog.ui	\
+	photo-dialog.ui		\
+	user-accounts-dialog.ui \
+	account-fingerprint.ui
+
+ INTLTOOL_DESKTOP_RULE@
+
+desktopdir = $(datadir)/applications
+Desktop_in_files = gnome-user-accounts-panel.desktop.in
+desktop_DATA = $(Desktop_in_files:.desktop.in=.desktop)
+
+EXTRA_DIST = 					\
+	gnome-user-accounts-panel.desktop.in.in	\
+	$(ui_DATA)
+
+CLEANFILES =					\
+	gnome-user-accounts-panel.desktop	\
+	$(NULL)
+
+DISTCLEANFILES =				\
+	$(NULL)
+
+-include $(top_srcdir)/git.mk
diff --git a/panels/user-accounts/data/account-dialog.ui b/panels/user-accounts/data/account-dialog.ui
new file mode 100644
index 0000000..5e229ce
--- /dev/null
+++ b/panels/user-accounts/data/account-dialog.ui
@@ -0,0 +1,268 @@
+<?xml version="1.0"?>
+<interface>
+  <!-- interface-requires gtk+ 2.12 -->
+  <!-- interface-naming-policy toplevel-contextual -->
+  <object class="GtkListStore" id="username-model">
+    <columns>
+      <!-- column-name gchararray -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
+  <object class="GtkListStore" id="account-type-model">
+    <columns>
+      <!-- column-name gchararray -->
+      <column type="gchararray"/>
+      <!-- column-name gint -->
+      <column type="gint"/>
+    </columns>
+    <data>
+      <row>
+        <col id="0" translatable="yes" context="Account type">Standard</col>
+        <col id="1">0</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes" context="Account type">Administrator</col>
+        <col id="1">1</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes" context="Account type">Supervised</col>
+        <col id="1">2</col>
+      </row>
+    </data>
+  </object>
+  <object class="GtkDialog" id="dialog">
+    <property name="border_width">5</property>
+    <property name="title"> </property>
+    <property name="resizable">False</property>
+    <property name="modal">True</property>
+    <property name="window_position">center-on-parent</property>
+    <property name="icon_name">system-users</property>
+    <property name="type_hint">dialog</property>
+    <child internal-child="vbox">
+      <object class="GtkVBox" id="content-area">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child>
+          <object class="GtkVBox" id="vbox1">
+            <property name="visible">True</property>
+            <property name="border_width">10</property>
+            <property name="spacing">6</property>
+            <child>
+              <object class="GtkTable" id="table1">
+                <property name="visible">True</property>
+                <property name="n_rows">5</property>
+                <property name="n_columns">2</property>
+                <property name="column_spacing">6</property>
+                <property name="row_spacing">6</property>
+                <child>
+                  <object class="GtkComboBoxEntry" id="username-combo">
+                    <property name="visible">True</property>
+                    <property name="model">username-model</property>
+                    <property name="text_column">0</property>
+                    <child internal-child="entry">
+                      <object class="GtkEntry" id="username-entry">
+                        <property name="activates_default">True</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">4</property>
+                    <property name="bottom_attach">5</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label6">
+                    <property name="visible">True</property>
+                    <property name="xalign">1</property>
+                    <property name="label" translatable="yes">_Username:</property>
+                    <property name="use_underline">True</property>
+                    <property name="mnemonic_widget">username-combo</property>
+                    <attributes>
+                      <attribute name="foreground" value="#555555555555"/>
+                    </attributes>
+                  </object>
+                  <packing>
+                    <property name="top_attach">4</property>
+                    <property name="bottom_attach">5</property>
+                    <property name="x_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkHBox" id="hbox1">
+                    <property name="visible">True</property>
+                    <child>
+                      <object class="GtkLabel" id="label1">
+                        <property name="visible">True</property>
+                      </object>
+                      <packing>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="x_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label2">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">Create new account</property>
+                    <attributes>
+                      <attribute name="weight" value="bold"/>
+                      <attribute name="scale" value="1.200000"/>
+                    </attributes>
+                  </object>
+                  <packing>
+                    <property name="right_attach">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label3">
+                    <property name="visible">True</property>
+                  </object>
+                  <packing>
+                    <property name="top_attach">1</property>
+                    <property name="bottom_attach">2</property>
+                    <property name="x_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label4">
+                    <property name="visible">True</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">1</property>
+                    <property name="bottom_attach">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkEntry" id="name-entry">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="activates_default">True</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">3</property>
+                    <property name="bottom_attach">4</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label5">
+                    <property name="visible">True</property>
+                    <property name="xalign">1</property>
+                    <property name="label" translatable="yes">_Full name:</property>
+                    <property name="use_underline">True</property>
+                    <property name="mnemonic_widget">name-entry</property>
+                    <attributes>
+                      <attribute name="foreground" value="#555555555555"/>
+                    </attributes>
+                  </object>
+                  <packing>
+                    <property name="top_attach">3</property>
+                    <property name="bottom_attach">4</property>
+                    <property name="x_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label7">
+                    <property name="visible">True</property>
+                    <property name="xalign">1</property>
+                    <property name="label" translatable="yes">_Account Type:</property>
+                    <property name="use_underline">True</property>
+                    <property name="mnemonic_widget">account-type-combo</property>
+                    <attributes>
+                      <attribute name="foreground" value="#555555555555"/>
+                    </attributes>
+                  </object>
+                  <packing>
+                    <property name="top_attach">2</property>
+                    <property name="bottom_attach">3</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkComboBox" id="account-type-combo">
+                    <property name="visible">True</property>
+                    <property name="model">account-type-model</property>
+                    <child>
+                      <object class="GtkCellRendererText" id="account-type-cell"/>
+                      <attributes>
+                        <attribute name="text">0</attribute>
+                      </attributes>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">2</property>
+                    <property name="bottom_attach">3</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <object class="GtkHButtonBox" id="dialog-action_area9">
+            <property name="visible">True</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="cancel-button">
+                <property name="label">gtk-cancel</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="ok-button">
+                <property name="label" translatable="yes">Cr_eate</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="can_default">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_underline">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="0">cancel-button</action-widget>
+      <action-widget response="0">ok-button</action-widget>
+    </action-widgets>
+  </object>
+</interface>
diff --git a/panels/user-accounts/data/account-fingerprint.ui b/panels/user-accounts/data/account-fingerprint.ui
new file mode 100644
index 0000000..93a194e
--- /dev/null
+++ b/panels/user-accounts/data/account-fingerprint.ui
@@ -0,0 +1,278 @@
+<?xml version="1.0"?>
+<interface>
+  <requires lib="gtk+" version="2.16"/>
+  <!-- interface-naming-policy toplevel-contextual -->
+  <object class="GtkListStore" id="model1">
+    <columns>
+      <!-- column-name gchararray -->
+      <column type="gchararray"/>
+    </columns>
+    <data>
+      <row>
+        <col id="0" translatable="yes">Left thumb</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Left middle finger</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Left ring finger</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Left little finger</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Right thumb</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Right middle finger</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Right ring finger</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Right little finger</col>
+      </row>
+    </data>
+  </object>
+  <object class="GtkAssistant" id="assistant">
+    <property name="border_width">12</property>
+    <property name="title" translatable="yes">Enable Fingerprint Login</property>
+    <property name="icon_name">system-users</property>
+    <child>
+      <placeholder/>
+    </child>
+    <child>
+      <object class="GtkVBox" id="page1">
+        <property name="visible">True</property>
+        <property name="border_width">12</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">12</property>
+        <child>
+          <object class="GtkHBox" id="hbox74">
+            <property name="visible">True</property>
+            <property name="spacing">6</property>
+            <child>
+              <object class="GtkImage" id="image">
+                <property name="visible">True</property>
+                <property name="stock">gtk-dialog-info</property>
+                <property name="icon-size">6</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="intro-label">
+                <property name="visible">True</property>
+                <property name="label">To enable fingerprint login, you need to save one of your fingerprints, using the Acme Foobar 5000.</property>
+                <property name="wrap">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkVBox" id="vbox70">
+            <property name="visible">True</property>
+            <property name="orientation">vertical</property>
+            <child>
+              <object class="GtkRadioButton" id="radiobutton1">
+                <property name="label" translatable="yes">Right index finger</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_underline">True</property>
+                <property name="active">True</property>
+                <property name="draw_indicator">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkRadioButton" id="radiobutton2">
+                <property name="label" translatable="yes">Left index finger</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_underline">True</property>
+                <property name="draw_indicator">True</property>
+                <property name="group">radiobutton1</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkHBox" id="radiobutton3-hbox">
+                <property name="visible">True</property>
+                <property name="spacing">6</property>
+                <child>
+                  <object class="GtkRadioButton" id="radiobutton3">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">Other finger: </property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">False</property>
+                    <property name="use_underline">True</property>
+                    <property name="draw_indicator">True</property>
+                    <property name="group">radiobutton1</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkComboBox" id="finger_combobox">
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="model">model1</property>
+                    <child>
+                      <object class="GtkCellRendererText" id="renderer1"/>
+                      <attributes>
+                        <attribute name="text">0</attribute>
+                      </attributes>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <child>
+      <object class="GtkVBox" id="page2">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <child>
+          <object class="GtkLabel" id="enroll-label">
+            <property name="visible">True</property>
+            <property name="label">In order to save your fingerprints, you need to swipe your thumb on the "Acme foobar" device.</property>
+            <property name="wrap">True</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkHBox" id="enroll_hbox">
+            <property name="visible">True</property>
+            <child>
+              <placeholder/>
+            </child>
+            <child>
+              <object class="GtkImage" id="image1">
+                <property name="visible">True</property>
+                <property name="stock">gtk-no</property>
+                <property name="icon-size">6</property>
+              </object>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkImage" id="image2">
+                <property name="visible">True</property>
+                <property name="stock">gtk-no</property>
+                <property name="icon-size">6</property>
+              </object>
+              <packing>
+                <property name="position">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkImage" id="image3">
+                <property name="visible">True</property>
+                <property name="stock">gtk-no</property>
+                <property name="icon-size">6</property>
+              </object>
+              <packing>
+                <property name="position">3</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkImage" id="image4">
+                <property name="visible">True</property>
+                <property name="stock">gtk-no</property>
+                <property name="icon-size">6</property>
+              </object>
+              <packing>
+                <property name="position">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkImage" id="image5">
+                <property name="visible">True</property>
+                <property name="stock">gtk-no</property>
+                <property name="icon-size">6</property>
+              </object>
+              <packing>
+                <property name="position">5</property>
+              </packing>
+            </child>
+            <child>
+              <placeholder/>
+            </child>
+          </object>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="status-label">
+            <property name="visible">True</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <child>
+      <object class="GtkLabel" id="page3">
+        <property name="visible">True</property>
+        <property name="label" translatable="yes">Your fingerprint was successfully saved. You should now be able to log in using your fingerprint reader.</property>
+        <property name="wrap">True</property>
+      </object>
+      <packing>
+        <property name="page_type">summary</property>
+      </packing>
+    </child>
+  </object>
+  <object class="GtkSizeGroup" id="sizegroup">
+    <property name="mode">both</property>
+    <widgets>
+      <widget name="radiobutton1"/>
+      <widget name="radiobutton2"/>
+      <widget name="radiobutton3-hbox"/>
+    </widgets>
+  </object>
+</interface>
diff --git a/panels/user-accounts/data/gnome-user-accounts-panel.desktop.in.in b/panels/user-accounts/data/gnome-user-accounts-panel.desktop.in.in
new file mode 100644
index 0000000..af3102f
--- /dev/null
+++ b/panels/user-accounts/data/gnome-user-accounts-panel.desktop.in.in
@@ -0,0 +1,15 @@
+[Desktop Entry]
+_Name=User Accounts
+_Comment=Add or remove users
+Exec=gnome-control-center user-accounts
+Icon=system-users
+Terminal=false
+Type=Application
+StartupNotify=true
+Categories=System;Settings;X-GNOME-Settings-Panel;
+OnlyShowIn=GNOME;
+X-GNOME-Bugzilla-Bugzilla=GNOME
+X-GNOME-Bugzilla-Product=gnome-control-center
+X-GNOME-Bugzilla-Component=user-accounts
+X-GNOME-Bugzilla-Version= VERSION@
+X-GNOME-Settings-Panel=user-accounts
diff --git a/panels/user-accounts/data/icons/Makefile.am b/panels/user-accounts/data/icons/Makefile.am
new file mode 100644
index 0000000..218ac84
--- /dev/null
+++ b/panels/user-accounts/data/icons/Makefile.am
@@ -0,0 +1,31 @@
+pixmapsdir = $(pkgdatadir)/pixmaps
+pixmaps_DATA =			\
+	gnome-about-me-lock.png	\
+	gnome-about-me-lock-open.png	\
+	left-index-finger.svg	\
+	left-little-finger.svg	\
+	left-middle-finger.svg	\
+	left-ring-finger.svg	\
+	left-thumb.svg		\
+	print_error.svg		\
+	print_ok.svg		\
+	right-index-finger.svg	\
+	right-little-finger.svg	\
+	right-middle-finger.svg	\
+	right-ring-finger.svg	\
+	right-thumb.svg		\
+	left-index-finger.png	\
+	left-middle-finger.png	\
+	left-little-finger.png	\
+	left-ring-finger.png	\
+	left-thumb.png		\
+	print_error.png		\
+	print_ok.png		\
+	right-index-finger.png	\
+	right-middle-finger.png	\
+	right-little-finger.png	\
+	right-ring-finger.png	\
+	right-thumb.png
+
+EXTRA_DIST = $(pixmaps_DATA)
+
diff --git a/panels/user-accounts/data/icons/gnome-about-me-lock-open.png b/panels/user-accounts/data/icons/gnome-about-me-lock-open.png
new file mode 100644
index 0000000..1f01905
Binary files /dev/null and b/panels/user-accounts/data/icons/gnome-about-me-lock-open.png differ
diff --git a/panels/user-accounts/data/icons/gnome-about-me-lock.png b/panels/user-accounts/data/icons/gnome-about-me-lock.png
new file mode 100644
index 0000000..f24ae3a
Binary files /dev/null and b/panels/user-accounts/data/icons/gnome-about-me-lock.png differ
diff --git a/panels/user-accounts/data/icons/left-index-finger.png b/panels/user-accounts/data/icons/left-index-finger.png
new file mode 100644
index 0000000..1a9cb2c
Binary files /dev/null and b/panels/user-accounts/data/icons/left-index-finger.png differ
diff --git a/panels/user-accounts/data/icons/left-index-finger.svg b/panels/user-accounts/data/icons/left-index-finger.svg
new file mode 100644
index 0000000..3c36aea
--- /dev/null
+++ b/panels/user-accounts/data/icons/left-index-finger.svg
@@ -0,0 +1,177 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948)  -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:xlink="http://www.w3.org/1999/xlink";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   version="1.0"
+   x="0px"
+   y="0px"
+   width="48"
+   height="48"
+   viewBox="0 0 40.425 46.214"
+   enable-background="new 0 0 40.425 46.214"
+   xml:space="preserve"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   sodipodi:docname="left-index-finger.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"><metadata
+   id="metadata44"><rdf:RDF><cc:Work
+       rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+         rdf:resource="http://purl.org/dc/dcmitype/StillImage"; /></cc:Work></rdf:RDF></metadata><defs
+   id="defs42"><inkscape:perspective
+   sodipodi:type="inkscape:persp3d"
+   inkscape:vp_x="0 : 23.107 : 1"
+   inkscape:vp_y="0 : 1000 : 0"
+   inkscape:vp_z="40.424999 : 23.107 : 1"
+   inkscape:persp3d-origin="20.2125 : 15.404667 : 1"
+   id="perspective46" />
+	
+	
+	
+	
+	
+	
+<radialGradient
+   r="8.341651"
+   fy="9.3411446"
+   fx="38.658855"
+   cy="9.3411446"
+   cx="38.658855"
+   gradientUnits="userSpaceOnUse"
+   id="radialGradient2479"
+   xlink:href="#linearGradient2378"
+   inkscape:collect="always" /><linearGradient
+   id="linearGradient2378"><stop
+     id="stop2386"
+     offset="0"
+     style="stop-color:#ffffff;stop-opacity:1;" /><stop
+     style="stop-color:#27dc16;stop-opacity:1;"
+     offset="1"
+     id="stop2382" /></linearGradient><linearGradient
+   id="linearGradient3702"><stop
+     id="stop3704"
+     offset="0"
+     style="stop-color:black;stop-opacity:0;" /><stop
+     style="stop-color:black;stop-opacity:1;"
+     offset="0.5"
+     id="stop3710" /><stop
+     id="stop3706"
+     offset="1"
+     style="stop-color:black;stop-opacity:0;" /></linearGradient><linearGradient
+   id="linearGradient6732"><stop
+     id="stop6734"
+     offset="0"
+     style="stop-color:#ffffff;stop-opacity:1;" /><stop
+     id="stop6736"
+     offset="1"
+     style="stop-color:#dddddd;stop-opacity:1;" /></linearGradient><linearGradient
+   id="linearGradient4585"><stop
+     id="stop4587"
+     offset="0"
+     style="stop-color:#9e9e9e;stop-opacity:1;" /><stop
+     id="stop4589"
+     offset="1"
+     style="stop-color:#dddddd;stop-opacity:0;" /></linearGradient><inkscape:perspective
+   id="perspective2516"
+   inkscape:persp3d-origin="24 : 16 : 1"
+   inkscape:vp_z="48 : 24 : 1"
+   inkscape:vp_y="0 : 1000 : 0"
+   inkscape:vp_x="0 : 24 : 1"
+   sodipodi:type="inkscape:persp3d" /><radialGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient2378"
+   id="radialGradient86956"
+   cx="26.49"
+   cy="5.5700002"
+   fx="26.49"
+   fy="5.5700002"
+   r="4.0552225"
+   gradientUnits="userSpaceOnUse"
+   gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)" /><radialGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient2378"
+   id="radialGradient86964"
+   gradientUnits="userSpaceOnUse"
+   gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+   cx="26.49"
+   cy="5.5700002"
+   fx="26.49"
+   fy="5.5700002"
+   r="4.0552225" /><radialGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient2378"
+   id="radialGradient86966"
+   gradientUnits="userSpaceOnUse"
+   gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+   cx="26.49"
+   cy="5.5700002"
+   fx="26.49"
+   fy="5.5700002"
+   r="4.0552225" /></defs><sodipodi:namedview
+   inkscape:window-height="933"
+   inkscape:window-width="1054"
+   inkscape:pageshadow="2"
+   inkscape:pageopacity="0.0"
+   guidetolerance="10.0"
+   gridtolerance="10.0"
+   objecttolerance="10.0"
+   borderopacity="1.0"
+   bordercolor="#666666"
+   pagecolor="#ffffff"
+   id="base"
+   showgrid="false"
+   inkscape:zoom="11.122171"
+   inkscape:cx="22.316511"
+   inkscape:cy="30.299841"
+   inkscape:window-x="36"
+   inkscape:window-y="91"
+   inkscape:current-layer="svg2" />
+<g
+   id="g35"
+   style="fill:url(#radialGradient86956);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+   transform="matrix(1.1605241,0,0,1.3370602,-4.3871473,-0.7984997)">
+		<circle
+   style="fill:url(#radialGradient86964);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+   sodipodi:ry="3.829"
+   sodipodi:rx="3.829"
+   sodipodi:cy="5.5700002"
+   sodipodi:cx="26.49"
+   id="circle37"
+   r="3.829"
+   cy="5.5700002"
+   cx="26.49"
+   stroke-miterlimit="3.8637" />
+		<path
+   style="fill:url(#radialGradient86966);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+   id="path39"
+   stroke-miterlimit="3.8637"
+   d="" />
+	</g><g
+   id="Background">
+</g>
+<g
+   id="Guides"
+   display="none"
+   style="display:none">
+</g>
+<g
+   id="g7"
+   style="fill:#2f2f2f;fill-opacity:1">
+		<path
+   style="fill:#2f2f2f;fill-opacity:1;fill-rule:evenodd"
+   id="path9"
+   d="M 20.569,13.286 C 20.843,15.459 20.791,17.834 20.82,18.542 C 20.865,18.917 21.913,19.241 22.094,18.877 C 22.301,17.514 22.586,14.847 22.92,13.455 C 23.372,9.917 23.886,8.247 24.072,7.257 C 24.58,4.567 25.014,3.12 26.762,3.12 C 28.384,3.12 28.623,5.167 28.153,8.165 C 28.025,9.379 28.036,12.24 27.433,14.894 C 27.165,16.691 26.962,21.278 27.139,24.981 C 27.189,26.045 27.669,27.315 28.242,27.945 C 29.462,27.773 30.379,24.377 31.988,22.847 C 32.809,21.464 34.883,19.299 36.951,19.299 C 39.243,19.299 39.292,21 38.345,22.262 C 37.187,23.806 36.525,24.528 36.079,25.802 C 35.633,27.076 33.758,29.778 33.471,31.209 C 32.902,34.054 32.471,35.105 29.284,37.661 C 27.783,38.865 27.302,39.637 26.855,40.401 C 26.347,41.273 26.409,44.721 26.409,46.212 L 10.64,46.212 C 10.64,46.212 10.767,43.587 10.513,42.058 C 10.461,41.746 10.105,39.613 9.176,38.231 C 8.317,36.954 5.902,32.306 5.902,26.836 C 5.902,24.026 4.39,21.718 3.854,19.533 C 3.591,17.833 2.638,15.423 2.57,14.709 C 1.684,11.559 2.1
 32,10.118 3.741,10.118 C 5.132,10.118 5.528,11.927 6.093,13.622 C 6.258,14.52 7.505,16.934 7.788,18.233 C 8.038,19.088 8.897,21.556 9.437,21.727 C 9.75,21.784 10.151,21.523 10.291,21.043 C 10.52,20.26 9.818,18.945 9.539,15.26 C 9.087,12.343 9.17,10.139 9.116,8.949 C 8.653,5.424 9.133,3.598 10.693,3.598 C 12.176,3.598 12.568,4.455 13.02,7.936 C 13.189,9.518 13.754,12.095 14.037,14.864 C 14.213,16.364 14.639,18.601 14.98,19.17 C 15.285,19.503 15.919,19.198 15.9,18.848 C 15.894,16.377 15.732,14.977 15.958,12.999 C 15.845,10.287 16.219,7.823 16.219,6.467 C 16.219,3.494 16.502,1.473 18.358,1.473 C 20.333,1.473 20.287,3.776 20.287,6.806 C 20.399,7.545 20.456,10.087 20.569,13.286 z"
+   clip-rule="evenodd" />
+	</g>
+<g
+   style="display:inline"
+   inkscape:label="Base"
+   id="layer1"
+   transform="translate(-52.466647,2.6102791)" /></svg>
\ No newline at end of file
diff --git a/panels/user-accounts/data/icons/left-little-finger.png b/panels/user-accounts/data/icons/left-little-finger.png
new file mode 100644
index 0000000..978942e
Binary files /dev/null and b/panels/user-accounts/data/icons/left-little-finger.png differ
diff --git a/panels/user-accounts/data/icons/left-little-finger.svg b/panels/user-accounts/data/icons/left-little-finger.svg
new file mode 100644
index 0000000..0835854
--- /dev/null
+++ b/panels/user-accounts/data/icons/left-little-finger.svg
@@ -0,0 +1,180 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948)  -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:xlink="http://www.w3.org/1999/xlink";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   version="1.0"
+   x="0px"
+   y="0px"
+   width="48"
+   height="48"
+   viewBox="0 0 40.425 46.214"
+   enable-background="new 0 0 40.425 46.214"
+   xml:space="preserve"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   sodipodi:docname="left-pinky-finger.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   inkscape:export-filename="/Users/mlanglie/Desktop/Fingerprint Enrollment Icons/Vector/left-ring-finger.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90"><metadata
+   id="metadata44"><rdf:RDF><cc:Work
+       rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+         rdf:resource="http://purl.org/dc/dcmitype/StillImage"; /></cc:Work></rdf:RDF></metadata><defs
+   id="defs42"><inkscape:perspective
+   sodipodi:type="inkscape:persp3d"
+   inkscape:vp_x="0 : 23.107 : 1"
+   inkscape:vp_y="0 : 1000 : 0"
+   inkscape:vp_z="40.424999 : 23.107 : 1"
+   inkscape:persp3d-origin="20.2125 : 15.404667 : 1"
+   id="perspective46" />
+	
+	
+	
+	
+	
+	
+<radialGradient
+   r="8.341651"
+   fy="9.3411446"
+   fx="38.658855"
+   cy="9.3411446"
+   cx="38.658855"
+   gradientUnits="userSpaceOnUse"
+   id="radialGradient2479"
+   xlink:href="#linearGradient2378"
+   inkscape:collect="always" /><linearGradient
+   id="linearGradient2378"><stop
+     id="stop2386"
+     offset="0"
+     style="stop-color:#ffffff;stop-opacity:1;" /><stop
+     style="stop-color:#27dc16;stop-opacity:1;"
+     offset="1"
+     id="stop2382" /></linearGradient><linearGradient
+   id="linearGradient3702"><stop
+     id="stop3704"
+     offset="0"
+     style="stop-color:black;stop-opacity:0;" /><stop
+     style="stop-color:black;stop-opacity:1;"
+     offset="0.5"
+     id="stop3710" /><stop
+     id="stop3706"
+     offset="1"
+     style="stop-color:black;stop-opacity:0;" /></linearGradient><linearGradient
+   id="linearGradient6732"><stop
+     id="stop6734"
+     offset="0"
+     style="stop-color:#ffffff;stop-opacity:1;" /><stop
+     id="stop6736"
+     offset="1"
+     style="stop-color:#dddddd;stop-opacity:1;" /></linearGradient><linearGradient
+   id="linearGradient4585"><stop
+     id="stop4587"
+     offset="0"
+     style="stop-color:#9e9e9e;stop-opacity:1;" /><stop
+     id="stop4589"
+     offset="1"
+     style="stop-color:#dddddd;stop-opacity:0;" /></linearGradient><inkscape:perspective
+   id="perspective2516"
+   inkscape:persp3d-origin="24 : 16 : 1"
+   inkscape:vp_z="48 : 24 : 1"
+   inkscape:vp_y="0 : 1000 : 0"
+   inkscape:vp_x="0 : 24 : 1"
+   sodipodi:type="inkscape:persp3d" /><radialGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient2378"
+   id="radialGradient86956"
+   cx="26.49"
+   cy="5.5700002"
+   fx="26.49"
+   fy="5.5700002"
+   r="4.0552225"
+   gradientUnits="userSpaceOnUse"
+   gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)" /><radialGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient2378"
+   id="radialGradient86964"
+   gradientUnits="userSpaceOnUse"
+   gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+   cx="26.49"
+   cy="5.5700002"
+   fx="26.49"
+   fy="5.5700002"
+   r="4.0552225" /><radialGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient2378"
+   id="radialGradient86966"
+   gradientUnits="userSpaceOnUse"
+   gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+   cx="26.49"
+   cy="5.5700002"
+   fx="26.49"
+   fy="5.5700002"
+   r="4.0552225" /></defs><sodipodi:namedview
+   inkscape:window-height="933"
+   inkscape:window-width="1054"
+   inkscape:pageshadow="2"
+   inkscape:pageopacity="0.0"
+   guidetolerance="10.0"
+   gridtolerance="10.0"
+   objecttolerance="10.0"
+   borderopacity="1.0"
+   bordercolor="#666666"
+   pagecolor="#ffffff"
+   id="base"
+   showgrid="false"
+   inkscape:zoom="11.122171"
+   inkscape:cx="22.316511"
+   inkscape:cy="30.299841"
+   inkscape:window-x="122"
+   inkscape:window-y="443"
+   inkscape:current-layer="svg2" />
+<g
+   id="g35"
+   style="fill:url(#radialGradient86956);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+   transform="matrix(1.1074589,0,0,1.2726911,-25.531655,5.5330271)">
+		<circle
+   style="fill:url(#radialGradient86964);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+   sodipodi:ry="3.829"
+   sodipodi:rx="3.829"
+   sodipodi:cy="5.5700002"
+   sodipodi:cx="26.49"
+   id="circle37"
+   r="3.829"
+   cy="5.5700002"
+   cx="26.49"
+   stroke-miterlimit="3.8637" />
+		<path
+   style="fill:url(#radialGradient86966);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+   id="path39"
+   stroke-miterlimit="3.8637"
+   d="" />
+	</g><g
+   id="Background">
+</g>
+<g
+   id="Guides"
+   display="none"
+   style="display:none">
+</g>
+<g
+   id="g7"
+   style="fill:#2f2f2f;fill-opacity:1">
+		<path
+   style="fill:#2f2f2f;fill-opacity:1;fill-rule:evenodd"
+   id="path9"
+   d="M 20.569,13.286 C 20.843,15.459 20.791,17.834 20.82,18.542 C 20.865,18.917 21.913,19.241 22.094,18.877 C 22.301,17.514 22.586,14.847 22.92,13.455 C 23.372,9.917 23.886,8.247 24.072,7.257 C 24.58,4.567 25.014,3.12 26.762,3.12 C 28.384,3.12 28.623,5.167 28.153,8.165 C 28.025,9.379 28.036,12.24 27.433,14.894 C 27.165,16.691 26.962,21.278 27.139,24.981 C 27.189,26.045 27.669,27.315 28.242,27.945 C 29.462,27.773 30.379,24.377 31.988,22.847 C 32.809,21.464 34.883,19.299 36.951,19.299 C 39.243,19.299 39.292,21 38.345,22.262 C 37.187,23.806 36.525,24.528 36.079,25.802 C 35.633,27.076 33.758,29.778 33.471,31.209 C 32.902,34.054 32.471,35.105 29.284,37.661 C 27.783,38.865 27.302,39.637 26.855,40.401 C 26.347,41.273 26.409,44.721 26.409,46.212 L 10.64,46.212 C 10.64,46.212 10.767,43.587 10.513,42.058 C 10.461,41.746 10.105,39.613 9.176,38.231 C 8.317,36.954 5.902,32.306 5.902,26.836 C 5.902,24.026 4.39,21.718 3.854,19.533 C 3.591,17.833 2.638,15.423 2.57,14.709 C 1.684,11.559 2.1
 32,10.118 3.741,10.118 C 5.132,10.118 5.528,11.927 6.093,13.622 C 6.258,14.52 7.505,16.934 7.788,18.233 C 8.038,19.088 8.897,21.556 9.437,21.727 C 9.75,21.784 10.151,21.523 10.291,21.043 C 10.52,20.26 9.818,18.945 9.539,15.26 C 9.087,12.343 9.17,10.139 9.116,8.949 C 8.653,5.424 9.133,3.598 10.693,3.598 C 12.176,3.598 12.568,4.455 13.02,7.936 C 13.189,9.518 13.754,12.095 14.037,14.864 C 14.213,16.364 14.639,18.601 14.98,19.17 C 15.285,19.503 15.919,19.198 15.9,18.848 C 15.894,16.377 15.732,14.977 15.958,12.999 C 15.845,10.287 16.219,7.823 16.219,6.467 C 16.219,3.494 16.502,1.473 18.358,1.473 C 20.333,1.473 20.287,3.776 20.287,6.806 C 20.399,7.545 20.456,10.087 20.569,13.286 z"
+   clip-rule="evenodd" />
+	</g>
+<g
+   style="display:inline"
+   inkscape:label="Base"
+   id="layer1"
+   transform="translate(-52.466647,2.6102791)" /></svg>
\ No newline at end of file
diff --git a/panels/user-accounts/data/icons/left-middle-finger.png b/panels/user-accounts/data/icons/left-middle-finger.png
new file mode 100644
index 0000000..406925e
Binary files /dev/null and b/panels/user-accounts/data/icons/left-middle-finger.png differ
diff --git a/panels/user-accounts/data/icons/left-middle-finger.svg b/panels/user-accounts/data/icons/left-middle-finger.svg
new file mode 100644
index 0000000..1082da2
--- /dev/null
+++ b/panels/user-accounts/data/icons/left-middle-finger.svg
@@ -0,0 +1,180 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948)  -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:xlink="http://www.w3.org/1999/xlink";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   version="1.0"
+   x="0px"
+   y="0px"
+   width="48"
+   height="48"
+   viewBox="0 0 40.425 46.214"
+   enable-background="new 0 0 40.425 46.214"
+   xml:space="preserve"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   sodipodi:docname="left-middle-finger.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   inkscape:export-filename="/Users/mlanglie/Desktop/Fingerprint Enrollment Icons/Vector/left-index-finger.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90"><metadata
+   id="metadata44"><rdf:RDF><cc:Work
+       rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+         rdf:resource="http://purl.org/dc/dcmitype/StillImage"; /></cc:Work></rdf:RDF></metadata><defs
+   id="defs42"><inkscape:perspective
+   sodipodi:type="inkscape:persp3d"
+   inkscape:vp_x="0 : 23.107 : 1"
+   inkscape:vp_y="0 : 1000 : 0"
+   inkscape:vp_z="40.424999 : 23.107 : 1"
+   inkscape:persp3d-origin="20.2125 : 15.404667 : 1"
+   id="perspective46" />
+	
+	
+	
+	
+	
+	
+<radialGradient
+   r="8.341651"
+   fy="9.3411446"
+   fx="38.658855"
+   cy="9.3411446"
+   cx="38.658855"
+   gradientUnits="userSpaceOnUse"
+   id="radialGradient2479"
+   xlink:href="#linearGradient2378"
+   inkscape:collect="always" /><linearGradient
+   id="linearGradient2378"><stop
+     id="stop2386"
+     offset="0"
+     style="stop-color:#ffffff;stop-opacity:1;" /><stop
+     style="stop-color:#27dc16;stop-opacity:1;"
+     offset="1"
+     id="stop2382" /></linearGradient><linearGradient
+   id="linearGradient3702"><stop
+     id="stop3704"
+     offset="0"
+     style="stop-color:black;stop-opacity:0;" /><stop
+     style="stop-color:black;stop-opacity:1;"
+     offset="0.5"
+     id="stop3710" /><stop
+     id="stop3706"
+     offset="1"
+     style="stop-color:black;stop-opacity:0;" /></linearGradient><linearGradient
+   id="linearGradient6732"><stop
+     id="stop6734"
+     offset="0"
+     style="stop-color:#ffffff;stop-opacity:1;" /><stop
+     id="stop6736"
+     offset="1"
+     style="stop-color:#dddddd;stop-opacity:1;" /></linearGradient><linearGradient
+   id="linearGradient4585"><stop
+     id="stop4587"
+     offset="0"
+     style="stop-color:#9e9e9e;stop-opacity:1;" /><stop
+     id="stop4589"
+     offset="1"
+     style="stop-color:#dddddd;stop-opacity:0;" /></linearGradient><inkscape:perspective
+   id="perspective2516"
+   inkscape:persp3d-origin="24 : 16 : 1"
+   inkscape:vp_z="48 : 24 : 1"
+   inkscape:vp_y="0 : 1000 : 0"
+   inkscape:vp_x="0 : 24 : 1"
+   sodipodi:type="inkscape:persp3d" /><radialGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient2378"
+   id="radialGradient86956"
+   cx="26.49"
+   cy="5.5700002"
+   fx="26.49"
+   fy="5.5700002"
+   r="4.0552225"
+   gradientUnits="userSpaceOnUse"
+   gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)" /><radialGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient2378"
+   id="radialGradient86964"
+   gradientUnits="userSpaceOnUse"
+   gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+   cx="26.49"
+   cy="5.5700002"
+   fx="26.49"
+   fy="5.5700002"
+   r="4.0552225" /><radialGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient2378"
+   id="radialGradient86966"
+   gradientUnits="userSpaceOnUse"
+   gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+   cx="26.49"
+   cy="5.5700002"
+   fx="26.49"
+   fy="5.5700002"
+   r="4.0552225" /></defs><sodipodi:namedview
+   inkscape:window-height="933"
+   inkscape:window-width="1054"
+   inkscape:pageshadow="2"
+   inkscape:pageopacity="0.0"
+   guidetolerance="10.0"
+   gridtolerance="10.0"
+   objecttolerance="10.0"
+   borderopacity="1.0"
+   bordercolor="#666666"
+   pagecolor="#ffffff"
+   id="base"
+   showgrid="false"
+   inkscape:zoom="11.122171"
+   inkscape:cx="22.316511"
+   inkscape:cy="30.299841"
+   inkscape:window-x="122"
+   inkscape:window-y="443"
+   inkscape:current-layer="svg2" />
+<g
+   id="g35"
+   style="fill:url(#radialGradient86956);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+   transform="matrix(1.1824583,0,0,1.3363867,-12.845608,-2.0066594)">
+		<circle
+   style="fill:url(#radialGradient86964);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+   sodipodi:ry="3.829"
+   sodipodi:rx="3.829"
+   sodipodi:cy="5.5700002"
+   sodipodi:cx="26.49"
+   id="circle37"
+   r="3.829"
+   cy="5.5700002"
+   cx="26.49"
+   stroke-miterlimit="3.8637" />
+		<path
+   style="fill:url(#radialGradient86966);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+   id="path39"
+   stroke-miterlimit="3.8637"
+   d="" />
+	</g><g
+   id="Background">
+</g>
+<g
+   id="Guides"
+   display="none"
+   style="display:none">
+</g>
+<g
+   id="g7"
+   style="fill:#2f2f2f;fill-opacity:1">
+		<path
+   style="fill:#2f2f2f;fill-opacity:1;fill-rule:evenodd"
+   id="path9"
+   d="M 20.569,13.286 C 20.843,15.459 20.791,17.834 20.82,18.542 C 20.865,18.917 21.913,19.241 22.094,18.877 C 22.301,17.514 22.586,14.847 22.92,13.455 C 23.372,9.917 23.886,8.247 24.072,7.257 C 24.58,4.567 25.014,3.12 26.762,3.12 C 28.384,3.12 28.623,5.167 28.153,8.165 C 28.025,9.379 28.036,12.24 27.433,14.894 C 27.165,16.691 26.962,21.278 27.139,24.981 C 27.189,26.045 27.669,27.315 28.242,27.945 C 29.462,27.773 30.379,24.377 31.988,22.847 C 32.809,21.464 34.883,19.299 36.951,19.299 C 39.243,19.299 39.292,21 38.345,22.262 C 37.187,23.806 36.525,24.528 36.079,25.802 C 35.633,27.076 33.758,29.778 33.471,31.209 C 32.902,34.054 32.471,35.105 29.284,37.661 C 27.783,38.865 27.302,39.637 26.855,40.401 C 26.347,41.273 26.409,44.721 26.409,46.212 L 10.64,46.212 C 10.64,46.212 10.767,43.587 10.513,42.058 C 10.461,41.746 10.105,39.613 9.176,38.231 C 8.317,36.954 5.902,32.306 5.902,26.836 C 5.902,24.026 4.39,21.718 3.854,19.533 C 3.591,17.833 2.638,15.423 2.57,14.709 C 1.684,11.559 2.1
 32,10.118 3.741,10.118 C 5.132,10.118 5.528,11.927 6.093,13.622 C 6.258,14.52 7.505,16.934 7.788,18.233 C 8.038,19.088 8.897,21.556 9.437,21.727 C 9.75,21.784 10.151,21.523 10.291,21.043 C 10.52,20.26 9.818,18.945 9.539,15.26 C 9.087,12.343 9.17,10.139 9.116,8.949 C 8.653,5.424 9.133,3.598 10.693,3.598 C 12.176,3.598 12.568,4.455 13.02,7.936 C 13.189,9.518 13.754,12.095 14.037,14.864 C 14.213,16.364 14.639,18.601 14.98,19.17 C 15.285,19.503 15.919,19.198 15.9,18.848 C 15.894,16.377 15.732,14.977 15.958,12.999 C 15.845,10.287 16.219,7.823 16.219,6.467 C 16.219,3.494 16.502,1.473 18.358,1.473 C 20.333,1.473 20.287,3.776 20.287,6.806 C 20.399,7.545 20.456,10.087 20.569,13.286 z"
+   clip-rule="evenodd" />
+	</g>
+<g
+   style="display:inline"
+   inkscape:label="Base"
+   id="layer1"
+   transform="translate(-52.466647,2.6102791)" /></svg>
\ No newline at end of file
diff --git a/panels/user-accounts/data/icons/left-ring-finger.png b/panels/user-accounts/data/icons/left-ring-finger.png
new file mode 100644
index 0000000..169ff68
Binary files /dev/null and b/panels/user-accounts/data/icons/left-ring-finger.png differ
diff --git a/panels/user-accounts/data/icons/left-ring-finger.svg b/panels/user-accounts/data/icons/left-ring-finger.svg
new file mode 100644
index 0000000..50ace80
--- /dev/null
+++ b/panels/user-accounts/data/icons/left-ring-finger.svg
@@ -0,0 +1,180 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948)  -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:xlink="http://www.w3.org/1999/xlink";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   version="1.0"
+   x="0px"
+   y="0px"
+   width="48"
+   height="48"
+   viewBox="0 0 40.425 46.214"
+   enable-background="new 0 0 40.425 46.214"
+   xml:space="preserve"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   sodipodi:docname="left-ring-finger.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   inkscape:export-filename="/Users/mlanglie/Desktop/Fingerprint Enrollment Icons/Vector/left-middle-finger.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90"><metadata
+   id="metadata44"><rdf:RDF><cc:Work
+       rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+         rdf:resource="http://purl.org/dc/dcmitype/StillImage"; /></cc:Work></rdf:RDF></metadata><defs
+   id="defs42"><inkscape:perspective
+   sodipodi:type="inkscape:persp3d"
+   inkscape:vp_x="0 : 23.107 : 1"
+   inkscape:vp_y="0 : 1000 : 0"
+   inkscape:vp_z="40.424999 : 23.107 : 1"
+   inkscape:persp3d-origin="20.2125 : 15.404667 : 1"
+   id="perspective46" />
+	
+	
+	
+	
+	
+	
+<radialGradient
+   r="8.341651"
+   fy="9.3411446"
+   fx="38.658855"
+   cy="9.3411446"
+   cx="38.658855"
+   gradientUnits="userSpaceOnUse"
+   id="radialGradient2479"
+   xlink:href="#linearGradient2378"
+   inkscape:collect="always" /><linearGradient
+   id="linearGradient2378"><stop
+     id="stop2386"
+     offset="0"
+     style="stop-color:#ffffff;stop-opacity:1;" /><stop
+     style="stop-color:#27dc16;stop-opacity:1;"
+     offset="1"
+     id="stop2382" /></linearGradient><linearGradient
+   id="linearGradient3702"><stop
+     id="stop3704"
+     offset="0"
+     style="stop-color:black;stop-opacity:0;" /><stop
+     style="stop-color:black;stop-opacity:1;"
+     offset="0.5"
+     id="stop3710" /><stop
+     id="stop3706"
+     offset="1"
+     style="stop-color:black;stop-opacity:0;" /></linearGradient><linearGradient
+   id="linearGradient6732"><stop
+     id="stop6734"
+     offset="0"
+     style="stop-color:#ffffff;stop-opacity:1;" /><stop
+     id="stop6736"
+     offset="1"
+     style="stop-color:#dddddd;stop-opacity:1;" /></linearGradient><linearGradient
+   id="linearGradient4585"><stop
+     id="stop4587"
+     offset="0"
+     style="stop-color:#9e9e9e;stop-opacity:1;" /><stop
+     id="stop4589"
+     offset="1"
+     style="stop-color:#dddddd;stop-opacity:0;" /></linearGradient><inkscape:perspective
+   id="perspective2516"
+   inkscape:persp3d-origin="24 : 16 : 1"
+   inkscape:vp_z="48 : 24 : 1"
+   inkscape:vp_y="0 : 1000 : 0"
+   inkscape:vp_x="0 : 24 : 1"
+   sodipodi:type="inkscape:persp3d" /><radialGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient2378"
+   id="radialGradient86956"
+   cx="26.49"
+   cy="5.5700002"
+   fx="26.49"
+   fy="5.5700002"
+   r="4.0552225"
+   gradientUnits="userSpaceOnUse"
+   gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)" /><radialGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient2378"
+   id="radialGradient86964"
+   gradientUnits="userSpaceOnUse"
+   gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+   cx="26.49"
+   cy="5.5700002"
+   fx="26.49"
+   fy="5.5700002"
+   r="4.0552225" /><radialGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient2378"
+   id="radialGradient86966"
+   gradientUnits="userSpaceOnUse"
+   gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+   cx="26.49"
+   cy="5.5700002"
+   fx="26.49"
+   fy="5.5700002"
+   r="4.0552225" /></defs><sodipodi:namedview
+   inkscape:window-height="933"
+   inkscape:window-width="1054"
+   inkscape:pageshadow="2"
+   inkscape:pageopacity="0.0"
+   guidetolerance="10.0"
+   gridtolerance="10.0"
+   objecttolerance="10.0"
+   borderopacity="1.0"
+   bordercolor="#666666"
+   pagecolor="#ffffff"
+   id="base"
+   showgrid="false"
+   inkscape:zoom="11.122171"
+   inkscape:cx="22.316511"
+   inkscape:cy="30.299841"
+   inkscape:window-x="122"
+   inkscape:window-y="443"
+   inkscape:current-layer="svg2" />
+<g
+   id="g35"
+   style="fill:url(#radialGradient86956);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+   transform="matrix(1.1824583,0,0,1.3363867,-20.636466,-0.7947482)">
+		<circle
+   style="fill:url(#radialGradient86964);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+   sodipodi:ry="3.829"
+   sodipodi:rx="3.829"
+   sodipodi:cy="5.5700002"
+   sodipodi:cx="26.49"
+   id="circle37"
+   r="3.829"
+   cy="5.5700002"
+   cx="26.49"
+   stroke-miterlimit="3.8637" />
+		<path
+   style="fill:url(#radialGradient86966);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+   id="path39"
+   stroke-miterlimit="3.8637"
+   d="" />
+	</g><g
+   id="Background">
+</g>
+<g
+   id="Guides"
+   display="none"
+   style="display:none">
+</g>
+<g
+   id="g7"
+   style="fill:#2f2f2f;fill-opacity:1">
+		<path
+   style="fill:#2f2f2f;fill-opacity:1;fill-rule:evenodd"
+   id="path9"
+   d="M 20.569,13.286 C 20.843,15.459 20.791,17.834 20.82,18.542 C 20.865,18.917 21.913,19.241 22.094,18.877 C 22.301,17.514 22.586,14.847 22.92,13.455 C 23.372,9.917 23.886,8.247 24.072,7.257 C 24.58,4.567 25.014,3.12 26.762,3.12 C 28.384,3.12 28.623,5.167 28.153,8.165 C 28.025,9.379 28.036,12.24 27.433,14.894 C 27.165,16.691 26.962,21.278 27.139,24.981 C 27.189,26.045 27.669,27.315 28.242,27.945 C 29.462,27.773 30.379,24.377 31.988,22.847 C 32.809,21.464 34.883,19.299 36.951,19.299 C 39.243,19.299 39.292,21 38.345,22.262 C 37.187,23.806 36.525,24.528 36.079,25.802 C 35.633,27.076 33.758,29.778 33.471,31.209 C 32.902,34.054 32.471,35.105 29.284,37.661 C 27.783,38.865 27.302,39.637 26.855,40.401 C 26.347,41.273 26.409,44.721 26.409,46.212 L 10.64,46.212 C 10.64,46.212 10.767,43.587 10.513,42.058 C 10.461,41.746 10.105,39.613 9.176,38.231 C 8.317,36.954 5.902,32.306 5.902,26.836 C 5.902,24.026 4.39,21.718 3.854,19.533 C 3.591,17.833 2.638,15.423 2.57,14.709 C 1.684,11.559 2.1
 32,10.118 3.741,10.118 C 5.132,10.118 5.528,11.927 6.093,13.622 C 6.258,14.52 7.505,16.934 7.788,18.233 C 8.038,19.088 8.897,21.556 9.437,21.727 C 9.75,21.784 10.151,21.523 10.291,21.043 C 10.52,20.26 9.818,18.945 9.539,15.26 C 9.087,12.343 9.17,10.139 9.116,8.949 C 8.653,5.424 9.133,3.598 10.693,3.598 C 12.176,3.598 12.568,4.455 13.02,7.936 C 13.189,9.518 13.754,12.095 14.037,14.864 C 14.213,16.364 14.639,18.601 14.98,19.17 C 15.285,19.503 15.919,19.198 15.9,18.848 C 15.894,16.377 15.732,14.977 15.958,12.999 C 15.845,10.287 16.219,7.823 16.219,6.467 C 16.219,3.494 16.502,1.473 18.358,1.473 C 20.333,1.473 20.287,3.776 20.287,6.806 C 20.399,7.545 20.456,10.087 20.569,13.286 z"
+   clip-rule="evenodd" />
+	</g>
+<g
+   style="display:inline"
+   inkscape:label="Base"
+   id="layer1"
+   transform="translate(-52.466647,2.6102791)" /></svg>
\ No newline at end of file
diff --git a/panels/user-accounts/data/icons/left-thumb.png b/panels/user-accounts/data/icons/left-thumb.png
new file mode 100644
index 0000000..eaf875d
Binary files /dev/null and b/panels/user-accounts/data/icons/left-thumb.png differ
diff --git a/panels/user-accounts/data/icons/left-thumb.svg b/panels/user-accounts/data/icons/left-thumb.svg
new file mode 100644
index 0000000..fd0f582
--- /dev/null
+++ b/panels/user-accounts/data/icons/left-thumb.svg
@@ -0,0 +1,180 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948)  -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:xlink="http://www.w3.org/1999/xlink";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   version="1.0"
+   x="0px"
+   y="0px"
+   width="48"
+   height="48"
+   viewBox="0 0 40.425 46.214"
+   enable-background="new 0 0 40.425 46.214"
+   xml:space="preserve"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   sodipodi:docname="left-thumb.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   inkscape:export-filename="/Users/mlanglie/Desktop/Fingerprint Enrollment Icons/Vector/left-pinky-finger.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90"><metadata
+   id="metadata44"><rdf:RDF><cc:Work
+       rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+         rdf:resource="http://purl.org/dc/dcmitype/StillImage"; /></cc:Work></rdf:RDF></metadata><defs
+   id="defs42"><inkscape:perspective
+   sodipodi:type="inkscape:persp3d"
+   inkscape:vp_x="0 : 23.107 : 1"
+   inkscape:vp_y="0 : 1000 : 0"
+   inkscape:vp_z="40.424999 : 23.107 : 1"
+   inkscape:persp3d-origin="20.2125 : 15.404667 : 1"
+   id="perspective46" />
+	
+	
+	
+	
+	
+	
+<radialGradient
+   r="8.341651"
+   fy="9.3411446"
+   fx="38.658855"
+   cy="9.3411446"
+   cx="38.658855"
+   gradientUnits="userSpaceOnUse"
+   id="radialGradient2479"
+   xlink:href="#linearGradient2378"
+   inkscape:collect="always" /><linearGradient
+   id="linearGradient2378"><stop
+     id="stop2386"
+     offset="0"
+     style="stop-color:#ffffff;stop-opacity:1;" /><stop
+     style="stop-color:#27dc16;stop-opacity:1;"
+     offset="1"
+     id="stop2382" /></linearGradient><linearGradient
+   id="linearGradient3702"><stop
+     id="stop3704"
+     offset="0"
+     style="stop-color:black;stop-opacity:0;" /><stop
+     style="stop-color:black;stop-opacity:1;"
+     offset="0.5"
+     id="stop3710" /><stop
+     id="stop3706"
+     offset="1"
+     style="stop-color:black;stop-opacity:0;" /></linearGradient><linearGradient
+   id="linearGradient6732"><stop
+     id="stop6734"
+     offset="0"
+     style="stop-color:#ffffff;stop-opacity:1;" /><stop
+     id="stop6736"
+     offset="1"
+     style="stop-color:#dddddd;stop-opacity:1;" /></linearGradient><linearGradient
+   id="linearGradient4585"><stop
+     id="stop4587"
+     offset="0"
+     style="stop-color:#9e9e9e;stop-opacity:1;" /><stop
+     id="stop4589"
+     offset="1"
+     style="stop-color:#dddddd;stop-opacity:0;" /></linearGradient><inkscape:perspective
+   id="perspective2516"
+   inkscape:persp3d-origin="24 : 16 : 1"
+   inkscape:vp_z="48 : 24 : 1"
+   inkscape:vp_y="0 : 1000 : 0"
+   inkscape:vp_x="0 : 24 : 1"
+   sodipodi:type="inkscape:persp3d" /><radialGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient2378"
+   id="radialGradient86956"
+   cx="26.49"
+   cy="5.5700002"
+   fx="26.49"
+   fy="5.5700002"
+   r="4.0552225"
+   gradientUnits="userSpaceOnUse"
+   gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)" /><radialGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient2378"
+   id="radialGradient86964"
+   gradientUnits="userSpaceOnUse"
+   gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+   cx="26.49"
+   cy="5.5700002"
+   fx="26.49"
+   fy="5.5700002"
+   r="4.0552225" /><radialGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient2378"
+   id="radialGradient86966"
+   gradientUnits="userSpaceOnUse"
+   gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+   cx="26.49"
+   cy="5.5700002"
+   fx="26.49"
+   fy="5.5700002"
+   r="4.0552225" /></defs><sodipodi:namedview
+   inkscape:window-height="933"
+   inkscape:window-width="1054"
+   inkscape:pageshadow="2"
+   inkscape:pageopacity="0.0"
+   guidetolerance="10.0"
+   gridtolerance="10.0"
+   objecttolerance="10.0"
+   borderopacity="1.0"
+   bordercolor="#666666"
+   pagecolor="#ffffff"
+   id="base"
+   showgrid="false"
+   inkscape:zoom="11.122171"
+   inkscape:cx="22.316511"
+   inkscape:cy="30.299841"
+   inkscape:window-x="116"
+   inkscape:window-y="498"
+   inkscape:current-layer="svg2" />
+<g
+   id="g35"
+   style="fill:url(#radialGradient86956);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+   transform="matrix(1.1916623,0,0,1.4021101,4.5265732,14.334323)">
+		<circle
+   style="fill:url(#radialGradient86964);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+   sodipodi:ry="3.829"
+   sodipodi:rx="3.829"
+   sodipodi:cy="5.5700002"
+   sodipodi:cx="26.49"
+   id="circle37"
+   r="3.829"
+   cy="5.5700002"
+   cx="26.49"
+   stroke-miterlimit="3.8637" />
+		<path
+   style="fill:url(#radialGradient86966);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+   id="path39"
+   stroke-miterlimit="3.8637"
+   d="" />
+	</g><g
+   id="Background">
+</g>
+<g
+   id="Guides"
+   display="none"
+   style="display:none">
+</g>
+<g
+   id="g7"
+   style="fill:#2f2f2f;fill-opacity:1">
+		<path
+   style="fill:#2f2f2f;fill-opacity:1;fill-rule:evenodd"
+   id="path9"
+   d="M 20.569,13.286 C 20.843,15.459 20.791,17.834 20.82,18.542 C 20.865,18.917 21.913,19.241 22.094,18.877 C 22.301,17.514 22.586,14.847 22.92,13.455 C 23.372,9.917 23.886,8.247 24.072,7.257 C 24.58,4.567 25.014,3.12 26.762,3.12 C 28.384,3.12 28.623,5.167 28.153,8.165 C 28.025,9.379 28.036,12.24 27.433,14.894 C 27.165,16.691 26.962,21.278 27.139,24.981 C 27.189,26.045 27.669,27.315 28.242,27.945 C 29.462,27.773 30.379,24.377 31.988,22.847 C 32.809,21.464 34.883,19.299 36.951,19.299 C 39.243,19.299 39.292,21 38.345,22.262 C 37.187,23.806 36.525,24.528 36.079,25.802 C 35.633,27.076 33.758,29.778 33.471,31.209 C 32.902,34.054 32.471,35.105 29.284,37.661 C 27.783,38.865 27.302,39.637 26.855,40.401 C 26.347,41.273 26.409,44.721 26.409,46.212 L 10.64,46.212 C 10.64,46.212 10.767,43.587 10.513,42.058 C 10.461,41.746 10.105,39.613 9.176,38.231 C 8.317,36.954 5.902,32.306 5.902,26.836 C 5.902,24.026 4.39,21.718 3.854,19.533 C 3.591,17.833 2.638,15.423 2.57,14.709 C 1.684,11.559 2.1
 32,10.118 3.741,10.118 C 5.132,10.118 5.528,11.927 6.093,13.622 C 6.258,14.52 7.505,16.934 7.788,18.233 C 8.038,19.088 8.897,21.556 9.437,21.727 C 9.75,21.784 10.151,21.523 10.291,21.043 C 10.52,20.26 9.818,18.945 9.539,15.26 C 9.087,12.343 9.17,10.139 9.116,8.949 C 8.653,5.424 9.133,3.598 10.693,3.598 C 12.176,3.598 12.568,4.455 13.02,7.936 C 13.189,9.518 13.754,12.095 14.037,14.864 C 14.213,16.364 14.639,18.601 14.98,19.17 C 15.285,19.503 15.919,19.198 15.9,18.848 C 15.894,16.377 15.732,14.977 15.958,12.999 C 15.845,10.287 16.219,7.823 16.219,6.467 C 16.219,3.494 16.502,1.473 18.358,1.473 C 20.333,1.473 20.287,3.776 20.287,6.806 C 20.399,7.545 20.456,10.087 20.569,13.286 z"
+   clip-rule="evenodd" />
+	</g>
+<g
+   style="display:inline"
+   inkscape:label="Base"
+   id="layer1"
+   transform="translate(-52.466647,2.6102791)" /></svg>
\ No newline at end of file
diff --git a/panels/user-accounts/data/icons/print_error.png b/panels/user-accounts/data/icons/print_error.png
new file mode 100644
index 0000000..d67150b
Binary files /dev/null and b/panels/user-accounts/data/icons/print_error.png differ
diff --git a/panels/user-accounts/data/icons/print_error.svg b/panels/user-accounts/data/icons/print_error.svg
new file mode 100644
index 0000000..4ad6bee
--- /dev/null
+++ b/panels/user-accounts/data/icons/print_error.svg
@@ -0,0 +1,525 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948)  -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:xlink="http://www.w3.org/1999/xlink";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   version="1.0"
+   x="0px"
+   y="0px"
+   width="48"
+   height="48"
+   viewBox="0 0 36.184 43.865"
+   enable-background="new 0 0 36.184 43.865"
+   xml:space="preserve"
+   id="svg2419"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   sodipodi:docname="print_error.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   inkscape:export-filename="/Users/mlanglie/Desktop/print_error.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90"><metadata
+   id="metadata2435"><rdf:RDF><cc:Work
+       rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+         rdf:resource="http://purl.org/dc/dcmitype/StillImage"; /></cc:Work></rdf:RDF></metadata><defs
+   id="defs2433"><linearGradient
+   inkscape:collect="always"
+   id="linearGradient84104"><stop
+     style="stop-color:#fffffc;stop-opacity:1;"
+     offset="0"
+     id="stop84106" /><stop
+     style="stop-color:#fffffc;stop-opacity:0;"
+     offset="1"
+     id="stop84108" /></linearGradient><linearGradient
+   id="linearGradient84076"><stop
+     style="stop-color:#73d216;stop-opacity:1;"
+     offset="0"
+     id="stop84078" /><stop
+     id="stop84090"
+     offset="0.31459025"
+     style="stop-color:#73d216;stop-opacity:1;" /><stop
+     style="stop-color:#4e9a06;stop-opacity:1;"
+     offset="1"
+     id="stop84080" /></linearGradient><linearGradient
+   id="linearGradient3531"><stop
+     id="stop3533"
+     offset="0"
+     style="stop-color:#9b9b9b;stop-opacity:1;" /><stop
+     id="stop3535"
+     offset="1"
+     style="stop-color:#414141;stop-opacity:1;" /></linearGradient><linearGradient
+   id="linearGradient3483"><stop
+     id="stop3485"
+     offset="0"
+     style="stop-color:#000000;stop-opacity:1;" /><stop
+     id="stop3487"
+     offset="1"
+     style="stop-color:#787878;stop-opacity:1" /></linearGradient><linearGradient
+   id="linearGradient3263"><stop
+     id="stop3265"
+     offset="0"
+     style="stop-color:#ffffff;stop-opacity:1;" /><stop
+     id="stop3267"
+     offset="1"
+     style="stop-color:#ffffff;stop-opacity:0;" /></linearGradient><linearGradient
+   id="linearGradient3247"><stop
+     style="stop-color:#52a714;stop-opacity:1;"
+     offset="0"
+     id="stop3249" /><stop
+     style="stop-color:#398800;stop-opacity:1;"
+     offset="1"
+     id="stop3251" /></linearGradient><linearGradient
+   id="linearGradient3233"><stop
+     id="stop3235"
+     offset="0"
+     style="stop-color:#398800;stop-opacity:1;" /><stop
+     id="stop3237"
+     offset="1"
+     style="stop-color:#84c706;stop-opacity:1;" /></linearGradient><inkscape:perspective
+   sodipodi:type="inkscape:persp3d"
+   inkscape:vp_x="0 : 21.932501 : 1"
+   inkscape:vp_y="0 : 1000 : 0"
+   inkscape:vp_z="36.183998 : 21.932501 : 1"
+   inkscape:persp3d-origin="18.091999 : 14.621667 : 1"
+   id="perspective2437" />
+	
+	
+
+		
+		
+	<filter
+   inkscape:collect="always"
+   id="filter3471"><feGaussianBlur
+     inkscape:collect="always"
+     stdDeviation="0.057808254"
+     id="feGaussianBlur3473" /></filter><linearGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient3233"
+   id="linearGradient3517"
+   gradientUnits="userSpaceOnUse"
+   x1="25.144751"
+   y1="43.865002"
+   x2="25.144751"
+   y2="23.838018" /><linearGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient3247"
+   id="linearGradient3519"
+   gradientUnits="userSpaceOnUse"
+   x1="30.691881"
+   y1="23.365002"
+   x2="30.691881"
+   y2="44.365963" /><linearGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient3263"
+   id="linearGradient3521"
+   gradientUnits="userSpaceOnUse"
+   x1="26.455547"
+   y1="24.322035"
+   x2="26.455547"
+   y2="30.466549" /><linearGradient
+   gradientUnits="userSpaceOnUse"
+   y2="55.692348"
+   x2="18.072493"
+   y1="29.205048"
+   x1="21.55229"
+   id="linearGradient5138"
+   xlink:href="#linearGradient5132"
+   inkscape:collect="always" /><linearGradient
+   id="linearGradient5132"
+   inkscape:collect="always"><stop
+     id="stop5134"
+     offset="0"
+     style="stop-color:white;stop-opacity:1;" /><stop
+     id="stop5136"
+     offset="1"
+     style="stop-color:white;stop-opacity:0;" /></linearGradient><linearGradient
+   id="linearGradient1913"><stop
+     id="stop1915"
+     offset="0"
+     style="stop-color:#73d216;stop-opacity:1" /><stop
+     id="stop1917"
+     offset="1"
+     style="stop-color:#8ae234;stop-opacity:1" /></linearGradient><inkscape:perspective
+   id="perspective84036"
+   inkscape:persp3d-origin="24 : 16 : 1"
+   inkscape:vp_z="48 : 24 : 1"
+   inkscape:vp_y="0 : 1000 : 0"
+   inkscape:vp_x="0 : 24 : 1"
+   sodipodi:type="inkscape:persp3d" /><radialGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient84076"
+   id="radialGradient84088"
+   cx="26.183998"
+   cy="40.111427"
+   fx="26.183998"
+   fy="40.111427"
+   r="10.5"
+   gradientUnits="userSpaceOnUse"
+   gradientTransform="matrix(0.9228377,7.3282173e-8,-7.9001009e-8,0.8924238,2.0204218,4.4167191)" /><linearGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient3263"
+   id="linearGradient84092"
+   gradientUnits="userSpaceOnUse"
+   x1="26.455547"
+   y1="24.322035"
+   x2="26.455547"
+   y2="30.466549" /><linearGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient84104"
+   id="linearGradient84110"
+   x1="28.185518"
+   y1="22.649143"
+   x2="27.596079"
+   y2="42.648415"
+   gradientUnits="userSpaceOnUse" /><radialGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient84076"
+   id="radialGradient84134"
+   gradientUnits="userSpaceOnUse"
+   gradientTransform="matrix(1.0862379,-2.5925308e-8,1.5464794e-8,0.8186283,-2.2580516,7.302016)"
+   cx="26.183998"
+   cy="39.098457"
+   fx="26.183998"
+   fy="39.098457"
+   r="10.5" /><linearGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient3263"
+   id="linearGradient84136"
+   gradientUnits="userSpaceOnUse"
+   x1="26.455547"
+   y1="24.322035"
+   x2="26.455547"
+   y2="30.466549" /><linearGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient84104"
+   id="linearGradient84138"
+   gradientUnits="userSpaceOnUse"
+   x1="21.515692"
+   y1="23.09075"
+   x2="34.488232"
+   y2="40.661182" /><filter
+   inkscape:collect="always"
+   id="filter84266"
+   x="-0.07103052"
+   width="1.142061"
+   y="-0.5276553"
+   height="2.0553105"><feGaussianBlur
+     inkscape:collect="always"
+     stdDeviation="0.45756194"
+     id="feGaussianBlur84268" /></filter><linearGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient3263"
+   id="linearGradient84277"
+   gradientUnits="userSpaceOnUse"
+   x1="26.455547"
+   y1="24.322035"
+   x2="26.455547"
+   y2="30.466549" /><linearGradient
+   id="linearGradient5171"><stop
+     style="stop-color:#fe3a00;stop-opacity:1"
+     offset="0"
+     id="stop5173" /><stop
+     style="stop-color:#c00;stop-opacity:1;"
+     offset="1"
+     id="stop5175" /></linearGradient><inkscape:perspective
+   id="perspective7871"
+   inkscape:persp3d-origin="24 : 16 : 1"
+   inkscape:vp_z="48 : 24 : 1"
+   inkscape:vp_y="0 : 1000 : 0"
+   inkscape:vp_x="0 : 24 : 1"
+   sodipodi:type="inkscape:persp3d" /><inkscape:perspective
+   id="perspective7973"
+   inkscape:persp3d-origin="14 : 9.3333333 : 1"
+   inkscape:vp_z="28 : 14 : 1"
+   inkscape:vp_y="0 : 1000 : 0"
+   inkscape:vp_x="0 : 14 : 1"
+   sodipodi:type="inkscape:persp3d" />
+	
+<radialGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient5171"
+   id="radialGradient8812"
+   cx="26.184002"
+   cy="39.797016"
+   fx="26.184002"
+   fy="39.797016"
+   r="10.65866"
+   gradientUnits="userSpaceOnUse"
+   gradientTransform="matrix(0.9444304,0,0,0.7220468,1.4550326,11.504981)" /><linearGradient
+   y2="40.661182"
+   x2="34.488232"
+   y1="23.09075"
+   x1="21.515692"
+   gradientUnits="userSpaceOnUse"
+   id="linearGradient84279"
+   xlink:href="#linearGradient84104"
+   inkscape:collect="always" /><linearGradient
+   y2="30.466549"
+   x2="26.455547"
+   y1="24.322035"
+   x1="26.455547"
+   gradientUnits="userSpaceOnUse"
+   id="linearGradient9095"
+   xlink:href="#linearGradient3263"
+   inkscape:collect="always" /><linearGradient
+   y2="40.661182"
+   x2="34.488232"
+   y1="23.09075"
+   x1="21.515692"
+   gradientUnits="userSpaceOnUse"
+   id="linearGradient9089"
+   xlink:href="#linearGradient84104"
+   inkscape:collect="always" /><linearGradient
+   y2="30.466549"
+   x2="26.455547"
+   y1="24.322035"
+   x1="26.455547"
+   gradientUnits="userSpaceOnUse"
+   id="linearGradient9087"
+   xlink:href="#linearGradient3263"
+   inkscape:collect="always" /><radialGradient
+   r="10.5"
+   fy="39.098457"
+   fx="26.183998"
+   cy="39.098457"
+   cx="26.183998"
+   gradientTransform="matrix(1.0862379,-2.5925308e-8,1.5464794e-8,0.8186283,-2.2580516,7.302016)"
+   gradientUnits="userSpaceOnUse"
+   id="radialGradient9085"
+   xlink:href="#linearGradient84076"
+   inkscape:collect="always" /><linearGradient
+   gradientUnits="userSpaceOnUse"
+   y2="42.648415"
+   x2="27.596079"
+   y1="22.649143"
+   x1="28.185518"
+   id="linearGradient9083"
+   xlink:href="#linearGradient84104"
+   inkscape:collect="always" /><linearGradient
+   y2="30.466549"
+   x2="26.455547"
+   y1="24.322035"
+   x1="26.455547"
+   gradientUnits="userSpaceOnUse"
+   id="linearGradient9081"
+   xlink:href="#linearGradient3263"
+   inkscape:collect="always" /><radialGradient
+   gradientTransform="matrix(0.9228377,7.3282173e-8,-7.9001009e-8,0.8924238,2.0204218,4.4167191)"
+   gradientUnits="userSpaceOnUse"
+   r="10.5"
+   fy="40.111427"
+   fx="26.183998"
+   cy="40.111427"
+   cx="26.183998"
+   id="radialGradient9079"
+   xlink:href="#linearGradient84076"
+   inkscape:collect="always" /><inkscape:perspective
+   sodipodi:type="inkscape:persp3d"
+   inkscape:vp_x="0 : 24 : 1"
+   inkscape:vp_y="0 : 1000 : 0"
+   inkscape:vp_z="48 : 24 : 1"
+   inkscape:persp3d-origin="24 : 16 : 1"
+   id="perspective9077" /><linearGradient
+   id="linearGradient9071"><stop
+     style="stop-color:#73d216;stop-opacity:1"
+     offset="0"
+     id="stop9073" /><stop
+     style="stop-color:#8ae234;stop-opacity:1"
+     offset="1"
+     id="stop9075" /></linearGradient><linearGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient5132"
+   id="linearGradient9063"
+   x1="21.55229"
+   y1="29.205048"
+   x2="18.072493"
+   y2="55.692348"
+   gradientUnits="userSpaceOnUse" /><linearGradient
+   y2="30.466549"
+   x2="26.455547"
+   y1="24.322035"
+   x1="26.455547"
+   gradientUnits="userSpaceOnUse"
+   id="linearGradient9061"
+   xlink:href="#linearGradient3263"
+   inkscape:collect="always" /><linearGradient
+   y2="44.365963"
+   x2="30.691881"
+   y1="23.365002"
+   x1="30.691881"
+   gradientUnits="userSpaceOnUse"
+   id="linearGradient9059"
+   xlink:href="#linearGradient3247"
+   inkscape:collect="always" /><linearGradient
+   y2="23.838018"
+   x2="25.144751"
+   y1="43.865002"
+   x1="25.144751"
+   gradientUnits="userSpaceOnUse"
+   id="linearGradient9057"
+   xlink:href="#linearGradient3233"
+   inkscape:collect="always" />
+	
+	
+
+		
+		
+	<inkscape:perspective
+   id="perspective9051"
+   inkscape:persp3d-origin="18.091999 : 14.621667 : 1"
+   inkscape:vp_z="36.183998 : 21.932501 : 1"
+   inkscape:vp_y="0 : 1000 : 0"
+   inkscape:vp_x="0 : 21.932501 : 1"
+   sodipodi:type="inkscape:persp3d" /><linearGradient
+   id="linearGradient9045"><stop
+     style="stop-color:#398800;stop-opacity:1;"
+     offset="0"
+     id="stop9047" /><stop
+     style="stop-color:#84c706;stop-opacity:1;"
+     offset="1"
+     id="stop9049" /></linearGradient><linearGradient
+   id="linearGradient9039"><stop
+     id="stop9041"
+     offset="0"
+     style="stop-color:#52a714;stop-opacity:1;" /><stop
+     id="stop9043"
+     offset="1"
+     style="stop-color:#398800;stop-opacity:1;" /></linearGradient><linearGradient
+   id="linearGradient9033"><stop
+     style="stop-color:#ffffff;stop-opacity:1;"
+     offset="0"
+     id="stop9035" /><stop
+     style="stop-color:#ffffff;stop-opacity:0;"
+     offset="1"
+     id="stop9037" /></linearGradient><linearGradient
+   id="linearGradient9027"><stop
+     style="stop-color:#000000;stop-opacity:1;"
+     offset="0"
+     id="stop9029" /><stop
+     style="stop-color:#787878;stop-opacity:1"
+     offset="1"
+     id="stop9031" /></linearGradient><linearGradient
+   id="linearGradient9021"><stop
+     style="stop-color:#9b9b9b;stop-opacity:1;"
+     offset="0"
+     id="stop9023" /><stop
+     style="stop-color:#414141;stop-opacity:1;"
+     offset="1"
+     id="stop9025" /></linearGradient><linearGradient
+   id="linearGradient9013"><stop
+     id="stop9015"
+     offset="0"
+     style="stop-color:#73d216;stop-opacity:1;" /><stop
+     style="stop-color:#73d216;stop-opacity:1;"
+     offset="0.31459025"
+     id="stop9017" /><stop
+     id="stop9019"
+     offset="1"
+     style="stop-color:#4e9a06;stop-opacity:1;" /></linearGradient><linearGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient3263"
+   id="linearGradient9115"
+   gradientUnits="userSpaceOnUse"
+   x1="26.455547"
+   y1="24.322035"
+   x2="26.455547"
+   y2="30.466549" /></defs><sodipodi:namedview
+   inkscape:window-height="733"
+   inkscape:window-width="1263"
+   inkscape:pageshadow="2"
+   inkscape:pageopacity="0.0"
+   guidetolerance="10.0"
+   gridtolerance="10.0"
+   objecttolerance="10.0"
+   borderopacity="1.0"
+   bordercolor="#666666"
+   pagecolor="#ffffff"
+   id="base"
+   showgrid="false"
+   inkscape:zoom="10.958333"
+   inkscape:cx="16.307224"
+   inkscape:cy="24"
+   inkscape:window-x="6"
+   inkscape:window-y="140"
+   inkscape:current-layer="svg2419" />
+<path
+   id="path2424"
+   d="M 11.485207,8.6743869 C 11.872117,8.5219533 18.066562,7.5772471 17.547442,14.819684 C 16.836811,24.751336 10.199071,21.863582 8.4570051,28.091683 C 9.1530536,27.855507 9.3319265,27.184615 9.77036,26.633222 C 11.09052,24.971517 11.912946,24.144427 13.199081,23.591154 C 17.777838,21.620819 20.261644,13.237019 16.405184,9.3659791 C 14.958646,7.9131637 12.270692,8.0514823 11.485207,8.6743869 z M -0.41567362,30.622819 C -0.62079412,30.073309 -0.81036052,29.508743 -0.98534482,28.932886 C 0.28134733,30.510848 2.408639,29.511665 3.7800623,29.851546 C 7.7792565,30.842672 10.201988,29.700696 12.4972,27.002072 C 14.538683,24.600785 15.730521,26.026314 17.692291,22.415916 C 18.187107,21.506024 19.527682,20.515211 20.049718,16.478567 C 20.335526,14.26641 21.73087,14.007651 21.560747,12.407106 C 21.300215,9.95501 21.209476,9.6012157 20.182901,7.9460967 C 18.706228,5.5636294 16.443158,4.9249489 14.396731,4.9187631 C 12.674334,4.9140584 11.84411,5.6088349 11.260829,5.8365431 C 15.3902
 32,4.8356399 18.977454,6.2618089 19.977781,8.6743869 C 20.486207,9.9004346 20.744795,10.273048 20.835204,11.578136 C 20.978108,13.644446 20.307334,14.416019 20.263588,13.790293 C 20.079855,11.11331 19.152438,7.8049552 16.050354,6.738867 C 14.094417,6.0670338 11.302445,6.5779657 9.6303729,7.8454158 C 7.5908326,9.7988133 6.4952361,12.616937 6.4952361,14.474358 C 6.4952361,18.037708 6.4689884,19.168722 5.854599,22.494014 C 5.596011,23.89696 4.6627611,25.357303 5.2022963,27.278709 C 5.9975029,26.985134 6.7110502,25.878585 6.9949136,25.111717 C 8.9868188,19.727642 10.292396,20.99227 12.343602,18.829042 C 12.831614,18.314346 13.669595,16.922691 13.771669,16.409877 C 14.018591,15.167833 14.629092,12.200099 12.557472,12.269729 C 10.832904,13.36875 11.557145,15.649595 10.237957,17.872102 C 12.271664,16.963152 12.138481,13.127869 12.885082,13.037538 C 13.533495,12.95944 13.493638,14.504468 13.351707,15.328734 C 13.046456,17.100529 12.422345,18.101693 11.019554,19.120734 C 9.9006261,19
 .933709 8.8604412,20.065441 7.8484484,21.773252 C 7.6579099,22.073413 6.3027534,25.346012 6.134574,25.654641 C 5.2858998,27.216607 5.3879741,25.564311 6.3212239,22.946607 C 6.3212239,22.946607 7.2311425,20.110606 7.1115699,17.014904 C 7.0571303,15.581848 7.1368454,9.9201951 10.843597,7.9150456 C 12.438871,7.052201 14.9149,6.5102179 16.620025,7.776727 C 21.95802,11.740919 19.47227,21.463682 15.405828,24.214058 C 13.770697,25.320606 12.413596,25.389296 11.019554,27.516768 C 9.932706,29.17565 6.8500655,30.289726 4.7074794,29.321496 C 5.5649027,28.845379 6.8957558,28.803036 7.2787772,27.73883 C 10.085332,19.931827 15.530262,23.306048 16.183536,14.966471 C 16.414904,12.009088 14.877959,9.6953099 12.69746,9.6953099 C 10.466409,9.6953099 8.9664042,12.675276 8.6281009,15.440706 C 8.4657544,16.774023 8.3782621,18.528881 8.2713273,19.450064 C 10.056167,18.413145 8.4851971,11.162239 12.484562,10.747283 C 15.963834,10.386902 15.66636,14.964589 15.26973,16.96127 C 14.967396,18.483716 14.
 270374,19.795389 11.270365,21.516375 C 9.690645,22.422502 8.643655,23.573275 7.8426157,25.457043 C 7.3730743,26.56171 6.4126046,28.452065 4.547077,28.632726 C 4.3332073,28.653426 3.9268547,26.573943 3.8004772,25.47304 C 3.6138271,23.848031 4.453752,22.765006 4.7327549,21.015793 C 5.0438382,19.072746 5.2615964,17.525836 5.2781228,14.197721 C 4.4936096,9.0893427 5.2917327,7.5791289 7.4226532,5.1562011 C 9.9142358,2.3220811 12.045219,2.0705493 13.508882,2.0570557 C 15.652565,2.0393053 16.899028,3.5509526 16.263252,3.4276891 C 14.62326,3.1105913 11.630055,2.6909308 9.0577845,5.2945196 C 7.6229131,6.7454536 6.0402768,8.6122845 6.2084562,10.886543 C 6.8802017,7.6195895 10.334508,3.7516736 13.747676,3.7516736 C 17.577206,3.7516736 19.976808,5.1712562 21.120039,7.0155042 C 22.280769,8.8889209 22.761976,10.297513 22.761976,12.822062 C 22.761976,14.686071 21.730541,15.451057 21.262943,16.962211 C 21.083098,17.542773 20.463848,19.045459 20.191651,20.211286 C 19.097998,24.896241 18.3095
 96,27.152622 14.271346,30.220096 C 12.511782,31.556235 11.111907,31.646565 10.179629,31.285243 C 10.187406,31.13281 12.366934,30.934272 13.724035,28.937591 C 15.002392,27.055705 16.650162,27.007717 17.396761,24.840726 C 16.622941,25.778846 15.419438,26.673683 14.41425,27.115925 C 14.130387,27.241071 13.618072,27.886557 13.421701,28.116148 C 11.368551,30.531548 9.713004,31.103642 7.3458545,31.373692 C 7.7220709,31.550589 8.110925,31.687026 8.5231103,31.739719 C 11.53187,32.124565 13.387675,32.163143 15.774267,30.055431 C 19.142717,27.08111 19.696834,25.201106 20.047775,22.967308 C 20.307334,21.313131 21.669648,17.436727 22.261326,15.868175 C 23.094574,13.65922 22.570465,18.105457 22.332292,18.688842 C 20.93825,22.115755 21.500144,26.735784 17.955739,30.380997 C 15.523456,32.882964 12.32416,33.811675 7.1358733,32.637379 C 5.7525248,32.324044 6.253216,31.857336 4.671552,31.373692 C 4.1971499,31.159157 1.6540024,31.013311 1.3623619,31.011429 C 0.72269676,31.007665 0.11997297,30.
 875933 -0.41567362,30.622819 z M 4.2680743,5.1477326 C 2.8681995,6.7162844 3.1442858,7.9310416 2.2158966,9.2445983 C 0.39119867,11.826545 1.4517984,15.393659 1.0658607,17.99913 C 0.56618308,21.378997 0.52283784,20.110089 0.0065640818,17.990301 C -0.75463862,14.864849 -0.20180392,13.731954 -0.076398418,12.407106 C 0.6186783,9.1298026 1.2262629,7.7560263 2.8691715,5.6887748 C 4.2253003,3.9828454 6.149156,3.0371977 4.2680743,5.1477326 z M 24.036445,36.450079 C 23.488161,37.083333 22.896131,37.673305 22.262298,38.211523 L 21.475841,38.506979 C 18.241547,39.711387 16.58114,39.821477 11.857534,39.082837 C 9.932706,38.781735 7.3050248,38.411944 5.4978253,39.277612 C 6.5839482,39.510065 10.395401,38.361053 11.576587,39.986142 C 11.459931,40.156453 9.2113823,39.88358 7.0960157,40.347465 C 6.5837004,40.058595 6.0888836,39.731146 5.6115651,39.367002 C 5.1527173,39.009443 4.8173306,38.720573 4.4926375,38.413826 C 6.9570004,37.030641 10.904842,37.507699 13.34879,37.820091 C 17.581468,38.
 362075 19.260345,38.181414 21.964825,37.188718 C 22.696843,36.919609 23.388031,36.670259 24.036445,36.450079 z M 26.094456,7.8981086 C 27.151167,9.9813566 28.257457,11.575313 28.257457,14.734999 C 28.257457,18.212845 25.759069,19.908303 25.360494,22.223022 C 24.987194,24.390014 24.927894,26.193802 24.599312,26.193802 C 24.132687,26.193802 23.98395,24.125609 24.054915,22.674675 C 24.126854,21.205864 24.314124,20.404861 24.655344,19.310545 C 25.039337,18.081673 25.62266,15.331577 25.504059,13.251152 C 25.348517,10.505481 25.590559,11.089486 26.303134,12.745546 C 26.769759,13.828571 26.261622,15.950138 26.303134,17.484815 C 27.329709,15.648996 27.135261,12.882863 26.349775,10.877714 C 26.087298,10.20494 25.726989,8.8446969 26.094456,7.8981086 z M 24.622001,9.2587722 C 24.485902,8.654687 23.723397,6.4935811 22.726959,5.2026076 C 21.232786,3.2689699 22.578201,3.6726143 23.649494,4.846911 C 24.696483,5.9948613 25.472289,7.3598893 25.501453,8.680032 C 25.560753,11.39277 25.122651,1
 1.470929 24.622001,9.2587722 z M 28.324534,16.874703 C 28.602565,16.515264 28.874762,18.765998 28.371196,19.556391 C 27.026733,21.665043 27.509885,25.128655 26.639823,27.894085 C 25.254531,32.293934 20.848813,35.618286 15.998831,35.528896 C 19.543236,34.354599 22.714341,33.813557 24.183237,26.840229 C 24.312532,26.225793 25.174816,26.557005 24.397107,29.459814 C 25.254531,28.223415 25.999186,25.124891 26.111954,22.623864 C 26.186809,20.930167 27.729588,18.502534 28.324534,16.874703 z M 0.35036898,7.0776065 C 3.1160939,2.0115701 8.6912897,0.54275818 13.214636,0.54275818 C 16.041605,0.54275818 18.507912,1.0273437 20.818678,2.3550142 C 21.174479,2.6147144 21.713042,2.9355759 22.002738,3.2253863 C 22.938905,4.1653883 21.369626,3.7445623 19.405193,2.8753556 C 15.80217,1.2811182 13.224356,1.5241817 11.057467,1.8713897 C 9.4544161,2.1282671 8.4327017,3.4107521 7.629718,4.1889118 C 4.6705382,7.05126 4.2097461,9.6106249 4.5655476,12.822062 C 5.0068971,16.806955 4.2680743,21.015793 3.
 3367686,23.309812 C 2.8604223,24.48505 2.9236112,26.011258 3.1365088,26.978548 C 3.5214743,28.723056 5.0173803,29.448829 3.1481744,29.208582 C -0.12595652,28.787761 -0.12403302,24.289333 0.99392257,21.109887 C 2.1361815,17.860811 1.50895,15.966631 1.7492717,13.57764 C 2.8163869,2.8893489 3.1267874,15.841548 3.0655428,16.408937 C 2.7077971,19.726701 2.2340211,20.608302 1.7385783,22.084704 C 0.6727661,25.260787 1.9314335,27.1104 2.2661583,27.366598 C 0.91096007,23.04949 3.2794126,21.655634 3.4660626,16.648877 C 3.5117529,15.433179 3.5311956,14.688893 3.3455178,13.046948 C 2.7748744,7.9799706 4.0814242,5.0574021 6.9725545,2.7097496 C 5.2188225,2.7266866 3.8724152,3.9950776 2.6825216,5.1477326 C 1.376944,6.4114188 0.16469114,9.2935264 -0.21249732,10.402898 C -0.77633582,12.06178 -1.2711526,10.046281 0.35036898,7.0776065 z M -1.1097781,28.513226 C -2.0128918,25.368594 -2.4649347,21.861701 -2.3900803,18.216487 C -2.3609163,16.765553 -2.2306501,15.171597 -1.7834679,13.305707 C -0.9
 1243472,9.6699043 -0.68197602,11.586122 -0.74034592,12.032491 C -1.892347,20.8421 1.6144968,19.138912 -0.52455272,25.744091 C -1.2711526,25.202108 -0.48304042,21.510409 -1.656139,19.312946 C -1.3508469,21.734954 -2.0167804,25.74309 0.62937185,28.271403 C 1.3856931,28.994988 2.8681995,29.389244 0.72269676,29.208582 C -0.014181718,29.14648 -0.61787772,28.901835 -1.1097781,28.513226 z M 0.48744008,32.752173 C 0.31731635,32.398379 0.15496979,32.036116 -0.001544018,31.666325 C 1.0075324,31.547766 3.0567937,31.442381 4.827052,32.187607 C 5.8555711,32.620441 3.7965886,32.40967 2.0000826,32.51976 C 1.3565291,32.558339 0.82574314,32.712653 0.48744008,32.752173 z M 1.3409749,34.366831 C 1.1446035,34.029973 0.95600926,33.683706 0.77422,33.328971 C 5.2207668,32.537638 7.1728144,33.319562 10.628756,33.606549 C 14.190659,33.902946 18.050036,32.097277 19.263261,30.020616 C 19.886399,28.953587 20.061384,28.694827 20.186789,28.414427 C 20.295669,28.171663 20.367606,27.912904 20.662164,27.098
 048 C 21.315439,25.292378 21.284331,27.753885 21.120039,28.360793 C 20.008889,32.4586 19.076611,31.735955 17.211084,33.542565 C 21.502088,32.007888 22.154392,28.937591 21.595413,24.661006 C 21.461259,23.63726 22.257437,20.869947 22.622961,19.880074 C 22.622961,19.880074 23.390948,17.397867 23.395808,12.997078 C 23.398724,10.126261 22.460614,5.7019479 18.621652,4.0505932 C 17.335517,3.4973188 15.549704,1.9767551 15.549704,1.9767551 C 16.345283,2.4005401 18.263906,2.6674072 20.120685,3.773956 C 20.191651,3.8162985 24.211429,6.0576243 24.612921,11.923462 C 24.802488,14.69548 24.823213,14.824989 24.636563,16.630658 C 24.636563,16.630658 24.522513,18.48748 23.87021,20.022157 C 23.555238,20.876533 23.217907,23.396378 23.404558,24.661006 C 23.836185,27.588279 22.063983,34.896582 14.845879,34.896582 C 11.657275,34.896582 9.7168927,34.487272 8.1906401,34.251096 C 6.8082637,34.036561 4.0143469,33.91612 1.3409749,34.366831 z M 3.9297711,37.852084 C 3.5603597,37.465356 3.2055303,37.0551
 05 2.865283,36.622271 C 3.9113006,36.029477 4.8299684,36.020068 6.6935517,36.070879 C 8.8283608,36.070879 12.045156,36.916786 11.057467,37.195306 C 11.009832,37.207538 6.4806541,36.578988 3.9297711,37.852084 z M 14.733111,41.653493 C 14.310232,41.716536 13.88152,41.763583 13.44406,41.791811 C 11.361746,41.927308 9.4310844,41.515174 7.6851297,40.656094 C 8.5367202,40.538475 10.183517,40.482019 11.744767,40.7022 C 12.669268,40.832991 13.723062,41.288407 14.733111,41.653493 z M 20.761322,39.340655 C 19.332282,40.284421 17.738953,40.992951 16.005636,41.406965 C 14.734083,41.029648 11.984449,40.585503 12.005589,39.75495 C 12.021421,39.132891 15.493321,40.331468 17.489114,40.076472 C 18.855937,39.902398 19.892232,39.635171 20.761322,39.340655 z M 26.76134,32.003183 C 27.309624,31.472491 26.651489,34.623708 23.573708,35.937265 C 21.48945,36.675905 18.394173,38.324437 13.07076,36.917727 C 12.417485,36.744594 10.347808,36.196965 9.8870164,36.103812 C 6.2998369,35.382109 4.4372258,35.
 597584 2.4064351,36.01254 C 2.1702062,35.685092 1.9417545,35.345412 1.7210798,34.995381 C 2.3753268,34.730976 4.0192075,34.628413 5.200352,34.626531 C 8.9615437,34.619945 14.003037,35.980548 15.996887,36.070879 C 20.670913,36.282591 23.680644,33.000582 24.053944,33.000582 C 24.986221,33.000582 23.179994,34.632178 22.678372,35.082889 C 22.251605,35.467734 24.361138,34.516441 26.76134,32.003183 z M 28.531599,25.021387 C 28.408138,27.148859 28.247735,30.101537 26.467755,31.577877 C 23.628148,33.933056 24.799572,32.277938 26.039044,30.634111 C 28.194268,27.774586 27.297959,21.332891 28.708527,20.0852 C 28.725053,21.437335 28.621035,23.498941 28.531599,25.021387 z"
+   style="fill:#a1a1a1;fill-opacity:1"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90"
+   sodipodi:nodetypes="cscssscccssssssscsssscsscsssccssscscssssscsssscssssssscsssscsssssscscsscssssssscsccssscsccccscccscssccssssssscsccsssccsscscsccscsssssssssssscsscssccsssccsscccsscccssssscscsscssccsssccccsccscscccsscccssccssssccsscc" /><path
+   sodipodi:type="arc"
+   style="opacity:0.24299999;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter84266)"
+   id="path84140"
+   sodipodi:cx="27.093658"
+   sodipodi:cy="38.810692"
+   sodipodi:rx="7.7301183"
+   sodipodi:ry="1.0405928"
+   d="M 34.823777,38.810692 A 7.7301183,1.0405928 0 1 1 19.36354,38.810692 A 7.7301183,1.0405928 0 1 1 34.823777,38.810692 z"
+   transform="matrix(1.1911672,0,0,2.1266149,-5.0625748,-41.775272)" /><g
+   id="Background">
+</g>
+<g
+   id="Guides">
+</g>
+
+<circle
+   clip-rule="evenodd"
+   cx="26.184"
+   cy="33.865002"
+   r="10"
+   id="circle2428"
+   sodipodi:cx="26.184"
+   sodipodi:cy="33.865002"
+   sodipodi:rx="10"
+   sodipodi:ry="10"
+   style="fill:url(#radialGradient8812);fill-opacity:1;fill-rule:evenodd;stroke:#a40000;stroke-width:1.31732059000000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+   transform="matrix(1.1263785,0,0,1.1511056,-2.2713556,-9.1997707)" /><path
+   sodipodi:type="arc"
+   style="opacity:0.5;fill:url(#linearGradient84277);fill-opacity:1;stroke:none;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+   id="path3253"
+   sodipodi:cx="26.455547"
+   sodipodi:cy="27.394291"
+   sodipodi:rx="6.1445141"
+   sodipodi:ry="3.072257"
+   d="M 32.600061,27.394291 A 6.1445141,3.072257 0 1 1 20.311033,27.394291 A 6.1445141,3.072257 0 1 1 32.600061,27.394291 z"
+   transform="matrix(1.1246822,0,0,1.4387643,-2.5144268,-14.969086)" /><path
+   sodipodi:type="arc"
+   style="opacity:0.48;fill:none;fill-opacity:1;stroke:#e64837;stroke-width:1.21842730000000010;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+   id="path84102"
+   sodipodi:cx="28.185518"
+   sodipodi:cy="31.917336"
+   sodipodi:rx="10.027505"
+   sodipodi:ry="10.240856"
+   d="M 38.213023,31.917336 A 10.027505,10.240856 0 1 1 18.158013,31.917336 A 10.027505,10.240856 0 1 1 38.213023,31.917336 z"
+   transform="matrix(0.9962424,0,0,0.9957004,-0.8393988,-2.0505383)" /><g
+   id="g7978"
+   transform="translate(103.26268,8.6771365)">
+</g><g
+   style="display:none"
+   id="g7980"
+   display="none"
+   transform="translate(103.26268,8.6771365)">
+</g><path
+   id="path7993"
+   style="opacity:0.55;fill:#a40000;fill-opacity:1;fill-rule:evenodd;stroke:#a40000;stroke-width:1.14231765000000007;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+   d="M 27.143847,37.652725 C 26.708227,37.652725 26.326837,37.518032 25.998788,37.249507 C 25.677852,36.974118 25.516939,36.592349 25.516939,36.10334 C 25.516939,35.676959 25.66985,35.315778 25.977452,35.018942 C 26.291276,34.7161 26.672666,34.565107 27.122511,34.56425 C 27.571466,34.56425 27.953745,34.7161 28.26757,35.018942 C 28.588505,35.31492 28.749418,35.676959 28.749418,36.10334 C 28.749418,36.585484 28.588505,36.963823 28.26757,37.239212 C 27.946633,37.515458 27.571466,37.652725 27.143847,37.652725 z M 25.956115,30.858079 L 25.613842,25.912229 C 25.549833,24.94794 25.517828,24.256464 25.517828,23.836088 C 25.517828,23.26472 25.670739,22.82118 25.978341,22.504613 C 26.292165,22.18118 26.702004,22.019893 27.208746,22.019035 C 27.82217,22.019035 28.232008,22.225791 28.439151,22.638445 C 28.645403,23.045095 28.749418,23.633622 28.749418,24.404025 C 28.749418,24.858717 28.724526,25.320272 28.674741,25.787834 L 28.214228,30.878669 C 28.164443,31.484354 28.056871,31.94934 2
 7.893292,32.272773 C 27.728822,32.596205 27.457671,32.758349 27.079838,32.758349 C 26.694892,32.758349 26.427296,32.603067 26.277052,32.293362 C 26.126807,31.976794 26.020125,31.498939 25.956115,30.858079 z" /><path
+   id="path8814"
+   style="fill:#ffffff;fill-rule:evenodd"
+   d="M 27.143847,36.992527 C 26.708227,36.992527 26.326837,36.857834 25.998788,36.589309 C 25.677852,36.31392 25.516939,35.932151 25.516939,35.443142 C 25.516939,35.016761 25.66985,34.65558 25.977452,34.358744 C 26.291276,34.055902 26.672666,33.904909 27.122511,33.904052 C 27.571466,33.904052 27.953745,34.055902 28.26757,34.358744 C 28.588505,34.654722 28.749418,35.016761 28.749418,35.443142 C 28.749418,35.925286 28.588505,36.303625 28.26757,36.579014 C 27.946633,36.85526 27.571466,36.992527 27.143847,36.992527 z M 25.956115,30.197881 L 25.613842,25.252031 C 25.549833,24.287742 25.517828,23.596266 25.517828,23.17589 C 25.517828,22.604522 25.670739,22.160982 25.978341,21.844415 C 26.292165,21.520982 26.702004,21.359695 27.208746,21.358837 C 27.82217,21.358837 28.232008,21.565593 28.439151,21.978247 C 28.645403,22.384897 28.749418,22.973424 28.749418,23.743827 C 28.749418,24.198519 28.724526,24.660074 28.674741,25.127636 L 28.214228,30.218471 C 28.164443,30.824156 28.056871,3
 1.289142 27.893292,31.612575 C 27.728822,31.936007 27.457671,32.098151 27.079838,32.098151 C 26.694892,32.098151 26.427296,31.942869 26.277052,31.633164 C 26.126807,31.316596 26.020125,30.838741 25.956115,30.197881 z" /><rect
+   style="fill:#666666;fill-opacity:0.75;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+   id="rect9126"
+   width="1.8060035"
+   height="42.650608"
+   x="-26.038683"
+   y="-24.284592"
+   transform="matrix(-0.6420845,-0.7666339,0.7632254,-0.6461324,0,0)"
+   ry="0"
+   rx="0.018515259" /></svg>
\ No newline at end of file
diff --git a/panels/user-accounts/data/icons/print_ok.png b/panels/user-accounts/data/icons/print_ok.png
new file mode 100644
index 0000000..4dd615e
Binary files /dev/null and b/panels/user-accounts/data/icons/print_ok.png differ
diff --git a/panels/user-accounts/data/icons/print_ok.svg b/panels/user-accounts/data/icons/print_ok.svg
new file mode 100644
index 0000000..ba821ef
--- /dev/null
+++ b/panels/user-accounts/data/icons/print_ok.svg
@@ -0,0 +1,310 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948)  -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:xlink="http://www.w3.org/1999/xlink";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   version="1.0"
+   x="0px"
+   y="0px"
+   width="48"
+   height="48"
+   viewBox="0 0 36.184 43.865"
+   enable-background="new 0 0 36.184 43.865"
+   xml:space="preserve"
+   id="svg2419"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   sodipodi:docname="print_ok.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   inkscape:export-filename="/Users/mlanglie/Desktop/Fingerprint Enrollment Icons/Vector/print_ok.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90"><metadata
+   id="metadata2435"><rdf:RDF><cc:Work
+       rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+         rdf:resource="http://purl.org/dc/dcmitype/StillImage"; /></cc:Work></rdf:RDF></metadata><defs
+   id="defs2433"><linearGradient
+   inkscape:collect="always"
+   id="linearGradient84104"><stop
+     style="stop-color:#fffffc;stop-opacity:1;"
+     offset="0"
+     id="stop84106" /><stop
+     style="stop-color:#fffffc;stop-opacity:0;"
+     offset="1"
+     id="stop84108" /></linearGradient><linearGradient
+   id="linearGradient84076"><stop
+     style="stop-color:#73d216;stop-opacity:1;"
+     offset="0"
+     id="stop84078" /><stop
+     id="stop84090"
+     offset="0.31459025"
+     style="stop-color:#73d216;stop-opacity:1;" /><stop
+     style="stop-color:#4e9a06;stop-opacity:1;"
+     offset="1"
+     id="stop84080" /></linearGradient><linearGradient
+   id="linearGradient3531"><stop
+     id="stop3533"
+     offset="0"
+     style="stop-color:#9b9b9b;stop-opacity:1;" /><stop
+     id="stop3535"
+     offset="1"
+     style="stop-color:#414141;stop-opacity:1;" /></linearGradient><linearGradient
+   id="linearGradient3483"><stop
+     id="stop3485"
+     offset="0"
+     style="stop-color:#000000;stop-opacity:1;" /><stop
+     id="stop3487"
+     offset="1"
+     style="stop-color:#787878;stop-opacity:1" /></linearGradient><linearGradient
+   id="linearGradient3263"><stop
+     id="stop3265"
+     offset="0"
+     style="stop-color:#ffffff;stop-opacity:1;" /><stop
+     id="stop3267"
+     offset="1"
+     style="stop-color:#ffffff;stop-opacity:0;" /></linearGradient><linearGradient
+   id="linearGradient3247"><stop
+     style="stop-color:#52a714;stop-opacity:1;"
+     offset="0"
+     id="stop3249" /><stop
+     style="stop-color:#398800;stop-opacity:1;"
+     offset="1"
+     id="stop3251" /></linearGradient><linearGradient
+   id="linearGradient3233"><stop
+     id="stop3235"
+     offset="0"
+     style="stop-color:#398800;stop-opacity:1;" /><stop
+     id="stop3237"
+     offset="1"
+     style="stop-color:#84c706;stop-opacity:1;" /></linearGradient><inkscape:perspective
+   sodipodi:type="inkscape:persp3d"
+   inkscape:vp_x="0 : 21.932501 : 1"
+   inkscape:vp_y="0 : 1000 : 0"
+   inkscape:vp_z="36.183998 : 21.932501 : 1"
+   inkscape:persp3d-origin="18.091999 : 14.621667 : 1"
+   id="perspective2437" />
+	
+	
+
+		
+		
+	<filter
+   inkscape:collect="always"
+   id="filter3471"><feGaussianBlur
+     inkscape:collect="always"
+     stdDeviation="0.057808254"
+     id="feGaussianBlur3473" /></filter><linearGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient3233"
+   id="linearGradient3517"
+   gradientUnits="userSpaceOnUse"
+   x1="25.144751"
+   y1="43.865002"
+   x2="25.144751"
+   y2="23.838018" /><linearGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient3247"
+   id="linearGradient3519"
+   gradientUnits="userSpaceOnUse"
+   x1="30.691881"
+   y1="23.365002"
+   x2="30.691881"
+   y2="44.365963" /><linearGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient3263"
+   id="linearGradient3521"
+   gradientUnits="userSpaceOnUse"
+   x1="26.455547"
+   y1="24.322035"
+   x2="26.455547"
+   y2="30.466549" /><linearGradient
+   gradientUnits="userSpaceOnUse"
+   y2="55.692348"
+   x2="18.072493"
+   y1="29.205048"
+   x1="21.55229"
+   id="linearGradient5138"
+   xlink:href="#linearGradient5132"
+   inkscape:collect="always" /><linearGradient
+   id="linearGradient5132"
+   inkscape:collect="always"><stop
+     id="stop5134"
+     offset="0"
+     style="stop-color:white;stop-opacity:1;" /><stop
+     id="stop5136"
+     offset="1"
+     style="stop-color:white;stop-opacity:0;" /></linearGradient><linearGradient
+   id="linearGradient1913"><stop
+     id="stop1915"
+     offset="0"
+     style="stop-color:#73d216;stop-opacity:1" /><stop
+     id="stop1917"
+     offset="1"
+     style="stop-color:#8ae234;stop-opacity:1" /></linearGradient><inkscape:perspective
+   id="perspective84036"
+   inkscape:persp3d-origin="24 : 16 : 1"
+   inkscape:vp_z="48 : 24 : 1"
+   inkscape:vp_y="0 : 1000 : 0"
+   inkscape:vp_x="0 : 24 : 1"
+   sodipodi:type="inkscape:persp3d" /><radialGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient84076"
+   id="radialGradient84088"
+   cx="26.183998"
+   cy="40.111427"
+   fx="26.183998"
+   fy="40.111427"
+   r="10.5"
+   gradientUnits="userSpaceOnUse"
+   gradientTransform="matrix(0.9228377,7.3282173e-8,-7.9001009e-8,0.8924238,2.0204218,4.4167191)" /><linearGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient3263"
+   id="linearGradient84092"
+   gradientUnits="userSpaceOnUse"
+   x1="26.455547"
+   y1="24.322035"
+   x2="26.455547"
+   y2="30.466549" /><linearGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient84104"
+   id="linearGradient84110"
+   x1="28.185518"
+   y1="22.649143"
+   x2="27.596079"
+   y2="42.648415"
+   gradientUnits="userSpaceOnUse" /><radialGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient84076"
+   id="radialGradient84134"
+   gradientUnits="userSpaceOnUse"
+   gradientTransform="matrix(1.0862379,-2.5925308e-8,1.5464794e-8,0.8186283,-2.2580516,7.302016)"
+   cx="26.183998"
+   cy="39.098457"
+   fx="26.183998"
+   fy="39.098457"
+   r="10.5" /><linearGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient3263"
+   id="linearGradient84136"
+   gradientUnits="userSpaceOnUse"
+   x1="26.455547"
+   y1="24.322035"
+   x2="26.455547"
+   y2="30.466549" /><linearGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient84104"
+   id="linearGradient84138"
+   gradientUnits="userSpaceOnUse"
+   x1="21.515692"
+   y1="23.09075"
+   x2="34.488232"
+   y2="40.661182" /><filter
+   inkscape:collect="always"
+   id="filter84266"
+   x="-0.07103052"
+   width="1.142061"
+   y="-0.5276553"
+   height="2.0553105"><feGaussianBlur
+     inkscape:collect="always"
+     stdDeviation="0.45756194"
+     id="feGaussianBlur84268" /></filter><linearGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient3263"
+   id="linearGradient84277"
+   gradientUnits="userSpaceOnUse"
+   x1="26.455547"
+   y1="24.322035"
+   x2="26.455547"
+   y2="30.466549" /><linearGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient84104"
+   id="linearGradient84279"
+   gradientUnits="userSpaceOnUse"
+   x1="21.515692"
+   y1="23.09075"
+   x2="34.488232"
+   y2="40.661182" /></defs><sodipodi:namedview
+   inkscape:window-height="713"
+   inkscape:window-width="1222"
+   inkscape:pageshadow="2"
+   inkscape:pageopacity="0.0"
+   guidetolerance="10.0"
+   gridtolerance="10.0"
+   objecttolerance="10.0"
+   borderopacity="1.0"
+   bordercolor="#666666"
+   pagecolor="#ffffff"
+   id="base"
+   showgrid="false"
+   inkscape:zoom="4.399364"
+   inkscape:cx="39.372624"
+   inkscape:cy="7.0437262"
+   inkscape:window-x="15"
+   inkscape:window-y="165"
+   inkscape:current-layer="svg2419" />
+<path
+   sodipodi:type="arc"
+   style="opacity:0.24299999;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter84266)"
+   id="path84140"
+   sodipodi:cx="27.093658"
+   sodipodi:cy="38.810692"
+   sodipodi:rx="7.7301183"
+   sodipodi:ry="1.0405928"
+   d="M 34.823777,38.810692 A 7.7301183,1.0405928 0 1 1 19.36354,38.810692 A 7.7301183,1.0405928 0 1 1 34.823777,38.810692 z"
+   transform="matrix(1.1911672,0,0,2.1266149,-5.0625748,-41.775272)" /><g
+   id="Background">
+</g>
+<g
+   id="Guides">
+</g>
+<path
+   id="path2424"
+   d="M 11.4715,8.6587828 C 11.85841,8.5063492 18.052855,7.561643 17.533735,14.80408 C 16.823104,24.735732 10.185364,21.847978 8.4432981,28.076079 C 9.1393466,27.839903 9.3182195,27.169011 9.756653,26.617618 C 11.076813,24.955913 11.899239,24.128823 13.185374,23.57555 C 17.764131,21.605215 20.247937,13.221415 16.391477,9.350375 C 14.944939,7.8975596 12.256985,8.0358782 11.4715,8.6587828 z M -0.42938057,30.607215 C -0.63450107,30.057705 -0.82406747,29.493139 -0.99905177,28.917282 C 0.26764038,30.495244 2.394932,29.496061 3.7663553,29.835942 C 7.7655495,30.827068 10.188281,29.685092 12.483493,26.986468 C 14.524976,24.585181 15.716814,26.01071 17.678584,22.400312 C 18.1734,21.49042 19.513975,20.499607 20.036011,16.462963 C 20.321819,14.250806 21.717163,13.992047 21.54704,12.391502 C 21.286508,9.9394059 21.195769,9.5856116 20.169194,7.9304926 C 18.692521,5.5480253 16.429451,4.9093448 14.383024,4.903159 C 12.660627,4.8984543 11.830403,5.5932308 11.247122,5.820939 C 15.376525,4.82
 00358 18.963747,6.2462048 19.964074,8.6587828 C 20.4725,9.8848305 20.731088,10.257444 20.821497,11.562532 C 20.964401,13.628842 20.293627,14.400415 20.249881,13.774689 C 20.066148,11.097706 19.138731,7.7893511 16.036647,6.7232629 C 14.08071,6.0514297 11.288738,6.5623616 9.6166659,7.8298117 C 7.5771256,9.7832092 6.4815291,12.601333 6.4815291,14.458754 C 6.4815291,18.022104 6.4552814,19.153118 5.840892,22.47841 C 5.582304,23.881356 4.6490541,25.341699 5.1885893,27.263105 C 5.9837959,26.96953 6.6973432,25.862981 6.9812066,25.096113 C 8.9731118,19.712038 10.278689,20.976666 12.329895,18.813438 C 12.817907,18.298742 13.655888,16.907087 13.757962,16.394273 C 14.004884,15.152229 14.615385,12.184495 12.543765,12.254125 C 10.819197,13.353146 11.543438,15.633991 10.22425,17.856498 C 12.257957,16.947548 12.124774,13.112265 12.871375,13.021934 C 13.519788,12.943836 13.479931,14.488864 13.338,15.31313 C 13.032749,17.084925 12.408638,18.086089 11.005847,19.10513 C 9.8869191,19.918105 8.84
 67342,20.049837 7.8347414,21.757648 C 7.6442029,22.057809 6.2890464,25.330408 6.120867,25.639037 C 5.2721928,27.201003 5.3742671,25.548707 6.3075169,22.931003 C 6.3075169,22.931003 7.2174355,20.095002 7.0978629,16.9993 C 7.0434233,15.566244 7.1231384,9.904591 10.82989,7.8994415 C 12.425164,7.0365969 14.901193,6.4946138 16.606318,7.7611229 C 21.944313,11.725315 19.458563,21.448078 15.392121,24.198454 C 13.75699,25.305002 12.399889,25.373692 11.005847,27.501164 C 9.918999,29.160046 6.8363585,30.274122 4.6937724,29.305892 C 5.5511957,28.829775 6.8820488,28.787432 7.2650702,27.723226 C 10.071625,19.916223 15.516555,23.290444 16.169829,14.950867 C 16.401197,11.993484 14.864252,9.6797058 12.683753,9.6797058 C 10.452702,9.6797058 8.9526972,12.659672 8.6143939,15.425102 C 8.4520474,16.758419 8.3645551,18.513277 8.2576203,19.43446 C 10.04246,18.397541 8.4714901,11.146635 12.470855,10.731679 C 15.950127,10.371298 15.652653,14.948985 15.256023,16.945666 C 14.953689,18.468112 14.256667,
 19.779785 11.256658,21.500771 C 9.676938,22.406898 8.629948,23.557671 7.8289087,25.441439 C 7.3593673,26.546106 6.3988976,28.436461 4.53337,28.617122 C 4.3195003,28.637822 3.9131477,26.558339 3.7867702,25.457436 C 3.6001201,23.832427 4.440045,22.749402 4.7190479,21.000189 C 5.0301312,19.057142 5.2478894,17.510232 5.2644158,14.182117 C 4.4799026,9.0737386 5.2780257,7.5635248 7.4089462,5.140597 C 9.9005288,2.306477 12.031512,2.0549452 13.495175,2.0414516 C 15.638858,2.0237012 16.885321,3.5353485 16.249545,3.412085 C 14.609553,3.0949872 11.616348,2.6753267 9.0440775,5.2789155 C 7.6092061,6.7298495 6.0265698,8.5966804 6.1947492,10.870939 C 6.8664947,7.6039854 10.320801,3.7360695 13.733969,3.7360695 C 17.563499,3.7360695 19.963101,5.1556521 21.106332,6.9999001 C 22.267062,8.8733168 22.748269,10.281909 22.748269,12.806458 C 22.748269,14.670467 21.716834,15.435453 21.249236,16.946607 C 21.069391,17.527169 20.450141,19.029855 20.177944,20.195682 C 19.084291,24.880637 18.295889,27.13
 7018 14.257639,30.204492 C 12.498075,31.540631 11.0982,31.630961 10.165922,31.269639 C 10.173699,31.117206 12.353227,30.918668 13.710328,28.921987 C 14.988685,27.040101 16.636455,26.992113 17.383054,24.825122 C 16.609234,25.763242 15.405731,26.658079 14.400543,27.100321 C 14.11668,27.225467 13.604365,27.870953 13.407994,28.100544 C 11.354844,30.515944 9.699297,31.088038 7.3321475,31.358088 C 7.7083639,31.534985 8.097218,31.671422 8.5094033,31.724115 C 11.518163,32.108961 13.373968,32.147539 15.76056,30.039827 C 19.12901,27.065506 19.683127,25.185502 20.034068,22.951704 C 20.293627,21.297527 21.655941,17.421123 22.247619,15.852571 C 23.080867,13.643616 22.556758,18.089853 22.318585,18.673238 C 20.924543,22.100151 21.486437,26.72018 17.942032,30.365393 C 15.509749,32.86736 12.310453,33.796071 7.1221663,32.621775 C 5.7388178,32.30844 6.239509,31.841732 4.657845,31.358088 C 4.1834429,31.143553 1.6402954,30.997707 1.3486549,30.995825 C 0.70898981,30.992061 0.10626602,30.860329 -0
 .42938057,30.607215 z M 4.2543673,5.1321285 C 2.8544925,6.7006803 3.1305788,7.9154375 2.2021896,9.2289942 C 0.37749172,11.810941 1.4380914,15.378055 1.0521537,17.983526 C 0.55247613,21.363393 0.50913089,20.094485 -0.0071428722,17.974697 C -0.76834557,14.849245 -0.21551087,13.71635 -0.090105372,12.391502 C 0.60497135,9.1141985 1.2125559,7.7404222 2.8554645,5.6731707 C 4.2115933,3.9672413 6.135449,3.0215936 4.2543673,5.1321285 z M 24.022738,36.434475 C 23.474454,37.067729 22.882424,37.657701 22.248591,38.195919 L 21.462134,38.491375 C 18.22784,39.695783 16.567433,39.805873 11.843827,39.067233 C 9.918999,38.766131 7.2913178,38.39634 5.4841183,39.262008 C 6.5702412,39.494461 10.381694,38.345449 11.56288,39.970538 C 11.446224,40.140849 9.1976753,39.867976 7.0823087,40.331861 C 6.5699934,40.042991 6.0751766,39.715542 5.5978581,39.351398 C 5.1390103,38.993839 4.8036236,38.704969 4.4789305,38.398222 C 6.9432934,37.015037 10.891135,37.492095 13.335083,37.804487 C 17.567761,38.346471 
 19.246638,38.16581 21.951118,37.173114 C 22.683136,36.904005 23.374324,36.654655 24.022738,36.434475 z M 26.080749,7.8825045 C 27.13746,9.9657525 28.24375,11.559709 28.24375,14.719395 C 28.24375,18.197241 25.745362,19.892699 25.346787,22.207418 C 24.973487,24.37441 24.914187,26.178198 24.585605,26.178198 C 24.11898,26.178198 23.970243,24.110005 24.041208,22.659071 C 24.113147,21.19026 24.300417,20.389257 24.641637,19.294941 C 25.02563,18.066069 25.608953,15.315973 25.490352,13.235548 C 25.33481,10.489877 25.576852,11.073882 26.289427,12.729942 C 26.756052,13.812967 26.247915,15.934534 26.289427,17.469211 C 27.316002,15.633392 27.121554,12.867259 26.336068,10.86211 C 26.073591,10.189336 25.713282,8.8290928 26.080749,7.8825045 z M 24.608294,9.2431681 C 24.472195,8.6390829 23.70969,6.477977 22.713252,5.1870035 C 21.219079,3.2533658 22.564494,3.6570102 23.635787,4.8313069 C 24.682776,5.9792572 25.458582,7.3442852 25.487746,8.6644279 C 25.547046,11.377166 25.108944,11.455325 24.6
 08294,9.2431681 z M 28.310827,16.859099 C 28.588858,16.49966 28.861055,18.750394 28.357489,19.540787 C 27.013026,21.649439 27.496178,25.113051 26.626116,27.878481 C 25.240824,32.27833 20.835106,35.602682 15.985124,35.513292 C 19.529529,34.338995 22.700634,33.797953 24.16953,26.824625 C 24.298825,26.210189 25.161109,26.541401 24.3834,29.44421 C 25.240824,28.207811 25.985479,25.109287 26.098247,22.60826 C 26.173102,20.914563 27.715881,18.48693 28.310827,16.859099 z M 0.33666203,7.0620024 C 3.1023869,1.995966 8.6775827,0.52715408 13.200929,0.52715408 C 16.027898,0.52715408 18.494205,1.0117396 20.804971,2.3394101 C 21.160772,2.5991103 21.699335,2.9199718 21.989031,3.2097822 C 22.925198,4.1497842 21.355919,3.7289582 19.391486,2.8597515 C 15.788463,1.2655141 13.210649,1.5085776 11.04376,1.8557856 C 9.4407091,2.112663 8.4189947,3.395148 7.616011,4.1733077 C 4.6568312,7.0356559 4.1960391,9.5950208 4.5518406,12.806458 C 4.9931901,16.791351 4.2543673,21.000189 3.3230616,23.294208 C 2.
 8467153,24.469446 2.9099042,25.995654 3.1228018,26.962944 C 3.5077673,28.707452 5.0036733,29.433225 3.1344674,29.192978 C -0.13966347,28.772157 -0.13773997,24.273729 0.98021562,21.094283 C 2.1224745,17.845207 1.495243,15.951027 1.7355647,13.562036 C 2.8026799,2.8737448 3.1130804,15.825944 3.0518358,16.393333 C 2.6940901,19.711097 2.2203141,20.592698 1.7248713,22.0691 C 0.65905915,25.245183 1.9177265,27.094796 2.2524513,27.350994 C 0.89725312,23.033886 3.2657056,21.64003 3.4523556,16.633273 C 3.4980459,15.417575 3.5174886,14.673289 3.3318108,13.031344 C 2.7611674,7.9643665 4.0677172,5.041798 6.9588475,2.6941455 C 5.2051155,2.7110825 3.8587082,3.9794735 2.6688146,5.1321285 C 1.363237,6.3958147 0.15098419,9.2779223 -0.22620427,10.387294 C -0.79004277,12.046176 -1.2848596,10.030677 0.33666203,7.0620024 z M -1.1234851,28.497622 C -2.0265988,25.35299 -2.4786417,21.846097 -2.4037873,18.200883 C -2.3746233,16.749949 -2.2443571,15.155993 -1.7971749,13.290103 C -0.92614167,9.6543002 -
 0.69568297,11.570518 -0.75405287,12.016887 C -1.906054,20.826496 1.6007898,19.123308 -0.53825967,25.728487 C -1.2848596,25.186504 -0.49674737,21.494805 -1.669846,19.297342 C -1.3645539,21.71935 -2.0304874,25.727486 0.6156649,28.255799 C 1.3719861,28.979384 2.8544925,29.37364 0.70898981,29.192978 C -0.027888672,29.130876 -0.63158467,28.886231 -1.1234851,28.497622 z M 0.47373313,32.736569 C 0.3036094,32.382775 0.14126284,32.020512 -0.015250972,31.650721 C 0.99382545,31.532162 3.0430867,31.426777 4.813345,32.172003 C 5.8418641,32.604837 3.7828816,32.394066 1.9863756,32.504156 C 1.3428221,32.542735 0.81203619,32.697049 0.47373313,32.736569 z M 1.3272679,34.351227 C 1.1308965,34.014369 0.94230231,33.668102 0.76051305,33.313367 C 5.2070598,32.522034 7.1591074,33.303958 10.615049,33.590945 C 14.176952,33.887342 18.036329,32.081673 19.249554,30.005012 C 19.872692,28.937983 20.047677,28.679223 20.173082,28.398823 C 20.281962,28.156059 20.353899,27.8973 20.648457,27.082444 C 21.301732
 ,25.276774 21.270624,27.738281 21.106332,28.345189 C 19.995182,32.442996 19.062904,31.720351 17.197377,33.526961 C 21.488381,31.992284 22.140685,28.921987 21.581706,24.645402 C 21.447552,23.621656 22.24373,20.854343 22.609254,19.86447 C 22.609254,19.86447 23.377241,17.382263 23.382101,12.981474 C 23.385017,10.110657 22.446907,5.6863438 18.607945,4.0349891 C 17.32181,3.4817147 15.535997,1.961151 15.535997,1.961151 C 16.331576,2.384936 18.250199,2.6518031 20.106978,3.7583519 C 20.177944,3.8006944 24.197722,6.0420202 24.599214,11.907858 C 24.788781,14.679876 24.809506,14.809385 24.622856,16.615054 C 24.622856,16.615054 24.508806,18.471876 23.856503,20.006553 C 23.541531,20.860929 23.2042,23.380774 23.390851,24.645402 C 23.822478,27.572675 22.050276,34.880978 14.832172,34.880978 C 11.643568,34.880978 9.7031857,34.471668 8.1769331,34.235492 C 6.7945567,34.020957 4.0006399,33.900516 1.3272679,34.351227 z M 3.9160641,37.83648 C 3.5466527,37.449752 3.1918233,37.039501 2.851576,36.60
 6667 C 3.8975936,36.013873 4.8162614,36.004464 6.6798447,36.055275 C 8.8146538,36.055275 12.031449,36.901182 11.04376,37.179702 C 10.996125,37.191934 6.4669471,36.563384 3.9160641,37.83648 z M 14.719404,41.637889 C 14.296525,41.700932 13.867813,41.747979 13.430353,41.776207 C 11.348039,41.911704 9.4173774,41.49957 7.6714227,40.64049 C 8.5230132,40.522871 10.16981,40.466415 11.73106,40.686596 C 12.655561,40.817387 13.709355,41.272803 14.719404,41.637889 z M 20.747615,39.325051 C 19.318575,40.268817 17.725246,40.977347 15.991929,41.391361 C 14.720376,41.014044 11.970742,40.569899 11.991882,39.739346 C 12.007714,39.117287 15.479614,40.315864 17.475407,40.060868 C 18.84223,39.886794 19.878525,39.619567 20.747615,39.325051 z M 26.747633,31.987579 C 27.295917,31.456887 26.637782,34.608104 23.560001,35.921661 C 21.475743,36.660301 18.380466,38.308833 13.057053,36.902123 C 12.403778,36.72899 10.334101,36.181361 9.8733094,36.088208 C 6.2861299,35.366505 4.4235188,35.58198 2.3927281,3
 5.996936 C 2.1564992,35.669488 1.9280475,35.329808 1.7073728,34.979777 C 2.3616198,34.715372 4.0055005,34.612809 5.186645,34.610927 C 8.9478367,34.604341 13.98933,35.964944 15.98318,36.055275 C 20.657206,36.266987 23.666937,32.984978 24.040237,32.984978 C 24.972514,32.984978 23.166287,34.616574 22.664665,35.067285 C 22.237898,35.45213 24.347431,34.500837 26.747633,31.987579 z M 28.517892,25.005783 C 28.394431,27.133255 28.234028,30.085933 26.454048,31.562273 C 23.614441,33.917452 24.785865,32.262334 26.025337,30.618507 C 28.180561,27.758982 27.284252,21.317287 28.69482,20.069596 C 28.711346,21.421731 28.607328,23.483337 28.517892,25.005783 z"
+   style="fill:#a1a1a1;fill-opacity:1"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90"
+   sodipodi:nodetypes="cscssscccssssssscsssscsscsssccssscscssssscsssscssssssscsssscsssssscscsscssssssscsccssscsccccscccscssccssssssscsccsssccsscscsccscsssssssssssscsscssccsssccsscccsscccssssscscsscssccsssccccsccscscccsscccssccssssccsscc" />
+<circle
+   clip-rule="evenodd"
+   cx="26.184"
+   cy="33.865002"
+   r="10"
+   id="circle2428"
+   sodipodi:cx="26.184"
+   sodipodi:cy="33.865002"
+   sodipodi:rx="10"
+   sodipodi:ry="10"
+   style="fill:url(#radialGradient84134);fill-opacity:1;fill-rule:evenodd;stroke:#448c00;stroke-width:1.31732059;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+   transform="matrix(1.1263785,0,0,1.1511056,-2.2713556,-9.1997707)" /><path
+   sodipodi:type="arc"
+   style="opacity:0.50746268;fill:url(#linearGradient84277);fill-opacity:1;stroke:none;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+   id="path3253"
+   sodipodi:cx="26.455547"
+   sodipodi:cy="27.394291"
+   sodipodi:rx="6.1445141"
+   sodipodi:ry="3.072257"
+   d="M 32.600061,27.394291 A 6.1445141,3.072257 0 1 1 20.311033,27.394291 A 6.1445141,3.072257 0 1 1 32.600061,27.394291 z"
+   transform="matrix(1.1111101,0,0,1.2758999,-2.2387648,-10.924499)" /><path
+   clip-rule="evenodd"
+   d="M 21.777021,33.575871 C 22.428021,34.222871 23.330021,35.596871 24.012021,36.209871 C 25.264021,34.898871 27.599021,31.912871 31.077021,29.499871 C 31.754021,29.029871 33.458021,29.462871 32.557021,30.487871 C 29.846021,33.287871 27.332021,36.692871 25.385021,39.387871 C 24.468021,40.656871 23.706021,39.994871 22.908021,38.978871 C 21.912021,37.682871 20.897021,36.071871 20.509021,35.011871 C 20.282021,34.392871 20.974021,32.785871 21.777021,33.575871 z"
+   id="path2430"
+   style="opacity:0.42786069;fill:#398800;fill-opacity:1;fill-rule:evenodd;stroke:#398800;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter3471)"
+   transform="matrix(1.1263785,0,0,1.1511056,-2.2713556,-9.1997707)" /><path
+   clip-rule="evenodd"
+   d="M 21.969435,28.185201 C 22.702707,28.929966 23.718701,30.511585 24.486892,31.217213 C 25.897117,29.708113 28.527211,26.270911 32.444755,23.493294 C 33.207314,22.952275 35.126663,23.450703 34.111795,24.630586 C 31.058183,27.853682 28.226468,31.773196 26.033409,34.875426 C 25.00052,36.33618 24.142219,35.574148 23.243369,34.404624 C 22.121497,32.912791 20.978222,31.05836 20.541188,29.838188 C 20.2855,29.125654 21.064954,27.275827 21.969435,28.185201 z"
+   id="path3469"
+   style="fill:#ffffff;fill-rule:evenodd" /><path
+   sodipodi:type="arc"
+   style="opacity:0.36815945;fill:none;fill-opacity:1;stroke:url(#linearGradient84279);stroke-width:1.2184273;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+   id="path84102"
+   sodipodi:cx="28.185518"
+   sodipodi:cy="31.917336"
+   sodipodi:rx="10.027505"
+   sodipodi:ry="10.240856"
+   d="M 38.213023,31.917336 A 10.027505,10.240856 0 1 1 18.158013,31.917336 A 10.027505,10.240856 0 1 1 38.213023,31.917336 z"
+   transform="matrix(1.0116992,0,0,1.0189783,-1.4418411,-2.7101136)" /></svg>
\ No newline at end of file
diff --git a/panels/user-accounts/data/icons/right-index-finger.png b/panels/user-accounts/data/icons/right-index-finger.png
new file mode 100644
index 0000000..4aaeaac
Binary files /dev/null and b/panels/user-accounts/data/icons/right-index-finger.png differ
diff --git a/panels/user-accounts/data/icons/right-index-finger.svg b/panels/user-accounts/data/icons/right-index-finger.svg
new file mode 100644
index 0000000..5a621a2
--- /dev/null
+++ b/panels/user-accounts/data/icons/right-index-finger.svg
@@ -0,0 +1,179 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948)  -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:xlink="http://www.w3.org/1999/xlink";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   version="1.0"
+   x="0px"
+   y="0px"
+   width="48"
+   height="48"
+   viewBox="0 0 40.425 46.214"
+   enable-background="new 0 0 40.425 46.214"
+   xml:space="preserve"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   sodipodi:docname="right-index-finger.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"><metadata
+   id="metadata44"><rdf:RDF><cc:Work
+       rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+         rdf:resource="http://purl.org/dc/dcmitype/StillImage"; /></cc:Work></rdf:RDF></metadata><defs
+   id="defs42"><inkscape:perspective
+   sodipodi:type="inkscape:persp3d"
+   inkscape:vp_x="0 : 23.107 : 1"
+   inkscape:vp_y="0 : 1000 : 0"
+   inkscape:vp_z="40.424999 : 23.107 : 1"
+   inkscape:persp3d-origin="20.2125 : 15.404667 : 1"
+   id="perspective46" />
+	
+	
+	
+	
+	
+	
+<radialGradient
+   r="8.341651"
+   fy="9.3411446"
+   fx="38.658855"
+   cy="9.3411446"
+   cx="38.658855"
+   gradientUnits="userSpaceOnUse"
+   id="radialGradient2479"
+   xlink:href="#linearGradient2378"
+   inkscape:collect="always" /><linearGradient
+   id="linearGradient2378"><stop
+     id="stop2386"
+     offset="0"
+     style="stop-color:#ffffff;stop-opacity:1;" /><stop
+     style="stop-color:#27dc16;stop-opacity:1;"
+     offset="1"
+     id="stop2382" /></linearGradient><linearGradient
+   id="linearGradient3702"><stop
+     id="stop3704"
+     offset="0"
+     style="stop-color:black;stop-opacity:0;" /><stop
+     style="stop-color:black;stop-opacity:1;"
+     offset="0.5"
+     id="stop3710" /><stop
+     id="stop3706"
+     offset="1"
+     style="stop-color:black;stop-opacity:0;" /></linearGradient><linearGradient
+   id="linearGradient6732"><stop
+     id="stop6734"
+     offset="0"
+     style="stop-color:#ffffff;stop-opacity:1;" /><stop
+     id="stop6736"
+     offset="1"
+     style="stop-color:#dddddd;stop-opacity:1;" /></linearGradient><linearGradient
+   id="linearGradient4585"><stop
+     id="stop4587"
+     offset="0"
+     style="stop-color:#9e9e9e;stop-opacity:1;" /><stop
+     id="stop4589"
+     offset="1"
+     style="stop-color:#dddddd;stop-opacity:0;" /></linearGradient><inkscape:perspective
+   id="perspective2516"
+   inkscape:persp3d-origin="24 : 16 : 1"
+   inkscape:vp_z="48 : 24 : 1"
+   inkscape:vp_y="0 : 1000 : 0"
+   inkscape:vp_x="0 : 24 : 1"
+   sodipodi:type="inkscape:persp3d" /><radialGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient2378"
+   id="radialGradient86956"
+   cx="26.49"
+   cy="5.5700002"
+   fx="26.49"
+   fy="5.5700002"
+   r="4.0552225"
+   gradientUnits="userSpaceOnUse"
+   gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)" /><radialGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient2378"
+   id="radialGradient86964"
+   gradientUnits="userSpaceOnUse"
+   gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+   cx="26.49"
+   cy="5.5700002"
+   fx="26.49"
+   fy="5.5700002"
+   r="4.0552225" /><radialGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient2378"
+   id="radialGradient86966"
+   gradientUnits="userSpaceOnUse"
+   gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+   cx="26.49"
+   cy="5.5700002"
+   fx="26.49"
+   fy="5.5700002"
+   r="4.0552225" /></defs><sodipodi:namedview
+   inkscape:window-height="922"
+   inkscape:window-width="1302"
+   inkscape:pageshadow="2"
+   inkscape:pageopacity="0.0"
+   guidetolerance="10.0"
+   gridtolerance="10.0"
+   objecttolerance="10.0"
+   borderopacity="1.0"
+   bordercolor="#666666"
+   pagecolor="#ffffff"
+   id="base"
+   showgrid="false"
+   inkscape:zoom="11.122171"
+   inkscape:cx="15.672125"
+   inkscape:cy="30.299841"
+   inkscape:window-x="36"
+   inkscape:window-y="91"
+   inkscape:current-layer="svg2" />
+<g
+   id="g35"
+   style="fill:url(#radialGradient86956);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+   transform="matrix(-1.1605241,0,0,1.3370602,44.823901,-0.7984997)">
+		<circle
+   style="fill:url(#radialGradient86964);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+   sodipodi:ry="3.829"
+   sodipodi:rx="3.829"
+   sodipodi:cy="5.5700002"
+   sodipodi:cx="26.49"
+   id="circle37"
+   r="3.829"
+   cy="5.5700002"
+   cx="26.49"
+   stroke-miterlimit="3.8637" />
+		<path
+   style="fill:url(#radialGradient86966);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+   id="path39"
+   stroke-miterlimit="3.8637"
+   d="" />
+	</g><g
+   id="Background"
+   transform="matrix(-1,0,0,1,40.436754,0)">
+</g>
+<g
+   id="Guides"
+   display="none"
+   style="display:none">
+</g>
+<g
+   id="g7"
+   style="fill:#2f2f2f;fill-opacity:1"
+   transform="matrix(-1,0,0,1,40.436754,0)">
+		<path
+   style="fill:#2f2f2f;fill-opacity:1;fill-rule:evenodd"
+   id="path9"
+   d="M 20.569,13.286 C 20.843,15.459 20.791,17.834 20.82,18.542 C 20.865,18.917 21.913,19.241 22.094,18.877 C 22.301,17.514 22.586,14.847 22.92,13.455 C 23.372,9.917 23.886,8.247 24.072,7.257 C 24.58,4.567 25.014,3.12 26.762,3.12 C 28.384,3.12 28.623,5.167 28.153,8.165 C 28.025,9.379 28.036,12.24 27.433,14.894 C 27.165,16.691 26.962,21.278 27.139,24.981 C 27.189,26.045 27.669,27.315 28.242,27.945 C 29.462,27.773 30.379,24.377 31.988,22.847 C 32.809,21.464 34.883,19.299 36.951,19.299 C 39.243,19.299 39.292,21 38.345,22.262 C 37.187,23.806 36.525,24.528 36.079,25.802 C 35.633,27.076 33.758,29.778 33.471,31.209 C 32.902,34.054 32.471,35.105 29.284,37.661 C 27.783,38.865 27.302,39.637 26.855,40.401 C 26.347,41.273 26.409,44.721 26.409,46.212 L 10.64,46.212 C 10.64,46.212 10.767,43.587 10.513,42.058 C 10.461,41.746 10.105,39.613 9.176,38.231 C 8.317,36.954 5.902,32.306 5.902,26.836 C 5.902,24.026 4.39,21.718 3.854,19.533 C 3.591,17.833 2.638,15.423 2.57,14.709 C 1.684,11.559 2.1
 32,10.118 3.741,10.118 C 5.132,10.118 5.528,11.927 6.093,13.622 C 6.258,14.52 7.505,16.934 7.788,18.233 C 8.038,19.088 8.897,21.556 9.437,21.727 C 9.75,21.784 10.151,21.523 10.291,21.043 C 10.52,20.26 9.818,18.945 9.539,15.26 C 9.087,12.343 9.17,10.139 9.116,8.949 C 8.653,5.424 9.133,3.598 10.693,3.598 C 12.176,3.598 12.568,4.455 13.02,7.936 C 13.189,9.518 13.754,12.095 14.037,14.864 C 14.213,16.364 14.639,18.601 14.98,19.17 C 15.285,19.503 15.919,19.198 15.9,18.848 C 15.894,16.377 15.732,14.977 15.958,12.999 C 15.845,10.287 16.219,7.823 16.219,6.467 C 16.219,3.494 16.502,1.473 18.358,1.473 C 20.333,1.473 20.287,3.776 20.287,6.806 C 20.399,7.545 20.456,10.087 20.569,13.286 z"
+   clip-rule="evenodd" />
+	</g>
+<g
+   style="display:inline"
+   inkscape:label="Base"
+   id="layer1"
+   transform="matrix(-1,0,0,1,92.903401,2.6102791)" /></svg>
\ No newline at end of file
diff --git a/panels/user-accounts/data/icons/right-little-finger.png b/panels/user-accounts/data/icons/right-little-finger.png
new file mode 100644
index 0000000..17946af
Binary files /dev/null and b/panels/user-accounts/data/icons/right-little-finger.png differ
diff --git a/panels/user-accounts/data/icons/right-little-finger.svg b/panels/user-accounts/data/icons/right-little-finger.svg
new file mode 100644
index 0000000..9fcec2a
--- /dev/null
+++ b/panels/user-accounts/data/icons/right-little-finger.svg
@@ -0,0 +1,182 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948)  -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:xlink="http://www.w3.org/1999/xlink";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   version="1.0"
+   x="0px"
+   y="0px"
+   width="48"
+   height="48"
+   viewBox="0 0 40.425 46.214"
+   enable-background="new 0 0 40.425 46.214"
+   xml:space="preserve"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   sodipodi:docname="right-pinky-finger.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   inkscape:export-filename="/Users/mlanglie/Desktop/Fingerprint Enrollment Icons/Vector/left-ring-finger.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90"><metadata
+   id="metadata44"><rdf:RDF><cc:Work
+       rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+         rdf:resource="http://purl.org/dc/dcmitype/StillImage"; /></cc:Work></rdf:RDF></metadata><defs
+   id="defs42"><inkscape:perspective
+   sodipodi:type="inkscape:persp3d"
+   inkscape:vp_x="0 : 23.107 : 1"
+   inkscape:vp_y="0 : 1000 : 0"
+   inkscape:vp_z="40.424999 : 23.107 : 1"
+   inkscape:persp3d-origin="20.2125 : 15.404667 : 1"
+   id="perspective46" />
+	
+	
+	
+	
+	
+	
+<radialGradient
+   r="8.341651"
+   fy="9.3411446"
+   fx="38.658855"
+   cy="9.3411446"
+   cx="38.658855"
+   gradientUnits="userSpaceOnUse"
+   id="radialGradient2479"
+   xlink:href="#linearGradient2378"
+   inkscape:collect="always" /><linearGradient
+   id="linearGradient2378"><stop
+     id="stop2386"
+     offset="0"
+     style="stop-color:#ffffff;stop-opacity:1;" /><stop
+     style="stop-color:#27dc16;stop-opacity:1;"
+     offset="1"
+     id="stop2382" /></linearGradient><linearGradient
+   id="linearGradient3702"><stop
+     id="stop3704"
+     offset="0"
+     style="stop-color:black;stop-opacity:0;" /><stop
+     style="stop-color:black;stop-opacity:1;"
+     offset="0.5"
+     id="stop3710" /><stop
+     id="stop3706"
+     offset="1"
+     style="stop-color:black;stop-opacity:0;" /></linearGradient><linearGradient
+   id="linearGradient6732"><stop
+     id="stop6734"
+     offset="0"
+     style="stop-color:#ffffff;stop-opacity:1;" /><stop
+     id="stop6736"
+     offset="1"
+     style="stop-color:#dddddd;stop-opacity:1;" /></linearGradient><linearGradient
+   id="linearGradient4585"><stop
+     id="stop4587"
+     offset="0"
+     style="stop-color:#9e9e9e;stop-opacity:1;" /><stop
+     id="stop4589"
+     offset="1"
+     style="stop-color:#dddddd;stop-opacity:0;" /></linearGradient><inkscape:perspective
+   id="perspective2516"
+   inkscape:persp3d-origin="24 : 16 : 1"
+   inkscape:vp_z="48 : 24 : 1"
+   inkscape:vp_y="0 : 1000 : 0"
+   inkscape:vp_x="0 : 24 : 1"
+   sodipodi:type="inkscape:persp3d" /><radialGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient2378"
+   id="radialGradient86956"
+   cx="26.49"
+   cy="5.5700002"
+   fx="26.49"
+   fy="5.5700002"
+   r="4.0552225"
+   gradientUnits="userSpaceOnUse"
+   gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)" /><radialGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient2378"
+   id="radialGradient86964"
+   gradientUnits="userSpaceOnUse"
+   gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+   cx="26.49"
+   cy="5.5700002"
+   fx="26.49"
+   fy="5.5700002"
+   r="4.0552225" /><radialGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient2378"
+   id="radialGradient86966"
+   gradientUnits="userSpaceOnUse"
+   gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+   cx="26.49"
+   cy="5.5700002"
+   fx="26.49"
+   fy="5.5700002"
+   r="4.0552225" /></defs><sodipodi:namedview
+   inkscape:window-height="933"
+   inkscape:window-width="1054"
+   inkscape:pageshadow="2"
+   inkscape:pageopacity="0.0"
+   guidetolerance="10.0"
+   gridtolerance="10.0"
+   objecttolerance="10.0"
+   borderopacity="1.0"
+   bordercolor="#666666"
+   pagecolor="#ffffff"
+   id="base"
+   showgrid="false"
+   inkscape:zoom="11.122171"
+   inkscape:cx="22.316511"
+   inkscape:cy="30.299841"
+   inkscape:window-x="346"
+   inkscape:window-y="109"
+   inkscape:current-layer="svg2" />
+<g
+   id="g35"
+   style="fill:url(#radialGradient86956);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+   transform="matrix(-1.1074589,0,0,1.2726911,65.968411,5.5330271)">
+		<circle
+   style="fill:url(#radialGradient86964);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+   sodipodi:ry="3.829"
+   sodipodi:rx="3.829"
+   sodipodi:cy="5.5700002"
+   sodipodi:cx="26.49"
+   id="circle37"
+   r="3.829"
+   cy="5.5700002"
+   cx="26.49"
+   stroke-miterlimit="3.8637" />
+		<path
+   style="fill:url(#radialGradient86966);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+   id="path39"
+   stroke-miterlimit="3.8637"
+   d="" />
+	</g><g
+   id="Background"
+   transform="matrix(-1,0,0,1,40.436756,0)">
+</g>
+<g
+   id="Guides"
+   display="none"
+   style="display:none">
+</g>
+<g
+   id="g7"
+   style="fill:#2f2f2f;fill-opacity:1"
+   transform="matrix(-1,0,0,1,40.436756,0)">
+		<path
+   style="fill:#2f2f2f;fill-opacity:1;fill-rule:evenodd"
+   id="path9"
+   d="M 20.569,13.286 C 20.843,15.459 20.791,17.834 20.82,18.542 C 20.865,18.917 21.913,19.241 22.094,18.877 C 22.301,17.514 22.586,14.847 22.92,13.455 C 23.372,9.917 23.886,8.247 24.072,7.257 C 24.58,4.567 25.014,3.12 26.762,3.12 C 28.384,3.12 28.623,5.167 28.153,8.165 C 28.025,9.379 28.036,12.24 27.433,14.894 C 27.165,16.691 26.962,21.278 27.139,24.981 C 27.189,26.045 27.669,27.315 28.242,27.945 C 29.462,27.773 30.379,24.377 31.988,22.847 C 32.809,21.464 34.883,19.299 36.951,19.299 C 39.243,19.299 39.292,21 38.345,22.262 C 37.187,23.806 36.525,24.528 36.079,25.802 C 35.633,27.076 33.758,29.778 33.471,31.209 C 32.902,34.054 32.471,35.105 29.284,37.661 C 27.783,38.865 27.302,39.637 26.855,40.401 C 26.347,41.273 26.409,44.721 26.409,46.212 L 10.64,46.212 C 10.64,46.212 10.767,43.587 10.513,42.058 C 10.461,41.746 10.105,39.613 9.176,38.231 C 8.317,36.954 5.902,32.306 5.902,26.836 C 5.902,24.026 4.39,21.718 3.854,19.533 C 3.591,17.833 2.638,15.423 2.57,14.709 C 1.684,11.559 2.1
 32,10.118 3.741,10.118 C 5.132,10.118 5.528,11.927 6.093,13.622 C 6.258,14.52 7.505,16.934 7.788,18.233 C 8.038,19.088 8.897,21.556 9.437,21.727 C 9.75,21.784 10.151,21.523 10.291,21.043 C 10.52,20.26 9.818,18.945 9.539,15.26 C 9.087,12.343 9.17,10.139 9.116,8.949 C 8.653,5.424 9.133,3.598 10.693,3.598 C 12.176,3.598 12.568,4.455 13.02,7.936 C 13.189,9.518 13.754,12.095 14.037,14.864 C 14.213,16.364 14.639,18.601 14.98,19.17 C 15.285,19.503 15.919,19.198 15.9,18.848 C 15.894,16.377 15.732,14.977 15.958,12.999 C 15.845,10.287 16.219,7.823 16.219,6.467 C 16.219,3.494 16.502,1.473 18.358,1.473 C 20.333,1.473 20.287,3.776 20.287,6.806 C 20.399,7.545 20.456,10.087 20.569,13.286 z"
+   clip-rule="evenodd" />
+	</g>
+<g
+   style="display:inline"
+   inkscape:label="Base"
+   id="layer1"
+   transform="matrix(-1,0,0,1,92.903403,2.6102791)" /></svg>
\ No newline at end of file
diff --git a/panels/user-accounts/data/icons/right-middle-finger.png b/panels/user-accounts/data/icons/right-middle-finger.png
new file mode 100644
index 0000000..71bd41b
Binary files /dev/null and b/panels/user-accounts/data/icons/right-middle-finger.png differ
diff --git a/panels/user-accounts/data/icons/right-middle-finger.svg b/panels/user-accounts/data/icons/right-middle-finger.svg
new file mode 100644
index 0000000..b33a654
--- /dev/null
+++ b/panels/user-accounts/data/icons/right-middle-finger.svg
@@ -0,0 +1,182 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948)  -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:xlink="http://www.w3.org/1999/xlink";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   version="1.0"
+   x="0px"
+   y="0px"
+   width="48"
+   height="48"
+   viewBox="0 0 40.425 46.214"
+   enable-background="new 0 0 40.425 46.214"
+   xml:space="preserve"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   sodipodi:docname="right-middle-finger.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   inkscape:export-filename="/Users/mlanglie/Desktop/Fingerprint Enrollment Icons/Vector/left-index-finger.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90"><metadata
+   id="metadata44"><rdf:RDF><cc:Work
+       rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+         rdf:resource="http://purl.org/dc/dcmitype/StillImage"; /></cc:Work></rdf:RDF></metadata><defs
+   id="defs42"><inkscape:perspective
+   sodipodi:type="inkscape:persp3d"
+   inkscape:vp_x="0 : 23.107 : 1"
+   inkscape:vp_y="0 : 1000 : 0"
+   inkscape:vp_z="40.424999 : 23.107 : 1"
+   inkscape:persp3d-origin="20.2125 : 15.404667 : 1"
+   id="perspective46" />
+	
+	
+	
+	
+	
+	
+<radialGradient
+   r="8.341651"
+   fy="9.3411446"
+   fx="38.658855"
+   cy="9.3411446"
+   cx="38.658855"
+   gradientUnits="userSpaceOnUse"
+   id="radialGradient2479"
+   xlink:href="#linearGradient2378"
+   inkscape:collect="always" /><linearGradient
+   id="linearGradient2378"><stop
+     id="stop2386"
+     offset="0"
+     style="stop-color:#ffffff;stop-opacity:1;" /><stop
+     style="stop-color:#27dc16;stop-opacity:1;"
+     offset="1"
+     id="stop2382" /></linearGradient><linearGradient
+   id="linearGradient3702"><stop
+     id="stop3704"
+     offset="0"
+     style="stop-color:black;stop-opacity:0;" /><stop
+     style="stop-color:black;stop-opacity:1;"
+     offset="0.5"
+     id="stop3710" /><stop
+     id="stop3706"
+     offset="1"
+     style="stop-color:black;stop-opacity:0;" /></linearGradient><linearGradient
+   id="linearGradient6732"><stop
+     id="stop6734"
+     offset="0"
+     style="stop-color:#ffffff;stop-opacity:1;" /><stop
+     id="stop6736"
+     offset="1"
+     style="stop-color:#dddddd;stop-opacity:1;" /></linearGradient><linearGradient
+   id="linearGradient4585"><stop
+     id="stop4587"
+     offset="0"
+     style="stop-color:#9e9e9e;stop-opacity:1;" /><stop
+     id="stop4589"
+     offset="1"
+     style="stop-color:#dddddd;stop-opacity:0;" /></linearGradient><inkscape:perspective
+   id="perspective2516"
+   inkscape:persp3d-origin="24 : 16 : 1"
+   inkscape:vp_z="48 : 24 : 1"
+   inkscape:vp_y="0 : 1000 : 0"
+   inkscape:vp_x="0 : 24 : 1"
+   sodipodi:type="inkscape:persp3d" /><radialGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient2378"
+   id="radialGradient86956"
+   cx="26.49"
+   cy="5.5700002"
+   fx="26.49"
+   fy="5.5700002"
+   r="4.0552225"
+   gradientUnits="userSpaceOnUse"
+   gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)" /><radialGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient2378"
+   id="radialGradient86964"
+   gradientUnits="userSpaceOnUse"
+   gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+   cx="26.49"
+   cy="5.5700002"
+   fx="26.49"
+   fy="5.5700002"
+   r="4.0552225" /><radialGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient2378"
+   id="radialGradient86966"
+   gradientUnits="userSpaceOnUse"
+   gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+   cx="26.49"
+   cy="5.5700002"
+   fx="26.49"
+   fy="5.5700002"
+   r="4.0552225" /></defs><sodipodi:namedview
+   inkscape:window-height="933"
+   inkscape:window-width="1054"
+   inkscape:pageshadow="2"
+   inkscape:pageopacity="0.0"
+   guidetolerance="10.0"
+   gridtolerance="10.0"
+   objecttolerance="10.0"
+   borderopacity="1.0"
+   bordercolor="#666666"
+   pagecolor="#ffffff"
+   id="base"
+   showgrid="false"
+   inkscape:zoom="11.122171"
+   inkscape:cx="22.316511"
+   inkscape:cy="30.299841"
+   inkscape:window-x="362"
+   inkscape:window-y="121"
+   inkscape:current-layer="svg2" />
+<g
+   id="g35"
+   style="fill:url(#radialGradient86956);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+   transform="matrix(-1.1824583,0,0,1.3363867,53.282364,-2.0066594)">
+		<circle
+   style="fill:url(#radialGradient86964);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+   sodipodi:ry="3.829"
+   sodipodi:rx="3.829"
+   sodipodi:cy="5.5700002"
+   sodipodi:cx="26.49"
+   id="circle37"
+   r="3.829"
+   cy="5.5700002"
+   cx="26.49"
+   stroke-miterlimit="3.8637" />
+		<path
+   style="fill:url(#radialGradient86966);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+   id="path39"
+   stroke-miterlimit="3.8637"
+   d="" />
+	</g><g
+   id="Background"
+   transform="matrix(-1,0,0,1,40.436756,0)">
+</g>
+<g
+   id="Guides"
+   display="none"
+   style="display:none">
+</g>
+<g
+   id="g7"
+   style="fill:#2f2f2f;fill-opacity:1"
+   transform="matrix(-1,0,0,1,40.436756,0)">
+		<path
+   style="fill:#2f2f2f;fill-opacity:1;fill-rule:evenodd"
+   id="path9"
+   d="M 20.569,13.286 C 20.843,15.459 20.791,17.834 20.82,18.542 C 20.865,18.917 21.913,19.241 22.094,18.877 C 22.301,17.514 22.586,14.847 22.92,13.455 C 23.372,9.917 23.886,8.247 24.072,7.257 C 24.58,4.567 25.014,3.12 26.762,3.12 C 28.384,3.12 28.623,5.167 28.153,8.165 C 28.025,9.379 28.036,12.24 27.433,14.894 C 27.165,16.691 26.962,21.278 27.139,24.981 C 27.189,26.045 27.669,27.315 28.242,27.945 C 29.462,27.773 30.379,24.377 31.988,22.847 C 32.809,21.464 34.883,19.299 36.951,19.299 C 39.243,19.299 39.292,21 38.345,22.262 C 37.187,23.806 36.525,24.528 36.079,25.802 C 35.633,27.076 33.758,29.778 33.471,31.209 C 32.902,34.054 32.471,35.105 29.284,37.661 C 27.783,38.865 27.302,39.637 26.855,40.401 C 26.347,41.273 26.409,44.721 26.409,46.212 L 10.64,46.212 C 10.64,46.212 10.767,43.587 10.513,42.058 C 10.461,41.746 10.105,39.613 9.176,38.231 C 8.317,36.954 5.902,32.306 5.902,26.836 C 5.902,24.026 4.39,21.718 3.854,19.533 C 3.591,17.833 2.638,15.423 2.57,14.709 C 1.684,11.559 2.1
 32,10.118 3.741,10.118 C 5.132,10.118 5.528,11.927 6.093,13.622 C 6.258,14.52 7.505,16.934 7.788,18.233 C 8.038,19.088 8.897,21.556 9.437,21.727 C 9.75,21.784 10.151,21.523 10.291,21.043 C 10.52,20.26 9.818,18.945 9.539,15.26 C 9.087,12.343 9.17,10.139 9.116,8.949 C 8.653,5.424 9.133,3.598 10.693,3.598 C 12.176,3.598 12.568,4.455 13.02,7.936 C 13.189,9.518 13.754,12.095 14.037,14.864 C 14.213,16.364 14.639,18.601 14.98,19.17 C 15.285,19.503 15.919,19.198 15.9,18.848 C 15.894,16.377 15.732,14.977 15.958,12.999 C 15.845,10.287 16.219,7.823 16.219,6.467 C 16.219,3.494 16.502,1.473 18.358,1.473 C 20.333,1.473 20.287,3.776 20.287,6.806 C 20.399,7.545 20.456,10.087 20.569,13.286 z"
+   clip-rule="evenodd" />
+	</g>
+<g
+   style="display:inline"
+   inkscape:label="Base"
+   id="layer1"
+   transform="matrix(-1,0,0,1,92.903403,2.6102791)" /></svg>
\ No newline at end of file
diff --git a/panels/user-accounts/data/icons/right-ring-finger.png b/panels/user-accounts/data/icons/right-ring-finger.png
new file mode 100644
index 0000000..aa73ae6
Binary files /dev/null and b/panels/user-accounts/data/icons/right-ring-finger.png differ
diff --git a/panels/user-accounts/data/icons/right-ring-finger.svg b/panels/user-accounts/data/icons/right-ring-finger.svg
new file mode 100644
index 0000000..9e264fe
--- /dev/null
+++ b/panels/user-accounts/data/icons/right-ring-finger.svg
@@ -0,0 +1,182 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948)  -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:xlink="http://www.w3.org/1999/xlink";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   version="1.0"
+   x="0px"
+   y="0px"
+   width="48"
+   height="48"
+   viewBox="0 0 40.425 46.214"
+   enable-background="new 0 0 40.425 46.214"
+   xml:space="preserve"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   sodipodi:docname="right-ring-finger.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   inkscape:export-filename="/Users/mlanglie/Desktop/Fingerprint Enrollment Icons/Vector/left-middle-finger.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90"><metadata
+   id="metadata44"><rdf:RDF><cc:Work
+       rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+         rdf:resource="http://purl.org/dc/dcmitype/StillImage"; /></cc:Work></rdf:RDF></metadata><defs
+   id="defs42"><inkscape:perspective
+   sodipodi:type="inkscape:persp3d"
+   inkscape:vp_x="0 : 23.107 : 1"
+   inkscape:vp_y="0 : 1000 : 0"
+   inkscape:vp_z="40.424999 : 23.107 : 1"
+   inkscape:persp3d-origin="20.2125 : 15.404667 : 1"
+   id="perspective46" />
+	
+	
+	
+	
+	
+	
+<radialGradient
+   r="8.341651"
+   fy="9.3411446"
+   fx="38.658855"
+   cy="9.3411446"
+   cx="38.658855"
+   gradientUnits="userSpaceOnUse"
+   id="radialGradient2479"
+   xlink:href="#linearGradient2378"
+   inkscape:collect="always" /><linearGradient
+   id="linearGradient2378"><stop
+     id="stop2386"
+     offset="0"
+     style="stop-color:#ffffff;stop-opacity:1;" /><stop
+     style="stop-color:#27dc16;stop-opacity:1;"
+     offset="1"
+     id="stop2382" /></linearGradient><linearGradient
+   id="linearGradient3702"><stop
+     id="stop3704"
+     offset="0"
+     style="stop-color:black;stop-opacity:0;" /><stop
+     style="stop-color:black;stop-opacity:1;"
+     offset="0.5"
+     id="stop3710" /><stop
+     id="stop3706"
+     offset="1"
+     style="stop-color:black;stop-opacity:0;" /></linearGradient><linearGradient
+   id="linearGradient6732"><stop
+     id="stop6734"
+     offset="0"
+     style="stop-color:#ffffff;stop-opacity:1;" /><stop
+     id="stop6736"
+     offset="1"
+     style="stop-color:#dddddd;stop-opacity:1;" /></linearGradient><linearGradient
+   id="linearGradient4585"><stop
+     id="stop4587"
+     offset="0"
+     style="stop-color:#9e9e9e;stop-opacity:1;" /><stop
+     id="stop4589"
+     offset="1"
+     style="stop-color:#dddddd;stop-opacity:0;" /></linearGradient><inkscape:perspective
+   id="perspective2516"
+   inkscape:persp3d-origin="24 : 16 : 1"
+   inkscape:vp_z="48 : 24 : 1"
+   inkscape:vp_y="0 : 1000 : 0"
+   inkscape:vp_x="0 : 24 : 1"
+   sodipodi:type="inkscape:persp3d" /><radialGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient2378"
+   id="radialGradient86956"
+   cx="26.49"
+   cy="5.5700002"
+   fx="26.49"
+   fy="5.5700002"
+   r="4.0552225"
+   gradientUnits="userSpaceOnUse"
+   gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)" /><radialGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient2378"
+   id="radialGradient86964"
+   gradientUnits="userSpaceOnUse"
+   gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+   cx="26.49"
+   cy="5.5700002"
+   fx="26.49"
+   fy="5.5700002"
+   r="4.0552225" /><radialGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient2378"
+   id="radialGradient86966"
+   gradientUnits="userSpaceOnUse"
+   gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+   cx="26.49"
+   cy="5.5700002"
+   fx="26.49"
+   fy="5.5700002"
+   r="4.0552225" /></defs><sodipodi:namedview
+   inkscape:window-height="933"
+   inkscape:window-width="1054"
+   inkscape:pageshadow="2"
+   inkscape:pageopacity="0.0"
+   guidetolerance="10.0"
+   gridtolerance="10.0"
+   objecttolerance="10.0"
+   borderopacity="1.0"
+   bordercolor="#666666"
+   pagecolor="#ffffff"
+   id="base"
+   showgrid="false"
+   inkscape:zoom="11.122171"
+   inkscape:cx="22.316511"
+   inkscape:cy="30.299841"
+   inkscape:window-x="424"
+   inkscape:window-y="91"
+   inkscape:current-layer="svg2" />
+<g
+   id="g35"
+   style="fill:url(#radialGradient86956);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+   transform="matrix(-1.1824583,0,0,1.3363867,61.073222,-0.7947482)">
+		<circle
+   style="fill:url(#radialGradient86964);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+   sodipodi:ry="3.829"
+   sodipodi:rx="3.829"
+   sodipodi:cy="5.5700002"
+   sodipodi:cx="26.49"
+   id="circle37"
+   r="3.829"
+   cy="5.5700002"
+   cx="26.49"
+   stroke-miterlimit="3.8637" />
+		<path
+   style="fill:url(#radialGradient86966);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+   id="path39"
+   stroke-miterlimit="3.8637"
+   d="" />
+	</g><g
+   id="Background"
+   transform="matrix(-1,0,0,1,40.436756,0)">
+</g>
+<g
+   id="Guides"
+   display="none"
+   style="display:none">
+</g>
+<g
+   id="g7"
+   style="fill:#2f2f2f;fill-opacity:1"
+   transform="matrix(-1,0,0,1,40.436756,0)">
+		<path
+   style="fill:#2f2f2f;fill-opacity:1;fill-rule:evenodd"
+   id="path9"
+   d="M 20.569,13.286 C 20.843,15.459 20.791,17.834 20.82,18.542 C 20.865,18.917 21.913,19.241 22.094,18.877 C 22.301,17.514 22.586,14.847 22.92,13.455 C 23.372,9.917 23.886,8.247 24.072,7.257 C 24.58,4.567 25.014,3.12 26.762,3.12 C 28.384,3.12 28.623,5.167 28.153,8.165 C 28.025,9.379 28.036,12.24 27.433,14.894 C 27.165,16.691 26.962,21.278 27.139,24.981 C 27.189,26.045 27.669,27.315 28.242,27.945 C 29.462,27.773 30.379,24.377 31.988,22.847 C 32.809,21.464 34.883,19.299 36.951,19.299 C 39.243,19.299 39.292,21 38.345,22.262 C 37.187,23.806 36.525,24.528 36.079,25.802 C 35.633,27.076 33.758,29.778 33.471,31.209 C 32.902,34.054 32.471,35.105 29.284,37.661 C 27.783,38.865 27.302,39.637 26.855,40.401 C 26.347,41.273 26.409,44.721 26.409,46.212 L 10.64,46.212 C 10.64,46.212 10.767,43.587 10.513,42.058 C 10.461,41.746 10.105,39.613 9.176,38.231 C 8.317,36.954 5.902,32.306 5.902,26.836 C 5.902,24.026 4.39,21.718 3.854,19.533 C 3.591,17.833 2.638,15.423 2.57,14.709 C 1.684,11.559 2.1
 32,10.118 3.741,10.118 C 5.132,10.118 5.528,11.927 6.093,13.622 C 6.258,14.52 7.505,16.934 7.788,18.233 C 8.038,19.088 8.897,21.556 9.437,21.727 C 9.75,21.784 10.151,21.523 10.291,21.043 C 10.52,20.26 9.818,18.945 9.539,15.26 C 9.087,12.343 9.17,10.139 9.116,8.949 C 8.653,5.424 9.133,3.598 10.693,3.598 C 12.176,3.598 12.568,4.455 13.02,7.936 C 13.189,9.518 13.754,12.095 14.037,14.864 C 14.213,16.364 14.639,18.601 14.98,19.17 C 15.285,19.503 15.919,19.198 15.9,18.848 C 15.894,16.377 15.732,14.977 15.958,12.999 C 15.845,10.287 16.219,7.823 16.219,6.467 C 16.219,3.494 16.502,1.473 18.358,1.473 C 20.333,1.473 20.287,3.776 20.287,6.806 C 20.399,7.545 20.456,10.087 20.569,13.286 z"
+   clip-rule="evenodd" />
+	</g>
+<g
+   style="display:inline"
+   inkscape:label="Base"
+   id="layer1"
+   transform="matrix(-1,0,0,1,92.903403,2.6102791)" /></svg>
\ No newline at end of file
diff --git a/panels/user-accounts/data/icons/right-thumb.png b/panels/user-accounts/data/icons/right-thumb.png
new file mode 100644
index 0000000..1c967d6
Binary files /dev/null and b/panels/user-accounts/data/icons/right-thumb.png differ
diff --git a/panels/user-accounts/data/icons/right-thumb.svg b/panels/user-accounts/data/icons/right-thumb.svg
new file mode 100644
index 0000000..0aa0f2e
--- /dev/null
+++ b/panels/user-accounts/data/icons/right-thumb.svg
@@ -0,0 +1,182 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948)  -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:xlink="http://www.w3.org/1999/xlink";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   version="1.0"
+   x="0px"
+   y="0px"
+   width="48"
+   height="48"
+   viewBox="0 0 40.425 46.214"
+   enable-background="new 0 0 40.425 46.214"
+   xml:space="preserve"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   sodipodi:docname="right-thumb.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   inkscape:export-filename="/Users/mlanglie/Desktop/Fingerprint Enrollment Icons/Vector/left-pinky-finger.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90"><metadata
+   id="metadata44"><rdf:RDF><cc:Work
+       rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+         rdf:resource="http://purl.org/dc/dcmitype/StillImage"; /></cc:Work></rdf:RDF></metadata><defs
+   id="defs42"><inkscape:perspective
+   sodipodi:type="inkscape:persp3d"
+   inkscape:vp_x="0 : 23.107 : 1"
+   inkscape:vp_y="0 : 1000 : 0"
+   inkscape:vp_z="40.424999 : 23.107 : 1"
+   inkscape:persp3d-origin="20.2125 : 15.404667 : 1"
+   id="perspective46" />
+	
+	
+	
+	
+	
+	
+<radialGradient
+   r="8.341651"
+   fy="9.3411446"
+   fx="38.658855"
+   cy="9.3411446"
+   cx="38.658855"
+   gradientUnits="userSpaceOnUse"
+   id="radialGradient2479"
+   xlink:href="#linearGradient2378"
+   inkscape:collect="always" /><linearGradient
+   id="linearGradient2378"><stop
+     id="stop2386"
+     offset="0"
+     style="stop-color:#ffffff;stop-opacity:1;" /><stop
+     style="stop-color:#27dc16;stop-opacity:1;"
+     offset="1"
+     id="stop2382" /></linearGradient><linearGradient
+   id="linearGradient3702"><stop
+     id="stop3704"
+     offset="0"
+     style="stop-color:black;stop-opacity:0;" /><stop
+     style="stop-color:black;stop-opacity:1;"
+     offset="0.5"
+     id="stop3710" /><stop
+     id="stop3706"
+     offset="1"
+     style="stop-color:black;stop-opacity:0;" /></linearGradient><linearGradient
+   id="linearGradient6732"><stop
+     id="stop6734"
+     offset="0"
+     style="stop-color:#ffffff;stop-opacity:1;" /><stop
+     id="stop6736"
+     offset="1"
+     style="stop-color:#dddddd;stop-opacity:1;" /></linearGradient><linearGradient
+   id="linearGradient4585"><stop
+     id="stop4587"
+     offset="0"
+     style="stop-color:#9e9e9e;stop-opacity:1;" /><stop
+     id="stop4589"
+     offset="1"
+     style="stop-color:#dddddd;stop-opacity:0;" /></linearGradient><inkscape:perspective
+   id="perspective2516"
+   inkscape:persp3d-origin="24 : 16 : 1"
+   inkscape:vp_z="48 : 24 : 1"
+   inkscape:vp_y="0 : 1000 : 0"
+   inkscape:vp_x="0 : 24 : 1"
+   sodipodi:type="inkscape:persp3d" /><radialGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient2378"
+   id="radialGradient86956"
+   cx="26.49"
+   cy="5.5700002"
+   fx="26.49"
+   fy="5.5700002"
+   r="4.0552225"
+   gradientUnits="userSpaceOnUse"
+   gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)" /><radialGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient2378"
+   id="radialGradient86964"
+   gradientUnits="userSpaceOnUse"
+   gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+   cx="26.49"
+   cy="5.5700002"
+   fx="26.49"
+   fy="5.5700002"
+   r="4.0552225" /><radialGradient
+   inkscape:collect="always"
+   xlink:href="#linearGradient2378"
+   id="radialGradient86966"
+   gradientUnits="userSpaceOnUse"
+   gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+   cx="26.49"
+   cy="5.5700002"
+   fx="26.49"
+   fy="5.5700002"
+   r="4.0552225" /></defs><sodipodi:namedview
+   inkscape:window-height="933"
+   inkscape:window-width="1054"
+   inkscape:pageshadow="2"
+   inkscape:pageopacity="0.0"
+   guidetolerance="10.0"
+   gridtolerance="10.0"
+   objecttolerance="10.0"
+   borderopacity="1.0"
+   bordercolor="#666666"
+   pagecolor="#ffffff"
+   id="base"
+   showgrid="false"
+   inkscape:zoom="11.122171"
+   inkscape:cx="22.316511"
+   inkscape:cy="30.299841"
+   inkscape:window-x="116"
+   inkscape:window-y="117"
+   inkscape:current-layer="svg2" />
+<g
+   id="g35"
+   style="fill:url(#radialGradient86956);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+   transform="matrix(-1.1916623,0,0,1.4021101,35.910183,14.334323)">
+		<circle
+   style="fill:url(#radialGradient86964);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+   sodipodi:ry="3.829"
+   sodipodi:rx="3.829"
+   sodipodi:cy="5.5700002"
+   sodipodi:cx="26.49"
+   id="circle37"
+   r="3.829"
+   cy="5.5700002"
+   cx="26.49"
+   stroke-miterlimit="3.8637" />
+		<path
+   style="fill:url(#radialGradient86966);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+   id="path39"
+   stroke-miterlimit="3.8637"
+   d="" />
+	</g><g
+   id="Background"
+   transform="matrix(-1,0,0,1,40.436756,0)">
+</g>
+<g
+   id="Guides"
+   display="none"
+   style="display:none">
+</g>
+<g
+   id="g7"
+   style="fill:#2f2f2f;fill-opacity:1"
+   transform="matrix(-1,0,0,1,40.436756,0)">
+		<path
+   style="fill:#2f2f2f;fill-opacity:1;fill-rule:evenodd"
+   id="path9"
+   d="M 20.569,13.286 C 20.843,15.459 20.791,17.834 20.82,18.542 C 20.865,18.917 21.913,19.241 22.094,18.877 C 22.301,17.514 22.586,14.847 22.92,13.455 C 23.372,9.917 23.886,8.247 24.072,7.257 C 24.58,4.567 25.014,3.12 26.762,3.12 C 28.384,3.12 28.623,5.167 28.153,8.165 C 28.025,9.379 28.036,12.24 27.433,14.894 C 27.165,16.691 26.962,21.278 27.139,24.981 C 27.189,26.045 27.669,27.315 28.242,27.945 C 29.462,27.773 30.379,24.377 31.988,22.847 C 32.809,21.464 34.883,19.299 36.951,19.299 C 39.243,19.299 39.292,21 38.345,22.262 C 37.187,23.806 36.525,24.528 36.079,25.802 C 35.633,27.076 33.758,29.778 33.471,31.209 C 32.902,34.054 32.471,35.105 29.284,37.661 C 27.783,38.865 27.302,39.637 26.855,40.401 C 26.347,41.273 26.409,44.721 26.409,46.212 L 10.64,46.212 C 10.64,46.212 10.767,43.587 10.513,42.058 C 10.461,41.746 10.105,39.613 9.176,38.231 C 8.317,36.954 5.902,32.306 5.902,26.836 C 5.902,24.026 4.39,21.718 3.854,19.533 C 3.591,17.833 2.638,15.423 2.57,14.709 C 1.684,11.559 2.1
 32,10.118 3.741,10.118 C 5.132,10.118 5.528,11.927 6.093,13.622 C 6.258,14.52 7.505,16.934 7.788,18.233 C 8.038,19.088 8.897,21.556 9.437,21.727 C 9.75,21.784 10.151,21.523 10.291,21.043 C 10.52,20.26 9.818,18.945 9.539,15.26 C 9.087,12.343 9.17,10.139 9.116,8.949 C 8.653,5.424 9.133,3.598 10.693,3.598 C 12.176,3.598 12.568,4.455 13.02,7.936 C 13.189,9.518 13.754,12.095 14.037,14.864 C 14.213,16.364 14.639,18.601 14.98,19.17 C 15.285,19.503 15.919,19.198 15.9,18.848 C 15.894,16.377 15.732,14.977 15.958,12.999 C 15.845,10.287 16.219,7.823 16.219,6.467 C 16.219,3.494 16.502,1.473 18.358,1.473 C 20.333,1.473 20.287,3.776 20.287,6.806 C 20.399,7.545 20.456,10.087 20.569,13.286 z"
+   clip-rule="evenodd" />
+	</g>
+<g
+   style="display:inline"
+   inkscape:label="Base"
+   id="layer1"
+   transform="matrix(-1,0,0,1,92.903403,2.6102791)" /></svg>
\ No newline at end of file
diff --git a/panels/user-accounts/data/language-chooser.ui b/panels/user-accounts/data/language-chooser.ui
new file mode 100644
index 0000000..b61e24b
--- /dev/null
+++ b/panels/user-accounts/data/language-chooser.ui
@@ -0,0 +1,90 @@
+<?xml version="1.0"?>
+<interface>
+  <object class="GtkDialog" id="dialog">
+    <property name="height_request">400</property>
+    <property name="border_width">5</property>
+    <property name="modal">True</property>
+    <property name="window_position">center-on-parent</property>
+    <property name="type_hint">dialog</property>
+    <property name="title"> </property>
+    <property name="icon_name">system-users</property>
+    <child internal-child="vbox">
+      <object class="GtkVBox" id="content-area">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child>
+          <object class="GtkAlignment" id="alignment1">
+            <property name="visible">True</property>
+            <property name="top_padding">10</property>
+            <property name="bottom_padding">10</property>
+            <property name="left_padding">10</property>
+            <property name="right_padding">10</property>
+            <child>
+              <object class="GtkScrolledWindow" id="scrolledwindow1">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="hscrollbar_policy">never</property>
+                <property name="vscrollbar_policy">automatic</property>
+                <property name="shadow_type">in</property>
+                <child>
+                  <object class="GtkTreeView" id="language-list">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="headers_visible">False</property>
+                    <property name="headers_clickable">False</property>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <object class="GtkHButtonBox" id="action-area">
+            <property name="visible">True</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="cancel-button">
+                <property name="label" translatable="yes">Cancel</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="ok-button">
+                <property name="label" translatable="yes">Select</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="can_default">True</property>
+                <property name="receives_default">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="-6">cancel-button</action-widget>
+      <action-widget response="-5">ok-button</action-widget>
+    </action-widgets>
+  </object>
+</interface>
diff --git a/panels/user-accounts/data/password-dialog.ui b/panels/user-accounts/data/password-dialog.ui
new file mode 100644
index 0000000..69e9d6f
--- /dev/null
+++ b/panels/user-accounts/data/password-dialog.ui
@@ -0,0 +1,531 @@
+<?xml version="1.0"?>
+<interface>
+  <!-- interface-requires gtk+ 2.12 -->
+  <!-- interface-naming-policy toplevel-contextual -->
+  <object class="GtkListStore" id="action-model">
+    <columns>
+      <!-- column-name gchararray -->
+      <column type="gchararray"/>
+      <!-- column-name gint -->
+      <column type="gint"/>
+    </columns>
+    <data>
+      <row>
+        <col id="0" translatable="yes">Set a password now</col>
+        <col id="1">0</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Choose password at next login</col>
+        <col id="1">1</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Log in without a password</col>
+        <col id="1">2</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Disable this account</col>
+        <col id="1">3</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Enable this account</col>
+        <col id="1">4</col>
+      </row>
+    </data>
+  </object>
+  <object class="GtkDialog" id="dialog">
+    <property name="border_width">5</property>
+    <property name="title"> </property>
+    <property name="resizable">False</property>
+    <property name="modal">True</property>
+    <property name="window_position">center-on-parent</property>
+    <property name="icon_name">system-users</property>
+    <property name="type_hint">dialog</property>
+    <child internal-child="vbox">
+      <object class="GtkVBox" id="dialog-vbox1">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">12</property>
+        <child>
+          <object class="GtkVBox" id="vbox7">
+            <property name="visible">True</property>
+            <property name="border_width">6</property>
+            <property name="orientation">vertical</property>
+            <property name="spacing">16</property>
+            <child>
+              <object class="GtkTable" id="table4">
+                <property name="visible">True</property>
+                <property name="n_rows">8</property>
+                <property name="n_columns">2</property>
+                <property name="column_spacing">10</property>
+                <property name="row_spacing">6</property>
+                <child>
+                  <object class="GtkVBox" id="vbox14">
+                    <property name="visible">True</property>
+                    <property name="orientation">vertical</property>
+                    <child>
+                      <object class="GtkLabel" id="password-normal-hint-label">
+                        <property name="visible">True</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes">_Hint:</property>
+                        <property name="use_underline">True</property>
+                        <property name="mnemonic_widget">normal-hint-entry</property>
+                        <attributes>
+                          <attribute name="foreground" value="#555555555555"/>
+                        </attributes>
+                      </object>
+                      <packing>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="label33">
+                        <property name="visible">True</property>
+                      </object>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="top_attach">7</property>
+                    <property name="bottom_attach">8</property>
+                    <property name="x_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkVBox" id="vbox15">
+                    <property name="visible">True</property>
+                    <property name="orientation">vertical</property>
+                    <child>
+                      <object class="GtkEntry" id="normal-hint-entry">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                      </object>
+                      <packing>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="password-normal-hint-description-label">
+                        <property name="visible">True</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">&lt;small&gt;This hint may be displayed at the login screen.  It will be visible to all users of this system.  Do &lt;b&gt;not&lt;/b&gt; include the password here.&lt;/small&gt;</property>
+                        <property name="use_markup">True</property>
+                        <property name="wrap">True</property>
+                      </object>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">7</property>
+                    <property name="bottom_attach">8</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkEntry" id="verify-entry">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="visibility">False</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">5</property>
+                    <property name="bottom_attach">6</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="password-normal-verify-label">
+                    <property name="visible">True</property>
+                    <property name="xalign">1</property>
+                    <property name="label" translatable="yes">C_onfirm password:</property>
+                    <property name="use_underline">True</property>
+                    <property name="mnemonic_widget">verify-entry</property>
+                    <attributes>
+                      <attribute name="foreground" value="#555555555555"/>
+                    </attributes>
+                  </object>
+                  <packing>
+                    <property name="top_attach">5</property>
+                    <property name="bottom_attach">6</property>
+                    <property name="x_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkVBox" id="vbox17">
+                    <property name="visible">True</property>
+                    <property name="orientation">vertical</property>
+                    <child>
+                      <object class="GtkLabel" id="password-normal-password-label">
+                        <property name="visible">True</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes">_New password:</property>
+                        <property name="use_underline">True</property>
+                        <attributes>
+                          <attribute name="foreground" value="#555555555555"/>
+                        </attributes>
+                      </object>
+                      <packing>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="label35">
+                        <property name="visible">True</property>
+                      </object>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="top_attach">4</property>
+                    <property name="bottom_attach">5</property>
+                    <property name="x_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkVBox" id="vbox16">
+                    <property name="visible">True</property>
+                    <property name="orientation">vertical</property>
+                    <property name="spacing">6</property>
+                    <child>
+                      <object class="GtkHBox" id="hbox1">
+                        <property name="visible">True</property>
+                        <property name="spacing">6</property>
+                        <child>
+                          <object class="GtkEntry" id="password-entry">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="visibility">False</property>
+                          </object>
+                          <packing>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkButton" id="generate-again-button">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">False</property>
+                            <property name="tooltip_text" translatable="yes">Choose a generated password</property>
+                            <child>
+                              <object class="GtkImage" id="generate-again-image">
+                                <property name="visible">True</property>
+                                <property name="stock">gtk-execute</property>
+                              </object>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkHBox" id="hbox13">
+                        <property name="visible">True</property>
+                        <property name="spacing">9</property>
+                        <child>
+                          <object class="GtkAlignment" id="alignment1">
+                            <property name="visible">True</property>
+                            <property name="top_padding">6</property>
+                            <property name="bottom_padding">6</property>
+                            <child>
+                              <object class="UmStrengthBar" id="strength-indicator">
+                                <property name="visible">True</property>
+                              </object>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkLabel" id="strength-indicator-label">
+                            <property name="visible">True</property>
+                            <property name="xalign">0</property>
+                            <property name="label" translatable="yes">Fair</property>
+                          </object>
+                          <packing>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">4</property>
+                    <property name="bottom_attach">5</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="old-password-label">
+                    <property name="visible">True</property>
+                    <property name="xalign">1</property>
+                    <property name="label" translatable="yes">Current _password:</property>
+                    <property name="use_underline">True</property>
+                    <property name="mnemonic_widget">old-password-entry</property>
+                    <attributes>
+                      <attribute name="foreground" value="#555555555555"/>
+                    </attributes>
+                  </object>
+                  <packing>
+                    <property name="top_attach">3</property>
+                    <property name="bottom_attach">4</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkEntry" id="old-password-entry">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="visibility">False</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">3</property>
+                    <property name="bottom_attach">4</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="action-label">
+                    <property name="visible">True</property>
+                    <property name="xalign">1</property>
+                    <property name="label" translatable="yes">_Action:</property>
+                    <property name="use_underline">True</property>
+                    <property name="mnemonic_widget">action-combo</property>
+                    <attributes>
+                      <attribute name="foreground" value="#555555555555"/>
+                    </attributes>
+                  </object>
+                  <packing>
+                    <property name="top_attach">2</property>
+                    <property name="bottom_attach">3</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkComboBox" id="action-combo">
+                    <property name="visible">True</property>
+                    <property name="model">action-model</property>
+                    <child>
+                      <object class="GtkCellRendererText" id="renderer"/>
+                      <attributes>
+                        <attribute name="text">0</attribute>
+                      </attributes>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">2</property>
+                    <property name="bottom_attach">3</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label1">
+                    <property name="visible">True</property>
+                  </object>
+                  <packing>
+                    <property name="top_attach">1</property>
+                    <property name="bottom_attach">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label2">
+                    <property name="visible">True</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">1</property>
+                    <property name="bottom_attach">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkHBox" id="hbox3">
+                    <property name="visible">True</property>
+                    <child>
+                      <object class="GtkLabel" id="blablalabel23">
+                        <property name="visible">True</property>
+                      </object>
+                      <packing>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkImage" id="user-icon">
+                        <property name="visible">True</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="x_options">GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkVBox" id="vbox6">
+                    <property name="visible">True</property>
+                    <property name="orientation">vertical</property>
+                    <child>
+                      <object class="GtkLabel" id="label8">
+                        <property name="visible">True</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">Changing password for:</property>
+                      </object>
+                      <packing>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="user-name">
+                        <property name="visible">True</property>
+                        <property name="xalign">0</property>
+                        <attributes>
+                          <attribute name="weight" value="bold"/>
+                          <attribute name="scale" value="1.200000"/>
+                        </attributes>
+                      </object>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkCheckButton" id="show-password-checkbutton">
+                    <property name="label" translatable="yes">_Show password</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">False</property>
+                    <property name="use_underline">True</property>
+                    <property name="draw_indicator">True</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">6</property>
+                    <property name="bottom_attach">7</property>
+                  </packing>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+              </object>
+              <packing>
+                <property name="position">0</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <object class="GtkHButtonBox" id="dialog-action_area1">
+            <property name="visible">True</property>
+            <property name="layout_style">edge</property>
+            <child>
+              <object class="GtkAlignment" id="alignment2">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <child>
+                  <object class="GtkLabel" id="password-normal-strength-hints-label">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="label" translatable="yes">&lt;a href="http://wolfram.org/writing/howto/password.html"&gt;How to choose a strong password&lt;/a&gt;</property>
+                    <property name="use_markup">True</property>
+                    <property name="track_visited_links">False</property>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+                <property name="secondary">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkHButtonBox" id="hbuttonbox1">
+                <property name="visible">True</property>
+                <property name="spacing">6</property>
+                <property name="layout_style">end</property>
+                <child>
+                  <object class="GtkButton" id="ok-button">
+                    <property name="label" translatable="yes">Ch_ange</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="can_default">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_underline">True</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="pack_type">end</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkButton" id="cancel-button">
+                    <property name="label">gtk-cancel</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_stock">True</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="pack_type">end</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+                <property name="secondary">True</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
+  <object class="GtkSizeGroup" id="sizegroup"/>
+</interface>
diff --git a/panels/user-accounts/data/photo-dialog.ui b/panels/user-accounts/data/photo-dialog.ui
new file mode 100644
index 0000000..5bc10d8
--- /dev/null
+++ b/panels/user-accounts/data/photo-dialog.ui
@@ -0,0 +1,304 @@
+<?xml version="1.0"?>
+<interface>
+  <object class="GtkAdjustment" id="browse-scale-adjustment">
+    <property name="lower">0</property>
+    <property name="upper">100</property>
+    <property name="page_size">0</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+    <property name="value">50</property>
+  </object>
+  <object class="GtkDialog" id="dialog">
+    <property name="border_width">5</property>
+    <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+    <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+    <property name="title"> </property>
+    <property name="icon_name">system-users</property>
+    <property name="modal">True</property>
+    <child internal-child="vbox">
+      <object class="GtkVBox" id="dialog-vbox7">
+        <property name="visible">True</property>
+        <property name="spacing">6</property>
+        <child>
+          <object class="GtkHBox" id="hbox17">
+            <property name="visible">True</property>
+            <property name="border_width">10</property>
+            <property name="spacing">10</property>
+            <child>
+              <object class="GtkVBox" id="vbox21">
+                <property name="visible">True</property>
+                <property name="spacing">10</property>
+                <child>
+                  <object class="GtkHBox" id="user-photo-dialog-user-box">
+                    <property name="visible">True</property>
+                    <property name="spacing">6</property>
+                    <child>
+                      <object class="GtkImage" id="user-icon">
+                        <property name="visible">True</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkVBox" id="blablabox">
+                        <property name="visible">True</property>
+                        <child>
+                          <object class="GtkLabel" id="blabla">
+                            <property name="visible">True</property>
+                            <property name="xalign">0</property>
+                            <property name="label" translatable="yes">Changing photo for:</property>
+                          </object>
+                        </child>
+                        <child>
+                          <object class="GtkLabel" id="user-name">
+                            <property name="visible">True</property>
+                            <property name="xalign">0</property>
+                            <attributes>
+                              <attribute name="weight" value="bold"/>
+                              <attribute name="scale" value="1.2"/>
+                            </attributes>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label52">
+                    <property name="visible">True</property>
+                  </object>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkVBox" id="vbox33">
+                    <property name="visible">True</property>
+                    <property name="spacing">10</property>
+                    <child>
+                      <object class="GtkLabel" id="label53">
+                        <property name="visible">True</property>
+                        <property name="xalign">0</property>
+                        <property name="yalign">0</property>
+                        <property name="label" translatable="yes">Choose a picture that will be shown at the login screen for this account.</property>
+                        <property name="justify">GTK_JUSTIFY_CENTER</property>
+                        <property name="wrap">True</property>
+                        <property name="width_chars">28</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkVBox" id="vbox22">
+                    <property name="visible">True</property>
+                    <property name="spacing">5</property>
+                    <child>
+                      <object class="GtkRadioButton" id="gallery-radiobutton">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">True</property>
+                        <property name="label" translatable="yes">Gallery</property>
+                        <property name="draw-indicator">False</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkRadioButton" id="browse-radiobutton">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">True</property>
+                        <property name="label" translatable="yes">Browse for more pictures</property>
+                        <property name="draw-indicator">False</property>
+                        <property name="group">gallery-radiobutton</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkRadioButton" id="photo-radiobutton">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">True</property>
+                        <property name="label" translatable="yes">Take a photograph</property>
+                        <property name="draw-indicator">False</property>
+                        <property name="group">gallery-radiobutton</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">3</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkNotebook" id="notebook">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="show_tabs">False</property>
+                <child>
+                  <object class="GtkVBox" id="vbox19">
+                    <property name="visible">True</property>
+                    <property name="spacing">5</property>
+                    <child>
+                      <object class="GtkScrolledWindow" id="scrolledwindow1">
+                        <property name="visible">True</property>
+                        <property name="hscrollbar_policy">never</property>
+                        <property name="vscrollbar_policy">automatic</property>
+                        <child>
+                          <object class="GtkIconView" id="gallery">
+                            <property name="visible">True</property>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child type="tab">
+                  <object class="GtkLabel" id="label54">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">Gallery</property>
+                  </object>
+                  <packing>
+                    <property name="tab_fill">False</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkVBox" id="vbox1234">
+                    <property name="visible">True</property>
+                    <property name="homogeneous">False</property>
+                    <child>
+                      <object class="GtkDrawingArea" id="browse-drawing-area">
+                        <property name="visible">True</property>
+                      </object>
+                      <packing>
+                        <property name="fill">True</property>
+                        <property name="expand">True</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkHBox" id="hbox1234">
+                        <property name="visible">False</property>
+                        <property name="homogeneous">False</property>
+                        <child>
+                          <object class="GtkImage" id="browse-scale-small">
+                            <property name="visible">True</property>
+                            <property name="icon_name">avatar-default</property>
+                            <property name="pixel_size">10</property>
+                          </object>
+                          <packing>
+                            <property name="fill">False</property>
+                            <property name="expand">False</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkHScale" id="browse-scale">
+                            <property name="visible">True</property>
+                            <property name="draw-value">False</property>
+                            <property name="adjustment">browse-scale-adjustment</property>
+                          </object>
+                          <packing>
+                            <property name="fill">True</property>
+                            <property name="expand">True</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkImage" id="browse-scale-big">
+                            <property name="visible">True</property>
+                            <property name="icon_name">avatar-default</property>
+                            <property name="pixel_size">20</property>
+                          </object>
+                          <packing>
+                            <property name="fill">False</property>
+                            <property name="expand">False</property>
+                          </packing>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="fill">True</property>
+                        <property name="expand">False</property>
+                      </packing>
+                    </child>
+                  </object>
+                </child>
+                <child type="tab">
+                  <object class="GtkLabel" id="label55">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">Browse</property>
+                  </object>
+                  <packing>
+                    <property name="position">1</property>
+                    <property name="tab_fill">False</property>
+                  </packing>
+                </child>
+                <child>
+                      <object class="GtkDrawingArea" id="photo">
+                        <property name="visible">True</property>
+                      </object>
+                </child>
+                <child type="tab">
+                  <object class="GtkLabel" id="label56">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">Photograph</property>
+                  </object>
+                  <packing>
+                    <property name="position">2</property>
+                    <property name="tab_fill">False</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <object class="GtkHButtonBox" id="dialog-action_area7">
+            <property name="visible">True</property>
+            <property name="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <object class="GtkButton" id="cancel-button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="label" translatable="yes">Cancel</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkButton" id="ok-button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="can_default">True</property>
+                <property name="receives_default">True</property>
+                <property name="label" translatable="yes">Select</property>
+              </object>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
+</interface>
diff --git a/panels/user-accounts/data/user-accounts-dialog.ui b/panels/user-accounts/data/user-accounts-dialog.ui
new file mode 100644
index 0000000..e6e4f8c
--- /dev/null
+++ b/panels/user-accounts/data/user-accounts-dialog.ui
@@ -0,0 +1,726 @@
+<?xml version="1.0"?>
+<interface>
+  <requires lib="gtk+" version="2.16"/>
+  <!-- interface-naming-policy toplevel-contextual -->
+  <object class="GtkListStore" id="shortname-model">
+    <columns>
+      <!-- column-name gchararray -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
+  <object class="GtkListStore" id="account-type-model">
+    <columns>
+      <!-- column-name gchararray -->
+      <column type="gchararray"/>
+      <!-- column-name gint -->
+      <column type="gint"/>
+    </columns>
+    <data>
+      <row>
+        <col id="0" translatable="yes" context="Account type">Standard</col>
+        <col id="1">0</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes" context="Account type">Administrator</col>
+        <col id="1">1</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes" context="Account type">Supervised</col>
+        <col id="1">2</col>
+      </row>
+    </data>
+  </object>
+  <object class="GtkListStore" id="language-model">
+    <columns>
+      <!-- column-name gchararray -->
+      <column type="gchararray"/>
+      <!-- column-name gchararray1 -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
+  <object class="GtkImage" id="plus">
+    <property name="pixel_size">12</property>
+    <property name="icon_name">list-add</property>
+  </object>
+  <object class="GtkImage" id="minus">
+    <property name="pixel_size">12</property>
+    <property name="icon_name">list-remove</property>
+  </object>
+  <object class="GtkWindow" id="user-account-window">
+    <property name="border_width">12</property>
+    <property name="title" translatable="yes">Account Information</property>
+    <property name="icon_name">system-users</property>
+    <child>
+      <object class="GtkVBox" id="user-account-main-vbox">
+        <property name="visible">True</property>
+        <property name="spacing">6</property>
+        <child>
+          <object class="GtkNotebook" id="top-level-notebook">
+            <property name="visible">True</property>
+            <property name="show_tabs">True</property>
+            <property name="show_border">True</property>
+            <property name="border_width">5</property>
+            <child>
+              <object class="GtkHBox" id="hbox2">
+                <property name="visible">True</property>
+                <property name="spacing">12</property>
+                <property name="border_width">12</property>
+                <child>
+                  <object class="GtkVBox" id="userlist-vbox">
+                    <property name="visible">True</property>
+                    <property name="orientation">vertical</property>
+                    <property name="spacing">2</property>
+                    <child>
+                      <object class="GtkScrolledWindow" id="scrolledwindow1">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="hscrollbar_policy">never</property>
+                        <property name="vscrollbar_policy">automatic</property>
+                        <property name="shadow_type">in</property>
+                        <child>
+                          <object class="GtkTreeView" id="list-treeview">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="headers_visible">False</property>
+                          </object>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkHBox" id="add-delete-buttonbox">
+                        <property name="visible">True</property>
+                        <property name="spacing">2</property>
+                        <child>
+                          <object class="GtkButton" id="add-user-button">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">True</property>
+                            <property name="tooltip_text" translatable="yes">Create a user</property>
+                            <property name="image">plus</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkButton" id="delete-user-button">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">True</property>
+                            <property name="tooltip_text" translatable="yes">Delete the selected user</property>
+                            <property name="image">minus</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkVBox" id="main-user-vbox">
+                    <property name="visible">True</property>
+                    <property name="orientation">vertical</property>
+                    <property name="spacing">6</property>
+                    <child>
+                      <object class="GtkHBox" id="hbox3">
+                        <property name="visible">True</property>
+                        <child>
+                          <object class="GtkTable" id="table1">
+                            <property name="visible">True</property>
+                            <property name="n_rows">8</property>
+                            <property name="n_columns">2</property>
+                            <property name="column_spacing">10</property>
+                            <child>
+                              <object class="GtkHBox" id="hbox20">
+                                <property name="visible">True</property>
+                                <child>
+                                  <object class="GtkButton" id="button11">
+                                    <property name="label" translatable="yes">Open</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">True</property>
+                                    <property name="xalign">0</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <placeholder/>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="left_attach">1</property>
+                                <property name="right_attach">2</property>
+                                <property name="top_attach">7</property>
+                                <property name="bottom_attach">8</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkHBox" id="hbox4">
+                                <child>
+                                  <object class="GtkButton" id="button10">
+                                    <property name="label" translatable="yes">Open</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">True</property>
+                                    <property name="xalign">0</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="left_attach">1</property>
+                                <property name="right_attach">2</property>
+                                <property name="top_attach">7</property>
+                                <property name="bottom_attach">8</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="account-parental-controls-label1">
+                                <property name="xalign">1</property>
+                                <property name="label" translatable="yes">Address Book Card:</property>
+                                <attributes>
+                                  <attribute name="foreground" value="#555555555555"/>
+                                </attributes>
+                              </object>
+                              <packing>
+                                <property name="top_attach">7</property>
+                                <property name="bottom_attach">8</property>
+                                <property name="x_options">GTK_FILL</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="UmEditableEntry" id="account-location-entry">
+                                <property name="visible">True</property>
+                              </object>
+                              <packing>
+                                <property name="left_attach">1</property>
+                                <property name="right_attach">2</property>
+                                <property name="top_attach">5</property>
+                                <property name="bottom_attach">6</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkNotebook" id="account-fingerprint-notebook">
+                                <property name="visible">True</property>
+                                <property name="show_tabs">False</property>
+                                <property name="show_border">False</property>
+                                <child>
+                                  <object class="GtkLabel" id="account-fingerprint-value-label">
+                                    <property name="visible">True</property>
+                                    <property name="xalign">0</property>
+                                  </object>
+                                </child>
+                                <child>
+                                  <object class="GtkButton" id="account-fingerprint-button">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">True</property>
+                                    <property name="relief">none</property>
+                                    <child>
+                                      <object class="GtkLabel" id="account-fingerprint-button-label">
+                                        <property name="visible">True</property>
+                                        <property name="xalign">0</property>
+                                      </object>
+                                    </child>
+                                  </object>
+                                  <packing>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="left_attach">1</property>
+                                <property name="right_attach">2</property>
+                                <property name="top_attach">6</property>
+                                <property name="bottom_attach">7</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="UmEditableCombo" id="account-type-combo">
+                                <property name="visible">True</property>
+                                <property name="model">account-type-model</property>
+                                <property name="text-column">0</property>
+                              </object>
+                              <packing>
+                                <property name="left_attach">1</property>
+                                <property name="right_attach">2</property>
+                                <property name="top_attach">1</property>
+                                <property name="bottom_attach">2</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="account-type-label">
+                                <property name="visible">True</property>
+                                <property name="xalign">1</property>
+                                <property name="label" translatable="yes">Account type:</property>
+                                <attributes>
+                                  <attribute name="foreground" value="#555555555555"/>
+                                </attributes>
+                              </object>
+                              <packing>
+                                <property name="top_attach">1</property>
+                                <property name="bottom_attach">2</property>
+                                <property name="x_options">GTK_FILL</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkVBox" id="vbox10">
+                                <property name="visible">True</property>
+                                <property name="orientation">vertical</property>
+                                <child>
+                                  <object class="GtkLabel" id="label20">
+                                    <property name="visible">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="UmEditableEntry" id="full-name-entry">
+                                    <property name="visible">True</property>
+                                    <property name="scale">1.2</property>
+                                    <property name="weight">700</property>
+                                  </object>
+                                  <packing>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="left_attach">1</property>
+                                <property name="right_attach">2</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="password-label">
+                                <property name="visible">True</property>
+                                <property name="xalign">1</property>
+                                <property name="label" translatable="yes">Password:</property>
+                                <attributes>
+                                  <attribute name="foreground" value="#555555555555"/>
+                                </attributes>
+                              </object>
+                              <packing>
+                                <property name="top_attach">2</property>
+                                <property name="bottom_attach">3</property>
+                                <property name="x_options">GTK_FILL</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="UmEditableButton" id="account-password-button">
+                                <property name="visible">True</property>
+                              </object>
+                              <packing>
+                                <property name="left_attach">1</property>
+                                <property name="right_attach">2</property>
+                                <property name="top_attach">2</property>
+                                <property name="bottom_attach">3</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="email-label">
+                                <property name="visible">True</property>
+                                <property name="xalign">1</property>
+                                <property name="label" translatable="yes">E-mail address:</property>
+                                <attributes>
+                                  <attribute name="foreground" value="#555555555555"/>
+                                </attributes>
+                              </object>
+                              <packing>
+                                <property name="top_attach">3</property>
+                                <property name="bottom_attach">4</property>
+                                <property name="x_options">GTK_FILL</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="UmEditableEntry" id="account-email-entry">
+                                <property name="visible">True</property>
+                              </object>
+                              <packing>
+                                <property name="left_attach">1</property>
+                                <property name="right_attach">2</property>
+                                <property name="top_attach">3</property>
+                                <property name="bottom_attach">4</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="language-label">
+                                <property name="visible">True</property>
+                                <property name="xalign">1</property>
+                                <property name="label" translatable="yes">Language:</property>
+                                <attributes>
+                                  <attribute name="foreground" value="#555555555555"/>
+                                </attributes>
+                              </object>
+                              <packing>
+                                <property name="top_attach">4</property>
+                                <property name="bottom_attach">5</property>
+                                <property name="x_options">GTK_FILL</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="location-label">
+                                <property name="visible">True</property>
+                                <property name="xalign">1</property>
+                                <property name="label" translatable="yes">Location:</property>
+                                <attributes>
+                                  <attribute name="foreground" value="#555555555555"/>
+                                </attributes>
+                              </object>
+                              <packing>
+                                <property name="top_attach">5</property>
+                                <property name="bottom_attach">6</property>
+                                <property name="x_options">GTK_FILL</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="account-fingerprint-label">
+                                <property name="visible">True</property>
+                                <property name="xalign">1</property>
+                                <property name="label" translatable="yes">Fingerprint Login:</property>
+                                <attributes>
+                                  <attribute name="foreground" value="#555555555555"/>
+                                </attributes>
+                              </object>
+                              <packing>
+                                <property name="top_attach">6</property>
+                                <property name="bottom_attach">7</property>
+                                <property name="x_options">GTK_FILL</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="account-parental-controls-label">
+                                <property name="visible">True</property>
+                                <property name="xalign">1</property>
+                                <property name="label" translatable="yes">Restrictions:</property>
+                                <attributes>
+                                  <attribute name="foreground" value="#555555555555"/>
+                                </attributes>
+                              </object>
+                              <packing>
+                                <property name="top_attach">7</property>
+                                <property name="bottom_attach">8</property>
+                                <property name="x_options">GTK_FILL</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkHBox" id="hbox5">
+                                <property name="visible">True</property>
+                                <child>
+                                  <object class="GtkLabel" id="label4">
+                                    <property name="visible">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkAlignment" id="user-icon-nonbutton">
+                                    <property name="xscale">0</property>
+                                    <property name="yscale">0</property>
+                                    <child>
+                                      <object class="GtkImage" id="user-icon-image">
+                                        <property name="visible">True</property>
+                                        <property name="icon_name">avatar-default</property>
+                                        <property name="icon-size">6</property>
+                                      </object>
+                                    </child>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkToggleButton" id="user-icon-button">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">True</property>
+                                    <property name="relief">none</property>
+                                    <child>
+                                      <object class="GtkImage" id="user-icon-image2">
+                                        <property name="visible">True</property>
+                                        <property name="icon_name">avatar-default</property>
+                                        <property name="icon-size">6</property>
+                                      </object>
+                                    </child>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="position">2</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="x_options">GTK_FILL</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="UmEditableCombo" id="account-language-combo">
+                                <property name="visible">True</property>
+                                <property name="model">language-model</property>
+                                <property name="text-column">1</property>
+                              </object>
+                              <packing>
+                                <property name="left_attach">1</property>
+                                <property name="right_attach">2</property>
+                                <property name="top_attach">4</property>
+                                <property name="bottom_attach">5</property>
+                                <property name="x_options">GTK_FILL</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <placeholder/>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+            </child>
+            <child type="tab">
+              <object class="GtkLabel" id="accounts-tab-label">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">Accounts</property>
+                <property name="justify">center</property>
+              </object>
+              <packing>
+                <property name="tab-fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <placeholder/>
+            </child>
+            <child type="tab">
+              <placeholder/>
+            </child>
+            <child>
+              <object class="GtkVBox" id="main-login-window-vbox">
+                <property name="visible">True</property>
+                <property name="orientation">vertical</property>
+                <property name="spacing">6</property>
+                <property name="border_width">12</property>
+                <child>
+                  <object class="GtkHBox" id="hbox6">
+                    <property name="visible">True</property>
+                    <property name="spacing">6</property>
+                    <child>
+                      <object class="GtkLabel" id="dm-automatic-login-label">
+                        <property name="visible">True</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">Automatic Login:</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkComboBox" id="dm-automatic-login-combobox">
+                        <property name="visible">True</property>
+                        <child>
+                          <object class="GtkCellRendererText" id="renderer1"/>
+                          <attributes>
+                            <attribute name="text">0</attribute>
+                          </attributes>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkCheckButton" id="dm-show-user-list-checkbutton">
+                    <property name="label" translatable="yes">Show list of users</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">False</property>
+                    <property name="active">True</property>
+                    <property name="draw_indicator">True</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkCheckButton" id="dm-show-power-buttons-checkbutton">
+                    <property name="label" translatable="yes">Show Shutdown, Suspend and Restart actions</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">False</property>
+                    <property name="active">True</property>
+                    <property name="draw_indicator">True</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkCheckButton" id="dm-show-password-hints-checkbutton">
+                    <property name="label" translatable="yes">Show password hints</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">False</property>
+                    <property name="active">True</property>
+                    <property name="draw_indicator">True</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">3</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label1">
+                    <property name="visible">True</property>
+                    <property name="xalign">0</property>
+                    <property name="yalign">0</property>
+                    <property name="label" translatable="yes">A guest account will allow anyone to temporarily log in to this computer without a password.  For security, remote logins to this account are not allowed.
+
+&lt;b&gt;When the guest user logs out, all files and data associated with the account will be deleted.&lt;/b&gt;</property>
+                    <property name="use_markup">True</property>
+                    <property name="wrap">True</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">4</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkCheckButton" id="dm-allow-guest-login-checkbutton">
+                    <property name="label" translatable="yes">Allow guests to log in to this computer</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">False</property>
+                    <property name="active">True</property>
+                    <property name="draw_indicator">True</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">5</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkHBox" id="hbox1">
+                    <property name="visible">True</property>
+                    <child>
+                      <object class="GtkAlignment" id="lockbutton-alignment">
+                        <property name="visible">True</property>
+                        <property name="xalign">0</property>
+                        <property name="yalign">1</property>
+                        <property name="xscale">0</property>
+                        <property name="yscale">0</property>
+                        <child>
+                          <placeholder/>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="position">6</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="position">2</property>
+              </packing>
+            </child>
+            <child type="tab">
+              <object class="GtkLabel" id="login-options-tab-label">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">Login Options</property>
+                <property name="justify">center</property>
+              </object>
+              <packing>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <placeholder/>
+            </child>
+            <child type="tab">
+              <placeholder/>
+            </child>
+          </object>
+          <packing>
+            <property name="position">0</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
+  <object class="GtkSizeGroup" id="user-icon-sizegroup">
+    <property name="mode">both</property>
+    <widgets>
+      <widget name="user-icon-button"/>
+      <widget name="user-icon-nonbutton"/>
+    </widgets>
+  </object>
+  <object class="GtkSizeGroup" id="label-width-sizegroup">
+    <widgets>
+      <widget name="account-fingerprint-label"/>
+      <widget name="location-label"/>
+      <widget name="language-label"/>
+      <widget name="email-label"/>
+      <widget name="password-label"/>
+      <widget name="account-type-label"/>
+    </widgets>
+  </object>
+</interface>
diff --git a/panels/user-accounts/fingerprint-strings.h b/panels/user-accounts/fingerprint-strings.h
new file mode 100644
index 0000000..6fb7cb3
--- /dev/null
+++ b/panels/user-accounts/fingerprint-strings.h
@@ -0,0 +1,111 @@
+/*
+ * Helper functions to translate statuses and actions to strings
+ * Copyright (C) 2008 Bastien Nocera <hadess hadess net>
+ * 
+ * Experimental code. This will be moved out of fprintd into it's own
+ * package once the system has matured.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+struct {
+	const char *dbus_name;
+	const char *place_str;
+	const char *swipe_str;
+} fingers[11] = {
+	{ "left-thumb", N_("Place your left thumb on %s"), N_("Swipe your left thumb on %s") },
+	{ "left-index-finger", N_("Place your left index finger on %s"), N_("Swipe your left index finger on %s") },
+	{ "left-middle-finger", N_("Place your left middle finger on %s"), N_("Swipe your left middle finger on %s") },
+	{ "left-ring-finger", N_("Place your left ring finger on %s"), N_("Swipe your left ring finger on %s") },
+	{ "left-little-finger", N_("Place your left little finger on %s"), N_("Swipe your left little finger on %s") },
+	{ "right-thumb", N_("Place your right thumb on %s"), N_("Swipe your right thumb on %s") },
+	{ "right-index-finger", N_("Place your right index finger on %s"), N_("Swipe your right index finger on %s") },
+	{ "right-middle-finger", N_("Place your right middle finger on %s"), N_("Swipe your right middle finger on %s") },
+	{ "right-ring-finger", N_("Place your right ring finger on %s"), N_("Swipe your right ring finger on %s") },
+	{ "right-little-finger", N_("Place your right little finger on %s"), N_("Swipe your right little finger on %s") },
+	{ NULL, NULL, NULL }
+};
+
+static const char *finger_str_to_msg(const char *finger_name, gboolean is_swipe)
+{
+	int i;
+
+	if (finger_name == NULL)
+		return NULL;
+
+	for (i = 0; fingers[i].dbus_name != NULL; i++) {
+		if (g_str_equal (fingers[i].dbus_name, finger_name)) {
+			if (is_swipe == FALSE)
+				return fingers[i].place_str;
+			else
+				return fingers[i].swipe_str;
+		}
+	}
+
+	return NULL;
+}
+
+/* Cases not handled:
+ * verify-no-match
+ * verify-match
+ * verify-unknown-error
+ */
+static const char *verify_result_str_to_msg(const char *result, gboolean is_swipe)
+{
+	if (result == NULL)
+		return NULL;
+
+	if (strcmp (result, "verify-retry-scan") == 0) {
+		if (is_swipe == FALSE)
+			return N_("Place your finger on the reader again");
+		else
+			return N_("Swipe your finger again");
+	}
+	if (strcmp (result, "verify-swipe-too-short") == 0)
+		return N_("Swipe was too short; try again");
+	if (strcmp (result, "verify-finger-not-centered") == 0)
+		return N_("Your finger was not centered; try swiping your finger again");
+	if (strcmp (result, "verify-remove-and-retry") == 0)
+		return N_("Remove your finger and try swiping it again");
+
+	return NULL;
+}
+
+/* Cases not handled:
+ * enroll-completed
+ * enroll-failed
+ * enroll-unknown-error
+ */
+static const char *enroll_result_str_to_msg(const char *result, gboolean is_swipe)
+{
+	if (result == NULL)
+		return NULL;
+
+	if (strcmp (result, "enroll-retry-scan") == 0 || strcmp (result, "enroll-stage-passed") == 0) {
+		if (is_swipe == FALSE)
+			return N_("Place your finger on the reader again");
+		else
+			return N_("Swipe your finger again");
+	}
+	if (strcmp (result, "enroll-swipe-too-short") == 0)
+		return N_("Swipe was too short, try again");
+	if (strcmp (result, "enroll-finger-not-centered") == 0)
+		return N_("Your finger was not centered, try swiping your finger again");
+	if (strcmp (result, "enroll-remove-and-retry") == 0)
+		return N_("Remove your finger, and try swiping your finger again");
+
+	return NULL;
+}
+
diff --git a/panels/user-accounts/fprintd-marshal.list b/panels/user-accounts/fprintd-marshal.list
new file mode 100644
index 0000000..c4effb6
--- /dev/null
+++ b/panels/user-accounts/fprintd-marshal.list
@@ -0,0 +1 @@
+VOID:STRING,BOOLEAN
diff --git a/panels/user-accounts/gdm-languages.c b/panels/user-accounts/gdm-languages.c
new file mode 100644
index 0000000..2c99e15
--- /dev/null
+++ b/panels/user-accounts/gdm-languages.c
@@ -0,0 +1,1003 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright 2008  Red Hat, Inc,
+ *           2007  William Jon McCann <mccann jhu edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Written by : William Jon McCann <mccann jhu edu>
+ *              Ray Strode <rstrode redhat com>
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <dirent.h>
+#include <locale.h>
+#include <langinfo.h>
+#include <sys/stat.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+
+#include "gdm-languages.h"
+
+#include <langinfo.h>
+#ifndef __LC_LAST
+#define __LC_LAST       13
+#endif
+#include "locarchive.h"
+
+#define ALIASES_FILE LIBLOCALEDIR "/locale.alias"
+#define ARCHIVE_FILE LIBLOCALEDIR "/locale-archive"
+#define ISO_CODES_DATADIR ISO_CODES_PREFIX "/share/xml/iso-codes"
+#define ISO_CODES_LOCALESDIR ISO_CODES_PREFIX "/share/locale"
+
+typedef struct _GdmLocale {
+        char *id;
+        char *name;
+        char *language_code;
+        char *territory_code;
+        char *codeset;
+        char *modifier;
+} GdmLocale;
+
+static GHashTable *gdm_languages_map;
+static GHashTable *gdm_territories_map;
+static GHashTable *gdm_available_locales_map;
+
+static void
+gdm_locale_free (GdmLocale *locale)
+{
+        if (locale == NULL) {
+                return;
+        }
+
+        g_free (locale->id);
+        g_free (locale->name);
+        g_free (locale->codeset);
+        g_free (locale->modifier);
+        g_free (locale);
+}
+
+static char *
+normalize_codeset (const char *codeset)
+{
+        char *normalized_codeset;
+        const char *p;
+        char *q;
+
+        normalized_codeset = g_strdup (codeset);
+
+        if (codeset != NULL) {
+                for (p = codeset, q = normalized_codeset;
+                     *p != '\0'; p++) {
+
+                        if (*p == '-' || *p == '_') {
+                                continue;
+                        }
+
+                        *q = g_ascii_tolower (*p);
+                        q++;
+                }
+                *q = '\0';
+        }
+
+        return normalized_codeset;
+}
+
+/*
+ * According to http://en.wikipedia.org/wiki/Locale
+ * locale names are of the form:
+ * [language[_territory][ codeset][ modifier]]
+ */
+gboolean
+gdm_parse_language_name (const char *name,
+                         char      **language_codep,
+                         char      **territory_codep,
+                         char      **codesetp,
+                         char      **modifierp)
+{
+        GRegex     *re;
+        GMatchInfo *match_info;
+        gboolean    res;
+        GError     *error;
+
+        error = NULL;
+        re = g_regex_new ("^(?P<language>[^_  [:space:]]+)"
+                          "(_(?P<territory>[[:upper:]]+))?"
+                          "(\\.(?P<codeset>[-_0-9a-zA-Z]+))?"
+                          "(@(?P<modifier>[[:ascii:]]+))?$",
+                          0, 0, &error);
+        if (re == NULL) {
+                g_critical ("%s", error->message);
+                return FALSE;
+        }
+
+        if (!g_regex_match (re, name, 0, &match_info) ||
+            g_match_info_is_partial_match (match_info)) {
+                g_match_info_free (match_info);
+                g_regex_unref (re);
+                g_warning ("locale %s isn't valid\n", name);
+                return FALSE;
+        }
+
+        res = g_match_info_matches (match_info);
+        if (! res) {
+                g_match_info_free (match_info);
+                g_regex_unref (re);
+                g_warning ("Unable to parse locale: %s", name);
+                return FALSE;
+        }
+
+        if (language_codep != NULL) {
+                *language_codep = g_match_info_fetch_named (match_info, "language");
+        }
+
+        if (territory_codep != NULL) {
+                *territory_codep = g_match_info_fetch_named (match_info, "territory");
+
+                if (*territory_codep != NULL &&
+                    *territory_codep[0] == '\0') {
+                        g_free (*territory_codep);
+                        *territory_codep = NULL;
+                }
+        }
+
+        if (codesetp != NULL) {
+                *codesetp = g_match_info_fetch_named (match_info, "codeset");
+
+                if (*codesetp != NULL &&
+                    *codesetp[0] == '\0') {
+                        g_free (*codesetp);
+                        *codesetp = NULL;
+                }
+
+                if (*codesetp != NULL) {
+                        char *codeset;
+
+                        codeset = normalize_codeset (*codesetp);
+                        g_free (*codesetp);
+                        *codesetp = codeset;
+                }
+        }
+
+        if (modifierp != NULL) {
+                *modifierp = g_match_info_fetch_named (match_info, "modifier");
+
+                if (*modifierp != NULL &&
+                    *modifierp[0] == '\0') {
+                        g_free (*modifierp);
+                        *modifierp = NULL;
+                }
+        }
+
+        g_match_info_free (match_info);
+        g_regex_unref (re);
+
+        return TRUE;
+}
+
+static char *
+construct_language_name (const char *language,
+                         const char *territory,
+                         const char *codeset,
+                         const char *modifier)
+{
+        char *name;
+
+        g_assert (language[0] != 0);
+        g_assert (territory == NULL || territory[0] != 0);
+        g_assert (codeset == NULL || codeset[0] != 0);
+        g_assert (modifier == NULL || modifier[0] != 0);
+
+        name = g_strdup_printf ("%s%s%s%s%s%s%s",
+                                language,
+                                territory != NULL? "_" : "",
+                                territory != NULL? territory : "",
+                                codeset != NULL? "." : "",
+                                codeset != NULL? codeset : "",
+                                modifier != NULL? "@" : "",
+                                modifier != NULL? modifier : "");
+
+        return name;
+}
+
+static void
+make_codeset_canonical_for_locale (const char  *name,
+                                   char       **codeset)
+{
+        char *old_locale;
+
+        old_locale = setlocale (LC_CTYPE, NULL);
+
+        if (setlocale (LC_CTYPE, name) == NULL) {
+                return;
+        }
+
+        g_free (*codeset);
+        *codeset = g_strdup (nl_langinfo (CODESET));
+
+        setlocale (LC_CTYPE, old_locale);
+}
+
+char *
+gdm_normalize_language_name (const char *name)
+{
+        char *normalized_name;
+        char *language_code;
+        char *territory_code;
+        char *codeset;
+        char *modifier;
+
+        if (name[0] == '\0') {
+                return NULL;
+        }
+
+        gdm_parse_language_name (name,
+                                 &language_code,
+                                 &territory_code,
+                                 &codeset, &modifier);
+
+        if (codeset != NULL) {
+                make_codeset_canonical_for_locale (name, &codeset);
+        }
+
+        normalized_name = construct_language_name (language_code,
+                                                   territory_code,
+                                                   codeset, modifier);
+        g_free (language_code);
+        g_free (territory_code);
+        g_free (codeset);
+        g_free (modifier);
+
+        return normalized_name;
+}
+
+static gboolean
+language_name_is_valid (const char *language_name)
+{
+        char     *old_locale;
+        gboolean  is_valid;
+
+        old_locale = g_strdup (setlocale (LC_MESSAGES, NULL));
+        is_valid = setlocale (LC_MESSAGES, language_name) != NULL;
+        setlocale (LC_MESSAGES, old_locale);
+        g_free (old_locale);
+
+        return is_valid;
+}
+
+static gboolean
+language_name_is_utf8 (const char *language_name)
+{
+        char     *old_locale;
+        char     *codeset;
+        gboolean  is_utf8;
+
+        old_locale = g_strdup (setlocale (LC_CTYPE, NULL));
+
+        if (setlocale (LC_CTYPE, language_name) == NULL) {
+                g_free (old_locale);
+                return FALSE;
+        }
+
+        codeset = normalize_codeset (nl_langinfo (CODESET));
+
+        is_utf8 = strcmp (codeset, "utf8") == 0;
+        g_free (codeset);
+
+        setlocale (LC_CTYPE, old_locale);
+        g_free (old_locale);
+
+        return is_utf8;
+}
+
+static gboolean
+language_name_has_translations (const char *language_name)
+{
+        GDir        *dir;
+        char        *path;
+        const char  *name;
+        gboolean     has_translations;
+
+        path = g_build_filename (GNOMELOCALEDIR, language_name, "LC_MESSAGES", NULL);
+
+        has_translations = FALSE;
+        dir = g_dir_open (path, 0, NULL);
+        g_free (path);
+
+        if (dir == NULL) {
+                goto out;
+        }
+
+        do {
+                name = g_dir_read_name (dir);
+
+                if (name == NULL) {
+                        break;
+                }
+
+                if (g_str_has_suffix (name, ".mo")) {
+                        has_translations = TRUE;
+                        break;
+                }
+        } while (name != NULL);
+        g_dir_close (dir);
+
+out:
+        return has_translations;
+}
+
+static gboolean
+add_locale (const char *language_name)
+{
+        GdmLocale *locale;
+        GdmLocale *old_locale;
+        char      *name;
+
+        if (language_name_is_utf8 (language_name)) {
+                name = g_strdup (language_name);
+        } else {
+                name = g_strdup_printf ("%s.utf8", language_name);
+
+                if (!language_name_is_utf8 (name)) {
+                        g_free (name);
+                        return FALSE;
+                }
+        }
+
+        if (!language_name_is_valid (name)) {
+                g_free (name);
+                return FALSE;
+        }
+
+
+        locale = g_new0 (GdmLocale, 1);
+        gdm_parse_language_name (name,
+                                 &locale->language_code,
+                                 &locale->territory_code,
+                                 &locale->codeset,
+                                 &locale->modifier);
+        g_free (name);
+        name = NULL;
+
+        locale->id = construct_language_name (locale->language_code, locale->territory_code,
+                                              NULL, locale->modifier);
+        locale->name = construct_language_name (locale->language_code, locale->territory_code,
+                                                locale->codeset, locale->modifier);
+
+        if (!language_name_has_translations (locale->name) &&
+            !language_name_has_translations (locale->id) &&
+            !language_name_has_translations (locale->language_code)) {
+                gdm_locale_free (locale);
+                return FALSE;
+        }
+
+        old_locale = g_hash_table_lookup (gdm_available_locales_map, locale->id);
+        if (old_locale != NULL) {
+                if (strlen (old_locale->name) > strlen (locale->name)) {
+                        gdm_locale_free (locale);
+                        return FALSE;
+                }
+        }
+
+        g_hash_table_insert (gdm_available_locales_map, g_strdup (locale->id), locale);
+
+        return TRUE;
+}
+
+struct nameent
+{
+        char    *name;
+        uint32_t locrec_offset;
+};
+
+static gboolean
+collect_locales_from_archive (void)
+{
+        GMappedFile        *mapped;
+        GError             *error;
+        char               *addr;
+        struct locarhead   *head;
+        struct namehashent *namehashtab;
+        struct nameent     *names;
+        uint32_t            used;
+        uint32_t            cnt;
+        gsize               len;
+        gboolean            locales_collected;
+
+        error = NULL;
+        mapped = g_mapped_file_new (ARCHIVE_FILE, FALSE, &error);
+        if (mapped == NULL) {
+                g_warning ("Mapping failed for %s: %s", ARCHIVE_FILE, error->message);
+                g_error_free (error);
+                return FALSE;
+        }
+
+        locales_collected = FALSE;
+
+        addr = g_mapped_file_get_contents (mapped);
+        len = g_mapped_file_get_length (mapped);
+
+        head = (struct locarhead *) addr;
+        if (head->namehash_offset + head->namehash_size > len
+            || head->string_offset + head->string_size > len
+            || head->locrectab_offset + head->locrectab_size > len
+            || head->sumhash_offset + head->sumhash_size > len) {
+                goto out;
+        }
+
+        namehashtab = (struct namehashent *) (addr + head->namehash_offset);
+
+        names = (struct nameent *) g_new0 (struct nameent, head->namehash_used);
+        for (cnt = used = 0; cnt < head->namehash_size; ++cnt) {
+                if (namehashtab[cnt].locrec_offset != 0) {
+                        names[used].name = addr + namehashtab[cnt].name_offset;
+                        names[used++].locrec_offset = namehashtab[cnt].locrec_offset;
+                }
+        }
+
+        for (cnt = 0; cnt < used; ++cnt) {
+                add_locale (names[cnt].name);
+        }
+
+        g_free (names);
+
+        locales_collected = TRUE;
+ out:
+
+        g_mapped_file_unref (mapped);
+        return locales_collected;
+}
+
+static int
+select_dirs (const struct dirent *dirent)
+{
+        int result = 0;
+
+        if (strcmp (dirent->d_name, ".") != 0 && strcmp (dirent->d_name, "..") != 0) {
+                mode_t mode = 0;
+
+#ifdef _DIRENT_HAVE_D_TYPE
+                if (dirent->d_type != DT_UNKNOWN && dirent->d_type != DT_LNK) {
+                        mode = DTTOIF (dirent->d_type);
+                } else
+#endif
+                        {
+                                struct stat st;
+                                char       *path;
+
+                                path = g_build_filename (LIBLOCALEDIR, dirent->d_name, NULL);
+                                if (g_stat (path, &st) == 0) {
+                                        mode = st.st_mode;
+                                }
+                                g_free (path);
+                        }
+
+                result = S_ISDIR (mode);
+        }
+
+        return result;
+}
+
+static void
+collect_locales_from_directory (void)
+{
+        struct dirent **dirents;
+        int             ndirents;
+        int             cnt;
+
+        ndirents = scandir (LIBLOCALEDIR, &dirents, select_dirs, alphasort);
+
+        for (cnt = 0; cnt < ndirents; ++cnt) {
+                add_locale (dirents[cnt]->d_name);
+        }
+
+        if (ndirents > 0) {
+                free (dirents);
+        }
+}
+
+static void
+collect_locales (void)
+{
+
+        if (gdm_available_locales_map == NULL) {
+                gdm_available_locales_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) gdm_locale_free);
+        }
+
+        if (collect_locales_from_archive ()) {
+                return;
+        } else {
+                g_warning ("Could not read list of available locales from libc, "
+                           "guessing possible locales from available translations, "
+                           "but list may be incomplete!");
+
+                collect_locales_from_directory ();
+        }
+}
+
+static gboolean
+is_fallback_language (const char *code)
+{
+        const char *fallback_language_names[] = { "C", "POSIX", NULL };
+        int i;
+
+        for (i = 0; fallback_language_names[i] != NULL; i++) {
+                if (strcmp (code, fallback_language_names[i]) == 0) {
+                        return TRUE;
+                }
+        }
+
+        return FALSE;
+}
+
+static const char *
+get_language (const char *code)
+{
+        const char *name;
+        int         len;
+
+        g_assert (code != NULL);
+
+        if (is_fallback_language (code)) {
+                return "Unspecified";
+        }
+
+        len = strlen (code);
+        if (len != 2 && len != 3) {
+                return NULL;
+        }
+
+        name = (const char *) g_hash_table_lookup (gdm_languages_map, code);
+
+        return name;
+}
+
+static char *
+get_first_item_in_semicolon_list (const char *list)
+{
+    char **items;
+    char  *item;
+
+    /* Some entries in iso codes have multiple values, separated
+     * by semicolons.  Not really sure which one to pick, so
+     * we just arbitrarily pick the first one.
+     */
+    items = g_strsplit (list, "; ", 2);
+
+    item = g_strdup (items[0]);
+    g_strfreev (items);
+
+    return item;
+}
+
+static char *
+get_translated_language (const char *code,
+                         const char *locale)
+{
+        const char *language;
+        char *name;
+
+        language = get_language (code);
+
+        name = NULL;
+        if (language != NULL) {
+                const char  *translated_name;
+                char        *old_locale;
+
+                if (locale != NULL) {
+                        old_locale = g_strdup (setlocale (LC_MESSAGES, NULL));
+                        setlocale (LC_MESSAGES, locale);
+                }
+
+                if (is_fallback_language (code)) {
+                        name = _("Unspecified");
+                } else {
+                        translated_name = dgettext ("iso_639", language);
+                        name = get_first_item_in_semicolon_list (translated_name);
+                }
+
+                if (locale != NULL) {
+                        setlocale (LC_MESSAGES, old_locale);
+                        g_free (old_locale);
+                }
+        }
+
+        return name;
+}
+
+static const char *
+get_territory (const char *code)
+{
+        const char *name;
+        int         len;
+
+        g_assert (code != NULL);
+
+        len = strlen (code);
+        if (len != 2 && len != 3) {
+                return NULL;
+        }
+
+        name = (const char *) g_hash_table_lookup (gdm_territories_map, code);
+
+        return name;
+}
+
+static const char *
+get_translated_territory (const char *code,
+                          const char *locale)
+{
+        const char *territory;
+        char *name;
+
+        territory = get_territory (code);
+
+        name = NULL;
+        if (territory != NULL) {
+                const char *translated_territory;
+                char       *old_locale;
+
+                if (locale != NULL) {
+                        old_locale = g_strdup (setlocale (LC_MESSAGES, NULL));
+                        setlocale (LC_MESSAGES, locale);
+                }
+
+                translated_territory = dgettext ("iso_3166", territory);
+                name = get_first_item_in_semicolon_list (translated_territory);
+
+                if (locale != NULL) {
+                        setlocale (LC_MESSAGES, old_locale);
+                        g_free (old_locale);
+                }
+        }
+
+        return name;
+}
+
+static void
+languages_parse_start_tag (GMarkupParseContext      *ctx,
+                           const char               *element_name,
+                           const char              **attr_names,
+                           const char              **attr_values,
+                           gpointer                  user_data,
+                           GError                  **error)
+{
+        const char *ccode_longB;
+        const char *ccode_longT;
+        const char *ccode;
+        const char *lang_name;
+
+        if (! g_str_equal (element_name, "iso_639_entry") || attr_names == NULL || attr_values == NULL) {
+                return;
+        }
+
+        ccode = NULL;
+        ccode_longB = NULL;
+        ccode_longT = NULL;
+        lang_name = NULL;
+
+        while (*attr_names && *attr_values) {
+                if (g_str_equal (*attr_names, "iso_639_1_code")) {
+                        /* skip if empty */
+                        if (**attr_values) {
+                                if (strlen (*attr_values) != 2) {
+                                        return;
+                                }
+                                ccode = *attr_values;
+                        }
+                } else if (g_str_equal (*attr_names, "iso_639_2B_code")) {
+                        /* skip if empty */
+                        if (**attr_values) {
+                                if (strlen (*attr_values) != 3) {
+                                        return;
+                                }
+                                ccode_longB = *attr_values;
+                        }
+                } else if (g_str_equal (*attr_names, "iso_639_2T_code")) {
+                        /* skip if empty */
+                        if (**attr_values) {
+                                if (strlen (*attr_values) != 3) {
+                                        return;
+                                }
+                                ccode_longT = *attr_values;
+                        }
+                } else if (g_str_equal (*attr_names, "name")) {
+                        lang_name = *attr_values;
+                }
+
+                ++attr_names;
+                ++attr_values;
+        }
+
+        if (lang_name == NULL) {
+                return;
+        }
+
+        if (ccode != NULL) {
+                g_hash_table_insert (gdm_languages_map,
+                                     g_strdup (ccode),
+                                     g_strdup (lang_name));
+        }
+        if (ccode_longB != NULL) {
+                g_hash_table_insert (gdm_languages_map,
+                                     g_strdup (ccode_longB),
+                                     g_strdup (lang_name));
+        }
+        if (ccode_longT != NULL) {
+                g_hash_table_insert (gdm_languages_map,
+                                     g_strdup (ccode_longT),
+                                     g_strdup (lang_name));
+        }
+}
+
+static void
+territories_parse_start_tag (GMarkupParseContext      *ctx,
+                             const char               *element_name,
+                             const char              **attr_names,
+                             const char              **attr_values,
+                             gpointer                  user_data,
+                             GError                  **error)
+{
+        const char *acode_2;
+        const char *acode_3;
+        const char *ncode;
+        const char *territory_common_name;
+        const char *territory_name;
+
+        if (! g_str_equal (element_name, "iso_3166_entry") || attr_names == NULL || attr_values == NULL) {
+                return;
+        }
+
+        acode_2 = NULL;
+        acode_3 = NULL;
+        ncode = NULL;
+        territory_common_name = NULL;
+        territory_name = NULL;
+
+        while (*attr_names && *attr_values) {
+                if (g_str_equal (*attr_names, "alpha_2_code")) {
+                        /* skip if empty */
+                        if (**attr_values) {
+                                if (strlen (*attr_values) != 2) {
+                                        return;
+                                }
+                                acode_2 = *attr_values;
+                        }
+                } else if (g_str_equal (*attr_names, "alpha_3_code")) {
+                        /* skip if empty */
+                        if (**attr_values) {
+                                if (strlen (*attr_values) != 3) {
+                                        return;
+                                }
+                                acode_3 = *attr_values;
+                        }
+                } else if (g_str_equal (*attr_names, "numeric_code")) {
+                        /* skip if empty */
+                        if (**attr_values) {
+                                if (strlen (*attr_values) != 3) {
+                                        return;
+                                }
+                                ncode = *attr_values;
+                        }
+                } else if (g_str_equal (*attr_names, "common_name")) {
+                        /* skip if empty */
+                        if (**attr_values) {
+                                territory_common_name = *attr_values;
+                        }
+                } else if (g_str_equal (*attr_names, "name")) {
+                        territory_name = *attr_values;
+                }
+
+                ++attr_names;
+                ++attr_values;
+        }
+
+        if (territory_common_name != NULL) {
+                territory_name = territory_common_name;
+        }
+
+        if (territory_name == NULL) {
+                return;
+        }
+
+        if (acode_2 != NULL) {
+                g_hash_table_insert (gdm_territories_map,
+                                     g_strdup (acode_2),
+                                     g_strdup (territory_name));
+        }
+        if (acode_3 != NULL) {
+                g_hash_table_insert (gdm_territories_map,
+                                     g_strdup (acode_3),
+                                     g_strdup (territory_name));
+        }
+        if (ncode != NULL) {
+                g_hash_table_insert (gdm_territories_map,
+                                     g_strdup (ncode),
+                                     g_strdup (territory_name));
+        }
+}
+
+static void
+languages_init (void)
+{
+        GError  *error;
+        gboolean res;
+        char    *buf;
+        gsize    buf_len;
+
+        bindtextdomain ("iso_639", ISO_CODES_LOCALESDIR);
+        bind_textdomain_codeset ("iso_639", "UTF-8");
+
+        gdm_languages_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+        error = NULL;
+        res = g_file_get_contents (ISO_CODES_DATADIR "/iso_639.xml",
+                                   &buf,
+                                   &buf_len,
+                                   &error);
+        if (res) {
+                GMarkupParseContext *ctx;
+                GMarkupParser        parser = { languages_parse_start_tag, NULL, NULL, NULL, NULL };
+
+                ctx = g_markup_parse_context_new (&parser, 0, NULL, NULL);
+
+                error = NULL;
+                res = g_markup_parse_context_parse (ctx, buf, buf_len, &error);
+
+                if (! res) {
+                        g_warning ("Failed to parse '%s': %s\n",
+                                   ISO_CODES_DATADIR "/iso_639.xml",
+                                   error->message);
+                        g_error_free (error);
+                }
+
+                g_markup_parse_context_free (ctx);
+                g_free (buf);
+        } else {
+                g_warning ("Failed to load '%s': %s\n",
+                           ISO_CODES_DATADIR "/iso_639.xml",
+                           error->message);
+                g_error_free (error);
+        }
+}
+
+static void
+territories_init (void)
+{
+        GError  *error;
+        gboolean res;
+        char    *buf;
+        gsize    buf_len;
+
+        bindtextdomain ("iso_3166", ISO_CODES_LOCALESDIR);
+        bind_textdomain_codeset ("iso_3166", "UTF-8");
+
+        gdm_territories_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+        error = NULL;
+        res = g_file_get_contents (ISO_CODES_DATADIR "/iso_3166.xml",
+                                   &buf,
+                                   &buf_len,
+                                   &error);
+        if (res) {
+                GMarkupParseContext *ctx;
+                GMarkupParser        parser = { territories_parse_start_tag, NULL, NULL, NULL, NULL };
+
+                ctx = g_markup_parse_context_new (&parser, 0, NULL, NULL);
+
+                error = NULL;
+                res = g_markup_parse_context_parse (ctx, buf, buf_len, &error);
+
+                if (! res) {
+                        g_warning ("Failed to parse '%s': %s\n",
+                                   ISO_CODES_DATADIR "/iso_3166.xml",
+                                   error->message);
+                        g_error_free (error);
+                }
+
+                g_markup_parse_context_free (ctx);
+                g_free (buf);
+        } else {
+                g_warning ("Failed to load '%s': %s\n",
+                           ISO_CODES_DATADIR "/iso_3166.xml",
+                           error->message);
+                g_error_free (error);
+        }
+}
+
+char *
+gdm_get_language_from_name (const char *name,
+                            const char *locale)
+{
+        char *full_language;
+        char *language_code;
+        char *territory_code;
+        const char *language;
+        const char *territory;
+
+        if (gdm_languages_map == NULL) {
+                languages_init ();
+        }
+
+        if (gdm_territories_map == NULL) {
+                territories_init ();
+        }
+
+        language_code = NULL;
+        territory_code = NULL;
+        full_language = NULL;
+
+        gdm_parse_language_name (name, &language_code, &territory_code,
+                                 NULL, NULL);
+
+        if (language_code == NULL) {
+                goto out;
+        }
+
+        language = get_translated_language (language_code, locale);
+
+        if (territory_code != NULL) {
+                territory = get_translated_territory (territory_code, locale);
+        } else {
+                territory = NULL;
+        }
+
+        if (territory != NULL) {
+                full_language  = g_strdup_printf ("%s (%s)",
+                        language ? language : "",
+                        territory ? territory : "");
+        } else {
+                full_language  = g_strdup (language);
+        }
+
+out:
+       g_free (language_code);
+       g_free (territory_code);
+
+       return full_language;
+}
+
+char **
+gdm_get_all_language_names (void)
+{
+        GHashTableIter iter;
+        gpointer key, value;
+        GPtrArray *array;
+
+        if (gdm_available_locales_map == NULL) {
+                collect_locales ();
+        }
+
+        array = g_ptr_array_new ();
+        g_hash_table_iter_init (&iter, gdm_available_locales_map);
+        while (g_hash_table_iter_next (&iter, &key, &value)) {
+                GdmLocale *locale;
+
+                locale = (GdmLocale *) value;
+
+                g_ptr_array_add (array, g_strdup (locale->name));
+        }
+        g_ptr_array_add (array, NULL);
+
+        return (char **) g_ptr_array_free (array, FALSE);
+}
diff --git a/panels/user-accounts/gdm-languages.h b/panels/user-accounts/gdm-languages.h
new file mode 100644
index 0000000..5b4560f
--- /dev/null
+++ b/panels/user-accounts/gdm-languages.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright 2008 Red Hat, Inc.
+ * Copyright 2007 William Jon McCann <mccann jhu edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Written by: Ray Strode
+ *             William Jon McCann
+ */
+
+#ifndef __GDM_LANGUAGES_H
+#define __GDM_LANGUAGES_H
+
+G_BEGIN_DECLS
+
+char *        gdm_get_language_from_name  (const char *name,
+                                           const char *locale);
+char **       gdm_get_all_language_names  (void);
+gboolean      gdm_parse_language_name     (const char *name,
+                                           char      **language_codep,
+                                           char      **territory_codep,
+                                           char      **codesetp,
+                                           char      **modifierp);
+char *        gdm_normalize_language_name (const char *name);
+
+G_END_DECLS
+
+#endif /* __GDM_LANGUAGE_CHOOSER_WIDGET_H */
diff --git a/panels/user-accounts/locarchive.h b/panels/user-accounts/locarchive.h
new file mode 100644
index 0000000..f933f4d
--- /dev/null
+++ b/panels/user-accounts/locarchive.h
@@ -0,0 +1,97 @@
+/* Definitions for locale archive handling.
+   Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _LOCARCHIVE_H
+#define _LOCARCHIVE_H 1
+
+#include <stdint.h>
+
+#define AR_MAGIC 0xde020109
+
+struct locarhead
+{
+  uint32_t magic;
+  /* Serial number.  */
+  uint32_t serial;
+  /* Name hash table.  */
+  uint32_t namehash_offset;
+  uint32_t namehash_used;
+  uint32_t namehash_size;
+  /* String table.  */
+  uint32_t string_offset;
+  uint32_t string_used;
+  uint32_t string_size;
+  /* Table with locale records.  */
+  uint32_t locrectab_offset;
+  uint32_t locrectab_used;
+  uint32_t locrectab_size;
+  /* MD5 sum hash table.  */
+  uint32_t sumhash_offset;
+  uint32_t sumhash_used;
+  uint32_t sumhash_size;
+};
+
+
+struct namehashent
+{
+  /* Hash value of the name.  */
+  uint32_t hashval;
+  /* Offset of the name in the string table.  */
+  uint32_t name_offset;
+  /* Offset of the locale record.  */
+  uint32_t locrec_offset;
+};
+
+
+struct sumhashent
+{
+  /* MD5 sum.  */
+  char sum[16];
+  /* Offset of the file in the archive.  */
+  uint32_t file_offset;
+};
+
+struct locrecent
+{
+  uint32_t refs;		/* # of namehashent records that point here */
+  struct
+  {
+    uint32_t offset;
+    uint32_t len;
+  } record[__LC_LAST];
+};
+
+
+struct locarhandle
+{
+  int fd;
+  void *addr;
+  size_t len;
+};
+
+
+/* In memory data for the locales with their checksums.  */
+typedef struct locale_category_data
+{
+  off_t size;
+  void *addr;
+  char sum[16];
+} locale_data_t[__LC_LAST];
+
+#endif	/* locarchive.h */
diff --git a/panels/user-accounts/run-passwd.c b/panels/user-accounts/run-passwd.c
new file mode 100644
index 0000000..6f7cfab
--- /dev/null
+++ b/panels/user-accounts/run-passwd.c
@@ -0,0 +1,772 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* run-passwd.c: this file is part of users-admin, a gnome-system-tools frontend
+ * for user administration.
+ *
+ * Copyright (C) 2002 Diego Gonzalez
+ * Copyright (C) 2006 Johannes H. Jensen
+ * Copyright (C) 2010 Milan Bouchet-Valat
+ *
+ * Written by: Diego Gonzalez <diego pemas net>
+ * Modified by: Johannes H. Jensen <joh deworks net>,
+ *              Milan Bouchet-Valat <nalimilan club fr>.
+ *
+ * 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, 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.
+ *
+ * Most of this code originally comes from gnome-about-me-password.c,
+ * from gnome-control-center.
+ */
+
+#include <config.h>
+#include <glib/gi18n.h>
+
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/wait.h>
+
+#if __sun
+#include <sys/types.h>
+#include <signal.h>
+#endif
+
+#include "run-passwd.h"
+
+/* Passwd states */
+typedef enum {
+        PASSWD_STATE_NONE,              /* Passwd is not asking for anything */
+        PASSWD_STATE_AUTH,              /* Passwd is asking for our current password */
+        PASSWD_STATE_NEW,               /* Passwd is asking for our new password */
+        PASSWD_STATE_RETYPE,            /* Passwd is asking for our retyped new password */
+        PASSWD_STATE_DONE,              /* Passwd succeeded but has not yet exited */
+        PASSWD_STATE_ERR                /* Passwd reported an error but has not yet exited */
+} PasswdState;
+
+struct PasswdHandler {
+        const char *current_password;
+        const char *new_password;
+
+        /* Communication with the passwd program */
+        GPid backend_pid;
+
+        GIOChannel *backend_stdin;
+        GIOChannel *backend_stdout;
+
+        GQueue *backend_stdin_queue;            /* Write queue to backend_stdin */
+
+        /* GMainLoop IDs */
+        guint backend_child_watch_id;           /* g_child_watch_add (PID) */
+        guint backend_stdout_watch_id;          /* g_io_add_watch (stdout) */
+
+        /* State of the passwd program */
+        PasswdState backend_state;
+        gboolean    changing_password;
+
+        PasswdCallback auth_cb;
+        gpointer       auth_cb_data;
+
+        PasswdCallback chpasswd_cb;
+        gpointer       chpasswd_cb_data;
+};
+
+/* Buffer size for backend output */
+#define BUFSIZE 64
+
+
+static GQuark
+passwd_error_quark (void)
+{
+        static GQuark q = 0;
+
+        if (q == 0) {
+                q = g_quark_from_static_string("passwd_error");
+        }
+
+        return q;
+}
+
+/* Error handling */
+#define PASSWD_ERROR (passwd_error_quark ())
+
+
+static void
+stop_passwd (PasswdHandler *passwd_handler);
+
+static void
+free_passwd_resources (PasswdHandler *passwd_handler);
+
+static gboolean
+io_watch_stdout (GIOChannel *source, GIOCondition condition, PasswdHandler *passwd_handler);
+
+
+/*
+ * Spawning and closing of backend {{
+ */
+
+/* Child watcher */
+static void
+child_watch_cb (GPid pid, gint status, PasswdHandler *passwd_handler)
+{
+        if (WIFEXITED (status)) {
+                if (WEXITSTATUS (status) >= 255) {
+                        g_warning ("Child exited unexpectedly");
+                }
+                if (WEXITSTATUS (status) == 0) {
+                        if (passwd_handler->backend_state == PASSWD_STATE_RETYPE) {
+                                passwd_handler->backend_state = PASSWD_STATE_DONE;
+                                if (passwd_handler->chpasswd_cb)
+                                                passwd_handler->chpasswd_cb (passwd_handler,
+                                                                             NULL,
+                                                                             passwd_handler->auth_cb_data);
+                        }
+                }
+        }
+
+        free_passwd_resources (passwd_handler);
+}
+
+static void
+ignore_sigpipe (gpointer data)
+{
+        signal (SIGPIPE, SIG_IGN);
+}
+
+/* Spawn passwd backend
+ * Returns: TRUE on success, FALSE otherwise and sets error appropriately */
+static gboolean
+spawn_passwd (PasswdHandler *passwd_handler, GError **error)
+{
+        gchar   *argv[2];
+        gchar   *envp[1];
+        gint    my_stdin, my_stdout, my_stderr;
+
+        argv[0] = "/usr/bin/passwd";    /* Is it safe to rely on a hard-coded path? */
+        argv[1] = NULL;
+
+        envp[0] = NULL;                 /* If we pass an empty array as the environment,
+                                         * will the childs environment be empty, and the
+                                         * locales set to the C default? From the manual:
+                                         * "If envp is NULL, the child inherits its
+                                         * parent'senvironment."
+                                         * If I'm wrong here, we somehow have to set
+                                         * the locales here.
+                                         */
+
+        if (!g_spawn_async_with_pipes (NULL,                            /* Working directory */
+                                       argv,                            /* Argument vector */
+                                       envp,                            /* Environment */
+                                       G_SPAWN_DO_NOT_REAP_CHILD,       /* Flags */
+                                       ignore_sigpipe,                  /* Child setup */
+                                       NULL,                            /* Data to child setup */
+                                       &passwd_handler->backend_pid,    /* PID */
+                                       &my_stdin,                       /* Stdin */
+                                       &my_stdout,                      /* Stdout */
+                                       &my_stderr,                      /* Stderr */
+                                       error)) {                        /* GError */
+
+                /* An error occured */
+                free_passwd_resources (passwd_handler);
+
+                return FALSE;
+        }
+
+        /* 2>&1 */
+        if (dup2 (my_stderr, my_stdout) == -1) {
+                /* Failed! */
+                g_set_error_literal (error,
+                                     PASSWD_ERROR,
+                                     PASSWD_ERROR_BACKEND,
+                                     strerror (errno));
+
+                /* Clean up */
+                stop_passwd (passwd_handler);
+
+                return FALSE;
+        }
+
+        /* Open IO Channels */
+        passwd_handler->backend_stdin = g_io_channel_unix_new (my_stdin);
+        passwd_handler->backend_stdout = g_io_channel_unix_new (my_stdout);
+
+        /* Set raw encoding */
+        /* Set nonblocking mode */
+        if (g_io_channel_set_encoding (passwd_handler->backend_stdin, NULL, error) != G_IO_STATUS_NORMAL ||
+                g_io_channel_set_encoding (passwd_handler->backend_stdout, NULL, error) != G_IO_STATUS_NORMAL ||
+                g_io_channel_set_flags (passwd_handler->backend_stdin, G_IO_FLAG_NONBLOCK, error) != G_IO_STATUS_NORMAL ||
+                g_io_channel_set_flags (passwd_handler->backend_stdout, G_IO_FLAG_NONBLOCK, error) != G_IO_STATUS_NORMAL ) {
+
+                /* Clean up */
+                stop_passwd (passwd_handler);
+                return FALSE;
+        }
+
+        /* Turn off buffering */
+        g_io_channel_set_buffered (passwd_handler->backend_stdin, FALSE);
+        g_io_channel_set_buffered (passwd_handler->backend_stdout, FALSE);
+
+        /* Add IO Channel watcher */
+        passwd_handler->backend_stdout_watch_id = g_io_add_watch (passwd_handler->backend_stdout,
+                                                                  G_IO_IN | G_IO_PRI,
+                                                                  (GIOFunc) io_watch_stdout, passwd_handler);
+
+        /* Add child watcher */
+        passwd_handler->backend_child_watch_id = g_child_watch_add (passwd_handler->backend_pid, (GChildWatchFunc) child_watch_cb, passwd_handler);
+
+        /* Success! */
+
+        return TRUE;
+}
+
+/* Stop passwd backend */
+static void
+stop_passwd (PasswdHandler *passwd_handler)
+{
+        /* This is the standard way of returning from the dialog with passwd.
+         * If we return this way we can safely kill passwd as it has completed
+         * its task.
+         */
+
+        if (passwd_handler->backend_pid != -1) {
+                kill (passwd_handler->backend_pid, 9);
+        }
+
+        /* We must run free_passwd_resources here and not let our child
+         * watcher do it, since it will access invalid memory after the
+         * dialog has been closed and cleaned up.
+         *
+         * If we had more than a single thread we'd need to remove
+         * the child watch before trying to kill the child.
+         */
+        free_passwd_resources (passwd_handler);
+}
+
+/* Clean up passwd resources */
+static void
+free_passwd_resources (PasswdHandler *passwd_handler)
+{
+        GError  *error = NULL;
+
+        /* Remove the child watcher */
+        if (passwd_handler->backend_child_watch_id != 0) {
+
+                g_source_remove (passwd_handler->backend_child_watch_id);
+
+                passwd_handler->backend_child_watch_id = 0;
+        }
+
+
+        /* Close IO channels (internal file descriptors are automatically closed) */
+        if (passwd_handler->backend_stdin != NULL) {
+
+                if (g_io_channel_shutdown (passwd_handler->backend_stdin, TRUE, &error) != G_IO_STATUS_NORMAL) {
+                        g_warning ("Could not shutdown backend_stdin IO channel: %s", error->message);
+                        g_error_free (error);
+                        error = NULL;
+                }
+
+                g_io_channel_unref (passwd_handler->backend_stdin);
+                passwd_handler->backend_stdin = NULL;
+        }
+
+        if (passwd_handler->backend_stdout != NULL) {
+
+                if (g_io_channel_shutdown (passwd_handler->backend_stdout, TRUE, &error) != G_IO_STATUS_NORMAL) {
+                        g_warning ("Could not shutdown backend_stdout IO channel: %s", error->message);
+                        g_error_free (error);
+                        error = NULL;
+                }
+
+                g_io_channel_unref (passwd_handler->backend_stdout);
+
+                passwd_handler->backend_stdout = NULL;
+        }
+
+        /* Remove IO watcher */
+        if (passwd_handler->backend_stdout_watch_id != 0) {
+
+                g_source_remove (passwd_handler->backend_stdout_watch_id);
+
+                passwd_handler->backend_stdout_watch_id = 0;
+        }
+
+        /* Close PID */
+        if (passwd_handler->backend_pid != -1) {
+
+                g_spawn_close_pid (passwd_handler->backend_pid);
+
+                passwd_handler->backend_pid = -1;
+        }
+
+        /* Clear backend state */
+        passwd_handler->backend_state = PASSWD_STATE_NONE;
+}
+
+/*
+ * }} Spawning and closing of backend
+ */
+
+/*
+ * Backend communication code {{
+ */
+
+/* Write the first element of queue through channel */
+static void
+io_queue_pop (GQueue *queue, GIOChannel *channel)
+{
+        gchar   *buf;
+        gsize   bytes_written;
+        GError  *error = NULL;
+
+        buf = g_queue_pop_head (queue);
+
+        if (buf != NULL) {
+
+                if (g_io_channel_write_chars (channel, buf, -1, &bytes_written, &error) != G_IO_STATUS_NORMAL) {
+                        g_warning ("Could not write queue element \"%s\" to channel: %s", buf, error->message);
+                        g_error_free (error);
+                }
+
+                /* Ensure passwords are cleared from memory */
+                memset (buf, 0, strlen (buf));
+                g_free (buf);
+        }
+}
+
+/* Goes through the argument list, checking if one of them occurs in str
+ * Returns: TRUE as soon as an element is found to match, FALSE otherwise */
+static gboolean
+is_string_complete (gchar *str, ...)
+{
+        va_list ap;
+        gchar   *arg;
+
+        if (strlen (str) == 0) {
+                return FALSE;
+        }
+
+        va_start (ap, str);
+
+        while ((arg = va_arg (ap, char *)) != NULL) {
+                if (strstr (str, arg) != NULL) {
+                        va_end (ap);
+                        return TRUE;
+                }
+        }
+
+        va_end (ap);
+
+        return FALSE;
+}
+
+/*
+ * IO watcher for stdout, called whenever there is data to read from the backend.
+ * This is where most of the actual IO handling happens.
+ */
+static gboolean
+io_watch_stdout (GIOChannel *source, GIOCondition condition, PasswdHandler *passwd_handler)
+{
+        static GString *str = NULL;     /* Persistent buffer */
+
+        gchar           buf[BUFSIZE];           /* Temporary buffer */
+        gsize           bytes_read;
+        GError          *gio_error = NULL;      /* Error returned by functions */
+        GError          *error = NULL;          /* Error sent to callbacks */
+
+        gboolean        reinit = FALSE;
+
+        /* Initialize buffer */
+        if (str == NULL) {
+                str = g_string_new ("");
+        }
+
+        if (g_io_channel_read_chars (source, buf, BUFSIZE, &bytes_read, &gio_error)
+            != G_IO_STATUS_NORMAL) {
+                g_warning ("IO Channel read error: %s", gio_error->message);
+                g_error_free (gio_error);
+
+                return TRUE;
+        }
+
+        str = g_string_append_len (str, buf, bytes_read);
+
+        /* In which state is the backend? */
+        switch (passwd_handler->backend_state) {
+                case PASSWD_STATE_AUTH:
+                        /* Passwd is asking for our current password */
+
+                        if (is_string_complete (str->str, "assword: ", "failure", "wrong", "error", NULL)) {
+
+                                if (strstr (str->str, "assword: ") != NULL) {
+                                        /* Authentication successful */
+
+                                        passwd_handler->backend_state = PASSWD_STATE_NEW;
+
+                                        /* Trigger callback to update authentication status */
+                                        if (passwd_handler->auth_cb)
+                                                passwd_handler->auth_cb (passwd_handler,
+                                                                         NULL,
+                                                                         passwd_handler->auth_cb_data);
+
+                                } else {
+                                        /* Authentication failed */
+
+                                        error = g_error_new_literal (PASSWD_ERROR, PASSWD_ERROR_AUTH_FAILED,
+                                                                     _("Authentication failed"));
+
+                                        passwd_handler->changing_password = FALSE;
+
+                                        /* This error can happen both while authenticating or while changing password:
+                                         * if chpasswd_cb is set, this means we're already changing password */
+                                        if (passwd_handler->chpasswd_cb)
+                                                passwd_handler->chpasswd_cb (passwd_handler,
+                                                                             error,
+                                                                             passwd_handler->auth_cb_data);
+                                        else if (passwd_handler->auth_cb)
+                                                passwd_handler->auth_cb (passwd_handler,
+                                                                         error,
+                                                                         passwd_handler->auth_cb_data);
+
+                                        g_error_free (error);
+                                }
+
+                                reinit = TRUE;
+                        }
+                        break;
+                case PASSWD_STATE_NEW:
+                        /* Passwd is asking for our new password */
+
+                        if (is_string_complete (str->str, "assword: ", NULL)) {
+                                /* Advance to next state */
+                                passwd_handler->backend_state = PASSWD_STATE_RETYPE;
+
+                                /* Pop retyped password from queue and into IO channel */
+                                io_queue_pop (passwd_handler->backend_stdin_queue, passwd_handler->backend_stdin);
+
+                                reinit = TRUE;
+                        }
+                        break;
+                case PASSWD_STATE_RETYPE:
+                        /* Passwd is asking for our retyped new password */
+
+                        if (is_string_complete (str->str,
+                                                "successfully",
+                                                "short",
+                                                "longer",
+                                                "palindrome",
+                                                "dictionary",
+                                                "simple",
+                                                "simplistic",
+                                                "similar",
+                                                "case",
+                                                "different",
+                                                "wrapped",
+                                                "recovered",
+                                                "recent",
+                                                "unchanged",
+                                                "match",
+                                                "1 numeric or special",
+                                                "failure",
+                                                "DIFFERENT",
+                                                "BAD PASSWORD",
+                                                NULL)) {
+
+                                if (strstr (str->str, "successfully") != NULL) {
+                                        /* Hooray! */
+
+                                        passwd_handler->backend_state = PASSWD_STATE_DONE;
+                                        /* Trigger callback to update status */
+                                        if (passwd_handler->chpasswd_cb)
+                                                passwd_handler->chpasswd_cb (passwd_handler,
+                                                                             NULL,
+                                                                             passwd_handler->chpasswd_cb_data);
+                                }
+                                else {
+                                        /* Ohnoes! */
+
+                                        if (strstr (str->str, "recovered") != NULL) {
+                                                /* What does this indicate?
+                                                 * "Authentication information cannot be recovered?" from libpam? */
+                                                error = g_error_new_literal (PASSWD_ERROR, PASSWD_ERROR_UNKNOWN,
+                                                                             str->str);
+                                        } else if (strstr (str->str, "short") != NULL ||
+                                                   strstr (str->str, "longer") != NULL) {
+                                                error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED,
+                                                                     _("The new password is too short"));
+                                        } else if (strstr (str->str, "palindrome") != NULL ||
+                                                   strstr (str->str, "simple") != NULL ||
+                                                   strstr (str->str, "simplistic") != NULL ||
+                                                   strstr (str->str, "dictionary") != NULL) {
+                                                error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED,
+                                                                     _("The new password is too simple"));
+                                        } else if (strstr (str->str, "similar") != NULL ||
+                                                   strstr (str->str, "different") != NULL ||
+                                                   strstr (str->str, "case") != NULL ||
+                                                   strstr (str->str, "wrapped") != NULL) {
+                                                error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED,
+                                                                     _("The old and new passwords are too similar"));
+                                        } else if (strstr (str->str, "recent") != NULL) {
+                                                error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED,
+                                                                     _("The new password has already been used recently."));
+                                        } else if (strstr (str->str, "1 numeric or special") != NULL) {
+                                                error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED,
+                                                                     _("The new password must contain numeric or special characters"));
+                                        } else if (strstr (str->str, "unchanged") != NULL ||
+                                                   strstr (str->str, "match") != NULL) {
+                                                error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED,
+                                                                     _("The old and new passwords are the same"));
+                                        } else if (strstr (str->str, "failure") != NULL) {
+                                                /* Authentication failure */
+                                                error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_AUTH_FAILED,
+                                                                     _("Your password has been changed since you initially authenticated!"));
+                                        }
+                                        else if (strstr (str->str, "DIFFERENT")) {
+                                                error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_REJECTED,
+                                                                     _("The new password does not contain enough different characters"));
+                                        }
+                                        else {
+                                                error = g_error_new (PASSWD_ERROR, PASSWD_ERROR_UNKNOWN,
+                                                                     _("Unknown error"));
+                                        }
+
+                                        /* At this point, passwd might have exited, in which case
+                                         * child_watch_cb should clean up for us and remove this watcher.
+                                         * On some error conditions though, passwd just re-prompts us
+                                         * for our new password. */
+                                        passwd_handler->backend_state = PASSWD_STATE_ERR;
+
+                                        passwd_handler->changing_password = FALSE;
+
+                                        /* Trigger callback to update status */
+                                        if (passwd_handler->chpasswd_cb)
+                                                passwd_handler->chpasswd_cb (passwd_handler,
+                                                                             error,
+                                                                             passwd_handler->chpasswd_cb_data);
+
+                                        g_error_free (error);
+
+                                }
+
+                                reinit = TRUE;
+
+                                /* child_watch_cb should clean up for us now */
+                        }
+                        break;
+                case PASSWD_STATE_NONE:
+                        /* Passwd is not asking for anything yet */
+                        if (is_string_complete (str->str, "assword: ", NULL)) {
+
+                                /* If the user does not have a password set,
+                                 * passwd will immediately ask for the new password,
+                                 * so skip the AUTH phase */
+                                if (is_string_complete (str->str, "new", "New", NULL)) {
+                                        gchar *pw;
+
+                                        passwd_handler->backend_state = PASSWD_STATE_NEW;
+
+                                        /* since passwd didn't ask for our old password
+                                         * in this case, simply remove it from the queue */
+                                        pw = g_queue_pop_head (passwd_handler->backend_stdin_queue);
+                                        g_free (pw);
+
+                                        /* Pop the IO queue, i.e. send new password */
+                                        io_queue_pop (passwd_handler->backend_stdin_queue, passwd_handler->backend_stdin);
+
+                                } else {
+
+                                        passwd_handler->backend_state = PASSWD_STATE_AUTH;
+
+                                        /* Pop the IO queue, i.e. send current password */
+                                        io_queue_pop (passwd_handler->backend_stdin_queue, passwd_handler->backend_stdin);
+                                }
+
+                                reinit = TRUE;
+                        }
+                        break;
+                default:
+                        /* Passwd has returned an error */
+                        reinit = TRUE;
+                        break;
+        }
+
+        if (reinit) {
+                g_string_free (str, TRUE);
+                str = NULL;
+        }
+
+        /* Continue calling us */
+        return TRUE;
+}
+
+/*
+ * }} Backend communication code
+ */
+
+/* Adds the current password to the IO queue */
+static void
+authenticate (PasswdHandler *passwd_handler)
+{
+        gchar   *s;
+
+        s = g_strdup_printf ("%s\n", passwd_handler->current_password);
+
+        g_queue_push_tail (passwd_handler->backend_stdin_queue, s);
+}
+
+/* Adds the new password twice to the IO queue */
+static void
+update_password (PasswdHandler *passwd_handler)
+{
+        gchar   *s;
+
+        s = g_strdup_printf ("%s\n", passwd_handler->new_password);
+
+        g_queue_push_tail (passwd_handler->backend_stdin_queue, s);
+        /* We need to allocate new space because io_queue_pop() g_free()s
+         * every element of the queue after it's done */
+        g_queue_push_tail (passwd_handler->backend_stdin_queue, g_strdup (s));
+}
+
+
+PasswdHandler *
+passwd_init (void)
+{
+        PasswdHandler *passwd_handler;
+
+        passwd_handler = g_new0 (PasswdHandler, 1);
+
+        /* Initialize backend_pid. -1 means the backend is not running */
+        passwd_handler->backend_pid = -1;
+
+        /* Initialize IO Channels */
+        passwd_handler->backend_stdin = NULL;
+        passwd_handler->backend_stdout = NULL;
+
+        /* Initialize write queue */
+        passwd_handler->backend_stdin_queue = g_queue_new ();
+
+        /* Initialize watchers */
+        passwd_handler->backend_child_watch_id = 0;
+        passwd_handler->backend_stdout_watch_id = 0;
+
+        /* Initialize backend state */
+        passwd_handler->backend_state = PASSWD_STATE_NONE;
+        passwd_handler->changing_password = FALSE;
+
+        return passwd_handler;
+}
+
+void
+passwd_destroy (PasswdHandler *passwd_handler)
+{
+        g_queue_free (passwd_handler->backend_stdin_queue);
+        stop_passwd (passwd_handler);
+        g_free (passwd_handler);
+}
+
+void
+passwd_authenticate (PasswdHandler *passwd_handler,
+                     const char    *current_password,
+                     PasswdCallback cb,
+                     const gpointer user_data)
+{
+        GError *error = NULL;
+
+        /* Don't stop if we've already started chaging password */
+        if (passwd_handler->changing_password)
+                return;
+
+        /* Clear data from possible previous attempts to change password */
+        passwd_handler->new_password = NULL;
+        passwd_handler->chpasswd_cb = NULL;
+        passwd_handler->chpasswd_cb_data = NULL;
+        g_queue_foreach (passwd_handler->backend_stdin_queue, (GFunc) g_free, NULL);
+        g_queue_clear (passwd_handler->backend_stdin_queue);
+
+        passwd_handler->current_password = current_password;
+        passwd_handler->auth_cb = cb;
+        passwd_handler->auth_cb_data = user_data;
+
+        /* Spawn backend */
+        stop_passwd (passwd_handler);
+
+        if (!spawn_passwd (passwd_handler, &error)) {
+                g_warning ("%s", error->message);
+                g_error_free (error);
+
+                return;
+        }
+
+        authenticate (passwd_handler);
+
+        /* Our IO watcher should now handle the rest */
+}
+
+gboolean
+passwd_change_password (PasswdHandler *passwd_handler,
+                        const char    *new_password,
+                        PasswdCallback cb,
+                        const gpointer user_data)
+{
+        GError *error = NULL;
+
+        passwd_handler->changing_password = TRUE;
+
+        passwd_handler->new_password = new_password;
+        passwd_handler->chpasswd_cb = cb;
+        passwd_handler->chpasswd_cb_data = user_data;
+
+        /* Stop passwd if an error occured and it is still running */
+        if (passwd_handler->backend_state == PASSWD_STATE_ERR) {
+
+                /* Stop passwd, free resources */
+                stop_passwd (passwd_handler);
+        }
+
+        /* Check that the backend is still running, or that an error
+         * has occured but it has not yet exited */
+        if (passwd_handler->backend_pid == -1) {
+                /* If it is not, re-run authentication */
+
+                /* Spawn backend */
+                stop_passwd (passwd_handler);
+
+                if (!spawn_passwd (passwd_handler, &error)) {
+                        g_warning ("%s", error->message);
+                        g_error_free (error);
+
+                        return FALSE;
+                }
+
+                /* Add current and new passwords to queue */
+                authenticate (passwd_handler);
+                update_password (passwd_handler);
+        } else {
+                /* Only add new passwords to queue */
+                update_password (passwd_handler);
+        }
+
+        /* Pop new password through the backend.
+         * If user has no password, popping the queue would output current
+         * password, while 'passwd' is waiting for the new one. So wait for
+         * io_watch_stdout() to remove current password from the queue,
+         * and output the new one for us.
+         */
+        if (passwd_handler->current_password)
+                io_queue_pop (passwd_handler->backend_stdin_queue, passwd_handler->backend_stdin);
+
+        /* Our IO watcher should now handle the rest */
+
+        return TRUE;
+}
diff --git a/panels/user-accounts/run-passwd.h b/panels/user-accounts/run-passwd.h
new file mode 100644
index 0000000..2b07185
--- /dev/null
+++ b/panels/user-accounts/run-passwd.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* run-passwd.h: this file is part of users-admin, a gnome-system-tools frontend
+ * for user administration.
+ *
+ * Copyright (C) 2010 Milan Bouchet-Valat
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors: Milan Bouchet-Valat <nalimilan club fr>
+ */
+
+#ifndef _RUN_PASSWD_H
+#define _RUN_PASSWD_H
+
+struct PasswdHandler;
+
+typedef struct PasswdHandler PasswdHandler;
+
+typedef void (*PasswdCallback) (PasswdHandler *passwd_handler, GError *error, const gpointer user_data);
+
+/* Error codes */
+typedef enum {
+        PASSWD_ERROR_REJECTED,          /* New password is not secure enough */
+        PASSWD_ERROR_AUTH_FAILED,       /* Wrong old password, or PAM failure */
+        PASSWD_ERROR_REAUTH_FAILED,     /* Password has changed since first authentication */
+        PASSWD_ERROR_BACKEND,           /* Backend error */
+        PASSWD_ERROR_UNKNOWN            /* General error */
+} PasswdError;
+
+
+PasswdHandler *passwd_init                (void);
+
+void           passwd_destroy             (PasswdHandler *passwd_handler);
+
+void           passwd_authenticate        (PasswdHandler *passwd_handler,
+                                           const char    *current_password,
+                                           PasswdCallback cb,
+                                           gpointer       user_data);
+
+gboolean       passwd_change_password     (PasswdHandler *passwd_handler,
+                                           const char    *new_password,
+                                           PasswdCallback cb,
+                                           const gpointer user_data);
+
+#endif /* _RUN_PASSWD_H */
+
diff --git a/panels/user-accounts/um-account-dialog.c b/panels/user-accounts/um-account-dialog.c
new file mode 100644
index 0000000..93e10b5
--- /dev/null
+++ b/panels/user-accounts/um-account-dialog.c
@@ -0,0 +1,493 @@
+/* -*- 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 <stdlib.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <utmp.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include "um-account-dialog.h"
+#include "um-user-manager.h"
+#include "um-utils.h"
+
+#define MAXNAMELEN  (UT_NAMESIZE - 1)
+
+struct _UmAccountDialog {
+        GtkWidget *dialog;
+        GtkWidget *username_combo;
+        GtkWidget *name_entry;
+        GtkWidget *account_type_combo;
+        GtkWidget *ok_button;
+
+        gboolean valid_name;
+        gboolean valid_username;
+
+        UserCreatedCallback user_created_callback;
+        gpointer            user_created_data;
+};
+
+static void
+cancel_account_dialog (GtkButton       *button,
+                       UmAccountDialog *um)
+{
+        gtk_widget_hide (um->dialog);
+}
+
+static void
+create_user_done (UmUserManager   *manager,
+                  GAsyncResult    *res,
+                  UmAccountDialog *um)
+{
+        UmUser *user;
+        GError *error;
+
+        error = NULL;
+        if (!um_user_manager_create_user_finish (manager, res, &user, &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_get_transient_for (GTK_WINDOW (um->dialog)),
+                                                         GTK_DIALOG_DESTROY_WITH_PARENT,
+                                                         GTK_MESSAGE_ERROR,
+                                                         GTK_BUTTONS_CLOSE,
+                                                         _("Failed to create 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);
+        }
+        else {
+                um->user_created_callback (user, um->user_created_data);
+        }
+}
+
+static void
+accept_account_dialog (GtkButton       *button,
+                       UmAccountDialog *um)
+{
+        UmUserManager *manager;
+        const gchar *username;
+        const gchar *name;
+        gint account_type;
+        GtkTreeModel *model;
+        GtkTreeIter iter;
+
+        name = gtk_entry_get_text (GTK_ENTRY (um->name_entry));
+        username = gtk_combo_box_get_active_text (GTK_COMBO_BOX (um->username_combo));
+        model = gtk_combo_box_get_model (GTK_COMBO_BOX (um->account_type_combo));
+        gtk_combo_box_get_active_iter (GTK_COMBO_BOX (um->account_type_combo), &iter);
+        gtk_tree_model_get (model, &iter, 1, &account_type, -1);
+
+        manager = um_user_manager_ref_default ();
+        um_user_manager_create_user (manager,
+                                     username,
+                                     name,
+                                     account_type,
+                                     (GAsyncReadyCallback)create_user_done,
+                                     um,
+                                     NULL);
+        g_object_unref (manager);
+
+        gtk_widget_hide (um->dialog);
+}
+
+static gboolean
+is_username_used (const gchar *username)
+{
+        struct passwd *pwent;
+
+        pwent = getpwnam (username);
+
+        return pwent != NULL;
+}
+
+static void
+username_changed (GtkComboBox     *combo,
+                   UmAccountDialog *um)
+{
+        gboolean in_use;
+        gboolean empty;
+        gboolean valid;
+        gboolean toolong;
+        const gchar *username;
+        const gchar *c;
+        gchar *tip;
+        GtkWidget *entry;
+
+        username = gtk_combo_box_get_active_text (combo);
+
+        in_use = is_username_used (username);
+        empty = username[0] == 0;
+        toolong = strlen (username) > MAXNAMELEN;
+        valid = TRUE;
+
+        if (!in_use && !empty && !toolong) {
+                /* First char must be a letter, and it must only composed
+                 * of ASCII letters, digits, and a '.', '-', '_'
+                 */
+                for (c = username; *c; c++) {
+                        if (! ((*c >= 'a' && *c <= 'z') ||
+                               (*c >= 'A' && *c <= 'Z') ||
+                               (*c >= '0' && *c <= '9') ||
+                               (*c == '_') || (*c == '.') ||
+                               (*c == '-' && c != username)))
+                           valid = FALSE;
+                }
+        }
+
+        um->valid_username = !empty && !in_use && !toolong && valid;
+        gtk_widget_set_sensitive (um->ok_button, um->valid_name && um->valid_username);
+
+        entry = gtk_bin_get_child (GTK_BIN (combo));
+
+        if (!empty && (in_use || toolong || !valid)) {
+                if (in_use) {
+                        tip = g_strdup_printf (_("A user with the username '%s' already exists"),
+                                               username);
+                }
+                else if (toolong) {
+                        tip = g_strdup_printf (_("The username is too long"));
+                }
+                else if (username[0] == '-') {
+                        tip = g_strdup (_("The username cannot start with a '-'"));
+                }
+                else {
+                        tip = g_strdup (_("The username must consist of:\n"
+                                          " \xe2\x9e\xa3 letters from the English alphabet\n"
+                                          " \xe2\x9e\xa3 digits\n"
+                                          " \xe2\x9e\xa3 any of the characters '.', '-' and '_'"));
+                }
+
+                set_entry_validation_error (GTK_ENTRY (entry), tip);
+
+                g_free (tip);
+        }
+        else {
+                clear_entry_validation_error (GTK_ENTRY (entry));
+        }
+}
+
+static void
+name_changed (GtkEntry        *name_entry,
+              GParamSpec      *pspec,
+              UmAccountDialog *um)
+{
+        GtkWidget *entry;
+        GtkTreeModel *model;
+        gboolean in_use;
+        const char *name;
+        char *lc_name, *ascii_name, *stripped_name;
+        char **words1;
+        char **words2 = NULL;
+        char **w1, **w2;
+        char *c;
+        char *unicode_fallback = "?";
+        GString *first_word, *last_word;
+        GString *item1, *item2, *item3, *item4;
+        int len;
+        int nwords1, nwords2, i;
+        GHashTable *items;
+
+        entry = gtk_bin_get_child (GTK_BIN (um->username_combo));
+        model = gtk_combo_box_get_model (GTK_COMBO_BOX (um->username_combo));
+        gtk_list_store_clear (GTK_LIST_STORE (model));
+
+        name = gtk_entry_get_text (GTK_ENTRY (name_entry));
+
+        um->valid_name = (strlen (name) > 0);
+        gtk_widget_set_sensitive (um->ok_button, um->valid_name && um->valid_username);
+
+        if (!um->valid_name) {
+                gtk_entry_set_text (GTK_ENTRY (entry), "");
+                return;
+        }
+
+        ascii_name = g_convert_with_fallback (name, -1, "ASCII//TRANSLIT", "UTF-8",
+                                              unicode_fallback, NULL, NULL, NULL);
+
+        lc_name = g_ascii_strdown (ascii_name, -1);
+
+        /* remove all non ASCII alphanumeric chars from the name,
+         * apart from the few allowed symbols
+         */
+        stripped_name = g_strnfill (strlen (lc_name) + 1, '\0');
+        i = 0;
+        for (c = lc_name; *c; c++) {
+                if (!(g_ascii_isdigit (*c) || g_ascii_islower (*c) ||
+                    *c == ' ' || *c == '-' || *c == '.' || *c == '_' ||
+                    /* used to track invalid words, removed below */
+                    *c == '?') )
+                        continue;
+
+                    stripped_name[i] = *c;
+                    i++;
+        }
+
+        if (strlen (stripped_name) == 0) {
+                g_free (ascii_name);
+                g_free (lc_name);
+                g_free (stripped_name);
+                return;
+        }
+
+        /* we split name on spaces, and then on dashes, so that we can treat
+         * words linked with dashes the same way, i.e. both fully shown, or
+         * both abbreviated
+         */
+        words1 = g_strsplit_set (stripped_name, " ", -1);
+        len = g_strv_length (words1);
+
+        g_free (ascii_name);
+        g_free (lc_name);
+        g_free (stripped_name);
+
+        /* Concatenate the whole first word with the first letter of each
+         * word (item1), and the last word with the first letter of each
+         * word (item2). item3 and item4 are symmetrical respectively to
+         * item1 and item2.
+         *
+         * Constant 5 is the max reasonable number of words we may get when
+         * splitting on dashes, since we can't guess it at this point,
+         * and reallocating would be too bad.
+         */
+        item1 = g_string_sized_new (strlen (words1[0]) + len - 1 + 5);
+        item3 = g_string_sized_new (strlen (words1[0]) + len - 1 + 5);
+
+        item2 = g_string_sized_new (strlen (words1[len - 1]) + len - 1 + 5);
+        item4 = g_string_sized_new (strlen (words1[len - 1]) + len - 1 + 5);
+
+        /* again, guess at the max size of names */
+        first_word = g_string_sized_new (20);
+        last_word = g_string_sized_new (20);
+
+        nwords1 = 0;
+        nwords2 = 0;
+        for (w1 = words1; *w1; w1++) {
+                if (strlen (*w1) == 0)
+                        continue;
+
+                /* skip words with string '?', most likely resulting
+                 * from failed transliteration to ASCII
+                 */
+                if (strstr (*w1, unicode_fallback) != NULL)
+                        continue;
+
+                nwords1++; /* count real words, excluding empty string */
+
+                words2 = g_strsplit_set (*w1, "-", -1);
+                /* reset last word if a new non-empty word has been found */
+                if (strlen (*words2) > 0)
+                        last_word = g_string_set_size (last_word, 0);
+
+                for (w2 = words2; *w2; w2++) {
+                        if (strlen (*w2) == 0)
+                                continue;
+
+                        nwords2++;
+
+                        /* part of the first "toplevel" real word */
+                        if (nwords1 == 1) {
+                                item1 = g_string_append (item1, *w2);
+                                first_word = g_string_append (first_word, *w2);
+                        }
+                        else {
+                                item1 = g_string_append_unichar (item1,
+                                                                 g_utf8_get_char (*w2));
+                                item3 = g_string_append_unichar (item3,
+                                                                 g_utf8_get_char (*w2));
+                        }
+
+                        /* not part of the last "toplevel" word */
+                        if (w1 != words1 + len - 1) {
+                                item2 = g_string_append_unichar (item2,
+                                                                 g_utf8_get_char (*w2));
+                                item4 = g_string_append_unichar (item4,
+                                                                 g_utf8_get_char (*w2));
+                        }
+
+                        /* always save current word so that we have it if last one reveals empty */
+                        last_word = g_string_append (last_word, *w2);
+                }
+
+                g_strfreev (words2);
+        }
+        item2 = g_string_append (item2, last_word->str);
+        item3 = g_string_append (item3, first_word->str);
+        item4 = g_string_prepend (item4, last_word->str);
+
+        items = g_hash_table_new (g_str_hash, g_str_equal);
+
+        in_use = is_username_used (item1->str);
+        if (nwords2 > 0 && !in_use && !g_ascii_isdigit (item1->str[0])) {
+                gtk_combo_box_append_text (GTK_COMBO_BOX (um->username_combo), item1->str);
+                g_hash_table_insert (items, item1->str, item1->str);
+        }
+
+        /* if there's only one word, would be the same as item1 */
+        if (nwords2 > 1) {
+                /* add other items */
+                in_use = is_username_used (item2->str);
+                if (!in_use && !g_ascii_isdigit (item2->str[0]) &&
+                    !g_hash_table_lookup (items, item2->str)) {
+                        gtk_combo_box_append_text (GTK_COMBO_BOX (um->username_combo), item2->str);
+                        g_hash_table_insert (items, item2->str, item2->str);
+                }
+
+                in_use = is_username_used (item3->str);
+                if (!in_use && !g_ascii_isdigit (item3->str[0]) &&
+                    !g_hash_table_lookup (items, item3->str)) {
+                        gtk_combo_box_append_text (GTK_COMBO_BOX (um->username_combo), item3->str);
+                        g_hash_table_insert (items, item3->str, item3->str);
+                }
+
+                in_use = is_username_used (item4->str);
+                if (!in_use && !g_ascii_isdigit (item4->str[0]) &&
+                    !g_hash_table_lookup (items, item4->str)) {
+                        gtk_combo_box_append_text (GTK_COMBO_BOX (um->username_combo), item4->str);
+                        g_hash_table_insert (items, item4->str, item4->str);
+                }
+
+                /* add the last word */
+                in_use = is_username_used (last_word->str);
+                if (!in_use && !g_ascii_isdigit (last_word->str[0]) &&
+                    !g_hash_table_lookup (items, last_word->str)) {
+                        gtk_combo_box_append_text (GTK_COMBO_BOX (um->username_combo), last_word->str);
+                        g_hash_table_insert (items, last_word->str, last_word->str);
+                }
+
+                /* ...and the first one */
+                in_use = is_username_used (first_word->str);
+                if (!in_use && !g_ascii_isdigit (first_word->str[0]) &&
+                    !g_hash_table_lookup (items, first_word->str)) {
+                        gtk_combo_box_append_text (GTK_COMBO_BOX (um->username_combo), first_word->str);
+                        g_hash_table_insert (items, first_word->str, first_word->str);
+                }
+        }
+
+        gtk_combo_box_set_active (GTK_COMBO_BOX (um->username_combo), 0);
+        g_hash_table_destroy (items);
+        g_strfreev (words1);
+        g_string_free (first_word, TRUE);
+        g_string_free (last_word, TRUE);
+        g_string_free (item1, TRUE);
+        g_string_free (item2, TRUE);
+        g_string_free (item3, TRUE);
+        g_string_free (item4, TRUE);
+}
+
+UmAccountDialog *
+um_account_dialog_new (void)
+{
+        GtkBuilder *builder;
+        GtkWidget *widget;
+        UmAccountDialog *um;
+        const gchar *filename;
+        GError *error = NULL;
+
+        builder = gtk_builder_new ();
+
+        filename = UIDIR "/account-dialog.ui";
+        if (!g_file_test (filename, G_FILE_TEST_EXISTS))
+                filename = "../data/account-dialog.ui";
+        if (!gtk_builder_add_from_file (builder, filename, &error)) {
+                g_error ("%s", error->message);
+                g_error_free (error);
+                exit (1);
+        }
+
+        um = g_new0 (UmAccountDialog, 1);
+
+        widget = (GtkWidget *) gtk_builder_get_object (builder, "dialog");
+        g_signal_connect (widget, "delete-event",
+                          G_CALLBACK (gtk_widget_hide_on_delete), NULL);
+        um->dialog = widget;
+
+        widget = (GtkWidget *) gtk_builder_get_object (builder, "cancel-button");
+        g_signal_connect (widget, "clicked",
+                          G_CALLBACK (cancel_account_dialog), um);
+
+        widget = (GtkWidget *) gtk_builder_get_object (builder, "ok-button");
+        g_signal_connect (widget, "clicked",
+                          G_CALLBACK (accept_account_dialog), um);
+        gtk_widget_grab_default (widget);
+
+        widget = (GtkWidget *) gtk_builder_get_object (builder, "username-combo");
+        g_signal_connect (widget, "changed",
+                          G_CALLBACK (username_changed), um);
+        um->username_combo = widget;
+
+        widget = (GtkWidget *) gtk_builder_get_object (builder, "name-entry");
+        g_signal_connect (widget, "notify::text",
+                          G_CALLBACK (name_changed), um);
+        um->name_entry = widget;
+
+        um->ok_button = (GtkWidget *) gtk_builder_get_object (builder, "ok-button");
+
+        widget = (GtkWidget *) gtk_builder_get_object (builder, "account-type-combo");
+        um->account_type_combo = widget;
+
+        return um;
+}
+
+void
+um_account_dialog_free (UmAccountDialog *um)
+{
+        gtk_widget_destroy (um->dialog);
+        g_free (um);
+}
+
+void
+um_account_dialog_show (UmAccountDialog     *um,
+                        GtkWindow           *parent,
+                        UserCreatedCallback  user_created_callback,
+                        gpointer             user_created_data)
+{
+        GtkTreeModel *model;
+
+        gtk_entry_set_text (GTK_ENTRY (um->name_entry), "");
+        gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (um->username_combo))), "");
+        model = gtk_combo_box_get_model (GTK_COMBO_BOX (um->username_combo));
+        gtk_list_store_clear (GTK_LIST_STORE (model));
+        gtk_combo_box_set_active (GTK_COMBO_BOX (um->account_type_combo), 0);
+
+        gtk_window_set_transient_for (GTK_WINDOW (um->dialog), parent);
+        gtk_window_present (GTK_WINDOW (um->dialog));
+        gtk_widget_grab_focus (um->name_entry);
+
+        um->valid_name = um->valid_username = TRUE;
+
+        um->user_created_callback = user_created_callback;
+        um->user_created_data = user_created_data;
+}
+
+
diff --git a/panels/user-accounts/um-account-dialog.h b/panels/user-accounts/um-account-dialog.h
new file mode 100644
index 0000000..e3b2ebc
--- /dev/null
+++ b/panels/user-accounts/um-account-dialog.h
@@ -0,0 +1,43 @@
+/* -*- 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_ACCOUNT_DIALOG_H__
+#define __UM_ACCOUNT_DIALOG_H__
+
+#include <gtk/gtk.h>
+#include "um-user.h"
+
+G_BEGIN_DECLS
+
+typedef struct _UmAccountDialog UmAccountDialog;
+
+typedef void (*UserCreatedCallback) (UmUser *user, gpointer data);
+
+UmAccountDialog *um_account_dialog_new      (void);
+void             um_account_dialog_free     (UmAccountDialog     *dialog);
+void             um_account_dialog_show     (UmAccountDialog     *dialog,
+                                             GtkWindow           *parent,
+                                             UserCreatedCallback  user_created,
+                                             gpointer             data);
+
+G_END_DECLS
+
+#endif
diff --git a/panels/user-accounts/um-account-type.c b/panels/user-accounts/um-account-type.c
new file mode 100644
index 0000000..55064a8
--- /dev/null
+++ b/panels/user-accounts/um-account-type.c
@@ -0,0 +1,43 @@
+/* -*- 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 <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+
+#include "um-account-type.h"
+
+const gchar *
+um_account_type_get_name (UmAccountType account_type)
+{
+        switch (account_type) {
+        case UM_ACCOUNT_TYPE_STANDARD:
+                return C_("Account type", "Standard");
+        case UM_ACCOUNT_TYPE_ADMINISTRATOR:
+                return C_("Account type", "Administrator");
+        case UM_ACCOUNT_TYPE_SUPERVISED:
+                return C_("Account type", "Supervised");
+        default:
+                g_assert_not_reached ();
+        }
+}
diff --git a/panels/user-accounts/um-account-type.h b/panels/user-accounts/um-account-type.h
new file mode 100644
index 0000000..1e42e00
--- /dev/null
+++ b/panels/user-accounts/um-account-type.h
@@ -0,0 +1,37 @@
+/* -*- 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_ACCOUNT_TYPE__
+#define __UM_ACCOUNT_TYPE__
+
+G_BEGIN_DECLS
+
+typedef enum {
+  UM_ACCOUNT_TYPE_STANDARD,
+  UM_ACCOUNT_TYPE_ADMINISTRATOR,
+  UM_ACCOUNT_TYPE_SUPERVISED
+} UmAccountType;
+
+const gchar *um_account_type_get_name (UmAccountType account_type);
+
+G_END_DECLS
+
+#endif
diff --git a/panels/user-accounts/um-crop-area.c b/panels/user-accounts/um-crop-area.c
new file mode 100644
index 0000000..4b6bacb
--- /dev/null
+++ b/panels/user-accounts/um-crop-area.c
@@ -0,0 +1,817 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright 2009  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 <stdlib.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include "um-crop-area.h"
+
+struct _UmCropAreaPrivate {
+        GdkPixbuf *browse_pixbuf;
+        GdkPixbuf *pixbuf;
+        GdkPixbuf *color_shifted;
+        gdouble scale;
+        GdkRectangle image;
+        GdkCursorType current_cursor;
+        GdkRectangle crop;
+        gint active_region;
+        gint last_press_x;
+        gint last_press_y;
+        gint base_width;
+        gint base_height;
+        gdouble aspect;
+};
+
+G_DEFINE_TYPE (UmCropArea, um_crop_area, GTK_TYPE_DRAWING_AREA);
+
+static inline guchar
+shift_color_byte (guchar b,
+                  int    shift)
+{
+        return CLAMP(b + shift, 0, 255);
+}
+
+static void
+shift_colors (GdkPixbuf *pixbuf,
+              gint       red,
+              gint       green,
+              gint       blue,
+              gint       alpha)
+{
+        gint x, y, offset, y_offset, rowstride, width, height;
+        guchar *pixels;
+        gint channels;
+
+        width = gdk_pixbuf_get_width (pixbuf);
+        height = gdk_pixbuf_get_height (pixbuf);
+        rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+        pixels = gdk_pixbuf_get_pixels (pixbuf);
+        channels = gdk_pixbuf_get_n_channels (pixbuf);
+
+        for (y = 0; y < height; y++) {
+                y_offset = y * rowstride;
+                for (x = 0; x < width; x++) {
+                        offset = y_offset + x * channels;
+                        if (red != 0)
+                                pixels[offset] = shift_color_byte (pixels[offset], red);
+                        if (green != 0)
+                                pixels[offset + 1] = shift_color_byte (pixels[offset + 1], green);
+                        if (blue != 0)
+                                pixels[offset + 2] = shift_color_byte (pixels[offset + 2], blue);
+                        if (alpha != 0 && channels >= 4)
+                                pixels[offset + 3] = shift_color_byte (pixels[offset + 3], blue);
+                }
+        }
+}
+
+static void
+update_pixbufs (UmCropArea *area)
+{
+        gint width;
+        gint height;
+        GtkAllocation allocation;
+        gdouble scale;
+        GdkColor *color;
+        guint32 pixel;
+        gint dest_x, dest_y, dest_width, dest_height;
+        GtkWidget *widget;
+        GtkStyle *style;
+
+        widget = GTK_WIDGET (area);
+        gtk_widget_get_allocation (widget, &allocation);
+        style = gtk_widget_get_style (widget);
+
+        if (area->priv->pixbuf == NULL ||
+            gdk_pixbuf_get_width (area->priv->pixbuf) != allocation.width ||
+            gdk_pixbuf_get_height (area->priv->pixbuf) != allocation.height) {
+                if (area->priv->pixbuf != NULL)
+                        g_object_unref (area->priv->pixbuf);
+                area->priv->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
+                                                     gdk_pixbuf_get_has_alpha (area->priv->browse_pixbuf),
+                                                     8,
+                                                     allocation.width, allocation.height);
+
+                color = &style->bg[gtk_widget_get_state (widget)];
+                pixel = ((color->red & 0xff00) << 16) |
+                        ((color->green & 0xff00) << 8) |
+                         (color->blue & 0xff00);
+                gdk_pixbuf_fill (area->priv->pixbuf, pixel);
+
+                width = gdk_pixbuf_get_width (area->priv->browse_pixbuf);
+                height = gdk_pixbuf_get_height (area->priv->browse_pixbuf);
+
+                scale = allocation.height / (gdouble)height;
+                if (scale * width > allocation.width)
+                    scale = allocation.width / (gdouble)width;
+
+                dest_width = width * scale;
+                dest_height = height * scale;
+                dest_x = (allocation.width - dest_width) / 2;
+                dest_y = (allocation.height - dest_height) / 2,
+
+                gdk_pixbuf_scale (area->priv->browse_pixbuf,
+                                  area->priv->pixbuf,
+                                  dest_x, dest_y,
+                                  dest_width, dest_height,
+                                  dest_x, dest_y,
+                                  scale, scale,
+                                  GDK_INTERP_BILINEAR);
+
+                if (area->priv->color_shifted)
+                        g_object_unref (area->priv->color_shifted);
+                area->priv->color_shifted = gdk_pixbuf_copy (area->priv->pixbuf);
+                shift_colors (area->priv->color_shifted, -32, -32, -32, 0);
+
+                if (area->priv->scale == 0.0) {
+                        area->priv->crop.width = 2 * area->priv->base_width / scale;
+                        area->priv->crop.height = 2 * area->priv->base_height / scale;
+                        area->priv->crop.x = (gdk_pixbuf_get_width (area->priv->browse_pixbuf) - area->priv->crop.width) / 2;
+                        area->priv->crop.y = (gdk_pixbuf_get_height (area->priv->browse_pixbuf) - area->priv->crop.height) / 2;
+                }
+
+                area->priv->scale = scale;
+                area->priv->image.x = dest_x;
+                area->priv->image.y = dest_y;
+                area->priv->image.width = dest_width;
+                area->priv->image.height = dest_height;
+        }
+}
+
+static void
+crop_to_widget (UmCropArea    *area,
+                GdkRectangle  *crop)
+{
+        crop->x = area->priv->image.x + area->priv->crop.x * area->priv->scale;
+        crop->y = area->priv->image.y + area->priv->crop.y * area->priv->scale;
+        crop->width = area->priv->crop.width * area->priv->scale;
+        crop->height = area->priv->crop.height * area->priv->scale;
+}
+
+typedef enum {
+        OUTSIDE,
+        INSIDE,
+        TOP,
+        TOP_LEFT,
+        TOP_RIGHT,
+        BOTTOM,
+        BOTTOM_LEFT,
+        BOTTOM_RIGHT,
+        LEFT,
+        RIGHT
+} Location;
+
+static gboolean
+um_crop_area_draw (GtkWidget *widget,
+                   cairo_t   *cr)
+{
+        GdkRectangle area;
+        GdkRectangle crop;
+        gint width, height;
+        UmCropArea *uarea = UM_CROP_AREA (widget);
+
+        if (uarea->priv->browse_pixbuf == NULL)
+                return FALSE;
+
+        update_pixbufs (uarea);
+
+        width = gdk_pixbuf_get_width (uarea->priv->pixbuf);
+        height = gdk_pixbuf_get_height (uarea->priv->pixbuf);
+        crop_to_widget (uarea, &crop);
+
+        gdk_cairo_set_source_pixbuf (cr, uarea->priv->color_shifted, 0, 0);
+        cairo_rectangle (cr, 0, 0, width, crop.y);
+        cairo_rectangle (cr, 0, crop.y, crop.x, crop.height);
+        cairo_rectangle (cr, crop.x + crop.width, crop.y, width - crop.x - crop.width, crop.height);
+        cairo_rectangle (cr, 0, crop.y + crop.height, width, height - crop.y - crop.height);
+        cairo_fill (cr);
+
+        gdk_cairo_set_source_pixbuf (cr, uarea->priv->pixbuf, 0, 0);
+        cairo_rectangle (cr, crop.x, crop.y, crop.width, crop.height);
+        cairo_fill (cr);
+
+        if (uarea->priv->active_region != OUTSIDE) {
+                gint x1, x2, y1, y2;
+                cairo_set_source_rgb (cr, 1, 1, 1);
+                cairo_set_line_width (cr, 1.0);
+                x1 = crop.x + crop.width / 3.0;
+                x2 = crop.x + 2 * crop.width / 3.0;
+                y1 = crop.y + crop.height / 3.0;
+                y2 = crop.y + 2 * crop.height / 3.0;
+
+                cairo_move_to (cr, x1 + 0.5, crop.y);
+                cairo_line_to (cr, x1 + 0.5, crop.y + crop.height);
+
+                cairo_move_to (cr, x2 + 0.5, crop.y);
+                cairo_line_to (cr, x2 + 0.5, crop.y + crop.height);
+
+                cairo_move_to (cr, crop.x, y1 + 0.5);
+                cairo_line_to (cr, crop.x + crop.width, y1 + 0.5);
+
+                cairo_move_to (cr, crop.x, y2 + 0.5);
+                cairo_line_to (cr, crop.x + crop.width, y2 + 0.5);
+                cairo_stroke (cr);
+        }
+
+        cairo_set_source_rgb (cr,  0, 0, 0);
+        cairo_set_line_width (cr, 1.0);
+        cairo_rectangle (cr,
+                         crop.x + 0.5,
+                         crop.y + 0.5,
+                         crop.width - 1.0,
+                         crop.height - 1.0);
+        cairo_stroke (cr);
+
+        cairo_set_source_rgb (cr, 1, 1, 1);
+        cairo_set_line_width (cr, 2.0);
+        cairo_rectangle (cr,
+                         crop.x + 2.0,
+                         crop.y + 2.0,
+                         crop.width - 4.0,
+                         crop.height - 4.0);
+        cairo_stroke (cr);
+
+        return FALSE;
+}
+
+typedef enum {
+        BELOW,
+        LOWER,
+        BETWEEN,
+        UPPER,
+        ABOVE
+} Range;
+
+static Range
+find_range (gint x,
+            gint min,
+            gint max)
+{
+        gint tolerance = 12;
+
+        if (x < min - tolerance)
+                return BELOW;
+        if (x <= min + tolerance)
+                return LOWER;
+        if (x < max - tolerance)
+                return BETWEEN;
+        if (x <= max + tolerance)
+                return UPPER;
+        return ABOVE;
+}
+
+static Location
+find_location (GdkRectangle *rect,
+               gint          x,
+               gint          y)
+{
+        Range x_range, y_range;
+        Location location[5][5] = {
+                { OUTSIDE, OUTSIDE,     OUTSIDE, OUTSIDE,      OUTSIDE },
+                { OUTSIDE, TOP_LEFT,    TOP,     TOP_RIGHT,    OUTSIDE },
+                { OUTSIDE, LEFT,        INSIDE,  RIGHT,        OUTSIDE },
+                { OUTSIDE, BOTTOM_LEFT, BOTTOM,  BOTTOM_RIGHT, OUTSIDE },
+                { OUTSIDE, OUTSIDE,     OUTSIDE, OUTSIDE,      OUTSIDE }
+        };
+
+        x_range = find_range (x, rect->x, rect->x + rect->width);
+        y_range = find_range (y, rect->y, rect->y + rect->height);
+
+        return location[y_range][x_range];
+}
+
+static void
+update_cursor (UmCropArea *area,
+               gint           x,
+               gint           y)
+{
+        gint cursor_type;
+        GdkRectangle crop;
+        gint region;
+
+        region = area->priv->active_region;
+        if (region == OUTSIDE) {
+                crop_to_widget (area, &crop);
+                region = find_location (&crop, x, y);
+        }
+
+        switch (region) {
+        case OUTSIDE:
+                cursor_type = GDK_LEFT_PTR;
+                break;
+        case TOP_LEFT:
+                cursor_type = GDK_TOP_LEFT_CORNER;
+                break;
+        case TOP:
+                cursor_type = GDK_TOP_SIDE;
+                break;
+        case TOP_RIGHT:
+                cursor_type = GDK_TOP_RIGHT_CORNER;
+                break;
+        case LEFT:
+                cursor_type = GDK_LEFT_SIDE;
+                break;
+        case INSIDE:
+                cursor_type = GDK_FLEUR;
+                break;
+        case RIGHT:
+                cursor_type = GDK_RIGHT_SIDE;
+                break;
+        case BOTTOM_LEFT:
+                cursor_type = GDK_BOTTOM_LEFT_CORNER;
+                break;
+        case BOTTOM:
+                cursor_type = GDK_BOTTOM_SIDE;
+                break;
+        case BOTTOM_RIGHT:
+                cursor_type = GDK_BOTTOM_RIGHT_CORNER;
+                break;
+        }
+
+        if (cursor_type != area->priv->current_cursor) {
+                GdkCursor *cursor = gdk_cursor_new (cursor_type);
+                gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (area)), cursor);
+                gdk_cursor_unref (cursor);
+                area->priv->current_cursor = cursor_type;
+        }
+}
+
+static int
+eval_radial_line (gdouble center_x, gdouble center_y,
+                  gdouble bounds_x, gdouble bounds_y,
+                  gdouble user_x)
+{
+        gdouble decision_slope;
+        gdouble decision_intercept;
+
+        decision_slope = (bounds_y - center_y) / (bounds_x - center_x);
+        decision_intercept = bounds_y = -(decision_slope * bounds_x);
+
+        return (int) (decision_slope * user_x + decision_intercept);
+}
+
+static gboolean
+um_crop_area_motion_notify_event (GtkWidget      *widget,
+                                  GdkEventMotion *event)
+{
+        UmCropArea *area = UM_CROP_AREA (widget);
+        gint x, y;
+        gint delta_x, delta_y;
+        gint width, height;
+        gint adj_width, adj_height;
+        gint pb_width, pb_height;
+        GdkRectangle damage;
+        gint left, right, top, bottom;
+        gdouble new_width, new_height;
+        gdouble center_x, center_y;
+        gint min_width, min_height;
+
+        if (area->priv->browse_pixbuf == NULL)
+                return FALSE;
+
+        update_cursor (area, event->x, event->y);
+
+        crop_to_widget (area, &damage);
+        gtk_widget_queue_draw_area (widget,
+                                    damage.x - 1, damage.y - 1,
+                                    damage.width + 2, damage.height + 2);
+
+        pb_width = gdk_pixbuf_get_width (area->priv->browse_pixbuf);
+        pb_height = gdk_pixbuf_get_height (area->priv->browse_pixbuf);
+
+        x = (event->x - area->priv->image.x) / area->priv->scale;
+        y = (event->y - area->priv->image.y) / area->priv->scale;
+
+        delta_x = x - area->priv->last_press_x;
+        delta_y = y - area->priv->last_press_y;
+        area->priv->last_press_x = x;
+        area->priv->last_press_y = y;
+
+        left = area->priv->crop.x;
+        right = area->priv->crop.x + area->priv->crop.width - 1;
+        top = area->priv->crop.y;
+        bottom = area->priv->crop.y + area->priv->crop.height - 1;
+
+        center_x = (left + right) / 2.0;
+        center_y = (top + bottom) / 2.0;
+
+        switch (area->priv->active_region) {
+        case INSIDE:
+                width = right - left + 1;
+                height = bottom - top + 1;
+
+                left += delta_x;
+                right += delta_x;
+                top += delta_y;
+                bottom += delta_y;
+
+                if (left < 0)
+                        left = 0;
+                if (top < 0)
+                        top = 0;
+                if (right > pb_width)
+                        right = pb_width;
+                if (bottom > pb_height)
+                        bottom = pb_height;
+
+                adj_width = right - left + 1;
+                adj_height = bottom - top + 1;
+                if (adj_width != width) {
+                        if (delta_x < 0)
+                                right = left + width - 1;
+                        else
+                                left = right - width + 1;
+                }
+                if (adj_height != height) {
+                        if (delta_y < 0)
+                                bottom = top + height - 1;
+                        else
+                                top = bottom - height + 1;
+                }
+
+                break;
+
+        case TOP_LEFT:
+                if (area->priv->aspect < 0) {
+                        top = y;
+                        left = x;
+                }
+                else if (y < eval_radial_line (center_x, center_y, left, top, x)) {
+                        top = y;
+                        new_width = (bottom - top) * area->priv->aspect;
+                        left = right - new_width;
+                }
+                else {
+                        left = x;
+                        new_height = (right - left) / area->priv->aspect;
+                        top = bottom - new_height;
+                }
+                break;
+
+        case TOP:
+                top = y;
+                if (area->priv->aspect > 0) {
+                        new_width = (bottom - top) * area->priv->aspect;
+                        right = left + new_width;
+                }
+                break;
+
+        case TOP_RIGHT:
+                if (area->priv->aspect < 0) {
+                        top = y;
+                        right = x;
+                }
+                else if (y < eval_radial_line (center_x, center_y, right, top, x)) {
+                        top = y;
+                        new_width = (bottom - top) * area->priv->aspect;
+                        right = left + new_width;
+                }
+                else {
+                        right = x;
+                        new_height = (right - left) / area->priv->aspect;
+                        top = bottom - new_height;
+                }
+                break;
+
+        case LEFT:
+                left = x;
+                if (area->priv->aspect > 0) {
+                        new_height = (right - left) / area->priv->aspect;
+                        bottom = top + new_height;
+                }
+                break;
+
+        case BOTTOM_LEFT:
+                if (area->priv->aspect < 0) {
+                        bottom = y;
+                        left = x;
+                }
+                else if (y < eval_radial_line (center_x, center_y, left, bottom, x)) {
+                        left = x;
+                        new_height = (right - left) / area->priv->aspect;
+                        bottom = top + new_height;
+                }
+                else {
+                        bottom = y;
+                        new_width = (bottom - top) * area->priv->aspect;
+                        left = right - new_width;
+                }
+                break;
+
+        case RIGHT:
+                right = x;
+                if (area->priv->aspect > 0) {
+                        new_height = (right - left) / area->priv->aspect;
+                        bottom = top + new_height;
+                }
+                break;
+
+        case BOTTOM_RIGHT:
+                if (area->priv->aspect < 0) {
+                        bottom = y;
+                        right = x;
+                }
+                else if (y < eval_radial_line (center_x, center_y, right, bottom, x)) {
+                        right = x;
+                        new_height = (right - left) / area->priv->aspect;
+                        bottom = top + new_height;
+                }
+                else {
+                        bottom = y;
+                        new_width = (bottom - top) * area->priv->aspect;
+                        right = left + new_width;
+                }
+                break;
+
+        case BOTTOM:
+                bottom = y;
+                if (area->priv->aspect > 0) {
+                        new_width = (bottom - top) * area->priv->aspect;
+                        right= left + new_width;
+                }
+                break;
+
+        default:
+                return FALSE;
+        }
+
+        min_width = area->priv->base_width / area->priv->scale;
+        min_height = area->priv->base_height / area->priv->scale;
+
+        width = right - left + 1;
+        height = bottom - top + 1;
+        if (area->priv->aspect < 0) {
+                if (left < 0)
+                        left = 0;
+                if (top < 0)
+                        top = 0;
+                if (right > pb_width)
+                        right = pb_width;
+                if (bottom > pb_height)
+                        bottom = pb_height;
+
+                width = right - left + 1;
+                height = bottom - top + 1;
+
+                switch (area->priv->active_region) {
+                case LEFT:
+                case TOP_LEFT:
+                case BOTTOM_LEFT:
+                        if (width < min_width)
+                                left = right - min_width;
+                        break;
+                case RIGHT:
+                case TOP_RIGHT:
+                case BOTTOM_RIGHT:
+                        if (width < min_width)
+                                right = left + min_width;
+                        break;
+
+                default: ;
+                }
+
+                switch (area->priv->active_region) {
+                case TOP:
+                case TOP_LEFT:
+                case TOP_RIGHT:
+                        if (height < min_height)
+                                top = bottom - min_height;
+                        break;
+                case BOTTOM:
+                case BOTTOM_LEFT:
+                case BOTTOM_RIGHT:
+                        if (height < min_height)
+                                bottom = top + min_height;
+                        break;
+
+                default: ;
+                }
+        }
+        else {
+                if (left < 0 || top < 0 ||
+                    right > pb_width || bottom > pb_height ||
+                    width < min_width || height < min_height) {
+                        left = area->priv->crop.x;
+                        right = area->priv->crop.x + area->priv->crop.width - 1;
+                        top = area->priv->crop.y;
+                        bottom = area->priv->crop.y + area->priv->crop.height - 1;
+                }
+        }
+
+        area->priv->crop.x = left;
+        area->priv->crop.y = top;
+        area->priv->crop.width = right - left + 1;
+        area->priv->crop.height = bottom - top + 1;
+
+        crop_to_widget (area, &damage);
+        gtk_widget_queue_draw_area (widget,
+                                    damage.x - 1, damage.y - 1,
+                                    damage.width + 2, damage.height + 2);
+
+        return FALSE;
+}
+
+static gboolean
+um_crop_area_button_press_event (GtkWidget      *widget,
+                                 GdkEventButton *event)
+{
+        UmCropArea *area = UM_CROP_AREA (widget);
+        GdkRectangle crop;
+
+        if (area->priv->browse_pixbuf == NULL)
+                return FALSE;
+
+        crop_to_widget (area, &crop);
+
+        area->priv->last_press_x = (event->x - area->priv->image.x) / area->priv->scale;
+        area->priv->last_press_y = (event->y - area->priv->image.y) / area->priv->scale;
+        area->priv->active_region = find_location (&crop, event->x, event->y);
+
+        gtk_widget_queue_draw_area (widget,
+                                    crop.x - 1, crop.y - 1,
+                                    crop.width + 2, crop.height + 2);
+
+        return FALSE;
+}
+
+static gboolean
+um_crop_area_button_release_event (GtkWidget      *widget,
+                                   GdkEventButton *event)
+{
+        UmCropArea *area = UM_CROP_AREA (widget);
+        GdkRectangle crop;
+
+        if (area->priv->browse_pixbuf == NULL)
+                return FALSE;
+
+        crop_to_widget (area, &crop);
+
+        area->priv->last_press_x = -1;
+        area->priv->last_press_y = -1;
+        area->priv->active_region = OUTSIDE;
+
+        gtk_widget_queue_draw_area (widget,
+                                    crop.x - 1, crop.y - 1,
+                                    crop.width + 2, crop.height + 2);
+
+        return FALSE;
+}
+
+static void
+um_crop_area_finalize (GObject *object)
+{
+        UmCropArea *area = UM_CROP_AREA (object);
+
+        if (area->priv->browse_pixbuf) {
+                g_object_unref (area->priv->browse_pixbuf);
+                area->priv->browse_pixbuf = NULL;
+        }
+        if (area->priv->pixbuf) {
+                g_object_unref (area->priv->pixbuf);
+                area->priv->pixbuf = NULL;
+        }
+        if (area->priv->color_shifted) {
+                g_object_unref (area->priv->color_shifted);
+                area->priv->color_shifted = NULL;
+        }
+}
+
+static void
+um_crop_area_class_init (UmCropAreaClass *klass)
+{
+        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
+        GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+        object_class->finalize = um_crop_area_finalize;
+        widget_class->draw = um_crop_area_draw;
+        widget_class->button_press_event = um_crop_area_button_press_event;
+        widget_class->button_release_event = um_crop_area_button_release_event;
+        widget_class->motion_notify_event = um_crop_area_motion_notify_event;
+
+        g_type_class_add_private (klass, sizeof (UmCropAreaPrivate));
+}
+
+static void
+um_crop_area_init (UmCropArea *area)
+{
+        area->priv = (G_TYPE_INSTANCE_GET_PRIVATE ((area), UM_TYPE_CROP_AREA,
+                                                   UmCropAreaPrivate));
+
+        gtk_widget_add_events (GTK_WIDGET (area), GDK_POINTER_MOTION_MASK |
+                               GDK_BUTTON_PRESS_MASK |
+                               GDK_BUTTON_RELEASE_MASK);
+
+        area->priv->scale = 0.0;
+        area->priv->image.x = 0;
+        area->priv->image.y = 0;
+        area->priv->image.width = 0;
+        area->priv->image.height = 0;
+        area->priv->active_region = OUTSIDE;
+        area->priv->base_width = 48;
+        area->priv->base_height = 48;
+        area->priv->aspect = 1;
+}
+
+GtkWidget *
+um_crop_area_new (void)
+{
+        return g_object_new (UM_TYPE_CROP_AREA, NULL);
+}
+
+GdkPixbuf *
+um_crop_area_get_picture (UmCropArea *area)
+{
+        gint width, height;
+
+        width = gdk_pixbuf_get_width (area->priv->browse_pixbuf);
+        height = gdk_pixbuf_get_height (area->priv->browse_pixbuf);
+        width = MIN (area->priv->crop.width, width - area->priv->crop.x);
+        height = MIN (area->priv->crop.height, height - area->priv->crop.y);
+
+        return gdk_pixbuf_new_subpixbuf (area->priv->browse_pixbuf,
+                                         area->priv->crop.x,
+                                         area->priv->crop.y,
+                                         width, height);
+}
+
+void
+um_crop_area_set_picture (UmCropArea *area,
+                          GdkPixbuf  *pixbuf)
+{
+        int width;
+        int height;
+
+        if (area->priv->browse_pixbuf) {
+                g_object_unref (area->priv->browse_pixbuf);
+                area->priv->browse_pixbuf = NULL;
+        }
+        if (pixbuf) {
+                area->priv->browse_pixbuf = g_object_ref (pixbuf);
+                width = gdk_pixbuf_get_width (pixbuf);
+                height = gdk_pixbuf_get_height (pixbuf);
+        } else {
+                width = 0;
+                height = 0;
+        }
+
+        area->priv->crop.width = 2 * area->priv->base_width;
+        area->priv->crop.height = 2 * area->priv->base_height;
+        area->priv->crop.x = (width - area->priv->crop.width) / 2;
+        area->priv->crop.y = (height - area->priv->crop.height) / 2;
+
+        area->priv->scale = 0.0;
+        area->priv->image.x = 0;
+        area->priv->image.y = 0;
+        area->priv->image.width = 0;
+        area->priv->image.height = 0;
+
+        gtk_widget_queue_draw (GTK_WIDGET (area));
+}
+
+void
+um_crop_area_set_min_size (UmCropArea *area,
+                           gint        width,
+                           gint        height)
+{
+        area->priv->base_width = width;
+        area->priv->base_height = height;
+
+        if (area->priv->aspect > 0) {
+                area->priv->aspect = area->priv->base_width / (gdouble)area->priv->base_height;
+        }
+}
+
+void
+um_crop_area_set_constrain_aspect (UmCropArea *area,
+                                   gboolean    constrain)
+{
+        if (constrain) {
+                area->priv->aspect = area->priv->base_width / (gdouble)area->priv->base_height;
+        }
+        else {
+                area->priv->aspect = -1;
+        }
+}
+
diff --git a/panels/user-accounts/um-crop-area.h b/panels/user-accounts/um-crop-area.h
new file mode 100644
index 0000000..8992957
--- /dev/null
+++ b/panels/user-accounts/um-crop-area.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright © 2009 Bastien Nocera <hadess hadess net>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * 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/>.
+ */
+
+#ifndef _UM_CROP_AREA_H_
+#define _UM_CROP_AREA_H_
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define UM_TYPE_CROP_AREA (um_crop_area_get_type ())
+#define UM_CROP_AREA(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), UM_TYPE_CROP_AREA, \
+                                                                           UmCropArea))
+#define UM_CROP_AREA_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), UM_TYPE_CROP_AREA, \
+                                                                        UmCropAreaClass))
+#define UM_IS_CROP_AREA(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UM_TYPE_CROP_AREA))
+#define UM_IS_CROP_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UM_TYPE_CROP_AREA))
+#define UM_CROP_AREA_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), UM_TYPE_CROP_AREA, \
+                                                                          UmCropAreaClass))
+
+typedef struct _UmCropAreaClass UmCropAreaClass;
+typedef struct _UmCropArea UmCropArea;
+typedef struct _UmCropAreaPrivate UmCropAreaPrivate;
+
+struct _UmCropAreaClass {
+        GtkDrawingAreaClass parent_class;
+};
+
+struct _UmCropArea {
+        GtkDrawingArea parent_instance;
+        UmCropAreaPrivate *priv;
+};
+
+GType      um_crop_area_get_type             (void) G_GNUC_CONST;
+
+GtkWidget *um_crop_area_new                  (void);
+GdkPixbuf *um_crop_area_get_picture          (UmCropArea *area);
+void       um_crop_area_set_picture          (UmCropArea *area,
+                                              GdkPixbuf  *pixbuf);
+void       um_crop_area_set_min_size         (UmCropArea *area,
+                                              gint        width,
+                                              gint        height);
+void       um_crop_area_set_constrain_aspect (UmCropArea *area,
+                                              gboolean    constrain);
+
+G_END_DECLS
+
+#endif /* _UM_CROP_AREA_H_ */
diff --git a/panels/user-accounts/um-editable-button.c b/panels/user-accounts/um-editable-button.c
new file mode 100644
index 0000000..3212459
--- /dev/null
+++ b/panels/user-accounts/um-editable-button.c
@@ -0,0 +1,403 @@
+/* -*- 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 <gdk/gdkkeysyms.h>
+#include "um-editable-button.h"
+
+#define EMPTY_TEXT "\xe2\x80\x94"
+
+struct _UmEditableButtonPrivate {
+        GtkNotebook *notebook;
+        GtkLabel    *label;
+        GtkButton   *button;
+
+        gchar *text;
+        gboolean editable;
+        gint weight;
+        gboolean weight_set;
+        gdouble scale;
+        gboolean scale_set;
+};
+
+#define UM_EDITABLE_BUTTON_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), UM_TYPE_EDITABLE_BUTTON, UmEditableButtonPrivate))
+
+enum {
+        PROP_0,
+        PROP_TEXT,
+        PROP_EDITABLE,
+        PROP_SCALE,
+        PROP_SCALE_SET,
+        PROP_WEIGHT,
+        PROP_WEIGHT_SET
+};
+
+enum {
+        START_EDITING,
+        LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL] = { 0, };
+
+G_DEFINE_TYPE (UmEditableButton, um_editable_button, GTK_TYPE_ALIGNMENT);
+
+void
+um_editable_button_set_text (UmEditableButton *button,
+                             const gchar      *text)
+{
+        UmEditableButtonPrivate *priv;
+        gchar *tmp;
+        GtkWidget *label;
+
+        priv = button->priv;
+
+        tmp = g_strdup (text);
+        g_free (priv->text);
+        priv->text = tmp;
+
+        if (tmp == NULL || tmp[0] == '\0')
+                tmp = EMPTY_TEXT;
+
+        gtk_label_set_text (priv->label, tmp);
+        label = gtk_bin_get_child (GTK_BIN (priv->button));
+        gtk_label_set_text (GTK_LABEL (label), tmp);
+
+        g_object_notify (G_OBJECT (button), "text");
+}
+
+const gchar *
+um_editable_button_get_text (UmEditableButton *button)
+{
+        return button->priv->text;
+}
+
+void
+um_editable_button_set_editable (UmEditableButton *button,
+                                 gboolean          editable)
+{
+        UmEditableButtonPrivate *priv;
+
+        priv = button->priv;
+
+        if (priv->editable != editable) {
+                priv->editable = editable;
+
+                gtk_notebook_set_current_page (priv->notebook, editable ? 1 : 0);
+
+                g_object_notify (G_OBJECT (button), "editable");
+        }
+}
+
+gboolean
+um_editable_button_get_editable (UmEditableButton *button)
+{
+        return button->priv->editable;
+}
+
+static void
+update_fonts (UmEditableButton *button)
+{
+        PangoAttrList *attrs;
+        PangoAttribute *attr;
+        GtkWidget *label;
+
+        UmEditableButtonPrivate *priv = button->priv;
+
+        attrs = pango_attr_list_new ();
+        if (priv->scale_set) {
+                attr = pango_attr_scale_new (priv->scale);
+                pango_attr_list_insert (attrs, attr);
+        }
+        if (priv->weight_set) {
+                attr = pango_attr_weight_new (priv->weight);
+                pango_attr_list_insert (attrs, attr);
+        }
+
+        gtk_label_set_attributes (priv->label, attrs);
+
+        label = gtk_bin_get_child (GTK_BIN (priv->button));
+        gtk_label_set_attributes (GTK_LABEL (label), attrs);
+
+        pango_attr_list_unref (attrs);
+}
+
+void
+um_editable_button_set_weight (UmEditableButton *button,
+                               gint              weight)
+{
+        UmEditableButtonPrivate *priv = button->priv;
+
+        if (priv->weight == weight && priv->weight_set)
+                return;
+
+        priv->weight = weight;
+        priv->weight_set = TRUE;
+
+        update_fonts (button);
+
+        g_object_notify (G_OBJECT (button), "weight");
+        g_object_notify (G_OBJECT (button), "weight-set");
+}
+
+gint
+um_editable_button_get_weight (UmEditableButton *button)
+{
+        return button->priv->weight;
+}
+
+void
+um_editable_button_set_scale (UmEditableButton *button,
+                              gdouble           scale)
+{
+        UmEditableButtonPrivate *priv = button->priv;
+
+        if (priv->scale == scale && priv->scale_set)
+                return;
+
+        priv->scale = scale;
+        priv->scale_set = TRUE;
+
+        update_fonts (button);
+
+        g_object_notify (G_OBJECT (button), "scale");
+        g_object_notify (G_OBJECT (button), "scale-set");
+}
+
+gdouble
+um_editable_button_get_scale (UmEditableButton *button)
+{
+        return button->priv->scale;
+}
+
+static void
+um_editable_button_set_property (GObject      *object,
+                                 guint         prop_id,
+                                 const GValue *value,
+                                 GParamSpec   *pspec)
+{
+        UmEditableButton *button = UM_EDITABLE_BUTTON (object);
+
+        switch (prop_id) {
+        case PROP_TEXT:
+                um_editable_button_set_text (button, g_value_get_string (value));
+                break;
+        case PROP_EDITABLE:
+                um_editable_button_set_editable (button, g_value_get_boolean (value));
+                break;
+        case PROP_WEIGHT:
+                um_editable_button_set_weight (button, g_value_get_int (value));
+                break;
+        case PROP_WEIGHT_SET:
+                button->priv->weight_set = g_value_get_boolean (value);
+                break;
+        case PROP_SCALE:
+                um_editable_button_set_scale (button, g_value_get_double (value));
+                break;
+        case PROP_SCALE_SET:
+                button->priv->scale_set = g_value_get_boolean (value);
+                break;
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+        }
+}
+
+static void
+um_editable_button_get_property (GObject    *object,
+                                 guint       prop_id,
+                                 GValue     *value,
+                                 GParamSpec *pspec)
+{
+        UmEditableButton *button = UM_EDITABLE_BUTTON (object);
+
+        switch (prop_id) {
+        case PROP_TEXT:
+                g_value_set_string (value,
+                                    um_editable_button_get_text (button));
+                break;
+        case PROP_EDITABLE:
+                g_value_set_boolean (value,
+                                     um_editable_button_get_editable (button));
+                break;
+        case PROP_WEIGHT:
+                g_value_set_int (value,
+                                 um_editable_button_get_weight (button));
+                break;
+        case PROP_WEIGHT_SET:
+                g_value_set_boolean (value,
+                                     button->priv->weight_set);
+                break;
+        case PROP_SCALE:
+                g_value_set_double (value,
+                                    um_editable_button_get_scale (button));
+                break;
+        case PROP_SCALE_SET:
+                g_value_set_boolean (value,
+                                     button->priv->scale_set);
+                break;
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+        }
+}
+
+static void
+um_editable_button_finalize (GObject *object)
+{
+        UmEditableButton *button = (UmEditableButton*)object;
+
+        g_free (button->priv->text);
+
+        G_OBJECT_CLASS (um_editable_button_parent_class)->finalize (object);
+}
+
+static void
+um_editable_button_class_init (UmEditableButtonClass *class)
+{
+        GObjectClass *object_class;
+
+        object_class = G_OBJECT_CLASS (class);
+
+        object_class->set_property = um_editable_button_set_property;
+        object_class->get_property = um_editable_button_get_property;
+        object_class->finalize = um_editable_button_finalize;
+
+        signals[START_EDITING] =
+                g_signal_new ("start-editing",
+                              G_TYPE_FROM_CLASS (class),
+                              G_SIGNAL_RUN_LAST,
+                              G_STRUCT_OFFSET (UmEditableButtonClass, start_editing),
+                              NULL, NULL,
+                              g_cclosure_marshal_VOID__VOID,
+                              G_TYPE_NONE, 0);
+
+        g_object_class_install_property (object_class, PROP_TEXT,
+                g_param_spec_string ("text",
+                                     "Text", "The text of the button",
+                                     NULL,
+                                     G_PARAM_READWRITE));
+
+        g_object_class_install_property (object_class, PROP_EDITABLE,
+                g_param_spec_boolean ("editable",
+                                      "Editable", "Whether the text can be edited",
+                                      FALSE,
+                                      G_PARAM_READWRITE));
+
+        g_object_class_install_property (object_class, PROP_WEIGHT,
+                g_param_spec_int ("weight",
+                                  "Font Weight", "The font weight to use",
+                                  0, G_MAXINT, PANGO_WEIGHT_NORMAL,
+                                  G_PARAM_READWRITE));
+
+        g_object_class_install_property (object_class, PROP_WEIGHT_SET,
+                g_param_spec_boolean ("weight-set",
+                                      "Font Weight Set", "Whether a font weight is set",
+                                      FALSE,
+                                      G_PARAM_READWRITE));
+
+        g_object_class_install_property (object_class, PROP_SCALE,
+                g_param_spec_double ("scale",
+                                     "Font Scale", "The font scale to use",
+                                     0.0, G_MAXDOUBLE, 1.0,
+                                     G_PARAM_READWRITE));
+
+        g_object_class_install_property (object_class, PROP_SCALE_SET,
+                g_param_spec_boolean ("scale-set",
+                                      "Font Scale Set", "Whether a font scale is set",
+                                      FALSE,
+                                      G_PARAM_READWRITE));
+
+        g_type_class_add_private (class, sizeof (UmEditableButtonPrivate));
+}
+
+static void
+start_editing (UmEditableButton *button)
+{
+        g_signal_emit (button, signals[START_EDITING], 0);
+}
+
+static void
+button_clicked (GtkWidget        *widget,
+                UmEditableButton *button)
+{
+        start_editing (button);
+}
+
+static void
+update_button_padding (GtkWidget        *widget,
+                       GtkAllocation    *allocation,
+                       UmEditableButton *button)
+{
+        UmEditableButtonPrivate *priv = button->priv;
+        GtkAllocation parent_allocation;
+        gint offset;
+        gint pad;
+
+        gtk_widget_get_allocation (gtk_widget_get_parent (widget), &parent_allocation);
+
+        offset = allocation->x - parent_allocation.x;
+
+        gtk_misc_get_padding  (GTK_MISC (priv->label), &pad, NULL);
+        if (offset != pad)
+                gtk_misc_set_padding (GTK_MISC (priv->label), offset, 0);
+}
+
+static void
+um_editable_button_init (UmEditableButton *button)
+{
+        UmEditableButtonPrivate *priv;
+
+        priv = button->priv = UM_EDITABLE_BUTTON_GET_PRIVATE (button);
+
+        priv->weight = PANGO_WEIGHT_NORMAL;
+        priv->weight_set = FALSE;
+        priv->scale = 1.0;
+        priv->scale_set = FALSE;
+
+        priv->notebook = (GtkNotebook*)gtk_notebook_new ();
+        gtk_notebook_set_show_tabs (priv->notebook, FALSE);
+        gtk_notebook_set_show_border (priv->notebook, FALSE);
+
+        priv->label = (GtkLabel*)gtk_label_new (EMPTY_TEXT);
+        gtk_misc_set_alignment (GTK_MISC (priv->label), 0.0, 0.5);
+        gtk_notebook_append_page (priv->notebook, (GtkWidget*)priv->label, NULL);
+
+        priv->button = (GtkButton*)gtk_button_new_with_label (EMPTY_TEXT);
+        gtk_widget_set_receives_default ((GtkWidget*)priv->button, TRUE);
+        gtk_button_set_relief (priv->button, GTK_RELIEF_NONE);
+        gtk_button_set_alignment (priv->button, 0.0, 0.5);
+        gtk_notebook_append_page (priv->notebook, (GtkWidget*)priv->button, NULL);
+        g_signal_connect (priv->button, "clicked", G_CALLBACK (button_clicked), button);
+        g_signal_connect (gtk_bin_get_child (GTK_BIN (priv->button)), "size-allocate", G_CALLBACK (update_button_padding), button);
+
+        gtk_container_add (GTK_CONTAINER (button), (GtkWidget*)priv->notebook);
+
+        gtk_widget_show ((GtkWidget*)priv->notebook);
+        gtk_widget_show ((GtkWidget*)priv->label);
+        gtk_widget_show ((GtkWidget*)priv->button);
+
+        gtk_notebook_set_current_page (priv->notebook, 0);
+}
+
+GtkWidget *
+um_editable_button_new (void)
+{
+        return (GtkWidget *) g_object_new (UM_TYPE_EDITABLE_BUTTON, NULL);
+}
diff --git a/panels/user-accounts/um-editable-button.h b/panels/user-accounts/um-editable-button.h
new file mode 100644
index 0000000..36af622
--- /dev/null
+++ b/panels/user-accounts/um-editable-button.h
@@ -0,0 +1,72 @@
+/* -*- 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_EDITABLE_BUTTON_H
+#define _UM_EDITABLE_BUTTON_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define UM_TYPE_EDITABLE_BUTTON  um_editable_button_get_type()
+
+#define UM_EDITABLE_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), UM_TYPE_EDITABLE_BUTTON, UmEditableButton))
+#define UM_EDITABLE_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UM_TYPE_EDITABLE_BUTTON, UmEditableButtonClass))
+#define UM_IS_EDITABLE_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UM_TYPE_EDITABLE_BUTTON))
+#define UM_IS_EDITABLE_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UM_TYPE_EDITABLE_BUTTON))
+#define UM_EDITABLE_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), UM_TYPE_EDITABLE_BUTTON, UmEditableButtonClass))
+
+typedef struct _UmEditableButton UmEditableButton;
+typedef struct _UmEditableButtonClass UmEditableButtonClass;
+typedef struct _UmEditableButtonPrivate UmEditableButtonPrivate;
+
+struct _UmEditableButton
+{
+  GtkAlignment parent;
+
+  UmEditableButtonPrivate *priv;
+};
+
+struct _UmEditableButtonClass
+{
+  GtkAlignmentClass parent_class;
+
+  void (* start_editing) (UmEditableButton *button);
+};
+
+GType        um_editable_button_get_type     (void) G_GNUC_CONST;
+GtkWidget   *um_editable_button_new          (void);
+void         um_editable_button_set_text     (UmEditableButton *button,
+                                              const gchar      *text);
+const gchar *um_editable_button_get_text     (UmEditableButton *button);
+void         um_editable_button_set_editable (UmEditableButton *button,
+                                              gboolean          editable);
+gboolean     um_editable_button_get_editable (UmEditableButton *button);
+void         um_editable_button_set_weight   (UmEditableButton *button,
+                                              gint              weight);
+gint         um_editable_button_get_weight   (UmEditableButton *button);
+void         um_editable_button_set_scale    (UmEditableButton *button,
+                                              gdouble           scale);
+gdouble      um_editable_button_get_scale    (UmEditableButton *button);
+
+G_END_DECLS
+
+#endif /* _UM_EDITABLE_BUTTON_H_ */
diff --git a/panels/user-accounts/um-editable-combo.c b/panels/user-accounts/um-editable-combo.c
new file mode 100644
index 0000000..586bcdb
--- /dev/null
+++ b/panels/user-accounts/um-editable-combo.c
@@ -0,0 +1,439 @@
+/* -*- 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 <gdk/gdkkeysyms.h>
+#include "um-editable-combo.h"
+
+#define EMPTY_TEXT "\xe2\x80\x94"
+
+struct _UmEditableComboPrivate {
+        GtkNotebook *notebook;
+        GtkLabel    *label;
+        GtkButton   *button;
+        GtkComboBox *combo;
+        GtkWidget   *toplevel;
+
+        gint active;
+        gint editable;
+        gint text_column;
+};
+
+#define UM_EDITABLE_COMBO_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), UM_TYPE_EDITABLE_COMBO, UmEditableComboPrivate))
+
+enum {
+        PROP_0,
+        PROP_EDITABLE,
+        PROP_MODEL,
+        PROP_TEXT_COLUMN
+};
+
+enum {
+        EDITING_DONE,
+        LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL] = { 0, };
+
+G_DEFINE_TYPE (UmEditableCombo, um_editable_combo, GTK_TYPE_ALIGNMENT);
+
+void
+um_editable_combo_set_editable (UmEditableCombo *combo,
+                                gboolean         editable)
+{
+        UmEditableComboPrivate *priv;
+
+        priv = combo->priv;
+
+        if (priv->editable != editable) {
+                priv->editable = editable;
+
+                gtk_notebook_set_current_page (priv->notebook, editable ? 1 : 0);
+
+                g_object_notify (G_OBJECT (combo), "editable");
+        }
+}
+
+gboolean
+um_editable_combo_get_editable (UmEditableCombo *combo)
+{
+        return combo->priv->editable;
+}
+
+void
+um_editable_combo_set_model (UmEditableCombo *combo,
+                             GtkTreeModel    *model)
+{
+        gtk_combo_box_set_model (combo->priv->combo, model);
+
+        g_object_notify (G_OBJECT (combo), "model");
+}
+
+GtkTreeModel *
+um_editable_combo_get_model (UmEditableCombo *combo)
+{
+        return gtk_combo_box_get_model (combo->priv->combo);
+}
+
+void
+um_editable_combo_set_text_column (UmEditableCombo *combo,
+                                   gint             text_column)
+{
+        UmEditableComboPrivate *priv = combo->priv;
+        GList *cells;
+
+        if (priv->text_column == text_column)
+                return;
+
+        priv->text_column = text_column;
+
+        cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (priv->combo));
+        gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (priv->combo),
+                                        cells->data,
+                                        "text", text_column,
+                                        NULL);
+        g_list_free (cells);
+
+        g_object_notify (G_OBJECT (combo), "text-column");
+}
+
+gint
+um_editable_combo_get_text_column (UmEditableCombo *combo)
+{
+        return combo->priv->text_column;
+}
+
+void
+um_editable_combo_set_active (UmEditableCombo *combo,
+                              gint             active)
+{
+        GtkTreeModel *model;
+        GtkTreePath *path;
+        GtkTreeIter iter;
+
+        if (active == -1)
+                um_editable_combo_set_active_iter (combo, NULL);
+        else {
+                model = gtk_combo_box_get_model (combo->priv->combo);
+                path = gtk_tree_path_new_from_indices (active, -1);
+                gtk_tree_model_get_iter (model, &iter, path);
+                gtk_tree_path_free (path);
+                um_editable_combo_set_active_iter (combo, &iter);
+        }
+}
+
+void
+um_editable_combo_set_active_iter (UmEditableCombo *combo,
+                                   GtkTreeIter     *iter)
+{
+        UmEditableComboPrivate *priv = combo->priv;
+        GtkWidget *label;
+        gchar *text;
+        GtkTreeModel *model;
+
+        gtk_combo_box_set_active_iter (priv->combo, iter);
+        priv->active = gtk_combo_box_get_active (priv->combo);
+
+        if (priv->text_column == -1)
+                return;
+
+        if (iter) {
+                model = gtk_combo_box_get_model (priv->combo);
+                gtk_tree_model_get (model, iter, priv->text_column, &text, -1);
+        }
+        else {
+                text = g_strdup (EMPTY_TEXT);
+        }
+
+        gtk_label_set_text (priv->label, text);
+        label = gtk_bin_get_child ((GtkBin*)priv->button);
+        gtk_label_set_text (GTK_LABEL (label), text);
+
+        g_free (text);
+}
+
+gboolean
+um_editable_combo_get_active_iter (UmEditableCombo *combo,
+                                   GtkTreeIter     *iter)
+{
+        return gtk_combo_box_get_active_iter (combo->priv->combo, iter);
+}
+
+gint
+um_editable_combo_get_active (UmEditableCombo *combo)
+{
+        return combo->priv->active;
+}
+
+static void
+um_editable_combo_set_property (GObject      *object,
+                                guint         prop_id,
+                                const GValue *value,
+                                GParamSpec   *pspec)
+{
+        UmEditableCombo *combo = UM_EDITABLE_COMBO (object);
+
+        switch (prop_id) {
+        case PROP_EDITABLE:
+                um_editable_combo_set_editable (combo, g_value_get_boolean (value));
+                break;
+        case PROP_MODEL:
+                um_editable_combo_set_model (combo, g_value_get_object (value));
+                break;
+        case PROP_TEXT_COLUMN:
+                um_editable_combo_set_text_column (combo, g_value_get_int (value));
+                break;
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+        }
+}
+
+static void
+um_editable_combo_get_property (GObject    *object,
+                                guint       prop_id,
+                                GValue     *value,
+                                GParamSpec *pspec)
+{
+        UmEditableCombo *combo = UM_EDITABLE_COMBO (object);
+
+        switch (prop_id) {
+        case PROP_EDITABLE:
+                g_value_set_boolean (value,
+                                     um_editable_combo_get_editable (combo));
+                break;
+        case PROP_MODEL:
+                g_value_set_object (value,
+                                    um_editable_combo_get_model (combo));
+                break;
+        case PROP_TEXT_COLUMN:
+                g_value_set_int (value,
+                                 um_editable_combo_get_text_column (combo));
+                break;
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+        }
+}
+
+static void
+um_editable_combo_class_init (UmEditableComboClass *class)
+{
+        GObjectClass *object_class;
+
+        object_class = G_OBJECT_CLASS (class);
+
+        object_class->set_property = um_editable_combo_set_property;
+        object_class->get_property = um_editable_combo_get_property;
+
+        signals[EDITING_DONE] =
+                g_signal_new ("editing-done",
+                              G_TYPE_FROM_CLASS (class),
+                              G_SIGNAL_RUN_LAST,
+                              G_STRUCT_OFFSET (UmEditableComboClass, editing_done),
+                              NULL, NULL,
+                              g_cclosure_marshal_VOID__VOID,
+                              G_TYPE_NONE, 0);
+
+        g_object_class_install_property (object_class, PROP_MODEL,
+                g_param_spec_object ("model",
+                                     "Model", "The options to present in the combobox",
+                                     GTK_TYPE_TREE_MODEL,
+                                     G_PARAM_READWRITE));
+
+        g_object_class_install_property (object_class, PROP_TEXT_COLUMN,
+                g_param_spec_int ("text-column",
+                                  "Text Column", "The model column that contains the displayable text",
+                                  -1, G_MAXINT, -1,
+                                  G_PARAM_READWRITE));
+
+
+        g_object_class_install_property (object_class, PROP_EDITABLE,
+                g_param_spec_boolean ("editable",
+                                      "Editable", "Whether the text can be edited",
+                                      FALSE,
+                                      G_PARAM_READWRITE));
+
+        g_type_class_add_private (class, sizeof (UmEditableComboPrivate));
+}
+
+static void
+start_editing (UmEditableCombo *combo)
+{
+        gtk_notebook_set_current_page (combo->priv->notebook, 2);
+}
+
+static void
+stop_editing (UmEditableCombo *combo)
+{
+        um_editable_combo_set_active (combo,
+                                      gtk_combo_box_get_active (combo->priv->combo));
+        gtk_notebook_set_current_page (combo->priv->notebook, 1);
+
+        g_signal_emit (combo, signals[EDITING_DONE], 0);
+}
+
+static void
+cancel_editing (UmEditableCombo *combo)
+{
+        gtk_combo_box_set_active (combo->priv->combo,
+                                  um_editable_combo_get_active (combo));
+        gtk_notebook_set_current_page (combo->priv->notebook, 1);
+}
+
+static void
+button_clicked (GtkWidget       *widget,
+                UmEditableCombo *combo)
+{
+        if (combo->priv->editable)
+                start_editing (combo);
+}
+
+static void
+combo_changed (GtkWidget       *widget,
+               UmEditableCombo *combo)
+{
+        if (combo->priv->editable)
+                stop_editing (combo);
+}
+
+static gboolean
+combo_key_press (GtkWidget       *widget,
+                 GdkEventKey     *event,
+                 UmEditableCombo *combo)
+{
+        if (event->keyval == GDK_KEY_Escape) {
+                cancel_editing (combo);
+                return TRUE;
+        }
+        return FALSE;
+}
+
+static void
+focus_moved (GtkWindow       *window,
+             GtkWidget       *widget,
+             UmEditableCombo *combo)
+{
+        if (gtk_notebook_get_current_page (combo->priv->notebook) == 2 &&
+            (!widget || !gtk_widget_is_ancestor (widget, (GtkWidget *)combo)))
+                stop_editing (combo);
+}
+
+static void
+combo_hierarchy_changed (GtkWidget       *widget,
+                         GtkWidget       *previous_toplevel,
+                         UmEditableCombo *combo)
+{
+        UmEditableComboPrivate *priv;
+        GtkWidget *toplevel;
+
+        priv = combo->priv;
+
+        toplevel = gtk_widget_get_toplevel (widget);
+        if (priv->toplevel != toplevel) {
+                if (priv->toplevel)
+                        g_signal_handlers_disconnect_by_func (priv->toplevel,
+                                                              focus_moved, combo);
+
+                if (GTK_IS_WINDOW (toplevel))
+                        priv->toplevel = toplevel;
+                else
+                        priv->toplevel = NULL;
+
+                if (priv->toplevel)
+                        g_signal_connect (priv->toplevel, "set-focus",
+                                          G_CALLBACK (focus_moved), combo);
+        }
+}
+
+static void
+update_button_padding (GtkWidget       *widget,
+                       GtkAllocation   *allocation,
+                       UmEditableCombo *combo)
+{
+        UmEditableComboPrivate *priv = combo->priv;
+        GtkAllocation parent_allocation;
+        gint offset;
+        gint pad;
+
+        gtk_widget_get_allocation (gtk_widget_get_parent (widget), &parent_allocation);
+
+        offset = allocation->x - parent_allocation.x;
+
+        gtk_misc_get_padding  (GTK_MISC (priv->label), &pad, NULL);
+        if (offset != pad)
+                gtk_misc_set_padding (GTK_MISC (priv->label), offset, 0);
+}
+
+static void
+um_editable_combo_init (UmEditableCombo *combo)
+{
+        UmEditableComboPrivate *priv;
+        GtkCellRenderer *cell;
+
+        priv = combo->priv = UM_EDITABLE_COMBO_GET_PRIVATE (combo);
+
+        priv->active = -1;
+        priv->text_column = -1;
+
+        priv->notebook = (GtkNotebook*)gtk_notebook_new ();
+        gtk_notebook_set_show_tabs (priv->notebook, FALSE);
+        gtk_notebook_set_show_border (priv->notebook, FALSE);
+
+        priv->label = (GtkLabel*)gtk_label_new ("");
+        gtk_misc_set_alignment (GTK_MISC (priv->label), 0.0, 0.5);
+        gtk_notebook_append_page (priv->notebook, (GtkWidget*)priv->label, NULL);
+
+        priv->button = (GtkButton*)gtk_button_new_with_label ("");
+        gtk_widget_set_receives_default ((GtkWidget*)priv->button, TRUE);
+        gtk_button_set_relief (priv->button, GTK_RELIEF_NONE);
+        gtk_button_set_alignment (priv->button, 0.0, 0.5);
+        gtk_notebook_append_page (priv->notebook, (GtkWidget*)priv->button, NULL);
+        g_signal_connect (priv->button, "clicked", G_CALLBACK (button_clicked), combo);
+
+        priv->combo = (GtkComboBox*)gtk_combo_box_new ();
+        cell = gtk_cell_renderer_text_new ();
+        gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (priv->combo), cell, TRUE);
+        gtk_notebook_append_page (priv->notebook, (GtkWidget*)priv->combo, NULL);
+
+        g_signal_connect (priv->combo, "changed", G_CALLBACK (combo_changed), combo);
+        g_signal_connect (priv->combo, "key-press-event", G_CALLBACK (combo_key_press), combo);
+        g_signal_connect (gtk_bin_get_child (GTK_BIN (priv->button)), "size-allocate", G_CALLBACK (update_button_padding), combo);
+
+
+        gtk_container_add (GTK_CONTAINER (combo), (GtkWidget*)priv->notebook);
+
+        gtk_widget_show ((GtkWidget*)priv->notebook);
+        gtk_widget_show ((GtkWidget*)priv->label);
+        gtk_widget_show ((GtkWidget*)priv->button);
+        gtk_widget_show ((GtkWidget*)priv->combo);
+
+        gtk_notebook_set_current_page (priv->notebook, 0);
+
+        /* ugly hack to catch the combo box losing focus */
+        g_signal_connect (combo, "hierarchy-changed",
+                          G_CALLBACK (combo_hierarchy_changed), combo);
+}
+
+GtkWidget *
+um_editable_combo_new (void)
+{
+        return (GtkWidget *) g_object_new (UM_TYPE_EDITABLE_COMBO, NULL);
+}
diff --git a/panels/user-accounts/um-editable-combo.h b/panels/user-accounts/um-editable-combo.h
new file mode 100644
index 0000000..0d4e4a6
--- /dev/null
+++ b/panels/user-accounts/um-editable-combo.h
@@ -0,0 +1,76 @@
+/* -*- 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_EDITABLE_COMBO_H
+#define _UM_EDITABLE_COMBO_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define UM_TYPE_EDITABLE_COMBO  um_editable_combo_get_type()
+
+#define UM_EDITABLE_COMBO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), UM_TYPE_EDITABLE_COMBO, UmEditableCombo))
+#define UM_EDITABLE_COMBO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UM_TYPE_EDITABLE_COMBO, UmEditableComboClass))
+#define UM_IS_EDITABLE_COMBO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UM_TYPE_EDITABLE_COMBO))
+#define UM_IS_EDITABLE_COMBO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UM_TYPE_EDITABLE_COMBO))
+#define UM_EDITABLE_COMBO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), UM_TYPE_EDITABLE_COMBO, UmEditableComboClass))
+
+typedef struct _UmEditableCombo UmEditableCombo;
+typedef struct _UmEditableComboClass UmEditableComboClass;
+typedef struct _UmEditableComboPrivate UmEditableComboPrivate;
+
+struct _UmEditableCombo
+{
+  GtkAlignment parent;
+
+  UmEditableComboPrivate *priv;
+};
+
+struct _UmEditableComboClass
+{
+  GtkAlignmentClass parent_class;
+
+  void (* editing_done) (UmEditableCombo *combo);
+};
+
+GType         um_editable_combo_get_type        (void) G_GNUC_CONST;
+GtkWidget    *um_editable_combo_new             (void);
+void          um_editable_combo_set_editable    (UmEditableCombo *combo,
+                                                 gboolean         editable);
+gboolean      um_editable_combo_get_editable    (UmEditableCombo *combo);
+void          um_editable_combo_set_model       (UmEditableCombo *combo,
+                                                 GtkTreeModel    *model);
+GtkTreeModel *um_editable_combo_get_model       (UmEditableCombo *combo);
+void          um_editable_combo_set_text_column (UmEditableCombo *combo,
+                                                 gint             column);
+gint          um_editable_combo_get_text_column (UmEditableCombo *combo);
+gint          um_editable_combo_get_active      (UmEditableCombo *combo);
+void          um_editable_combo_set_active      (UmEditableCombo *combo,
+                                                 gint             active);
+gboolean      um_editable_combo_get_active_iter (UmEditableCombo *combo,
+                                                 GtkTreeIter     *iter);
+void          um_editable_combo_set_active_iter (UmEditableCombo *combo,
+                                                 GtkTreeIter     *iter);
+
+G_END_DECLS
+
+#endif /* _UM_EDITABLE_COMBO_H_ */
diff --git a/panels/user-accounts/um-editable-entry.c b/panels/user-accounts/um-editable-entry.c
new file mode 100644
index 0000000..2a18323
--- /dev/null
+++ b/panels/user-accounts/um-editable-entry.c
@@ -0,0 +1,489 @@
+/* -*- 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 <gdk/gdkkeysyms.h>
+#include "um-editable-entry.h"
+
+#define EMPTY_TEXT "\xe2\x80\x94"
+
+struct _UmEditableEntryPrivate {
+        GtkNotebook *notebook;
+        GtkLabel    *label;
+        GtkButton   *button;
+        GtkEntry    *entry;
+
+        gchar *text;
+        gboolean editable;
+        gint weight;
+        gboolean weight_set;
+        gdouble scale;
+        gboolean scale_set;
+};
+
+#define UM_EDITABLE_ENTRY_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), UM_TYPE_EDITABLE_ENTRY, UmEditableEntryPrivate))
+
+enum {
+        PROP_0,
+        PROP_TEXT,
+        PROP_EDITABLE,
+        PROP_SCALE,
+        PROP_SCALE_SET,
+        PROP_WEIGHT,
+        PROP_WEIGHT_SET
+};
+
+enum {
+        EDITING_DONE,
+        LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL] = { 0, };
+
+G_DEFINE_TYPE (UmEditableEntry, um_editable_entry, GTK_TYPE_ALIGNMENT);
+
+void
+um_editable_entry_set_text (UmEditableEntry *e,
+                             const gchar    *text)
+{
+        UmEditableEntryPrivate *priv;
+        gchar *tmp;
+        GtkWidget *label;
+
+        priv = e->priv;
+
+        tmp = g_strdup (text);
+        g_free (priv->text);
+        priv->text = tmp;
+
+        gtk_entry_set_text (priv->entry, tmp);
+
+        if (tmp == NULL || tmp[0] == '\0')
+                tmp = EMPTY_TEXT;
+
+        gtk_label_set_text (priv->label, tmp);
+        label = gtk_bin_get_child (GTK_BIN (priv->button));
+        gtk_label_set_text (GTK_LABEL (label), tmp);
+
+        g_object_notify (G_OBJECT (e), "text");
+}
+
+const gchar *
+um_editable_entry_get_text (UmEditableEntry *e)
+{
+        return e->priv->text;
+}
+
+void
+um_editable_entry_set_editable (UmEditableEntry *e,
+                                 gboolean        editable)
+{
+        UmEditableEntryPrivate *priv;
+
+        priv = e->priv;
+
+        if (priv->editable != editable) {
+                priv->editable = editable;
+
+                gtk_notebook_set_current_page (priv->notebook, editable ? 1 : 0);
+
+                g_object_notify (G_OBJECT (e), "editable");
+        }
+}
+
+gboolean
+um_editable_entry_get_editable (UmEditableEntry *e)
+{
+        return e->priv->editable;
+}
+
+static void
+update_entry_font (GtkWidget        *widget,
+                   GtkStyle         *previous_style,
+                   UmEditableEntry *e)
+{
+        UmEditableEntryPrivate *priv = e->priv;
+        PangoFontDescription *desc;
+        GtkStyle *style;
+        gint size;
+
+        if (!priv->weight_set && !priv->scale_set)
+                return;
+
+        g_signal_handlers_block_by_func (widget, update_entry_font, e);
+
+        gtk_widget_modify_font (widget, NULL);
+
+        style = gtk_widget_get_style (widget);
+        desc = pango_font_description_copy (style->font_desc);
+        if (priv->weight_set)
+                pango_font_description_set_weight (desc, priv->weight);
+        if (priv->scale_set) {
+                size = pango_font_description_get_size (desc);
+                pango_font_description_set_size (desc, priv->scale * size);
+        }
+        gtk_widget_modify_font (widget, desc);
+
+        pango_font_description_free (desc);
+
+        g_signal_handlers_unblock_by_func (widget, update_entry_font, e);
+}
+
+static void
+update_fonts (UmEditableEntry *e)
+{
+        PangoAttrList *attrs;
+        PangoAttribute *attr;
+        GtkWidget *label;
+
+        UmEditableEntryPrivate *priv = e->priv;
+
+        attrs = pango_attr_list_new ();
+        if (priv->scale_set) {
+                attr = pango_attr_scale_new (priv->scale);
+                pango_attr_list_insert (attrs, attr);
+        }
+        if (priv->weight_set) {
+                attr = pango_attr_weight_new (priv->weight);
+                pango_attr_list_insert (attrs, attr);
+        }
+
+        gtk_label_set_attributes (priv->label, attrs);
+
+        label = gtk_bin_get_child (GTK_BIN (priv->button));
+        gtk_label_set_attributes (GTK_LABEL (label), attrs);
+
+        pango_attr_list_unref (attrs);
+
+        update_entry_font ((GtkWidget *)priv->entry, NULL, e);
+}
+
+void
+um_editable_entry_set_weight (UmEditableEntry *e,
+                               gint            weight)
+{
+        UmEditableEntryPrivate *priv = e->priv;
+
+        if (priv->weight == weight && priv->weight_set)
+                return;
+
+        priv->weight = weight;
+        priv->weight_set = TRUE;
+
+        update_fonts (e);
+
+        g_object_notify (G_OBJECT (e), "weight");
+        g_object_notify (G_OBJECT (e), "weight-set");
+}
+
+gint
+um_editable_entry_get_weight (UmEditableEntry *e)
+{
+        return e->priv->weight;
+}
+
+void
+um_editable_entry_set_scale (UmEditableEntry *e,
+                              gdouble         scale)
+{
+        UmEditableEntryPrivate *priv = e->priv;
+
+        if (priv->scale == scale && priv->scale_set)
+                return;
+
+        priv->scale = scale;
+        priv->scale_set = TRUE;
+
+        update_fonts (e);
+
+        g_object_notify (G_OBJECT (e), "scale");
+        g_object_notify (G_OBJECT (e), "scale-set");
+}
+
+gdouble
+um_editable_entry_get_scale (UmEditableEntry *e)
+{
+        return e->priv->scale;
+}
+
+static void
+um_editable_entry_set_property (GObject      *object,
+                                guint         prop_id,
+                                const GValue *value,
+                                GParamSpec   *pspec)
+{
+        UmEditableEntry *e = UM_EDITABLE_ENTRY (object);
+
+        switch (prop_id) {
+        case PROP_TEXT:
+                um_editable_entry_set_text (e, g_value_get_string (value));
+                break;
+        case PROP_EDITABLE:
+                um_editable_entry_set_editable (e, g_value_get_boolean (value));
+                break;
+        case PROP_WEIGHT:
+                um_editable_entry_set_weight (e, g_value_get_int (value));
+                break;
+        case PROP_WEIGHT_SET:
+                e->priv->weight_set = g_value_get_boolean (value);
+                break;
+        case PROP_SCALE:
+                um_editable_entry_set_scale (e, g_value_get_double (value));
+                break;
+        case PROP_SCALE_SET:
+                e->priv->scale_set = g_value_get_boolean (value);
+                break;
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+        }
+}
+
+static void
+um_editable_entry_get_property (GObject    *object,
+                                guint       prop_id,
+                                GValue     *value,
+                                GParamSpec *pspec)
+{
+        UmEditableEntry *e = UM_EDITABLE_ENTRY (object);
+
+        switch (prop_id) {
+        case PROP_TEXT:
+                g_value_set_string (value,
+                                    um_editable_entry_get_text (e));
+                break;
+        case PROP_EDITABLE:
+                g_value_set_boolean (value,
+                                     um_editable_entry_get_editable (e));
+                break;
+        case PROP_WEIGHT:
+                g_value_set_int (value,
+                                 um_editable_entry_get_weight (e));
+                break;
+        case PROP_WEIGHT_SET:
+                g_value_set_boolean (value, e->priv->weight_set);
+                break;
+        case PROP_SCALE:
+                g_value_set_double (value,
+                                    um_editable_entry_get_scale (e));
+                break;
+        case PROP_SCALE_SET:
+                g_value_set_boolean (value, e->priv->scale_set);
+                break;
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+        }
+}
+
+static void
+um_editable_entry_finalize (GObject *object)
+{
+        UmEditableEntry *e = (UmEditableEntry*)object;
+
+        g_free (e->priv->text);
+
+        G_OBJECT_CLASS (um_editable_entry_parent_class)->finalize (object);
+}
+
+static void
+um_editable_entry_class_init (UmEditableEntryClass *class)
+{
+        GObjectClass *object_class;
+
+        object_class = G_OBJECT_CLASS (class);
+
+        object_class->set_property = um_editable_entry_set_property;
+        object_class->get_property = um_editable_entry_get_property;
+        object_class->finalize = um_editable_entry_finalize;
+
+        signals[EDITING_DONE] =
+                g_signal_new ("editing-done",
+                              G_TYPE_FROM_CLASS (class),
+                              G_SIGNAL_RUN_LAST,
+                              G_STRUCT_OFFSET (UmEditableEntryClass, editing_done),
+                              NULL, NULL,
+                              g_cclosure_marshal_VOID__VOID,
+                              G_TYPE_NONE, 0);
+
+        g_object_class_install_property (object_class, PROP_TEXT,
+                g_param_spec_string ("text",
+                                     "Text", "The text of the button",
+                                     NULL,
+                                     G_PARAM_READWRITE));
+
+        g_object_class_install_property (object_class, PROP_EDITABLE,
+                g_param_spec_boolean ("editable",
+                                      "Editable", "Whether the text can be edited",
+                                      FALSE,
+                                      G_PARAM_READWRITE));
+
+        g_object_class_install_property (object_class, PROP_WEIGHT,
+                g_param_spec_int ("weight",
+                                  "Font Weight", "The font weight to use",
+                                  0, G_MAXINT, PANGO_WEIGHT_NORMAL,
+                                  G_PARAM_READWRITE));
+
+        g_object_class_install_property (object_class, PROP_WEIGHT_SET,
+                g_param_spec_boolean ("weight-set",
+                                      "Font Weight Set", "Whether a font weight is set",
+                                      FALSE,
+                                      G_PARAM_READWRITE));
+
+        g_object_class_install_property (object_class, PROP_SCALE,
+                g_param_spec_double ("scale",
+                                     "Font Scale", "The font scale to use",
+                                     0.0, G_MAXDOUBLE, 1.0,
+                                     G_PARAM_READWRITE));
+
+        g_object_class_install_property (object_class, PROP_SCALE_SET,
+                g_param_spec_boolean ("scale-set",
+                                      "Font Scale Set", "Whether a font scale is set",
+                                      FALSE,
+                                      G_PARAM_READWRITE));
+
+        g_type_class_add_private (class, sizeof (UmEditableEntryPrivate));
+}
+
+static void
+start_editing (UmEditableEntry *e)
+{
+        gtk_notebook_set_current_page (e->priv->notebook, 2);
+}
+
+static void
+stop_editing (UmEditableEntry *e)
+{
+        um_editable_entry_set_text (e, gtk_entry_get_text (e->priv->entry));
+        gtk_notebook_set_current_page (e->priv->notebook, 1);
+        g_signal_emit (e, signals[EDITING_DONE], 0);
+}
+
+static void
+cancel_editing (UmEditableEntry *e)
+{
+        gtk_entry_set_text (e->priv->entry, um_editable_entry_get_text (e));
+        gtk_notebook_set_current_page (e->priv->notebook, 1);
+}
+
+static void
+button_clicked (GtkWidget       *widget,
+                UmEditableEntry *e)
+{
+        start_editing (e);
+}
+
+static void
+entry_activated (GtkWidget       *widget,
+                 UmEditableEntry *e)
+{
+        stop_editing (e);
+}
+
+static gboolean
+entry_focus_out (GtkWidget       *widget,
+                 GdkEventFocus   *event,
+                 UmEditableEntry *e)
+{
+        stop_editing (e);
+        return FALSE;
+}
+
+static gboolean
+entry_key_press (GtkWidget       *widget,
+                 GdkEventKey     *event,
+                 UmEditableEntry *e)
+{
+        if (event->keyval == GDK_KEY_Escape) {
+                cancel_editing (e);
+        }
+        return FALSE;
+}
+
+static void
+update_button_padding (GtkWidget       *widget,
+                       GtkAllocation   *allocation,
+                       UmEditableEntry *e)
+{
+        UmEditableEntryPrivate *priv = e->priv;
+        GtkAllocation alloc;
+        gint offset;
+        gint pad;
+
+        gtk_widget_get_allocation (gtk_widget_get_parent (widget), &alloc);
+
+        offset = allocation->x - alloc.x;
+
+        gtk_misc_get_padding  (GTK_MISC (priv->label), &pad, NULL);
+        if (offset != pad)
+                gtk_misc_set_padding (GTK_MISC (priv->label), offset, 0);
+}
+
+static void
+um_editable_entry_init (UmEditableEntry *e)
+{
+        UmEditableEntryPrivate *priv;
+
+        priv = e->priv = UM_EDITABLE_ENTRY_GET_PRIVATE (e);
+
+        priv->weight = PANGO_WEIGHT_NORMAL;
+        priv->weight_set = FALSE;
+        priv->scale = 1.0;
+        priv->scale_set = FALSE;
+
+        priv->notebook = (GtkNotebook*)gtk_notebook_new ();
+        gtk_notebook_set_show_tabs (priv->notebook, FALSE);
+        gtk_notebook_set_show_border (priv->notebook, FALSE);
+
+        priv->label = (GtkLabel*)gtk_label_new (EMPTY_TEXT);
+        gtk_misc_set_alignment (GTK_MISC (priv->label), 0.0, 0.5);
+        gtk_notebook_append_page (priv->notebook, (GtkWidget*)priv->label, NULL);
+
+        priv->button = (GtkButton*)gtk_button_new_with_label (EMPTY_TEXT);
+        gtk_widget_set_receives_default ((GtkWidget*)priv->button, TRUE);
+        gtk_button_set_relief (priv->button, GTK_RELIEF_NONE);
+        gtk_button_set_alignment (priv->button, 0.0, 0.5);
+        gtk_notebook_append_page (priv->notebook, (GtkWidget*)priv->button, NULL);
+        g_signal_connect (priv->button, "clicked", G_CALLBACK (button_clicked), e);
+
+        priv->entry = (GtkEntry*)gtk_entry_new ();
+        gtk_notebook_append_page (priv->notebook, (GtkWidget*)priv->entry, NULL);
+
+        g_signal_connect (priv->entry, "activate", G_CALLBACK (entry_activated), e);
+        g_signal_connect (priv->entry, "focus-out-event", G_CALLBACK (entry_focus_out), e);
+        g_signal_connect (priv->entry, "key-press-event", G_CALLBACK (entry_key_press), e);
+        g_signal_connect (priv->entry, "style-set", G_CALLBACK (update_entry_font), e);
+        g_signal_connect (gtk_bin_get_child (GTK_BIN (priv->button)), "size-allocate", G_CALLBACK (update_button_padding), e);
+
+        gtk_container_add (GTK_CONTAINER (e), (GtkWidget*)priv->notebook);
+
+        gtk_widget_show ((GtkWidget*)priv->notebook);
+        gtk_widget_show ((GtkWidget*)priv->label);
+        gtk_widget_show ((GtkWidget*)priv->button);
+        gtk_widget_show ((GtkWidget*)priv->entry);
+
+        gtk_notebook_set_current_page (priv->notebook, 0);
+}
+
+GtkWidget *
+um_editable_entry_new (void)
+{
+        return (GtkWidget *) g_object_new (UM_TYPE_EDITABLE_ENTRY, NULL);
+}
diff --git a/panels/user-accounts/um-editable-entry.h b/panels/user-accounts/um-editable-entry.h
new file mode 100644
index 0000000..1f5f3f4
--- /dev/null
+++ b/panels/user-accounts/um-editable-entry.h
@@ -0,0 +1,72 @@
+/* -*- 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_EDITABLE_ENTRY_H_
+#define _UM_EDITABLE_ENTRY_H_
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define UM_TYPE_EDITABLE_ENTRY  um_editable_entry_get_type()
+
+#define UM_EDITABLE_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), UM_TYPE_EDITABLE_ENTRY, UmEditableEntry))
+#define UM_EDITABLE_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UM_TYPE_EDITABLE_ENTRY, UmEditableEntryClass))
+#define UM_IS_EDITABLE_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UM_TYPE_EDITABLE_ENTRY))
+#define UM_IS_EDITABLE_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UM_TYPE_EDITABLE_ENTRY))
+#define UM_EDITABLE_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), UM_TYPE_EDITABLE_ENTRY, UmEditableEntryClass))
+
+typedef struct _UmEditableEntry UmEditableEntry;
+typedef struct _UmEditableEntryClass UmEditableEntryClass;
+typedef struct _UmEditableEntryPrivate UmEditableEntryPrivate;
+
+struct _UmEditableEntry
+{
+  GtkAlignment parent;
+
+  UmEditableEntryPrivate *priv;
+};
+
+struct _UmEditableEntryClass
+{
+  GtkAlignmentClass parent_class;
+
+  void (* editing_done) (UmEditableEntry *entry);
+};
+
+GType        um_editable_entry_get_type     (void) G_GNUC_CONST;
+GtkWidget   *um_editable_entry_new          (void);
+void         um_editable_entry_set_text     (UmEditableEntry *entry,
+                                             const gchar     *text);
+const gchar *um_editable_entry_get_text     (UmEditableEntry *entry);
+void         um_editable_entry_set_editable (UmEditableEntry *entry,
+                                             gboolean         editable);
+gboolean     um_editable_entry_get_editable (UmEditableEntry *entry);
+void         um_editable_entry_set_weight   (UmEditableEntry *entry,
+                                             gint             weight);
+gint         um_editable_entry_get_weight   (UmEditableEntry *entry);
+void         um_editable_entry_set_scale    (UmEditableEntry *entry,
+                                             gdouble          scale);
+gdouble      um_editable_entry_get_scale    (UmEditableEntry *entry);
+
+G_END_DECLS
+
+#endif /* _UM_EDITABLE_ENTRY_H_ */
diff --git a/panels/user-accounts/um-fingerprint-dialog.c b/panels/user-accounts/um-fingerprint-dialog.c
new file mode 100644
index 0000000..de11c95
--- /dev/null
+++ b/panels/user-accounts/um-fingerprint-dialog.c
@@ -0,0 +1,674 @@
+/* gnome-about-me-fingerprint.h
+ * Copyright (C) 2008 Bastien Nocera <hadess hadess net>
+ *
+ * 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, 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.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <dbus/dbus-glib-bindings.h>
+
+#include "um-fingerprint-dialog.h"
+
+#include "fingerprint-strings.h"
+
+/* Retrieve a widget from the UI object */
+#define WID(s) GTK_WIDGET (gtk_builder_get_object (dialog, s))
+
+/* Translate fprintd strings */
+#define TR(s) dgettext("fprintd", s)
+
+/* This must match the number of images on the 2nd page in the UI file */
+#define MAX_ENROLL_STAGES 5
+
+static DBusGProxy *manager = NULL;
+static DBusGConnection *connection = NULL;
+static gboolean is_disable = FALSE;
+
+enum {
+        STATE_NONE,
+        STATE_CLAIMED,
+        STATE_ENROLLING
+};
+
+typedef struct {
+        GtkWidget *label1;
+        GtkWidget *label2;
+
+        GtkWidget *ass;
+        GtkBuilder *dialog;
+
+        DBusGProxy *device;
+        gboolean is_swipe;
+        int num_enroll_stages;
+        int num_stages_done;
+        char *name;
+        const char *finger;
+        gint state;
+} EnrollData;
+
+static void create_manager (void)
+{
+        GError *error = NULL;
+
+        connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
+        if (connection == NULL) {
+                g_warning ("Failed to connect to session bus: %s", error->message);
+                return;
+        }
+
+        manager = dbus_g_proxy_new_for_name (connection,
+                                             "net.reactivated.Fprint",
+                                             "/net/reactivated/Fprint/Manager",
+                                             "net.reactivated.Fprint.Manager");
+}
+
+static DBusGProxy *
+get_first_device (void)
+{
+        DBusGProxy *device;
+        char *device_str;
+
+        if (!dbus_g_proxy_call (manager, "GetDefaultDevice", NULL, G_TYPE_INVALID,
+                                DBUS_TYPE_G_OBJECT_PATH, &device_str, G_TYPE_INVALID)) {
+                return NULL;
+        }
+
+        device = dbus_g_proxy_new_for_name(connection,
+                                           "net.reactivated.Fprint",
+                                           device_str,
+                                           "net.reactivated.Fprint.Device");
+
+        g_free (device_str);
+
+        return device;
+}
+
+static const char *
+get_reason_for_error (const char *dbus_error)
+{
+        if (g_str_equal (dbus_error, "net.reactivated.Fprint.Error.PermissionDenied"))
+                return N_("You are not allowed to access the device. Contact your system administrator.");
+        if (g_str_equal (dbus_error, "net.reactivated.Fprint.Error.AlreadyInUse"))
+                return N_("The device is already in use.");
+        if (g_str_equal (dbus_error, "net.reactivated.Fprint.Error.Internal"))
+                return N_("An internal error occurred.");
+
+        return NULL;
+}
+
+static GtkWidget *
+get_error_dialog (const char *title,
+                  const char *dbus_error,
+                  GtkWindow *parent)
+{
+        GtkWidget *error_dialog;
+        const char *reason;
+
+        if (dbus_error == NULL)
+                g_warning ("get_error_dialog called with reason == NULL");
+
+        error_dialog =
+                gtk_message_dialog_new (parent,
+                                GTK_DIALOG_MODAL,
+                                GTK_MESSAGE_ERROR,
+                                GTK_BUTTONS_OK,
+                                "%s", title);
+        reason = get_reason_for_error (dbus_error);
+        gtk_message_dialog_format_secondary_text
+                (GTK_MESSAGE_DIALOG (error_dialog), "%s", reason ? _(reason) : _(dbus_error));
+
+        gtk_window_set_title (GTK_WINDOW (error_dialog), ""); /* as per HIG */
+        gtk_container_set_border_width (GTK_CONTAINER (error_dialog), 5);
+        gtk_dialog_set_default_response (GTK_DIALOG (error_dialog),
+                                         GTK_RESPONSE_OK);
+        gtk_window_set_modal (GTK_WINDOW (error_dialog), TRUE);
+        gtk_window_set_position (GTK_WINDOW (error_dialog), GTK_WIN_POS_CENTER_ON_PARENT);
+
+        return error_dialog;
+}
+
+gboolean
+set_fingerprint_label (GtkWidget *label1,
+                       GtkWidget *label2)
+{
+        char **fingers;
+        DBusGProxy *device;
+        GError *error = NULL;
+
+        if (manager == NULL) {
+                create_manager ();
+                if (manager == NULL) {
+                        return FALSE;
+                }
+        }
+
+        device = get_first_device ();
+        if (device == NULL)
+                return FALSE;
+
+        if (!dbus_g_proxy_call (device, "ListEnrolledFingers", &error, G_TYPE_STRING, "", G_TYPE_INVALID,
+                                G_TYPE_STRV, &fingers, G_TYPE_INVALID)) {
+                if (dbus_g_error_has_name (error, "net.reactivated.Fprint.Error.NoEnrolledPrints") == FALSE) {
+                        g_object_unref (device);
+                        return FALSE;
+                }
+                fingers = NULL;
+        }
+
+        if (fingers == NULL || g_strv_length (fingers) == 0) {
+                is_disable = FALSE;
+                gtk_label_set_text (GTK_LABEL (label1), _("Disabled"));
+                gtk_label_set_text (GTK_LABEL (label2), _("Disabled"));
+        } else {
+                is_disable = TRUE;
+                gtk_label_set_text (GTK_LABEL (label1), _("Enabled"));
+                gtk_label_set_text (GTK_LABEL (label2), _("Enabled"));
+        }
+
+        g_strfreev (fingers);
+        g_object_unref (device);
+
+        return TRUE;
+}
+
+static void
+delete_fingerprints (void)
+{
+        DBusGProxy *device;
+
+        if (manager == NULL) {
+                create_manager ();
+                if (manager == NULL)
+                        return;
+        }
+
+        device = get_first_device ();
+        if (device == NULL)
+                return;
+
+        dbus_g_proxy_call (device, "DeleteEnrolledFingers", NULL, G_TYPE_STRING, "", G_TYPE_INVALID, G_TYPE_INVALID);
+
+        g_object_unref (device);
+}
+
+static void
+delete_fingerprints_question (GtkWindow *parent,
+                              GtkWidget *label1,
+                              GtkWidget *label2,
+                              UmUser    *user)
+{
+        GtkWidget *question;
+        GtkWidget *button;
+
+        question = gtk_message_dialog_new (parent,
+                                           GTK_DIALOG_MODAL,
+                                           GTK_MESSAGE_QUESTION,
+                                           GTK_BUTTONS_NONE,
+                                           _("Delete registered fingerprints?"));
+        gtk_dialog_add_button (GTK_DIALOG (question), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
+        gtk_window_set_modal (GTK_WINDOW (question), TRUE);
+
+        button = gtk_button_new_with_mnemonic (_("_Delete Fingerprints"));
+        gtk_button_set_image (GTK_BUTTON (button), gtk_image_new_from_stock (GTK_STOCK_DELETE, GTK_ICON_SIZE_BUTTON));
+        gtk_widget_set_can_default (button, TRUE);
+        gtk_widget_show (button);
+        gtk_dialog_add_action_widget (GTK_DIALOG (question), button, GTK_RESPONSE_OK);
+
+        gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (question),
+                                                  _("Do you want to delete your registered fingerprints so fingerprint login is disabled?"));
+        gtk_container_set_border_width (GTK_CONTAINER (question), 5);
+        gtk_dialog_set_default_response (GTK_DIALOG (question), GTK_RESPONSE_OK);
+        gtk_window_set_position (GTK_WINDOW (question), GTK_WIN_POS_CENTER_ON_PARENT);
+        gtk_window_set_modal (GTK_WINDOW (question), TRUE);
+
+        if (gtk_dialog_run (GTK_DIALOG (question)) == GTK_RESPONSE_OK) {
+                delete_fingerprints ();
+                set_fingerprint_label (label1, label2);
+        }
+
+        gtk_widget_destroy (question);
+}
+
+static void
+enroll_data_destroy (EnrollData *data)
+{
+        switch (data->state) {
+        case STATE_ENROLLING:
+                dbus_g_proxy_call(data->device, "EnrollStop", NULL, G_TYPE_INVALID, G_TYPE_INVALID);
+                /* fall-through */
+        case STATE_CLAIMED:
+                dbus_g_proxy_call(data->device, "Release", NULL, G_TYPE_INVALID, G_TYPE_INVALID);
+                /* fall-through */
+        case STATE_NONE:
+                g_free (data->name);
+                g_object_unref (data->device);
+                g_object_unref (data->dialog);
+                gtk_widget_destroy (data->ass);
+
+                g_free (data);
+        }
+}
+
+static const char *
+selected_finger (GtkBuilder *dialog)
+{
+        int index;
+
+        if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (WID ("radiobutton1")))) {
+                gtk_widget_set_sensitive (WID ("finger_combobox"), FALSE);
+                return "right-index-finger";
+        }
+        if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (WID ("radiobutton2")))) {
+                gtk_widget_set_sensitive (WID ("finger_combobox"), FALSE);
+                return "left-index-finger";
+        }
+        gtk_widget_set_sensitive (WID ("finger_combobox"), TRUE);
+        index = gtk_combo_box_get_active (GTK_COMBO_BOX (WID ("finger_combobox")));
+        switch (index) {
+        case 0:
+                return "left-thumb";
+        case 1:
+                return "left-middle-finger";
+        case 2:
+                return "left-ring-finger";
+        case 3:
+                return "left-little-finger";
+        case 4:
+                return "right-thumb";
+        case 5:
+                return "right-middle-finger";
+        case 6:
+                return "right-ring-finger";
+        case 7:
+                return "right-little-finger";
+        default:
+                g_assert_not_reached ();
+        }
+
+        return NULL;
+}
+
+static void
+finger_radio_button_toggled (GtkToggleButton *button, EnrollData *data)
+{
+        GtkBuilder *dialog = data->dialog;
+        char *msg;
+
+        data->finger = selected_finger (data->dialog);
+
+        msg = g_strdup_printf (TR(finger_str_to_msg (data->finger, data->is_swipe)), data->name);
+        gtk_label_set_text (GTK_LABEL (WID("enroll-label")), msg);
+        g_free (msg);
+}
+
+static void
+finger_combobox_changed (GtkComboBox *combobox, EnrollData *data)
+{
+        GtkBuilder *dialog = data->dialog;
+        char *msg;
+
+        data->finger = selected_finger (data->dialog);
+
+        msg = g_strdup_printf (TR(finger_str_to_msg (data->finger, data->is_swipe)), data->name);
+        gtk_label_set_text (GTK_LABEL (WID("enroll-label")), msg);
+        g_free (msg);
+}
+
+static void
+assistant_cancelled (GtkAssistant *ass, EnrollData *data)
+{
+        GtkWidget *label1, *label2;
+
+        label1 = data->label1;
+        label2 = data->label2;
+
+        enroll_data_destroy (data);
+        set_fingerprint_label (label1, label2);
+}
+
+static void
+enroll_result (GObject *object, const char *result, gboolean done, EnrollData *data)
+{
+        GtkBuilder *dialog = data->dialog;
+        char *msg;
+
+        if (g_str_equal (result, "enroll-completed") || g_str_equal (result, "enroll-stage-passed")) {
+                char *name, *path;
+
+                data->num_stages_done++;
+                name = g_strdup_printf ("image%d", data->num_stages_done);
+                path = g_build_filename (UM_PIXMAP_DIR, "print_ok.png", NULL);
+                gtk_image_set_from_file (GTK_IMAGE (WID (name)), path);
+                g_free (name);
+                g_free (path);
+        }
+        if (g_str_equal (result, "enroll-completed")) {
+                gtk_label_set_text (GTK_LABEL (WID ("status-label")), _("Done!"));
+                gtk_assistant_set_page_complete (GTK_ASSISTANT (data->ass), WID ("page2"), TRUE);
+        }
+
+        if (done != FALSE) {
+                dbus_g_proxy_call(data->device, "EnrollStop", NULL, G_TYPE_INVALID, G_TYPE_INVALID);
+                data->state = STATE_CLAIMED;
+                if (g_str_equal (result, "enroll-completed") == FALSE) {
+                        /* The enrollment failed, restart it */
+                        dbus_g_proxy_call(data->device, "EnrollStart", NULL, G_TYPE_STRING, data->finger, G_TYPE_INVALID, G_TYPE_INVALID);
+                        data->state = STATE_ENROLLING;
+                        result = "enroll-retry-scan";
+                } else {
+                        return;
+                }
+        }
+
+        msg = g_strdup_printf (TR(enroll_result_str_to_msg (result, data->is_swipe)), data->name);
+        gtk_label_set_text (GTK_LABEL (WID ("status-label")), msg);
+        g_free (msg);
+}
+
+static void
+assistant_prepare (GtkAssistant *ass, GtkWidget *page, EnrollData *data)
+{
+        const char *name;
+
+        name = g_object_get_data (G_OBJECT (page), "name");
+        if (name == NULL)
+                return;
+
+        if (g_str_equal (name, "enroll")) {
+                DBusGProxy *p;
+                GError *error = NULL;
+                GtkBuilder *dialog = data->dialog;
+                char *path;
+                guint i;
+                GValue value = { 0, };
+
+                if (!dbus_g_proxy_call (data->device, "Claim", &error, G_TYPE_STRING, "", G_TYPE_INVALID, G_TYPE_INVALID)) {
+                        GtkWidget *d;
+                        char *msg;
+
+                        /* translators:
+                         * The variable is the name of the device, for example:
+                         * "Could you not access "Digital Persona U.are.U 4000/4000B" device */
+                        msg = g_strdup_printf (_("Could not access '%s' device"), data->name);
+                        d = get_error_dialog (msg, dbus_g_error_get_name (error), GTK_WINDOW (data->ass));
+                        g_error_free (error);
+                        gtk_dialog_run (GTK_DIALOG (d));
+                        gtk_widget_destroy (d);
+                        g_free (msg);
+
+                        enroll_data_destroy (data);
+
+                        return;
+                }
+                data->state = STATE_CLAIMED;
+
+                p = dbus_g_proxy_new_from_proxy (data->device, "org.freedesktop.DBus.Properties", NULL);
+                if (!dbus_g_proxy_call (p, "Get", NULL, G_TYPE_STRING, "net.reactivated.Fprint.Device", G_TYPE_STRING, "num-enroll-stages", G_TYPE_INVALID,
+                                       G_TYPE_VALUE, &value, G_TYPE_INVALID) || g_value_get_int (&value) < 1) {
+                        GtkWidget *d;
+                        char *msg;
+
+                        /* translators:
+                         * The variable is the name of the device, for example:
+                         * "Could you not access "Digital Persona U.are.U 4000/4000B" device */
+                        msg = g_strdup_printf (_("Could not access '%s' device"), data->name);
+                        d = get_error_dialog (msg, "net.reactivated.Fprint.Error.Internal", GTK_WINDOW (data->ass));
+                        gtk_dialog_run (GTK_DIALOG (d));
+                        gtk_widget_destroy (d);
+                        g_free (msg);
+
+                        enroll_data_destroy (data);
+
+                        g_object_unref (p);
+                        return;
+                }
+                g_object_unref (p);
+
+                data->num_enroll_stages = g_value_get_int (&value);
+
+                /* Hide the extra "bulbs" if not needed */
+                for (i = MAX_ENROLL_STAGES; i > data->num_enroll_stages; i--) {
+                        char *name;
+
+                        name = g_strdup_printf ("image%d", i);
+                        gtk_widget_hide (WID (name));
+                        g_free (name);
+                }
+                /* And set the right image */
+                {
+                        char *filename;
+
+                        filename = g_strdup_printf ("%s.png", data->finger);
+                        path = g_build_filename (UM_PIXMAP_DIR, filename, NULL);
+                        g_free (filename);
+                }
+                for (i = 1; i <= data->num_enroll_stages; i++) {
+                        char *name;
+                        name = g_strdup_printf ("image%d", i);
+                        gtk_image_set_from_file (GTK_IMAGE (WID (name)), path);
+                        g_free (name);
+                }
+                g_free (path);
+
+                dbus_g_proxy_add_signal(data->device, "EnrollStatus", G_TYPE_STRING, G_TYPE_BOOLEAN, NULL);
+                dbus_g_proxy_connect_signal(data->device, "EnrollStatus", G_CALLBACK(enroll_result), data, NULL);
+
+                if (!dbus_g_proxy_call(data->device, "EnrollStart", &error, G_TYPE_STRING, data->finger, G_TYPE_INVALID, G_TYPE_INVALID)) {
+                        GtkWidget *d;
+                        char *msg;
+
+                        /* translators:
+                         * The variable is the name of the device, for example:
+                         * "Could you not access "Digital Persona U.are.U 4000/4000B" device */
+                        msg = g_strdup_printf (_("Could not start finger capture on '%s' device"), data->name);
+                        d = get_error_dialog (msg, dbus_g_error_get_name (error), GTK_WINDOW (data->ass));
+                        g_error_free (error);
+                        gtk_dialog_run (GTK_DIALOG (d));
+                        gtk_widget_destroy (d);
+                        g_free (msg);
+
+                        enroll_data_destroy (data);
+
+                        return;
+                }
+                data->state = STATE_ENROLLING;;
+        } else {
+                if (data->state == STATE_ENROLLING) {
+                        dbus_g_proxy_call(data->device, "EnrollStop", NULL, G_TYPE_INVALID, G_TYPE_INVALID);
+                        data->state = STATE_CLAIMED;
+                }
+                if (data->state == STATE_CLAIMED) {
+                        dbus_g_proxy_call(data->device, "Release", NULL, G_TYPE_INVALID, G_TYPE_INVALID);
+                        data->state = STATE_NONE;
+                }
+        }
+}
+
+static void
+align_image (GtkWidget *child, gpointer data)
+{
+        if (GTK_IS_IMAGE (child)) {
+                gtk_misc_set_alignment (GTK_MISC (child), 0, 0.5);
+                gtk_misc_set_padding (GTK_MISC (child), 10, 10);
+        }
+
+        if (GTK_IS_LABEL (child)) {
+                gtk_label_set_use_markup (GTK_LABEL (child), TRUE);
+                gtk_widget_modify_font (child, NULL);
+                gtk_misc_set_padding (GTK_MISC (child), 68, 10);
+        }
+}
+
+static void
+enroll_fingerprints (GtkWindow *parent,
+                     GtkWidget *label1,
+                     GtkWidget *label2,
+                     UmUser    *user)
+{
+        DBusGProxy *device, *p;
+        GHashTable *props;
+        GtkBuilder *dialog;
+        EnrollData *data;
+        GtkWidget *ass;
+        const char *filename;
+        char *msg;
+        GError *error = NULL;
+        GdkPixbuf *pixbuf;
+        gchar *title;
+        GtkStyle *style;
+
+        device = NULL;
+
+        if (manager == NULL) {
+                create_manager ();
+                if (manager != NULL)
+                        device = get_first_device ();
+        } else {
+                device = get_first_device ();
+        }
+
+        if (manager == NULL || device == NULL) {
+                GtkWidget *d;
+
+                d = get_error_dialog (_("Could not access any fingerprint readers"),
+                                      _("Please contact your system administrator for help."),
+                                      parent);
+                gtk_dialog_run (GTK_DIALOG (d));
+                gtk_widget_destroy (d);
+                return;
+        }
+
+        data = g_new0 (EnrollData, 1);
+        data->device = device;
+        data->label1 = label1;
+        data->label2 = label2;
+
+        /* Get some details about the device */
+        p = dbus_g_proxy_new_from_proxy (device, "org.freedesktop.DBus.Properties", NULL);
+        if (dbus_g_proxy_call (p, "GetAll", NULL, G_TYPE_STRING, "net.reactivated.Fprint.Device", G_TYPE_INVALID,
+                               dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), &props, G_TYPE_INVALID)) {
+                const char *scan_type;
+                data->name = g_value_dup_string (g_hash_table_lookup (props, "name"));
+                scan_type = g_value_dup_string (g_hash_table_lookup (props, "scan-type"));
+                if (g_str_equal (scan_type, "swipe"))
+                        data->is_swipe = TRUE;
+                g_hash_table_destroy (props);
+        }
+        g_object_unref (p);
+
+        dialog = gtk_builder_new ();
+        filename = UIDIR "/account-fingerprint.ui";
+        if (!g_file_test (filename, G_FILE_TEST_EXISTS))
+                filename = "../data/account-fingerprint.ui";
+        if (!gtk_builder_add_from_file (dialog, filename, &error)) {
+                g_error ("%s", error->message);
+                g_error_free (error);
+                exit (1);
+        }
+        data->dialog = dialog;
+
+        ass = WID ("assistant");
+        gtk_window_set_title (GTK_WINDOW (ass), _("Enable Fingerprint Login"));
+        gtk_window_set_transient_for (GTK_WINDOW (ass), parent);
+        gtk_window_set_modal (GTK_WINDOW (ass), TRUE);
+        gtk_window_set_position (GTK_WINDOW (ass), GTK_WIN_POS_CENTER_ON_PARENT);
+
+        gtk_widget_realize (ass);
+        style = gtk_widget_get_style (ass);
+        gtk_widget_modify_fg (ass, GTK_STATE_SELECTED, &style->fg[GTK_STATE_NORMAL]);
+        gtk_widget_modify_bg (ass, GTK_STATE_SELECTED, &style->bg[GTK_STATE_NORMAL]);
+
+        g_signal_connect (G_OBJECT (ass), "cancel",
+                          G_CALLBACK (assistant_cancelled), data);
+        g_signal_connect (G_OBJECT (ass), "close",
+                          G_CALLBACK (assistant_cancelled), data);
+        g_signal_connect (G_OBJECT (ass), "prepare",
+                          G_CALLBACK (assistant_prepare), data);
+
+        /* Page 1 */
+        gtk_combo_box_set_active (GTK_COMBO_BOX (WID ("finger_combobox")), 0);
+
+        g_signal_connect (G_OBJECT (WID ("radiobutton1")), "toggled",
+                          G_CALLBACK (finger_radio_button_toggled), data);
+        g_signal_connect (G_OBJECT (WID ("radiobutton2")), "toggled",
+                          G_CALLBACK (finger_radio_button_toggled), data);
+        g_signal_connect (G_OBJECT (WID ("radiobutton3")), "toggled",
+                          G_CALLBACK (finger_radio_button_toggled), data);
+        g_signal_connect (G_OBJECT (WID ("finger_combobox")), "changed",
+                          G_CALLBACK (finger_combobox_changed), data);
+
+        data->finger = selected_finger (dialog);
+
+        g_object_set_data (G_OBJECT (WID("page1")), "name", "intro");
+
+        /* translators:
+         * The variable is the name of the device, for example:
+         * "To enable fingerprint login, you need to save one of your fingerprints, using the
+         * 'Digital Persona U.are.U 4000/4000B' device." */
+        msg = g_strdup_printf (_("To enable fingerprint login, you need to save one of your fingerprints, using the '%s' device."),
+                               data->name);
+        gtk_label_set_text (GTK_LABEL (WID("intro-label")), msg);
+        g_free (msg);
+
+        gtk_assistant_set_page_complete (GTK_ASSISTANT (ass), WID("page1"), TRUE);
+
+        pixbuf = um_user_render_icon (user, FALSE, 48);
+        title = g_strdup_printf (_("Enrolling fingerprints for\n<b><big>%s</big></b>"), um_user_get_real_name (user));
+
+        gtk_assistant_set_page_header_image (GTK_ASSISTANT (ass), WID("page1"), pixbuf);
+        gtk_assistant_set_page_title (GTK_ASSISTANT (ass), WID("page1"), title);
+        gtk_assistant_set_page_header_image (GTK_ASSISTANT (ass), WID("page2"), pixbuf);
+        gtk_assistant_set_page_title (GTK_ASSISTANT (ass), WID("page2"), title);
+        gtk_assistant_set_page_header_image (GTK_ASSISTANT (ass), WID("page3"), pixbuf);
+        gtk_assistant_set_page_title (GTK_ASSISTANT (ass), WID("page3"), title);
+        gtk_container_forall (GTK_CONTAINER (ass), align_image, NULL);
+        g_object_unref (pixbuf);
+        g_free (title);
+
+        /* Page 2 */
+        g_object_set_data (G_OBJECT (WID("page2")), "name", "enroll");
+
+        msg = g_strdup_printf (TR(finger_str_to_msg (data->finger, data->is_swipe)), data->name);
+        gtk_label_set_text (GTK_LABEL (WID("enroll-label")), msg);
+        g_free (msg);
+
+        /* Page 3 */
+        g_object_set_data (G_OBJECT (WID("page3")), "name", "summary");
+
+        data->ass = ass;
+        gtk_widget_show_all (ass);
+}
+
+void
+fingerprint_button_clicked (GtkWindow *parent,
+                            GtkWidget *label1,
+                            GtkWidget *label2,
+                            UmUser    *user)
+{
+        bindtextdomain ("fprintd", GNOMELOCALEDIR);
+        bind_textdomain_codeset ("fprintd", "UTF-8");
+
+        if (is_disable != FALSE) {
+                delete_fingerprints_question (parent, label1, label2, user);
+        } else {
+                enroll_fingerprints (parent, label1, label2, user);
+        }
+}
+
diff --git a/panels/user-accounts/um-fingerprint-dialog.h b/panels/user-accounts/um-fingerprint-dialog.h
new file mode 100644
index 0000000..cca4b58
--- /dev/null
+++ b/panels/user-accounts/um-fingerprint-dialog.h
@@ -0,0 +1,28 @@
+/* gnome-about-me-fingerprint.h
+ * Copyright (C) 2008 Bastien Nocera <hadess hadess net>
+ *
+ * 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, 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.
+ */
+
+#include <gtk/gtk.h>
+#include "um-user.h"
+
+gboolean set_fingerprint_label (GtkWidget *label1,
+                                GtkWidget *label2);
+void fingerprint_button_clicked (GtkWindow *parent,
+                                 GtkWidget *label1,
+                                 GtkWidget *label2,
+                                 UmUser    *user);
diff --git a/panels/user-accounts/um-language-dialog.c b/panels/user-accounts/um-language-dialog.c
new file mode 100644
index 0000000..9362b62
--- /dev/null
+++ b/panels/user-accounts/um-language-dialog.c
@@ -0,0 +1,555 @@
+/* -*- 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 <stdlib.h>
+#include <locale.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include <fontconfig/fontconfig.h>
+
+#include "um-language-dialog.h"
+#include "um-user-manager.h"
+
+#include "gdm-languages.h"
+
+struct _UmLanguageDialog {
+        GtkWidget *dialog;
+        GtkWidget *user_icon;
+        GtkWidget *user_name;
+        GtkWidget *dialog_combo;
+        GtkListStore *dialog_store;
+
+        GtkWidget *chooser;
+        GtkWidget *chooser_list;
+        GtkListStore *chooser_store;
+
+        char *language;
+        UmUser *user;
+
+        gboolean force_setting;
+};
+
+enum {
+        LOCALE_COL,
+        DISPLAY_LOCALE_COL,
+        NUM_COLS
+};
+
+static void
+cancel_language_dialog (GtkButton        *button,
+                        UmLanguageDialog *um)
+{
+        if (um->force_setting)
+                um_user_set_language (um->user, um->language);
+        gtk_widget_hide (um->dialog);
+        um_language_dialog_set_user (um, NULL);
+
+}
+
+static void
+accept_language_dialog (GtkButton        *button,
+                        UmLanguageDialog *um)
+{
+        um_user_set_language (um->user, um->language);
+
+        gtk_widget_hide (um->dialog);
+        um_language_dialog_set_user (um, NULL);
+}
+
+gchar *
+um_language_chooser_get_language (GtkWidget *chooser)
+{
+        GtkTreeView *tv;
+        GtkTreeSelection *selection;
+        GtkTreeModel *model;
+        GtkTreeIter iter;
+        gchar *lang;
+
+        tv = (GtkTreeView *) g_object_get_data (G_OBJECT (chooser), "list");
+        selection = gtk_tree_view_get_selection (tv);
+        if (gtk_tree_selection_get_selected (selection, &model, &iter))
+                gtk_tree_model_get (model, &iter, LOCALE_COL, &lang, -1);
+        else
+                lang = NULL;
+
+        return lang;
+}
+
+static gint
+sort_languages (GtkTreeModel *model,
+                GtkTreeIter  *a,
+                GtkTreeIter  *b,
+                gpointer      data)
+{
+        char *ca, *cb;
+        char *la, *lb;
+        gint result;
+
+        gtk_tree_model_get (model, a, LOCALE_COL, &ca, DISPLAY_LOCALE_COL, &la, -1);
+        gtk_tree_model_get (model, b, LOCALE_COL, &cb, DISPLAY_LOCALE_COL, &lb, -1);
+
+        if (!ca)
+                result = 1;
+        else if (!cb)
+                result = -1;
+        else
+                result = strcmp (la, lb);
+
+        g_free (ca);
+        g_free (cb);
+        g_free (la);
+        g_free (lb);
+
+        return result;
+}
+
+gboolean
+um_get_iter_for_language (GtkTreeModel *model,
+                          const gchar  *lang,
+                          GtkTreeIter  *iter)
+{
+        char *l;
+        char *name;
+        char *language;
+
+        gtk_tree_model_get_iter_first (model, iter);
+        do {
+                gtk_tree_model_get (model, iter, LOCALE_COL, &l, -1);
+                if (g_strcmp0 (l, lang) == 0) {
+                        g_free (l);
+                        return TRUE;
+                }
+                g_free (l);
+        } while (gtk_tree_model_iter_next (model, iter));
+
+        name = gdm_normalize_language_name (lang);
+        if (name != NULL) {
+                language = gdm_get_language_from_name (name, NULL);
+
+                gtk_list_store_append (GTK_LIST_STORE (model), iter);
+                gtk_list_store_set (GTK_LIST_STORE (model), iter, LOCALE_COL, name, DISPLAY_LOCALE_COL, language, -1);
+                g_free (name);
+                g_free (language);
+                return TRUE;
+        }
+
+        return FALSE;
+}
+
+static void
+select_language (UmLanguageDialog *um,
+                 const gchar      *lang)
+{
+        if (um->chooser)
+                gtk_widget_hide (um->chooser);
+}
+
+static void
+row_activated (GtkTreeView       *tree_view,
+               GtkTreePath       *path,
+               GtkTreeViewColumn *column,
+               GtkWidget         *chooser)
+{
+        gtk_dialog_response (GTK_DIALOG (chooser), GTK_RESPONSE_OK);
+}
+
+static gboolean
+language_has_font (const gchar *locale)
+{
+        const FcCharSet *charset;
+        FcPattern       *pattern;
+        FcObjectSet     *object_set;
+        FcFontSet       *font_set;
+        gchar           *language_code;
+        gboolean         is_displayable;
+
+        is_displayable = FALSE;
+        pattern = NULL;
+        object_set = NULL;
+        font_set = NULL;
+
+        if (!gdm_parse_language_name (locale, &language_code, NULL, NULL, NULL))
+                return FALSE;
+
+        charset = FcLangGetCharSet ((FcChar8 *) language_code);
+        if (!charset) {
+                /* fontconfig does not know about this language */
+                is_displayable = TRUE;
+        }
+        else {
+                /* see if any fonts support rendering it */
+                pattern = FcPatternBuild (NULL, FC_LANG, FcTypeString, language_code, NULL);
+
+                if (pattern == NULL)
+                        goto done;
+
+                object_set = FcObjectSetCreate ();
+
+                if (object_set == NULL)
+                        goto done;
+
+                font_set = FcFontList (NULL, pattern, object_set);
+
+                if (font_set == NULL)
+                        goto done;
+
+                is_displayable = (font_set->nfont > 0);
+        }
+
+ done:
+        if (font_set != NULL)
+                FcFontSetDestroy (font_set);
+
+        if (object_set != NULL)
+                FcObjectSetDestroy (object_set);
+
+        if (pattern != NULL)
+                FcPatternDestroy (pattern);
+
+        g_free (language_code);
+
+        return is_displayable;
+}
+
+static void
+add_available_languages (GtkListStore *store)
+{
+        char **languages;
+        int i;
+        char *name;
+        char *language;
+        GtkTreeIter iter;
+
+        gtk_list_store_clear (store);
+
+        languages = gdm_get_all_language_names ();
+
+        for (i = 0; languages[i] != NULL; i++) {
+                if (!language_has_font (languages[i]))
+                        continue;
+
+                name = gdm_normalize_language_name (languages[i]);
+                language = gdm_get_language_from_name (name, NULL);
+
+                gtk_list_store_append (store, &iter);
+                gtk_list_store_set (store, &iter, LOCALE_COL, name, DISPLAY_LOCALE_COL, language, -1);
+
+                g_free (name);
+                g_free (language);
+        }
+
+        g_strfreev (languages);
+}
+
+void
+um_add_user_languages (GtkTreeModel *model)
+{
+        GHashTable *seen;
+        GSList *users, *l;
+        UmUser *user;
+        const char *lang;
+        char *name;
+        char *language;
+        GtkTreeIter iter;
+        UmUserManager *manager;
+        GtkListStore *store = GTK_LIST_STORE (model);
+
+        gtk_list_store_clear (store);
+
+        seen = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+        manager = um_user_manager_ref_default ();
+        users = um_user_manager_list_users (manager);
+        g_object_unref (manager);
+
+        for (l = users; l; l = l->next) {
+                user = l->data;
+                lang = um_user_get_language (user);
+                if (!lang || !language_has_font (lang)) {
+                        continue;
+                }
+
+                name = gdm_normalize_language_name (lang);
+
+                if (g_hash_table_lookup (seen, name)) {
+                        g_free (name);
+                        continue;
+                }
+
+                g_hash_table_insert (seen, name, GINT_TO_POINTER (TRUE));
+
+                language = gdm_get_language_from_name (name, NULL);
+                gtk_list_store_append (store, &iter);
+                gtk_list_store_set (store, &iter, LOCALE_COL, name, DISPLAY_LOCALE_COL, language, -1);
+
+                g_free (language);
+        }
+
+        g_slist_free (users);
+
+        /* Make sure the current locale is present */
+        name = um_get_current_language ();
+
+        if (!g_hash_table_lookup (seen, name)) {
+                language = gdm_get_language_from_name (name, NULL);
+                gtk_list_store_append (store, &iter);
+                gtk_list_store_set (store, &iter, LOCALE_COL, name, DISPLAY_LOCALE_COL, language, -1);
+                g_free (language);
+        }
+
+        g_free (name);
+
+        g_hash_table_destroy (seen);
+
+        gtk_list_store_append (store, &iter);
+        gtk_list_store_set (store, &iter, LOCALE_COL, NULL, DISPLAY_LOCALE_COL, _("Other..."), -1);
+}
+
+gchar *
+um_get_current_language (void)
+{
+        gchar *language;
+        const gchar *locale;
+
+        locale = (const gchar *) setlocale (LC_MESSAGES, NULL);
+        if (locale)
+                language = gdm_normalize_language_name (locale);
+        else
+                language = NULL;
+
+        return language;
+}
+
+GtkWidget *
+um_language_chooser_new (void)
+{
+        GtkBuilder *builder;
+        const char *filename;
+        GError *error = NULL;
+        GtkWidget *chooser;
+        GtkWidget *list;
+        GtkWidget *button;
+        GtkTreeViewColumn *column;
+        GtkCellRenderer *cell;
+        GtkListStore *store;
+
+        builder = gtk_builder_new ();
+        filename = UIDIR "/language-chooser.ui";
+        if (!g_file_test (filename, G_FILE_TEST_EXISTS))
+                filename = "../data/language-chooser.ui";
+        if (!gtk_builder_add_from_file (builder, filename, &error)) {
+                g_warning ("failed to load language chooser: %s", error->message);
+                g_error_free (error);
+                exit (1);
+        }
+
+        chooser = (GtkWidget *) gtk_builder_get_object (builder, "dialog");
+
+        list = (GtkWidget *) gtk_builder_get_object (builder, "language-list");
+        g_object_set_data (G_OBJECT (chooser), "list", list);
+        g_signal_connect (list, "row-activated",
+                          G_CALLBACK (row_activated), chooser);
+
+        button = (GtkWidget *) gtk_builder_get_object (builder, "cancel-button");
+        button = (GtkWidget *) gtk_builder_get_object (builder, "ok-button");
+        gtk_widget_grab_default (button);
+
+        cell = gtk_cell_renderer_text_new ();
+        column = gtk_tree_view_column_new_with_attributes (NULL, cell, "text", DISPLAY_LOCALE_COL, NULL);
+        gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
+        store = gtk_list_store_new (NUM_COLS, G_TYPE_STRING, G_TYPE_STRING);
+        gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (store),
+                                                 sort_languages, NULL, NULL);
+        gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
+                                              GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
+                                              GTK_SORT_ASCENDING);
+
+        gtk_tree_view_set_model (GTK_TREE_VIEW (list), GTK_TREE_MODEL (store));
+
+        add_available_languages (store);
+
+        g_object_unref (builder);
+
+        return chooser;
+}
+
+static void
+language_combo_changed (GtkComboBox      *combo,
+                        UmLanguageDialog *um)
+{
+        GtkTreeIter iter;
+        char *lang;
+
+        if (!gtk_combo_box_get_active_iter (combo, &iter))
+                return;
+
+        gtk_tree_model_get (GTK_TREE_MODEL (um->dialog_store), &iter, LOCALE_COL, &lang, -1);
+
+        if (lang) {
+                g_free (um->language);
+                um->language = lang;
+                return;
+        }
+
+#if 0
+        if (!um->chooser)
+                setup_language_chooser (um);
+#endif
+
+        gtk_window_present (GTK_WINDOW (um->chooser));
+        gtk_widget_grab_focus (um->chooser_list);
+
+        gtk_widget_set_sensitive (GTK_WIDGET (combo), FALSE);
+}
+
+UmLanguageDialog *
+um_language_dialog_new (void)
+{
+        GtkBuilder *builder;
+        GtkWidget *widget;
+        UmLanguageDialog *um;
+        const gchar *filename;
+        GtkListStore *store;
+        GError *error = NULL;
+
+        builder = gtk_builder_new ();
+
+        filename = UIDIR "/language-dialog.ui";
+        if (!g_file_test (filename, G_FILE_TEST_EXISTS))
+                filename = "../data/language-dialog.ui";
+        if (!gtk_builder_add_from_file (builder, filename, &error)) {
+                g_error ("%s", error->message);
+                g_error_free (error);
+                exit (1);
+        }
+
+        um = g_new0 (UmLanguageDialog, 1);
+
+        widget = (GtkWidget *) gtk_builder_get_object (builder, "dialog");
+        g_signal_connect (widget, "delete-event",
+                          G_CALLBACK (gtk_widget_hide_on_delete), NULL);
+        um->dialog = widget;
+
+        widget = (GtkWidget *) gtk_builder_get_object (builder, "cancel-button");
+        g_signal_connect (widget, "clicked",
+                          G_CALLBACK (cancel_language_dialog), um);
+
+        widget = (GtkWidget *) gtk_builder_get_object (builder, "ok-button");
+        g_signal_connect (widget, "clicked",
+                          G_CALLBACK (accept_language_dialog), um);
+        gtk_widget_grab_default (widget);
+
+        store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
+        gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (store),
+                                                 sort_languages, NULL, NULL);
+        gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
+                                              GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
+                                              GTK_SORT_ASCENDING);
+        um->dialog_store = store;
+
+        widget = (GtkWidget *) gtk_builder_get_object (builder, "language-combobox");
+        gtk_combo_box_set_model (GTK_COMBO_BOX (widget), GTK_TREE_MODEL (store));
+        g_signal_connect (widget, "changed",
+                          G_CALLBACK (language_combo_changed), um);
+        um->dialog_combo = widget;
+
+        um->user_icon = (GtkWidget *) gtk_builder_get_object (builder, "user-icon");
+        um->user_name = (GtkWidget *) gtk_builder_get_object (builder, "user-name");
+
+        return um;
+}
+
+void
+um_language_dialog_free (UmLanguageDialog *um)
+{
+        gtk_widget_destroy (um->dialog);
+
+        if (um->chooser)
+                gtk_widget_destroy (um->chooser);
+
+        g_free (um->language);
+
+        if (um->user)
+                g_object_unref (um->user);
+
+        g_free (um);
+}
+
+void
+um_language_dialog_set_user (UmLanguageDialog *um,
+                             UmUser           *user)
+{
+        GdkPixbuf *pixbuf;
+        const gchar *name;
+
+        if (um->user) {
+                g_object_unref (um->user);
+                um->user = NULL;
+        }
+        if (um->language) {
+                g_free (um->language);
+                um->language = NULL;
+        }
+        um->force_setting = FALSE;
+
+        um->user = user;
+        if (um->user) {
+                const gchar *language;
+
+                g_object_ref (user);
+
+                pixbuf = um_user_render_icon (user, FALSE, 48);
+                gtk_image_set_from_pixbuf (GTK_IMAGE (um->user_icon), pixbuf);
+                g_object_unref (pixbuf);
+
+                name = um_user_get_real_name (user);
+                gtk_label_set_label (GTK_LABEL (um->user_name), name);
+
+                um_add_user_languages (gtk_combo_box_get_model (GTK_COMBO_BOX (um->dialog_combo)));
+
+                language = um_user_get_language (user);
+                if (language) {
+                        select_language (um, language);
+                } else if (um_user_get_uid (user) == getuid ()) {
+                        gchar *lang;
+
+                        lang = um_get_current_language ();
+                        select_language (um, lang);
+                        g_free (lang);
+                        um->force_setting = TRUE;
+                }
+        }
+}
+
+void
+um_language_dialog_show (UmLanguageDialog *um,
+                         GtkWindow        *parent)
+{
+        gtk_window_set_transient_for (GTK_WINDOW (um->dialog), parent);
+        gtk_window_present (GTK_WINDOW (um->dialog));
+        gtk_widget_grab_focus (um->dialog_combo);
+}
+
diff --git a/panels/user-accounts/um-language-dialog.h b/panels/user-accounts/um-language-dialog.h
new file mode 100644
index 0000000..5df8af3
--- /dev/null
+++ b/panels/user-accounts/um-language-dialog.h
@@ -0,0 +1,49 @@
+/* -*- 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_LANGUAGE_DIALOG_H__
+#define __UM_LANGUAGE_DIALOG_H__
+
+#include <gtk/gtk.h>
+#include "um-user.h"
+
+G_BEGIN_DECLS
+
+typedef struct _UmLanguageDialog UmLanguageDialog;
+
+UmLanguageDialog *um_language_dialog_new      (void);
+void              um_language_dialog_free     (UmLanguageDialog *dialog);
+void              um_language_dialog_set_user (UmLanguageDialog *dialog,
+                                               UmUser            *user);
+void              um_language_dialog_show     (UmLanguageDialog *dialog,
+                                               GtkWindow        *parent);
+void              um_add_user_languages       (GtkTreeModel     *model);
+gchar            *um_get_current_language     (void);
+gboolean          um_get_iter_for_language    (GtkTreeModel     *model,
+                                               const gchar      *lang,
+                                               GtkTreeIter      *iter);
+
+GtkWidget        *um_language_chooser_new          (void);
+gchar            *um_language_chooser_get_language (GtkWidget *chooser);
+
+G_END_DECLS
+
+#endif
diff --git a/panels/user-accounts/um-lockbutton.c b/panels/user-accounts/um-lockbutton.c
new file mode 100644
index 0000000..88da58c
--- /dev/null
+++ b/panels/user-accounts/um-lockbutton.c
@@ -0,0 +1,637 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ * Author: Matthias Clasen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "um-lockbutton.h"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#define P_(s) s
+
+struct _UmLockButtonPrivate
+{
+  GPermission *permission;
+
+  gchar *text_lock;
+  gchar *text_unlock;
+  gchar *text_not_authorized;
+
+  gchar *tooltip_lock;
+  gchar *tooltip_unlock;
+  gchar *tooltip_not_authorized;
+
+  GtkWidget *box;
+  GtkWidget *eventbox;
+  GtkWidget *image;
+  GtkWidget *button;
+  GtkWidget *notebook;
+
+  GtkWidget *label_lock;
+  GtkWidget *label_unlock;
+  GtkWidget *label_not_authorized;
+
+  GCancellable *cancellable;
+
+  gboolean constructed;
+};
+
+enum
+{
+  PROP_0,
+  PROP_PERMISSION,
+  PROP_TEXT_LOCK,
+  PROP_TEXT_UNLOCK,
+  PROP_TEXT_NOT_AUTHORIZED,
+  PROP_TOOLTIP_LOCK,
+  PROP_TOOLTIP_UNLOCK,
+  PROP_TOOLTIP_NOT_AUTHORIZED
+};
+
+enum
+{
+  CHANGED_SIGNAL,
+  LAST_SIGNAL,
+};
+
+static guint signals[LAST_SIGNAL] = {0, };
+
+static void initiate_check (UmLockButton *button);
+static void do_sync_check (UmLockButton *button);
+static void update_state (UmLockButton *button);
+
+static void on_permission_changed (GPermission *permission,
+                                   GParamSpec  *pspec,
+                                   gpointer     user_data);
+
+static void on_clicked (GtkButton *button,
+                        gpointer   user_data);
+
+static void on_button_press (GtkWidget      *widget,
+                             GdkEventButton *event,
+                             gpointer        user_data);
+
+G_DEFINE_TYPE (UmLockButton, um_lock_button, GTK_TYPE_BIN);
+
+static void
+um_lock_button_finalize (GObject *object)
+{
+  UmLockButton *button = UM_LOCK_BUTTON (object);
+  UmLockButtonPrivate *priv = button->priv;
+
+  g_free (priv->text_lock);
+  g_free (priv->text_unlock);
+  g_free (priv->text_not_authorized);
+
+  g_free (priv->tooltip_lock);
+  g_free (priv->tooltip_unlock);
+  g_free (priv->tooltip_not_authorized);
+
+  if (priv->cancellable != NULL)
+    {
+      g_cancellable_cancel (priv->cancellable);
+      g_object_unref (priv->cancellable);
+    }
+
+  g_signal_handlers_disconnect_by_func (priv->permission,
+                                        on_permission_changed,
+                                        button);
+
+  g_object_unref (priv->permission);
+
+  G_OBJECT_CLASS (um_lock_button_parent_class)->finalize (object);
+}
+
+static void
+um_lock_button_get_property (GObject    *object,
+                             guint       property_id,
+                             GValue     *value,
+                             GParamSpec *pspec)
+{
+  UmLockButton *button = UM_LOCK_BUTTON (object);
+  UmLockButtonPrivate *priv = button->priv;
+
+  switch (property_id)
+    {
+    case PROP_PERMISSION:
+      g_value_set_object (value, priv->permission);
+      break;
+
+    case PROP_TEXT_LOCK:
+      g_value_set_string (value, priv->text_lock);
+      break;
+
+    case PROP_TEXT_UNLOCK:
+      g_value_set_string (value, priv->text_unlock);
+      break;
+
+    case PROP_TEXT_NOT_AUTHORIZED:
+      g_value_set_string (value, priv->text_not_authorized);
+      break;
+
+    case PROP_TOOLTIP_LOCK:
+      g_value_set_string (value, priv->tooltip_lock);
+      break;
+
+    case PROP_TOOLTIP_UNLOCK:
+      g_value_set_string (value, priv->tooltip_unlock);
+      break;
+
+    case PROP_TOOLTIP_NOT_AUTHORIZED:
+      g_value_set_string (value, priv->tooltip_not_authorized);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+um_lock_button_set_property (GObject      *object,
+                             guint         property_id,
+                             const GValue *value,
+                             GParamSpec   *pspec)
+{
+  UmLockButton *button = UM_LOCK_BUTTON (object);
+  UmLockButtonPrivate *priv = button->priv;
+
+  switch (property_id)
+    {
+    case PROP_PERMISSION:
+      priv->permission = g_value_get_object (value);
+      break;
+
+    case PROP_TEXT_LOCK:
+      g_free (priv->text_lock);
+      priv->text_lock = g_value_dup_string (value);
+      break;
+
+    case PROP_TEXT_UNLOCK:
+      g_free (priv->text_unlock);
+      priv->text_unlock = g_value_dup_string (value);
+      break;
+
+    case PROP_TEXT_NOT_AUTHORIZED:
+      g_free (priv->text_not_authorized);
+      priv->text_not_authorized = g_value_dup_string (value);
+      break;
+
+    case PROP_TOOLTIP_LOCK:
+      g_free (priv->tooltip_lock);
+      priv->tooltip_lock = g_value_dup_string (value);
+      break;
+
+    case PROP_TOOLTIP_UNLOCK:
+      g_free (priv->tooltip_unlock);
+      priv->tooltip_unlock = g_value_dup_string (value);
+      break;
+
+    case PROP_TOOLTIP_NOT_AUTHORIZED:
+      g_free (priv->tooltip_not_authorized);
+      priv->tooltip_not_authorized = g_value_dup_string (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+
+  if (priv->constructed)
+    update_state (button);
+}
+
+static void
+um_lock_button_init (UmLockButton *button)
+{
+  button->priv = G_TYPE_INSTANCE_GET_PRIVATE (button,
+                                              UM_TYPE_LOCK_BUTTON,
+                                              UmLockButtonPrivate);
+}
+
+static void
+um_lock_button_constructed (GObject *object)
+{
+  UmLockButton *button = UM_LOCK_BUTTON (object);
+  UmLockButtonPrivate *priv = button->priv;
+
+  priv->constructed = TRUE;
+
+  g_signal_connect (priv->permission, "notify",
+                    G_CALLBACK (on_permission_changed), button);
+
+  priv->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 6);
+  gtk_container_add (GTK_CONTAINER (button), priv->box);
+
+  priv->eventbox = gtk_event_box_new ();
+  gtk_event_box_set_visible_window (GTK_EVENT_BOX (priv->eventbox), FALSE);
+  gtk_container_add (GTK_CONTAINER (priv->box), priv->eventbox);
+  gtk_widget_show (priv->eventbox);
+
+  priv->image = gtk_image_new (); /* image is set in update_state() */
+  gtk_container_add (GTK_CONTAINER (priv->eventbox), priv->image);
+  gtk_widget_show (priv->image);
+
+  priv->notebook = gtk_notebook_new ();
+  gtk_notebook_set_show_tabs (GTK_NOTEBOOK (priv->notebook), FALSE);
+  gtk_notebook_set_show_border (GTK_NOTEBOOK (priv->notebook), FALSE);
+  gtk_widget_show (priv->notebook);
+
+  priv->button = gtk_button_new ();
+  gtk_container_add (GTK_CONTAINER (priv->button), priv->notebook);
+  gtk_widget_show (priv->button);
+
+  priv->label_lock = gtk_label_new (""); /* text is set in update_state */
+  gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook), priv->label_lock, NULL);
+  gtk_widget_show (priv->label_lock);
+
+  priv->label_unlock = gtk_label_new ("");
+  gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook), priv->label_unlock, NULL);
+  gtk_widget_show (priv->label_unlock);
+
+  priv->label_not_authorized = gtk_label_new ("");
+  gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook), priv->label_not_authorized, NULL);
+  gtk_widget_show (priv->label_not_authorized);
+
+  gtk_box_pack_start (GTK_BOX (priv->box), priv->button, FALSE, FALSE, 0);
+  gtk_widget_show (priv->button);
+
+  g_signal_connect (priv->eventbox, "button-press-event",
+                    G_CALLBACK (on_button_press), button);
+  g_signal_connect (priv->button, "clicked",
+                    G_CALLBACK (on_clicked), button);
+
+  gtk_widget_set_no_show_all (priv->box, TRUE);
+
+  update_state (button);
+
+  if (G_OBJECT_CLASS (um_lock_button_parent_class)->constructed != NULL)
+    G_OBJECT_CLASS (um_lock_button_parent_class)->constructed (object);
+}
+
+static void
+um_lock_button_size_request (GtkWidget      *widget,
+                             GtkRequisition *requisition)
+{
+  UmLockButtonPrivate *priv = UM_LOCK_BUTTON (widget)->priv;
+
+  gtk_widget_get_preferred_size (priv->box, requisition, NULL);
+}
+
+static void
+um_lock_button_size_allocate (GtkWidget     *widget,
+                              GtkAllocation *allocation)
+{
+  UmLockButtonPrivate *priv = UM_LOCK_BUTTON (widget)->priv;
+  GtkRequisition requisition;
+  GtkAllocation child_allocation;
+
+  gtk_widget_set_allocation (widget, allocation);
+  gtk_widget_get_preferred_size (priv->box, &requisition, NULL);
+  child_allocation.x = allocation->x;
+  child_allocation.y = allocation->y;
+  child_allocation.width = requisition.width;
+  child_allocation.height = requisition.height;
+  gtk_widget_size_allocate (priv->box, &child_allocation);
+}
+
+static void
+um_lock_button_class_init (UmLockButtonClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  gobject_class->finalize     = um_lock_button_finalize;
+  gobject_class->get_property = um_lock_button_get_property;
+  gobject_class->set_property = um_lock_button_set_property;
+  gobject_class->constructed  = um_lock_button_constructed;
+
+  widget_class->size_request = um_lock_button_size_request;
+  widget_class->size_allocate = um_lock_button_size_allocate;
+
+  g_type_class_add_private (klass, sizeof (UmLockButtonPrivate));
+
+  g_object_class_install_property (gobject_class, PROP_PERMISSION,
+    g_param_spec_object ("permission",
+                         P_("Permission"),
+                         P_("The GPermission object controlling this button"),
+                         G_TYPE_PERMISSION,
+                         G_PARAM_READWRITE |
+                         G_PARAM_CONSTRUCT_ONLY |
+                         G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_TEXT_LOCK,
+    g_param_spec_string ("text-lock",
+                         P_("Lock Text"),
+                         P_("The text to display when prompting the user to lock"),
+                         _("Lock"),
+                         G_PARAM_READWRITE |
+                         G_PARAM_CONSTRUCT |
+                         G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_TEXT_UNLOCK,
+    g_param_spec_string ("text-unlock",
+                         P_("Unlock Text"),
+                         P_("The text to display when prompting the user to unlock"),
+                         _("Unlock"),
+                         G_PARAM_READWRITE |
+                         G_PARAM_CONSTRUCT |
+                         G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_TEXT_NOT_AUTHORIZED,
+    g_param_spec_string ("text-not-authorized",
+                         P_("Not Authorized Text"),
+                         P_("The text to display when prompting the user cannot obtain authorization"),
+                         _("Locked"),
+                         G_PARAM_READWRITE |
+                         G_PARAM_CONSTRUCT |
+                         G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_TOOLTIP_LOCK,
+    g_param_spec_string ("tooltip-lock",
+                         P_("Lock Tooltip"),
+                         P_("The tooltip to display when prompting the user to lock"),
+                         _("Dialog is unlocked.\nClick to prevent further changes"),
+                         G_PARAM_READWRITE |
+                         G_PARAM_CONSTRUCT |
+                         G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_TOOLTIP_UNLOCK,
+    g_param_spec_string ("tooltip-unlock",
+                         P_("Unlock Tooltip"),
+                         P_("The tooltip to display when prompting the user to unlock"),
+                         _("Dialog is locked.\nClick to make changes"),
+                         G_PARAM_READWRITE |
+                         G_PARAM_CONSTRUCT |
+                         G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_TOOLTIP_NOT_AUTHORIZED,
+    g_param_spec_string ("tooltip-not-authorized",
+                         P_("Not Authorized Tooltip"),
+                         P_("The tooltip to display when prompting the user cannot obtain authorization"),
+                         _("System policy prevents changes.\nContact your system administrator"),
+                         G_PARAM_READWRITE |
+                         G_PARAM_CONSTRUCT |
+                         G_PARAM_STATIC_STRINGS));
+
+  signals[CHANGED_SIGNAL] = g_signal_new ("changed",
+                                          G_TYPE_FROM_CLASS (klass),
+                                          G_SIGNAL_RUN_LAST,
+                                          G_STRUCT_OFFSET (UmLockButtonClass, changed),
+                                          NULL,
+                                          NULL,
+                                          g_cclosure_marshal_VOID__VOID,
+                                          G_TYPE_NONE,
+                                          0);
+}
+
+/**
+ * um_lock_button_new:
+ * @permission: a #GPermission
+ *
+ * Creates a new lock button which reflects the @permission.
+ *
+ * Returns: a new #UmLockButton
+ *
+ * Since: 3.0
+ */
+GtkWidget *
+um_lock_button_new (GPermission *permission)
+{
+  g_return_val_if_fail (permission != NULL, NULL);
+
+  return GTK_WIDGET (g_object_new (UM_TYPE_LOCK_BUTTON,
+                                   "permission", permission,
+                                   NULL));
+}
+
+static void
+update_state (UmLockButton *button)
+{
+  UmLockButtonPrivate *priv = button->priv;
+  gint page;
+  const gchar *tooltip;
+  gboolean sensitive;
+  gboolean visible;
+  GIcon *icon;
+
+  visible = TRUE;
+  sensitive = TRUE;
+
+  gtk_label_set_text (GTK_LABEL (priv->label_lock), priv->text_lock);
+  gtk_label_set_text (GTK_LABEL (priv->label_unlock), priv->text_unlock);
+  gtk_label_set_text (GTK_LABEL (priv->label_not_authorized), priv->text_not_authorized);
+
+  if (g_permission_get_allowed (priv->permission))
+    {
+      if (g_permission_get_can_release (priv->permission))
+        {
+          page = 0;
+          tooltip = priv->tooltip_lock;
+          sensitive = TRUE;
+        }
+      else
+        {
+          page = 0;
+          tooltip = "";
+          visible = FALSE;
+        }
+    }
+  else
+    {
+      if (g_permission_get_can_acquire (priv->permission))
+        {
+          page = 1;
+          tooltip = button->priv->tooltip_unlock;
+          sensitive = TRUE;
+        }
+      else
+        {
+          page = 2;
+          tooltip = button->priv->tooltip_not_authorized;
+          sensitive = FALSE;
+        }
+    }
+
+  if (g_permission_get_allowed (priv->permission))
+    {
+      gchar *names[3];
+
+      names[0] = "changes-allow-symbolic";
+      names[1] = "changes-allow";
+      names[2] = NULL;
+      icon = g_themed_icon_new_from_names (names, -1);
+    }
+  else
+    {
+      gchar *names[3];
+
+      names[0] = "changes-prevent-symbolic";
+      names[1] = "changes-prevent";
+      names[2] = NULL;
+      icon = g_themed_icon_new_from_names (names, -1);
+    }
+
+  gtk_image_set_from_gicon (GTK_IMAGE (priv->image), icon, GTK_ICON_SIZE_BUTTON);
+  g_object_unref (icon);
+
+  gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), page);
+  gtk_widget_set_tooltip_markup (priv->box, tooltip);
+
+  gtk_widget_set_sensitive (priv->box, sensitive);
+
+  if (visible)
+    gtk_widget_show (priv->box);
+  else
+    gtk_widget_hide (priv->box);
+}
+
+static void
+on_permission_changed (GPermission *permission,
+                       GParamSpec  *pspec,
+                       gpointer     user_data)
+{
+  UmLockButton *button = UM_LOCK_BUTTON (user_data);
+
+  update_state (button);
+}
+
+static void
+acquire_cb (GObject      *source,
+            GAsyncResult *result,
+            gpointer      user_data)
+{
+  UmLockButton *button = UM_LOCK_BUTTON (user_data);
+  UmLockButtonPrivate *priv = button->priv;
+  GError *error;
+  gboolean res;
+
+  error = NULL;
+  res = g_permission_acquire_finish (priv->permission, result, &error);
+
+  if (error)
+    {
+      g_warning ("Error acquiring permission: %s", error->message);
+      g_error_free (error);
+    }
+
+  g_object_unref (priv->cancellable);
+  priv->cancellable = NULL;
+
+  update_state (button);
+}
+
+static void
+release_cb (GObject      *source,
+            GAsyncResult *result,
+            gpointer      user_data)
+{
+  UmLockButton *button = UM_LOCK_BUTTON (user_data);
+  UmLockButtonPrivate *priv = button->priv;
+  GError *error;
+  gboolean res;
+
+  error = NULL;
+  res = g_permission_release_finish (priv->permission, result, &error);
+
+  if (error)
+    {
+      g_warning ("Error releasing permission: %s", error->message);
+      g_error_free (error);
+    }
+
+  g_object_unref (priv->cancellable);
+  priv->cancellable = NULL;
+
+  update_state (button);
+}
+
+static void
+handle_click (UmLockButton *button)
+{
+  UmLockButtonPrivate *priv = button->priv;
+
+  if (!g_permission_get_allowed (priv->permission) &&
+       g_permission_get_can_acquire (priv->permission))
+    {
+      /* if we already have a pending interactive check, then do nothing */
+      if (priv->cancellable != NULL)
+        goto out;
+
+      priv->cancellable = g_cancellable_new ();
+
+      g_permission_acquire_async (priv->permission,
+                                  priv->cancellable,
+                                  acquire_cb,
+                                  button);
+    }
+  else if (g_permission_get_allowed (priv->permission) &&
+           g_permission_get_can_release (priv->permission))
+    {
+      /* if we already have a pending interactive check, then do nothing */
+      if (priv->cancellable != NULL)
+        goto out;
+
+      priv->cancellable = g_cancellable_new ();
+
+      g_permission_release_async (priv->permission,
+                                  priv->cancellable,
+                                  release_cb,
+                                  button);
+    }
+
+ out: ;
+}
+
+static void
+on_clicked (GtkButton *_button,
+            gpointer   user_data)
+
+{
+  handle_click (UM_LOCK_BUTTON (user_data));
+}
+
+static void
+on_button_press (GtkWidget      *widget,
+                 GdkEventButton *event,
+                 gpointer        user_data)
+{
+  handle_click (UM_LOCK_BUTTON (user_data));
+}
+
+/**
+ * um_lock_button_get_permission:
+ * @button: a #UmLockButton
+ *
+ * Obtains the #GPermission object that controls @button.
+ *
+ * Returns: the #GPermission of @button
+ *
+ * Since: 3.0
+ */
+GPermission *
+um_lock_button_get_permission (UmLockButton *button)
+{
+  g_return_val_if_fail (UM_IS_LOCK_BUTTON (button), NULL);
+
+  return button->priv->permission;
+}
+
diff --git a/panels/user-accounts/um-lockbutton.h b/panels/user-accounts/um-lockbutton.h
new file mode 100644
index 0000000..6becfbc
--- /dev/null
+++ b/panels/user-accounts/um-lockbutton.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ * Author: Matthias Clasen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __UM_LOCK_BUTTON_H__
+#define __UM_LOCK_BUTTON_H__
+
+#include <gtk/gtk.h>
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define UM_TYPE_LOCK_BUTTON         (um_lock_button_get_type ())
+#define UM_LOCK_BUTTON(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), UM_TYPE_LOCK_BUTTON, UmLockButton))
+#define UM_LOCK_BUTTON_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST ((k), UM_LOCK_BUTTON,  UmLockButtonClass))
+#define UM_IS_LOCK_BUTTON(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), UM_TYPE_LOCK_BUTTON))
+#define UM_IS_LOCK_BUTTON_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), UM_TYPE_LOCK_BUTTON))
+#define UM_LOCK_BUTTON_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), UM_TYPE_LOCK_BUTTON, UmLockButtonClass))
+
+typedef struct _UmLockButton        UmLockButton;
+typedef struct _UmLockButtonClass   UmLockButtonClass;
+typedef struct _UmLockButtonPrivate UmLockButtonPrivate;
+
+struct _UmLockButton
+{
+  GtkBin parent;
+
+  UmLockButtonPrivate *priv;
+};
+
+struct _UmLockButtonClass
+{
+  GtkBinClass parent_class;
+
+  void (*changed) (UmLockButton *button);
+
+  void (*reserved0) (void);
+  void (*reserved1) (void);
+  void (*reserved2) (void);
+  void (*reserved3) (void);
+  void (*reserved4) (void);
+  void (*reserved5) (void);
+  void (*reserved6) (void);
+  void (*reserved7) (void);
+};
+
+GType        um_lock_button_get_type       (void) G_GNUC_CONST;
+GtkWidget   *um_lock_button_new            (GPermission   *permission);
+GPermission *um_lock_button_get_permission (UmLockButton *button);
+
+
+G_END_DECLS
+
+#endif  /* __UM_LOCK_BUTTON_H__ */
diff --git a/panels/user-accounts/um-login-options.c b/panels/user-accounts/um-login-options.c
new file mode 100644
index 0000000..99b57ce
--- /dev/null
+++ b/panels/user-accounts/um-login-options.c
@@ -0,0 +1,433 @@
+/* -*- 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 <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <gconf/gconf-client.h>
+#include <gconf/gconf-value.h>
+#include <polkit/polkit.h>
+
+#include "um-login-options.h"
+#include "um-lockbutton.h"
+#include "um-user-manager.h"
+#include "um-user.h"
+
+struct _UmLoginOptions {
+        GtkWidget *autologin_combo;
+        GtkWidget *userlist_check;
+        GtkWidget *power_check;
+        GtkWidget *hints_check;
+        GtkWidget *guest_check;
+        GtkWidget *lock_button;
+        PolkitPermission *permission;
+
+        UmUserManager *manager;
+
+        DBusGProxy *proxy;
+        DBusGConnection *connection;
+};
+
+enum {
+        AUTOLOGIN_NAME_COL,
+        AUTOLOGIN_USER_COL,
+        NUM_AUTOLOGIN_COLS
+};
+
+static gint
+sort_login_users (GtkTreeModel *model,
+                  GtkTreeIter  *a,
+                  GtkTreeIter  *b,
+                  gpointer      data)
+{
+        UmUser *ua, *ub;
+        gint result;
+
+        gtk_tree_model_get (model, a, AUTOLOGIN_USER_COL, &ua, -1);
+        gtk_tree_model_get (model, b, AUTOLOGIN_USER_COL, &ub, -1);
+
+        if (ua == NULL)
+                result = -1;
+        else if (ub == NULL)
+                result = 1;
+        else if (um_user_get_uid (ua) == getuid ())
+                result = -1;
+        else if (um_user_get_uid (ub) == getuid ())
+                result = 1;
+        else
+                result = um_user_collate (ua, ub);
+
+        if (ua)
+                g_object_unref (ua);
+
+        if (ub)
+                g_object_unref (ub);
+
+        return result;
+}
+
+static void
+user_added (UmUserManager *um, UmUser *user, UmLoginOptions *d)
+{
+        GtkComboBox *combo;
+        GtkListStore *store;
+        GtkTreeIter iter;
+
+        g_debug ("adding user '%s', %d", um_user_get_user_name (user), um_user_get_automatic_login (user));
+        combo = GTK_COMBO_BOX (d->autologin_combo);
+        store = (GtkListStore*)gtk_combo_box_get_model (combo);
+        gtk_list_store_append (store, &iter);
+        gtk_list_store_set (store, &iter,
+                            AUTOLOGIN_NAME_COL, um_user_get_display_name (user),
+                            AUTOLOGIN_USER_COL, user,
+                            -1);
+
+        if (um_user_get_automatic_login (user)) {
+                gtk_combo_box_set_active_iter (combo, &iter);
+        }
+}
+
+static void
+user_removed (UmUserManager *um, UmUser *user, UmLoginOptions *d)
+{
+        GtkComboBox *combo;
+        GtkTreeModel *model;
+        GtkListStore *store;
+        GtkTreeIter iter;
+        UmUser *u;
+
+        combo = GTK_COMBO_BOX (d->autologin_combo);
+        model = gtk_combo_box_get_model (combo);
+        store = (GtkListStore*)model;
+
+        gtk_combo_box_get_active_iter (combo, &iter);
+        gtk_tree_model_get (model, &iter, AUTOLOGIN_USER_COL, &u, -1);
+        if (u != NULL) {
+                if (um_user_get_uid (user) == um_user_get_uid (u)) {
+                        /* autologin user got removed, set back to Disabled */
+                        gtk_list_store_remove (store, &iter);
+                        gtk_combo_box_set_active (combo, 0);
+                        g_object_unref (u);
+                        return;
+                }
+                g_object_unref (u);
+        }
+        if (gtk_tree_model_get_iter_first (model, &iter)) {
+                do {
+                        gtk_tree_model_get (model, &iter, AUTOLOGIN_USER_COL, &u, -1);
+
+                        if (u != NULL) {
+                                if (um_user_get_uid (user) == um_user_get_uid (u)) {
+                                        gtk_list_store_remove (store, &iter);
+                                        g_object_unref (u);
+                                        return;
+                                }
+                                g_object_unref (u);
+                        }
+                } while (gtk_tree_model_iter_next (model, &iter));
+        }
+}
+
+static void
+user_changed (UmUserManager  *manager,
+              UmUser         *user,
+              UmLoginOptions *d)
+{
+        /* FIXME */
+}
+
+static void
+users_loaded (UmUserManager  *manager,
+              UmLoginOptions *d)
+{
+        GSList *list, *l;
+        UmUser *user;
+
+        list = um_user_manager_list_users (manager);
+        for (l = list; l; l = l->next) {
+                user = l->data;
+                user_added (manager, user, d);
+        }
+        g_slist_free (list);
+
+        g_signal_connect (manager, "user-added", G_CALLBACK (user_added), d);
+        g_signal_connect (manager, "user-removed", G_CALLBACK (user_removed), d);
+        g_signal_connect (manager, "user-changed", G_CALLBACK (user_changed), d);
+}
+
+static void update_login_options (GtkWidget *widget, UmLoginOptions *d);
+
+static void
+update_boolean_from_gconf (GtkWidget      *widget,
+                           UmLoginOptions *d)
+{
+        gchar *cmdline;
+        gboolean value;
+        gchar *std_out;
+        gchar *std_err;
+        gint status;
+        GError *error;
+        const gchar *key;
+
+        key = g_object_get_data (G_OBJECT (widget), "gconf-key");
+
+        /* GConf fail.
+         * gconfd does not pick up any changes in the default or mandatory
+         * databases at runtime. Even a SIGHUP doesn't seem to help. So we
+         * have to use gconftool to go get the current mandatory values.
+         */
+        cmdline = g_strdup_printf ("gconftool-2 --direct --config-source=\"xml:readonly:/etc/gconf/gconf.xml.defaults;xml:readonly:/etc/gconf/gconf.xml.mandatory\" --get %s", key);
+
+        error = NULL;
+        std_out = NULL;
+        std_err = NULL;
+        if (!g_spawn_command_line_sync (cmdline, &std_out, &std_err, &status, &error)) {
+                g_warning ("Failed to run '%s': %s", cmdline, error->message);
+                g_error_free (error);
+                g_free (cmdline);
+                g_free (std_out);
+                g_free (std_err);
+                return;
+        }
+        if (WEXITSTATUS (status) != 0) {
+                g_warning ("Failed to run '%s': %s", cmdline, std_err);
+                g_free (cmdline);
+                g_free (std_out);
+                g_free (std_err);
+                return;
+        }
+
+        if (std_out[strlen (std_out) - 1] == '\n') {
+                std_out[strlen (std_out) - 1] = 0;
+        }
+
+        if (g_strcmp0 (std_out, "true") == 0) {
+                value = TRUE;
+        }
+        else {
+                value = FALSE;
+        }
+        g_signal_handlers_block_by_func (widget, update_login_options, d);
+        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), !value);
+        g_signal_handlers_unblock_by_func (widget, update_login_options, d);
+
+        g_free (cmdline);
+        g_free (std_out);
+        g_free (std_err);
+}
+
+static void
+update_login_options (GtkWidget      *widget,
+                      UmLoginOptions *d)
+{
+        GError *error;
+        gboolean active;
+        GConfValue *value;
+        const gchar *key = NULL;
+        gchar *value_string;
+
+        if (widget == d->userlist_check ||
+            widget == d->power_check) {
+                active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
+                key = g_object_get_data (G_OBJECT (widget), "gconf-key");
+        }
+        else {
+                g_warning ("unhandled option in update_login_options");
+                return;
+        }
+
+        error = NULL;
+        value = gconf_value_new (GCONF_VALUE_BOOL);
+        gconf_value_set_bool (value, !active);
+        value_string = gconf_value_encode (value);
+        if (!dbus_g_proxy_call (d->proxy, "SetMandatoryValue",
+                                &error,
+                                G_TYPE_STRING, key,
+                                G_TYPE_STRING, value_string,
+                                G_TYPE_INVALID,
+                                G_TYPE_INVALID)) {
+               g_warning ("error calling SetMandatoryValue: %s\n", error->message);
+               g_error_free (error);
+       }
+       g_free (value_string);
+       gconf_value_free (value);
+       update_boolean_from_gconf (widget, d);
+}
+
+static void
+update_autologin (GtkWidget      *widget,
+                  UmLoginOptions *d)
+{
+        GtkComboBox *combo = GTK_COMBO_BOX (widget);
+        GtkTreeModel *model;
+        GtkTreeIter iter;
+        UmUser *user;
+        gboolean enabled;
+
+        if (!gtk_widget_is_sensitive (widget))
+                return;
+
+        model = gtk_combo_box_get_model (combo);
+        gtk_combo_box_get_active_iter (combo, &iter);
+        gtk_tree_model_get (model, &iter, AUTOLOGIN_USER_COL, &user, -1);
+        if (user) {
+                enabled = TRUE;
+        }
+        else {
+                enabled = FALSE;
+                user = um_user_manager_get_user_by_id (d->manager, getuid ());
+                g_object_ref (user);
+        }
+
+        um_user_set_automatic_login (user, enabled);
+
+        g_object_unref (user);
+}
+
+static void
+lockbutton_changed (UmLockButton *button,
+                    gpointer      data)
+{
+        UmLoginOptions *d = data;
+        gboolean authorized;
+
+        authorized = g_permission_get_allowed (G_PERMISSION (d->permission));
+
+        gtk_widget_set_sensitive (d->autologin_combo, authorized);
+        gtk_widget_set_sensitive (d->userlist_check, authorized);
+        gtk_widget_set_sensitive (d->power_check, authorized);
+        gtk_widget_set_sensitive (d->hints_check, authorized);
+        gtk_widget_set_sensitive (d->guest_check, authorized);
+}
+
+UmLoginOptions *
+um_login_options_new (GtkBuilder *builder)
+{
+        GtkWidget *widget;
+        GtkWidget *box;
+        GtkListStore *store;
+        GtkTreeIter iter;
+        GError *error;
+        UmLoginOptions *um;
+
+        /* TODO: get actual login screen options */
+
+        um = g_new0 (UmLoginOptions, 1);
+
+        um->manager = um_user_manager_ref_default ();
+        g_signal_connect (um->manager, "users-loaded",
+                          G_CALLBACK (users_loaded), um);
+
+        widget = (GtkWidget *) gtk_builder_get_object (builder, "dm-automatic-login-combobox");
+        um->autologin_combo = widget;
+
+        store = gtk_list_store_new (2, G_TYPE_STRING, UM_TYPE_USER);
+        gtk_combo_box_set_model (GTK_COMBO_BOX (widget), GTK_TREE_MODEL (store));
+        gtk_list_store_append (store, &iter);
+        gtk_list_store_set (store, &iter,
+                            AUTOLOGIN_NAME_COL, _("Disabled"),
+                            AUTOLOGIN_USER_COL, NULL,
+                            -1);
+
+        gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0);
+
+        gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (store), sort_login_users, NULL, NULL);
+        gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, GTK_SORT_ASCENDING);
+
+        g_signal_connect (widget, "changed",
+                          G_CALLBACK (update_autologin), um);
+
+        widget = (GtkWidget *) gtk_builder_get_object (builder, "dm-show-user-list-checkbutton");
+        um->userlist_check = widget;
+        g_signal_connect (widget, "toggled",
+                          G_CALLBACK (update_login_options), um);
+        g_object_set_data (G_OBJECT (widget), "gconf-key",
+                           "/apps/gdm/simple-greeter/disable_user_list");
+        update_boolean_from_gconf (widget, um);
+
+        widget = (GtkWidget *) gtk_builder_get_object (builder, "dm-show-power-buttons-checkbutton");
+        um->power_check = widget;
+        g_signal_connect(widget, "toggled",
+                         G_CALLBACK (update_login_options), um);
+        g_object_set_data (G_OBJECT (widget), "gconf-key",
+                           "/apps/gdm/simple-greeter/disable_restart_buttons");
+        update_boolean_from_gconf (widget, um);
+
+        widget = (GtkWidget *) gtk_builder_get_object (builder, "dm-show-password-hints-checkbutton");
+        um->hints_check = widget;
+        g_signal_connect (widget, "toggled",
+                          G_CALLBACK (update_login_options), um);
+
+        widget = (GtkWidget *) gtk_builder_get_object (builder, "dm-allow-guest-login-checkbutton");
+        um->guest_check = widget;
+        g_signal_connect (widget, "toggled",
+                          G_CALLBACK (update_login_options), um);
+
+        um->permission = polkit_permission_new_sync ("org.freedesktop.accounts.set-login-option", NULL, NULL, NULL);
+        widget = um_lock_button_new (um->permission);
+        gtk_widget_show (widget);
+        box = (GtkWidget *)gtk_builder_get_object (builder, "lockbutton-alignment");
+        gtk_container_add (GTK_CONTAINER (box), widget);
+        g_signal_connect (widget, "changed",
+                          G_CALLBACK (lockbutton_changed), um);
+        lockbutton_changed (UM_LOCK_BUTTON (widget), um);
+        um->lock_button = widget;
+
+        error = NULL;
+        um->connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
+        if (error != NULL) {
+                g_warning ("Failed to get system bus connection: %s", error->message);
+                g_error_free (error);
+        }
+
+        um->proxy = dbus_g_proxy_new_for_name (um->connection,
+                                               "org.gnome.GConf.Defaults",
+                                               "/",
+                                               "org.gnome.GConf.Defaults");
+
+        if (um->proxy == NULL) {
+                g_warning ("Cannot connect to GConf defaults mechanism");
+        }
+
+        return um;
+}
+
+void
+um_login_options_free (UmLoginOptions *um)
+{
+  if (um->manager)
+    g_object_unref (um->manager);
+  if (um->proxy)
+    g_object_unref (um->proxy);
+  if (um->connection)
+    dbus_g_connection_unref (um->connection);
+
+  g_free (um);
+}
+
diff --git a/panels/user-accounts/um-login-options.h b/panels/user-accounts/um-login-options.h
new file mode 100644
index 0000000..949e0c4
--- /dev/null
+++ b/panels/user-accounts/um-login-options.h
@@ -0,0 +1,34 @@
+/* -*- 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_LOGIN_OPTIONS_H__
+#define __UM_LOGIN_OPTIONS_H__
+
+G_BEGIN_DECLS
+
+typedef struct _UmLoginOptions UmLoginOptions;
+
+UmLoginOptions *um_login_options_new      (GtkBuilder *builder);
+void            um_login_options_free     (UmLoginOptions *options);
+
+G_END_DECLS
+
+#endif
diff --git a/panels/user-accounts/um-password-dialog.c b/panels/user-accounts/um-password-dialog.c
new file mode 100644
index 0000000..bd6ad8c
--- /dev/null
+++ b/panels/user-accounts/um-password-dialog.c
@@ -0,0 +1,834 @@
+/* -*- 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 <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include "um-password-dialog.h"
+#include "um-user-manager.h"
+#include "um-strength-bar.h"
+#include "um-utils.h"
+#include "run-passwd.h"
+
+#define MIN_PASSWORD_LEN 6
+
+struct _UmPasswordDialog {
+        GtkWidget *dialog;
+        GtkWidget *user_icon;
+        GtkWidget *user_name;
+        GtkWidget *action_label;
+        GtkWidget *action_combo;
+        GtkWidget *password_entry;
+        GtkWidget *verify_entry;
+        GtkWidget *strength_indicator;
+        GtkWidget *strength_indicator_label;
+        GtkWidget *normal_hint_entry;
+        GtkWidget *normal_hint_label;
+        GtkWidget *generate_button;
+        GtkWidget *generate_menu;
+        GtkWidget *show_password_button;
+        GtkWidget *ok_button;
+
+        UmUser *user;
+
+        GtkWidget *old_password_label;
+        GtkWidget *old_password_entry;
+        gboolean   old_password_ok;
+
+        PasswdHandler *passwd_handler;
+};
+
+static void
+generate_clicked (GtkButton        *button,
+                  UmPasswordDialog *um)
+{
+        gtk_menu_popup (GTK_MENU (um->generate_menu),
+                        NULL, NULL,
+                        (GtkMenuPositionFunc) popup_menu_below_button, um->generate_button,
+                        0, gtk_get_current_event_time ());
+
+        gtk_widget_set_has_tooltip (um->generate_button, FALSE);
+}
+
+static void
+generate_draw (GtkWidget        *widget,
+               cairo_t          *cr,
+               UmPasswordDialog *um)
+{
+        GtkAllocation allocation;
+
+        if (!gtk_widget_is_sensitive (widget))
+                return;
+
+        gtk_widget_get_allocation (widget, &allocation);
+        gtk_paint_expander (gtk_widget_get_style (widget),
+                            cr,
+                            gtk_widget_get_state (widget),
+                            widget,
+                            NULL,
+                            allocation.x + allocation.width,
+                            allocation.y + allocation.height,
+                            GTK_EXPANDER_EXPANDED);
+}
+
+static void
+activate_password_item (GtkMenuItem      *item,
+                        UmPasswordDialog *um)
+{
+        const char *password;
+
+        password = gtk_menu_item_get_label (item);
+
+        gtk_entry_set_text (GTK_ENTRY (um->password_entry), password);
+        gtk_entry_set_text (GTK_ENTRY (um->verify_entry), "");
+        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (um->show_password_button), TRUE);
+        gtk_widget_grab_focus (um->verify_entry);
+}
+
+static void generate_passwords (UmPasswordDialog *um);
+
+static void
+activate_generate_item (GtkMenuItem      *item,
+                        UmPasswordDialog *um)
+{
+        generate_passwords (um);
+        generate_clicked (GTK_BUTTON (um->generate_button), um);
+}
+
+static void
+on_generate_menu_unmap (GtkWidget        *menu,
+                        UmPasswordDialog *um)
+{
+        gtk_widget_set_has_tooltip (um->generate_button, TRUE);
+}
+
+static void
+generate_passwords (UmPasswordDialog *um)
+{
+        gint min_len, max_len;
+        gchar *output, *err, *cmdline;
+        gint status;
+        GError *error;
+        gchar **lines;
+        gint i;
+        GtkWidget *item;
+
+        min_len = 6;
+        max_len = 12;
+
+        if (um->generate_menu) {
+                gtk_widget_destroy (um->generate_menu);
+        }
+
+        um->generate_menu = gtk_menu_new ();
+        g_signal_connect (um->generate_menu, "unmap",
+                          G_CALLBACK (on_generate_menu_unmap), um);
+
+        cmdline = g_strdup_printf ("apg -n 6 -M SNC -m %d -x %d", min_len, max_len);
+        error = NULL;
+        output = NULL;
+        err = NULL;
+        if (!g_spawn_command_line_sync (cmdline, &output, &err, &status, &error)) {
+                g_warning ("Failed to run apg: %s", error->message);
+                g_error_free (error);
+        }
+
+        if (WEXITSTATUS (status) == 0) {
+                lines = g_strsplit (output, "\n", 0);
+                for (i = 0; lines[i]; i++) {
+                        if (lines[i][0] == 0)
+                                continue;
+
+                        item = gtk_menu_item_new_with_label (lines[i]);
+                        g_signal_connect (item, "activate",
+                                          G_CALLBACK (activate_password_item), um);
+                        gtk_widget_show (item);
+                        gtk_menu_shell_append (GTK_MENU_SHELL (um->generate_menu), item);
+                }
+                g_strfreev (lines);
+        }
+        else {
+                g_warning ("agp returned an error: %s", err);
+        }
+
+        g_free (cmdline);
+        g_free (output);
+        g_free (err);
+
+        item = gtk_separator_menu_item_new ();
+        gtk_widget_show (item);
+        gtk_menu_shell_append (GTK_MENU_SHELL (um->generate_menu), item);
+
+        item = gtk_menu_item_new_with_label (_("More choices..."));
+        g_signal_connect (item, "activate",
+                          G_CALLBACK (activate_generate_item), um);
+        gtk_widget_show (item);
+        gtk_menu_shell_append (GTK_MENU_SHELL (um->generate_menu), item);
+}
+
+/* This code is based on the Master Password dialog in Firefox
+ * (pref-masterpass.js)
+ * Original code triple-licensed under the MPL, GPL, and LGPL
+ * so is license-compatible with this file
+ */
+static gdouble
+compute_password_strength (const gchar *password)
+{
+        gint length;
+        gint upper, lower, digit, misc;
+        gint i;
+        gdouble strength;
+
+        length = strlen (password);
+        upper = 0;
+        lower = 0;
+        digit = 0;
+        misc = 0;
+
+        for (i = 0; i < length ; i++) {
+                if (g_ascii_isdigit (password[i]))
+                        digit++;
+                else if (g_ascii_islower (password[i]))
+                        lower++;
+                else if (g_ascii_isupper (password[i]))
+                        upper++;
+                else
+                        misc++;
+        }
+
+        if (length > 5)
+                length = 5;
+
+        if (digit > 3)
+                digit = 3;
+
+        if (upper > 3)
+                upper = 3;
+
+        if (misc > 3)
+                misc = 3;
+
+        strength = ((length * 0.1) - 0.2) +
+                    (digit * 0.1) +
+                    (misc * 0.15) +
+                    (upper * 0.1);
+
+        strength = CLAMP (strength, 0.0, 1.0);
+
+        return strength;
+}
+
+static void
+finish_password_change (UmPasswordDialog *um)
+{
+        gtk_widget_hide (um->dialog);
+
+        gtk_entry_set_text (GTK_ENTRY (um->password_entry), " ");
+        gtk_entry_set_text (GTK_ENTRY (um->verify_entry), "");
+        gtk_entry_set_text (GTK_ENTRY (um->normal_hint_entry), "");
+        gtk_entry_set_text (GTK_ENTRY (um->old_password_entry), "");
+
+        um_password_dialog_set_user (um, NULL);
+}
+
+static void
+cancel_password_dialog (GtkButton        *button,
+                        UmPasswordDialog *um)
+{
+        finish_password_change (um);
+}
+
+static void
+dialog_closed (GtkWidget        *dialog,
+               gint              response_id,
+               UmPasswordDialog *um)
+{
+        gtk_widget_destroy (dialog);
+}
+
+static void
+password_changed_cb (PasswdHandler    *handler,
+                     GError           *error,
+                     UmPasswordDialog *um)
+{
+        GtkWidget *dialog;
+        const gchar *primary_text;
+        const gchar *secondary_text;
+
+        gtk_widget_set_sensitive (um->dialog, TRUE);
+        gdk_window_set_cursor (gtk_widget_get_window (um->dialog), NULL);
+
+        if (!error) {
+                finish_password_change (um);
+                return;
+        }
+
+        if (error->code == PASSWD_ERROR_REJECTED) {
+                primary_text = error->message;
+                secondary_text = _("Please choose another password.");
+
+                gtk_entry_set_text (GTK_ENTRY (um->password_entry), "");
+                gtk_widget_grab_focus (um->password_entry);
+
+                gtk_entry_set_text (GTK_ENTRY (um->verify_entry), "");
+        }
+        else if (error->code == PASSWD_ERROR_AUTH_FAILED) {
+                primary_text = error->message;
+                secondary_text = _("Please type your current password again.");
+
+                gtk_entry_set_text (GTK_ENTRY (um->old_password_entry), "");
+                gtk_widget_grab_focus (um->old_password_entry);
+        }
+        else {
+                primary_text = _("Password could not be changed");
+                secondary_text = error->message;
+        }
+
+        dialog = gtk_message_dialog_new (GTK_WINDOW (um->dialog),
+                                         GTK_DIALOG_MODAL,
+                                         GTK_MESSAGE_ERROR,
+                                         GTK_BUTTONS_CLOSE,
+                                         "%s", primary_text);
+        gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+                                                  "%s", secondary_text);
+        g_signal_connect (dialog, "response",
+                          G_CALLBACK (dialog_closed), um);
+        gtk_window_present (GTK_WINDOW (dialog));
+
+}
+
+static void
+accept_password_dialog (GtkButton        *button,
+                        UmPasswordDialog *um)
+{
+        GtkTreeModel *model;
+        GtkTreeIter iter;
+        gint mode;
+        const gchar *hint;
+        const gchar *password;
+
+        model = gtk_combo_box_get_model (GTK_COMBO_BOX (um->action_combo));
+        gtk_combo_box_get_active_iter (GTK_COMBO_BOX (um->action_combo), &iter);
+        gtk_tree_model_get (model, &iter, 1, &mode, -1);
+
+        password = gtk_entry_get_text (GTK_ENTRY (um->password_entry));
+        hint = gtk_entry_get_text (GTK_ENTRY (um->normal_hint_entry));
+
+        if (mode == 0 && um_user_get_uid (um->user) == getuid ()) {
+                GdkDisplay *display;
+                GdkCursor *cursor;
+
+                /* When setting a password for the current user,
+                 * use passwd directly, to preserve the audit trail
+                 * and to e.g. update the keyring password.
+                 */
+                passwd_change_password (um->passwd_handler, password, (PasswdCallback) password_changed_cb, um);
+                gtk_widget_set_sensitive (um->dialog, FALSE);
+                display = gtk_widget_get_display (um->dialog);
+                cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
+                gdk_window_set_cursor (gtk_widget_get_window (um->dialog), cursor);
+                gdk_display_flush (display);
+                gdk_cursor_unref (cursor);
+        }
+        else {
+                um_user_set_password (um->user, mode, password, hint);
+                finish_password_change (um);
+        }
+}
+
+static void
+update_sensitivity (UmPasswordDialog *um)
+{
+        const gchar *password, *verify;
+        const gchar *old_password;
+        const gchar *tooltip;
+        gboolean can_change;
+
+        password = gtk_entry_get_text (GTK_ENTRY (um->password_entry));
+        verify = gtk_entry_get_text (GTK_ENTRY (um->verify_entry));
+        old_password = gtk_entry_get_text (GTK_ENTRY (um->old_password_entry));
+
+        /* TODO: configurable policies for acceptable passwords */
+        if (strlen (password) < MIN_PASSWORD_LEN) {
+                can_change = FALSE;
+                if (password[0] == '\0') {
+                        tooltip = _("You need to enter a new password");
+                }
+                else {
+                        tooltip = _("The new password is too short");
+                }
+        }
+        else if (strcmp (password, verify) != 0) {
+                can_change = FALSE;
+                if (verify[0] == '\0') {
+                        tooltip = _("You need to confirm the password");
+                }
+                else {
+                        tooltip = _("The passwords do not match");
+                }
+        }
+        else if (!um->old_password_ok) {
+                can_change = FALSE;
+                if (old_password[0] == '\0') {
+                        tooltip = _("You need to enter your current password");
+                }
+                else {
+                        tooltip = _("The current password is not correct");
+                }
+        }
+        else {
+                can_change = TRUE;
+                tooltip = NULL;
+        }
+
+        gtk_widget_set_sensitive (um->ok_button, can_change);
+        gtk_widget_set_tooltip_text (um->ok_button, tooltip);
+}
+
+static void
+action_changed (GtkComboBox      *combo,
+                UmPasswordDialog *um)
+{
+        gint active;
+
+        active = gtk_combo_box_get_active (combo);
+        if (active == 0) {
+                gtk_widget_set_sensitive (um->password_entry, TRUE);
+                gtk_widget_set_sensitive (um->generate_button, TRUE);
+                gtk_widget_set_has_tooltip (um->generate_button, TRUE);
+                gtk_widget_set_sensitive (um->verify_entry, TRUE);
+                gtk_widget_set_sensitive (um->old_password_entry, TRUE);
+                gtk_widget_set_sensitive (um->normal_hint_entry, TRUE);
+                gtk_widget_set_sensitive (um->normal_hint_label, TRUE);
+                gtk_widget_set_sensitive (um->strength_indicator_label, TRUE);
+                gtk_widget_set_sensitive (um->show_password_button, TRUE);
+
+                update_sensitivity (um);
+        }
+        else {
+                gtk_widget_set_sensitive (um->password_entry, FALSE);
+                gtk_widget_set_sensitive (um->generate_button, FALSE);
+                gtk_widget_set_has_tooltip (um->generate_button, FALSE);
+                gtk_widget_set_sensitive (um->verify_entry, FALSE);
+                gtk_widget_set_sensitive (um->old_password_entry, FALSE);
+                gtk_widget_set_sensitive (um->normal_hint_entry, FALSE);
+                gtk_widget_set_sensitive (um->normal_hint_label, FALSE);
+                gtk_widget_set_sensitive (um->strength_indicator_label, FALSE);
+                gtk_widget_set_sensitive (um->show_password_button, FALSE);
+                gtk_widget_set_sensitive (um->ok_button, TRUE);
+        }
+}
+
+static void
+show_password_toggled (GtkToggleButton  *button,
+                       UmPasswordDialog *um)
+{
+        gboolean active;
+
+        active = gtk_toggle_button_get_active (button);
+        gtk_entry_set_visibility (GTK_ENTRY (um->password_entry), active);
+        gtk_entry_set_visibility (GTK_ENTRY (um->verify_entry), active);
+}
+
+static void
+update_password_strength (UmPasswordDialog *um)
+{
+        const gchar *password;
+        gdouble strength;
+        const gchar *hint;
+
+        password = gtk_entry_get_text (GTK_ENTRY (um->password_entry));
+
+        strength = compute_password_strength (password);
+
+        if (strlen (password) < MIN_PASSWORD_LEN) {
+                strength = 0.0;
+                if (password[0] == '\0')
+                        hint = "";
+                else
+                        hint = C_("Password strength", "Too short");
+        }
+        else if (strength < 0.50)
+                hint = C_("Password strength", "Weak");
+        else if (strength < 0.75)
+                hint = C_("Password strength", "Fair");
+        else if (strength < 0.90)
+                hint = C_("Password strength", "Good");
+        else
+                hint = C_("Password strength", "Strong");
+
+        um_strength_bar_set_strength (UM_STRENGTH_BAR (um->strength_indicator), strength);
+        gtk_label_set_label (GTK_LABEL (um->strength_indicator_label), hint);
+}
+
+static void
+password_entry_changed (GtkEntry         *entry,
+                        GParamSpec       *pspec,
+                        UmPasswordDialog *um)
+{
+        update_password_strength (um);
+        update_sensitivity (um);
+}
+
+static void
+verify_entry_changed (GtkEntry         *entry,
+                      GParamSpec       *pspec,
+                      UmPasswordDialog *um)
+{
+        clear_entry_validation_error (GTK_ENTRY (entry));
+        update_password_strength (um);
+        update_sensitivity (um);
+}
+
+static gboolean
+verify_entry_focus_out (GtkWidget        *entry,
+                        GdkEventFocus    *event,
+                        UmPasswordDialog *um)
+{
+        const char *password;
+        const char *verify;
+
+        password = gtk_entry_get_text (GTK_ENTRY (um->password_entry));
+        verify = gtk_entry_get_text (GTK_ENTRY (um->verify_entry));
+
+        if (strlen (password) > 0 && strlen (verify) > 0) {
+                if (strcmp (password, verify) != 0) {
+                        set_entry_validation_error (GTK_ENTRY (um->verify_entry),
+                                                    _("Passwords do not match"));
+                }
+                else {
+                        clear_entry_validation_error (GTK_ENTRY (um->verify_entry));
+                }
+        }
+
+        return FALSE;
+}
+
+static void
+entry_size_changed (GtkWidget     *entry,
+                    GtkAllocation *allocation,
+                    GtkWidget     *label)
+{
+        gtk_widget_set_size_request (label, allocation->width, -1);
+}
+
+static void
+auth_cb (PasswdHandler    *handler,
+         GError           *error,
+         UmPasswordDialog *um)
+{
+        if (error) {
+                um->old_password_ok = FALSE;
+                set_entry_validation_error (GTK_ENTRY (um->old_password_entry),
+                                            _("Wrong password"));
+        }
+        else {
+                um->old_password_ok = TRUE;
+                clear_entry_validation_error (GTK_ENTRY (um->old_password_entry));
+        }
+
+        update_sensitivity (um);
+}
+
+static gboolean
+old_password_entry_focus_out (GtkWidget        *entry,
+                              GdkEventFocus    *event,
+                              UmPasswordDialog *um)
+{
+        const char *text;
+
+        text = gtk_entry_get_text (GTK_ENTRY (entry));
+        if (strlen (text) > 0) {
+                passwd_authenticate (um->passwd_handler, text,
+                                     (PasswdCallback)auth_cb, um);
+        }
+
+        return FALSE;
+}
+
+static void
+old_password_entry_activate (GtkWidget        *entry,
+                             UmPasswordDialog *um)
+{
+        const char *text;
+
+        text = gtk_entry_get_text (GTK_ENTRY (entry));
+        if (strlen (text) > 0) {
+                passwd_authenticate (um->passwd_handler, text,
+                                     (PasswdCallback)auth_cb, um);
+        }
+}
+
+
+static void
+old_password_entry_changed (GtkEntry         *entry,
+                            GParamSpec       *pspec,
+                            UmPasswordDialog *um)
+{
+        clear_entry_validation_error (GTK_ENTRY (entry));
+        um->old_password_ok = FALSE;
+        update_sensitivity (um);
+}
+
+void
+um_password_dialog_set_privileged (UmPasswordDialog *um,
+                                   gboolean          privileged)
+{
+        if (privileged) {
+                gtk_widget_set_visible (um->action_label, TRUE);
+                gtk_widget_set_visible (um->action_combo, TRUE);
+        }
+        else {
+                gtk_combo_box_set_active (GTK_COMBO_BOX (um->action_combo), 0);
+                gtk_widget_set_visible (um->action_label, FALSE);
+                gtk_widget_set_visible (um->action_combo, FALSE);
+        }
+}
+
+UmPasswordDialog *
+um_password_dialog_new (void)
+{
+        GtkBuilder *builder;
+        GError *error;
+        const gchar *filename;
+        UmPasswordDialog *um;
+        GtkWidget *widget;
+        gint len;
+
+        builder = gtk_builder_new ();
+
+        error = NULL;
+        filename = UIDIR "/password-dialog.ui";
+        if (!g_file_test (filename, G_FILE_TEST_EXISTS))
+                filename = "../data/password-dialog.ui";
+        if (!gtk_builder_add_from_file (builder, filename, &error)) {
+                g_error ("%s", error->message);
+                g_error_free (error);
+                exit (1);
+        }
+
+        um = g_new0 (UmPasswordDialog, 1);
+
+        um->action_label = (GtkWidget *) gtk_builder_get_object (builder, "action-label");
+        widget = (GtkWidget *) gtk_builder_get_object (builder, "action-combo");
+        g_signal_connect (widget, "changed",
+                          G_CALLBACK (action_changed), um);
+        um->action_combo = widget;
+
+        widget = (GtkWidget *) gtk_builder_get_object (builder, "dialog");
+        g_signal_connect (widget, "delete-event",
+                          G_CALLBACK (gtk_widget_hide_on_delete), NULL);
+        um->dialog = widget;
+
+        um->user_icon = (GtkWidget *) gtk_builder_get_object (builder, "user-icon");
+        um->user_name = (GtkWidget *) gtk_builder_get_object (builder, "user-name");
+
+        widget = (GtkWidget *) gtk_builder_get_object (builder, "cancel-button");
+        g_signal_connect (widget, "clicked",
+                          G_CALLBACK (cancel_password_dialog), um);
+
+        widget = (GtkWidget *) gtk_builder_get_object (builder, "ok-button");
+        g_signal_connect (widget, "clicked",
+                          G_CALLBACK (accept_password_dialog), um);
+        gtk_widget_grab_default (widget);
+        um->ok_button = widget;
+
+        widget = (GtkWidget *) gtk_builder_get_object (builder, "show-password-checkbutton");
+        g_signal_connect (widget, "toggled",
+                          G_CALLBACK (show_password_toggled), um);
+        um->show_password_button = widget;
+
+        widget = (GtkWidget *) gtk_builder_get_object (builder, "password-entry");
+        g_signal_connect (widget, "notify::text",
+                          G_CALLBACK (password_entry_changed), um);
+        gtk_entry_set_visibility (GTK_ENTRY (widget), FALSE);
+
+        um->password_entry = widget;
+
+        widget = (GtkWidget *) gtk_builder_get_object (builder, "old-password-entry");
+        g_signal_connect_after (widget, "focus-out-event",
+                                G_CALLBACK (old_password_entry_focus_out), um);
+        g_signal_connect (widget, "notify::text",
+                          G_CALLBACK (old_password_entry_changed), um);
+        g_signal_connect (widget, "activate",
+                          G_CALLBACK (old_password_entry_activate), um);
+        um->old_password_entry = widget;
+        um->old_password_label = (GtkWidget *) gtk_builder_get_object (builder, "old-password-label");
+
+        widget = (GtkWidget *) gtk_builder_get_object (builder, "verify-entry");
+        g_signal_connect (widget, "notify::text",
+                          G_CALLBACK (verify_entry_changed), um);
+        g_signal_connect_after (widget, "focus-out-event",
+                                G_CALLBACK (verify_entry_focus_out), um);
+        um->verify_entry = widget;
+
+        len = 0;
+        len = MAX (len, strlen (C_("Password strength", "Too short")));
+        len = MAX (len, strlen (C_("Password strength", "Weak")));
+        len = MAX (len, strlen (C_("Password strength", "Fair")));
+        len = MAX (len, strlen (C_("Password strength", "Good")));
+        len = MAX (len, strlen (C_("Password strength", "Strong")));
+        len += 2;
+
+        widget = (GtkWidget *) gtk_builder_get_object (builder, "strength-indicator-label");
+        gtk_label_set_width_chars (GTK_LABEL (widget), len);
+
+
+        widget = (GtkWidget *) gtk_builder_get_object (builder, "generate-again-button");
+        g_signal_connect (widget, "clicked",
+                          G_CALLBACK (generate_clicked), um);
+#if 0
+        g_signal_connect (widget, "state-changed",
+                          G_CALLBACK (generate_state_changed), um);
+#endif
+        um->generate_button = widget;
+        g_signal_connect_after (gtk_bin_get_child (GTK_BIN (widget)), "draw",
+                                G_CALLBACK (generate_draw), um);
+
+        um->normal_hint_entry = (GtkWidget *) gtk_builder_get_object (builder, "normal-hint-entry");
+
+        /* Label size hack.
+         * This only sort-of works because the dialog is non-resizable.
+         */
+        widget = (GtkWidget *)gtk_builder_get_object (builder, "password-normal-hint-description-label");
+        g_signal_connect (um->normal_hint_entry, "size-allocate",
+                          G_CALLBACK (entry_size_changed), widget);
+        um->normal_hint_label = widget;
+
+        um->strength_indicator = (GtkWidget *) gtk_builder_get_object (builder, "strength-indicator");
+
+        um->strength_indicator_label = (GtkWidget *) gtk_builder_get_object (builder, "strength-indicator-label");
+
+        g_object_unref (builder);
+
+        generate_passwords (um);
+
+        return um;
+}
+
+void
+um_password_dialog_free (UmPasswordDialog *um)
+{
+        gtk_widget_destroy (um->dialog);
+
+        if (um->user)
+                g_object_unref (um->user);
+
+        if (um->passwd_handler)
+                passwd_destroy (um->passwd_handler);
+
+        g_free (um);
+}
+
+static gboolean
+visible_func (GtkTreeModel     *model,
+              GtkTreeIter      *iter,
+              UmPasswordDialog *um)
+{
+        if (um->user) {
+                gint mode; 
+                gboolean locked = um_user_get_locked (um->user);
+
+                gtk_tree_model_get (model, iter, 1, &mode, -1);
+
+                if (mode == 3 && locked)
+                        return FALSE;
+
+                if (mode == 4 && !locked)
+                        return FALSE;
+
+                return TRUE;
+        }
+
+        return TRUE;
+}
+
+void
+um_password_dialog_set_user (UmPasswordDialog *um,
+                             UmUser           *user)
+{
+        GdkPixbuf *pixbuf;
+        GtkTreeModel *model;
+
+        if (um->user) {
+                g_object_unref (um->user);
+                um->user = NULL;
+        }
+        if (user) {
+                um->user = g_object_ref (user);
+
+                pixbuf = um_user_render_icon (user, FALSE, 48);
+                gtk_image_set_from_pixbuf (GTK_IMAGE (um->user_icon), pixbuf);
+                g_object_unref (pixbuf);
+
+                gtk_label_set_label (GTK_LABEL (um->user_name),
+                                     um_user_get_real_name (user));
+
+                gtk_entry_set_text (GTK_ENTRY (um->password_entry), "");
+                gtk_entry_set_text (GTK_ENTRY (um->verify_entry), "");
+                gtk_entry_set_text (GTK_ENTRY (um->normal_hint_entry), "");
+                gtk_entry_set_text (GTK_ENTRY (um->old_password_entry), "");
+                gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (um->show_password_button), FALSE);
+                if (um_user_get_uid (um->user) == getuid()) {
+                        gtk_widget_show (um->old_password_label);
+                        gtk_widget_show (um->old_password_entry);
+                        if (um->passwd_handler != NULL)
+                                passwd_destroy (um->passwd_handler);
+                        um->passwd_handler = passwd_init ();
+                        um->old_password_ok = FALSE;
+                }
+                else {
+                        gtk_widget_hide (um->old_password_label);
+                        gtk_widget_hide (um->old_password_entry);
+                        um->old_password_ok = TRUE;
+                }
+        }
+
+        model = gtk_combo_box_get_model (GTK_COMBO_BOX (um->action_combo));
+        if (!GTK_IS_TREE_MODEL_FILTER (model)) {
+                model = gtk_tree_model_filter_new (model, NULL);
+                gtk_combo_box_set_model (GTK_COMBO_BOX (um->action_combo), model);
+                gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (model),
+                                                        (GtkTreeModelFilterVisibleFunc) visible_func,
+                                                        um, NULL);
+        }
+
+        gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (model));
+        gtk_combo_box_set_active (GTK_COMBO_BOX (um->action_combo), 0);
+}
+
+void
+um_password_dialog_show (UmPasswordDialog *um,
+                         GtkWindow        *parent)
+{
+        gtk_window_set_transient_for (GTK_WINDOW (um->dialog), parent);
+        gtk_window_present (GTK_WINDOW (um->dialog));
+        gtk_widget_grab_focus (um->password_entry);
+}
+
diff --git a/panels/user-accounts/um-password-dialog.h b/panels/user-accounts/um-password-dialog.h
new file mode 100644
index 0000000..8354e7c
--- /dev/null
+++ b/panels/user-accounts/um-password-dialog.h
@@ -0,0 +1,43 @@
+/* -*- 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_PASSWORD_DIALOG_H__
+#define __UM_PASSWORD_DIALOG_H__
+
+#include <gtk/gtk.h>
+#include "um-user.h"
+
+G_BEGIN_DECLS
+
+typedef struct _UmPasswordDialog UmPasswordDialog;
+
+UmPasswordDialog *um_password_dialog_new      (void);
+void              um_password_dialog_free     (UmPasswordDialog *dialog);
+void              um_password_dialog_set_user (UmPasswordDialog *dialog,
+                                               UmUser           *user);
+void              um_password_dialog_set_privileged (UmPasswordDialog *dialog,
+                                                     gboolean          privileged);
+void              um_password_dialog_show     (UmPasswordDialog *dialog,
+                                               GtkWindow        *parent);
+
+G_END_DECLS
+
+#endif
diff --git a/panels/user-accounts/um-photo-dialog.c b/panels/user-accounts/um-photo-dialog.c
new file mode 100644
index 0000000..2061ebe
--- /dev/null
+++ b/panels/user-accounts/um-photo-dialog.c
@@ -0,0 +1,693 @@
+/* -*- 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 <stdlib.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#define GNOME_DESKTOP_USE_UNSTABLE_API
+#include <libgnomeui/gnome-desktop-thumbnail.h>
+
+#ifdef HAVE_CHEESE
+#include <cheese-avatar-chooser.h>
+#include <cheese-camera-device-monitor.h>
+#endif /* HAVE_CHEESE */
+
+#include "um-photo-dialog.h"
+#include "um-user-manager.h"
+#include "um-crop-area.h"
+#include "um-utils.h"
+
+#define ROW_SPAN 6
+
+struct _UmPhotoDialog {
+        GtkWidget *photo_popup;
+        GtkWidget *popup_button;
+        GtkWidget *crop_area;
+
+#ifdef HAVE_CHEESE
+        CheeseCameraDeviceMonitor *monitor;
+        GtkWidget *take_photo_menuitem;
+        guint num_cameras;
+#endif /* HAVE_CHEESE */
+
+        GnomeDesktopThumbnailFactory *thumb_factory;
+
+        UmUser *user;
+};
+
+static void
+crop_dialog_response (GtkWidget     *dialog,
+                      gint           response_id,
+                      UmPhotoDialog *um)
+{
+        GdkPixbuf *pb, *pb2;
+
+        if (response_id != GTK_RESPONSE_ACCEPT) {
+                um->crop_area = NULL;
+                gtk_widget_destroy (dialog);
+                return;
+        }
+
+        pb = um_crop_area_get_picture (UM_CROP_AREA (um->crop_area));
+        pb2 = gdk_pixbuf_scale_simple (pb, 96, 96, GDK_INTERP_BILINEAR);
+
+        um_user_set_icon_data (um->user, pb2);
+
+        g_object_unref (pb2);
+        g_object_unref (pb);
+
+        um->crop_area = NULL;
+        gtk_widget_destroy (dialog);
+}
+
+static void
+um_photo_dialog_crop (UmPhotoDialog *um,
+                      GdkPixbuf     *pixbuf)
+{
+        GtkWidget *dialog;
+        GtkWidget *frame;
+
+        dialog = gtk_dialog_new_with_buttons ("",
+                                              GTK_WINDOW (gtk_widget_get_toplevel (um->popup_button)),
+                                              0,
+                                              GTK_STOCK_CANCEL,
+                                              GTK_RESPONSE_REJECT,
+                                              _("Select"),
+                                              GTK_RESPONSE_ACCEPT,
+                                              NULL);
+
+        gtk_window_set_icon_name (GTK_WINDOW (dialog), "system-users");
+
+        g_signal_connect (G_OBJECT (dialog), "response",
+                          G_CALLBACK (crop_dialog_response), um);
+
+        /* Content */
+        um->crop_area           = um_crop_area_new ();
+        um_crop_area_set_min_size (UM_CROP_AREA (um->crop_area), 48, 48);
+        um_crop_area_set_constrain_aspect (UM_CROP_AREA (um->crop_area), TRUE);
+        um_crop_area_set_picture (UM_CROP_AREA (um->crop_area), pixbuf);
+        frame                   = gtk_frame_new (NULL);
+        gtk_container_add (GTK_CONTAINER (frame), um->crop_area);
+        gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
+
+        gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
+                            frame,
+                            TRUE, TRUE, 8);
+
+        gtk_window_set_default_size (GTK_WINDOW (dialog), 400, 300);
+
+        gtk_widget_show_all (dialog);
+}
+
+static void
+file_chooser_response (GtkDialog     *chooser,
+                       gint           response,
+                       UmPhotoDialog *um)
+{
+        gchar *filename;
+        GError *error;
+        GdkPixbuf *pixbuf;
+
+        if (response != GTK_RESPONSE_ACCEPT) {
+                gtk_widget_destroy (GTK_WIDGET (chooser));
+                return;
+        }
+
+        filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser));
+
+        error = NULL;
+        pixbuf = gdk_pixbuf_new_from_file (filename, &error);
+        if (pixbuf == NULL) {
+                g_warning ("Failed to load %s: %s", filename, error->message);
+                g_error_free (error);
+        }
+        g_free (filename);
+
+        gtk_widget_destroy (GTK_WIDGET (chooser));
+
+        um_photo_dialog_crop (um, pixbuf);
+        g_object_unref (pixbuf);
+}
+
+static void
+update_preview (GtkFileChooser               *chooser,
+                GnomeDesktopThumbnailFactory *thumb_factory)
+{
+        gchar *uri;
+
+        uri = gtk_file_chooser_get_preview_uri (chooser);
+
+        if (uri) {
+                GdkPixbuf *pixbuf = NULL;
+                const gchar *mime_type = NULL;
+                GFile *file;
+                GFileInfo *file_info;
+                GtkWidget *preview;
+
+                preview = gtk_file_chooser_get_preview_widget (chooser);
+
+                file = g_file_new_for_uri (uri);
+                file_info = g_file_query_info (file,
+                                               G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+                                               G_FILE_QUERY_INFO_NONE,
+                                               NULL, NULL);
+                g_object_unref (file);
+
+                if (file_info != NULL) {
+                        mime_type = g_file_info_get_content_type (file_info);
+                        g_object_unref (file_info);
+                }
+
+                if (mime_type) {
+                        pixbuf = gnome_desktop_thumbnail_factory_generate_thumbnail (thumb_factory,
+                                                                                     uri,
+                                                                                     mime_type);
+                }
+
+                if (pixbuf != NULL) {
+                        gtk_image_set_from_pixbuf (GTK_IMAGE (preview), pixbuf);
+                        g_object_unref (pixbuf);
+                }
+                else {
+                        gtk_image_set_from_stock (GTK_IMAGE (preview),
+                                                  GTK_STOCK_DIALOG_QUESTION,
+                                                  GTK_ICON_SIZE_DIALOG);
+                }
+
+                g_free (uri);
+        }
+
+        gtk_file_chooser_set_preview_widget_active (chooser, TRUE);
+}
+
+static void
+um_photo_dialog_select_file (UmPhotoDialog *um)
+{
+        GtkWidget *chooser;
+        const gchar *folder;
+        GtkWidget *preview;
+
+        chooser = gtk_file_chooser_dialog_new (_("Browse for more pictures"),
+                                               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,
+                                               NULL);
+
+        gtk_window_set_modal (GTK_WINDOW (chooser), TRUE);
+
+        preview = gtk_image_new ();
+        gtk_widget_set_size_request (preview, 128, -1);
+        gtk_file_chooser_set_preview_widget (GTK_FILE_CHOOSER (chooser), preview);
+        gtk_file_chooser_set_use_preview_label (GTK_FILE_CHOOSER (chooser), FALSE);
+        gtk_widget_show (preview);
+        g_signal_connect (chooser, "update-preview",
+                          G_CALLBACK (update_preview), um->thumb_factory);
+
+        folder = g_get_user_special_dir (G_USER_DIRECTORY_PICTURES);
+        if (folder)
+                gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (chooser),
+                                                     folder);
+
+        g_signal_connect (chooser, "response",
+                          G_CALLBACK (file_chooser_response), um);
+
+        gtk_window_present (GTK_WINDOW (chooser));
+}
+
+static void
+none_icon_selected (GtkMenuItem   *menuitem,
+                    UmPhotoDialog *um)
+{
+        um_user_set_icon_file (um->user, NULL);
+}
+
+static void
+file_icon_selected (GtkMenuItem   *menuitem,
+                    UmPhotoDialog *um)
+{
+        um_photo_dialog_select_file (um);
+}
+
+#ifdef HAVE_CHEESE
+static gboolean
+destroy_chooser (GtkWidget *chooser)
+{
+        gtk_widget_destroy (chooser);
+        return FALSE;
+}
+
+static void
+webcam_response_cb (GtkDialog     *dialog,
+                    int            response,
+                    UmPhotoDialog  *um)
+{
+        if (response == GTK_RESPONSE_ACCEPT) {
+                GdkPixbuf *pb, *pb2;
+
+                g_object_get (G_OBJECT (dialog), "pixbuf", &pb, NULL);
+                pb2 = gdk_pixbuf_scale_simple (pb, 96, 96, GDK_INTERP_BILINEAR);
+
+                um_user_set_icon_data (um->user, pb2);
+
+                g_object_unref (pb2);
+                g_object_unref (pb);
+        }
+        if (response != GTK_RESPONSE_DELETE_EVENT &&
+            response != GTK_RESPONSE_NONE)
+                g_idle_add ((GSourceFunc) destroy_chooser, dialog);
+}
+
+static void
+webcam_icon_selected (GtkMenuItem   *menuitem,
+                      UmPhotoDialog *um)
+{
+        GtkWidget *window;
+
+        window = cheese_avatar_chooser_new ();
+        gtk_window_set_transient_for (GTK_WINDOW (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);
+        gtk_widget_show (window);
+}
+
+static void
+update_photo_menu_status (UmPhotoDialog *um)
+{
+        if (um->num_cameras == 0)
+                gtk_widget_set_sensitive (um->take_photo_menuitem, FALSE);
+        else
+                gtk_widget_set_sensitive (um->take_photo_menuitem, TRUE);
+}
+
+static void
+device_added (CheeseCameraDeviceMonitor *monitor,
+              const gchar               *id,
+              const gchar               *device_file,
+              const gchar               *product_name,
+              gint                       api_version,
+              UmPhotoDialog             *um)
+{
+        um->num_cameras++;
+        update_photo_menu_status (um);
+}
+
+static void
+device_removed (CheeseCameraDeviceMonitor *monitor,
+                const char                *id,
+                UmPhotoDialog             *um)
+{
+        um->num_cameras--;
+        update_photo_menu_status (um);
+}
+
+#endif /* HAVE_CHEESE */
+
+static void
+stock_icon_selected (GtkMenuItem   *menuitem,
+                     UmPhotoDialog *um)
+{
+        const char *filename;
+
+        filename = g_object_get_data (G_OBJECT (menuitem), "filename");
+        um_user_set_icon_file (um->user, filename);
+}
+
+static GtkWidget *
+menu_item_for_filename (UmPhotoDialog *um,
+                        const char    *filename)
+{
+        GtkWidget *image, *menuitem;
+        GFile *file;
+        GIcon *icon;
+
+        file = g_file_new_for_path (filename);
+        icon = g_file_icon_new (file);
+        g_object_unref (file);
+        image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_DIALOG);
+        g_object_unref (icon);
+
+        menuitem = gtk_menu_item_new ();
+        gtk_container_add (GTK_CONTAINER (menuitem), image);
+        gtk_widget_show_all (menuitem);
+
+        g_object_set_data_full (G_OBJECT (menuitem), "filename",
+                                g_strdup (filename), (GDestroyNotify) g_free);
+        g_signal_connect (G_OBJECT (menuitem), "activate",
+                          G_CALLBACK (stock_icon_selected), um);
+
+        return menuitem;
+}
+
+static void
+setup_photo_popup (UmPhotoDialog *um)
+{
+        GtkWidget *menu, *menuitem, *image;
+        guint x, y;
+        GDir *dir;
+        const char *face;
+        GError *error;
+
+        menu = gtk_menu_new ();
+
+        x = 0;
+        y = 0;
+
+        error = NULL;
+        dir = g_dir_open (DATADIR "/pixmaps/faces", 0, &error);
+        if (dir == NULL) {
+                g_warning ("Failed to load faces: %s", error->message);
+                g_error_free (error);
+                goto skip_faces;
+        }
+
+        while ((face = g_dir_read_name (dir)) != NULL) {
+                char *filename;
+
+                filename = g_build_filename (DATADIR "/pixmaps/faces", face, NULL);
+                menuitem = menu_item_for_filename (um, filename);
+                g_free (filename);
+                if (menuitem == NULL)
+                        continue;
+
+                gtk_menu_attach (GTK_MENU (menu), GTK_WIDGET (menuitem),
+                                 x, x + 1, y, y + 1);
+                gtk_widget_show (menuitem);
+
+                x++;
+                if (x >= ROW_SPAN - 1) {
+                        y++;
+                        x = 0;
+                }
+        }
+        g_dir_close (dir);
+
+        image = gtk_image_new_from_icon_name ("avatar-default", GTK_ICON_SIZE_DIALOG);
+        menuitem = gtk_menu_item_new ();
+        gtk_container_add (GTK_CONTAINER (menuitem), image);
+        gtk_widget_show_all (menuitem);
+        gtk_menu_attach (GTK_MENU (menu), GTK_WIDGET (menuitem),
+                         x, x + 1, y, y + 1);
+        g_signal_connect (G_OBJECT (menuitem), "activate",
+                          G_CALLBACK (none_icon_selected), um);
+        gtk_widget_show (menuitem);
+        y++;
+
+        /* Separator */
+        menuitem = gtk_separator_menu_item_new ();
+        gtk_menu_attach (GTK_MENU (menu), GTK_WIDGET (menuitem),
+                         0, ROW_SPAN - 1, y, y + 1);
+        gtk_widget_show (menuitem);
+
+        y++;
+
+skip_faces:
+
+#ifdef HAVE_CHEESE
+        um->take_photo_menuitem = gtk_menu_item_new_with_label (_("Take a photo..."));
+        gtk_menu_attach (GTK_MENU (menu), GTK_WIDGET (um->take_photo_menuitem),
+                         0, ROW_SPAN - 1, y, y + 1);
+        g_signal_connect (G_OBJECT (um->take_photo_menuitem), "activate",
+                          G_CALLBACK (webcam_icon_selected), um);
+        gtk_widget_set_sensitive (um->take_photo_menuitem, FALSE);
+        gtk_widget_show (um->take_photo_menuitem);
+
+        um->monitor = cheese_camera_device_monitor_new ();
+        g_signal_connect (G_OBJECT (um->monitor), "added",
+                          G_CALLBACK (device_added), um);
+        g_signal_connect (G_OBJECT (um->monitor), "removed",
+                          G_CALLBACK (device_removed), um);
+        cheese_camera_device_monitor_coldplug (um->monitor);
+
+        y++;
+#endif /* HAVE_CHEESE */
+
+        menuitem = gtk_menu_item_new_with_label (_("Browse for more pictures..."));
+        gtk_menu_attach (GTK_MENU (menu), GTK_WIDGET (menuitem),
+                         0, ROW_SPAN - 1, y, y + 1);
+        g_signal_connect (G_OBJECT (menuitem), "activate",
+                          G_CALLBACK (file_icon_selected), um);
+        gtk_widget_show (menuitem);
+
+        um->photo_popup = menu;
+}
+
+static void
+popup_icon_menu (GtkToggleButton *button, UmPhotoDialog *um)
+{
+        if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) && !gtk_widget_get_visible (um->photo_popup)) {
+                gtk_menu_popup (GTK_MENU (um->photo_popup),
+                                NULL, NULL,
+                                (GtkMenuPositionFunc) popup_menu_below_button, um->popup_button,
+                                0, gtk_get_current_event_time ());
+        } else {
+                gtk_menu_popdown (GTK_MENU (um->photo_popup));
+        }
+}
+
+static gboolean
+on_popup_button_button_pressed (GtkToggleButton *button,
+                                GdkEventButton *event,
+                                UmPhotoDialog  *um)
+{
+        if (event->button == 1) {
+                if (!gtk_widget_get_visible (um->photo_popup)) {
+                        popup_icon_menu (button, um);
+                        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
+                } else {
+                        gtk_menu_popdown (GTK_MENU (um->photo_popup));
+                        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), FALSE);
+                }
+
+                return TRUE;
+        }
+
+        return FALSE;
+}
+
+static void
+on_photo_popup_unmap (GtkWidget     *popup_menu,
+                      UmPhotoDialog *um)
+{
+        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (um->popup_button), FALSE);
+}
+
+static void
+popup_button_draw (GtkWidget      *widget,
+                   cairo_t        *cr,
+                   UmPhotoDialog  *um)
+{
+        GtkAllocation allocation;
+
+        if (gtk_widget_get_state (widget) != GTK_STATE_PRELIGHT &&
+            !gtk_widget_is_focus (gtk_widget_get_parent (widget))) {
+                return;
+        }
+
+        gtk_widget_get_allocation (widget, &allocation);
+        gtk_paint_expander (gtk_widget_get_style (widget),
+                            cr,
+                            gtk_widget_get_state (widget),
+                            widget,
+                            NULL,
+                            allocation.x + allocation.width,
+                            allocation.y + allocation.height,
+                            GTK_EXPANDER_EXPANDED);
+}
+
+static void
+popup_button_focus_changed (GObject       *button,
+                            GParamSpec    *pspec,
+                            UmPhotoDialog *um)
+{
+        gtk_widget_queue_draw (gtk_bin_get_child (GTK_BIN (button)));
+}
+
+UmPhotoDialog *
+um_photo_dialog_new (GtkWidget *button)
+{
+        UmPhotoDialog *um;
+
+        um = g_new0 (UmPhotoDialog, 1);
+
+        um->thumb_factory = gnome_desktop_thumbnail_factory_new (GNOME_DESKTOP_THUMBNAIL_SIZE_NORMAL);
+
+        /* Set up the popup */
+        um->popup_button = button;
+        setup_photo_popup (um);
+        g_signal_connect (button, "toggled",
+                          G_CALLBACK (popup_icon_menu), um);
+        g_signal_connect (button, "button-press-event",
+                          G_CALLBACK (on_popup_button_button_pressed), um);
+        g_signal_connect (button, "notify::is-focus",
+                          G_CALLBACK (popup_button_focus_changed), um);
+        g_signal_connect_after (gtk_bin_get_child (GTK_BIN (button)), "draw",
+                                G_CALLBACK (popup_button_draw), um);
+
+        g_signal_connect (um->photo_popup, "unmap",
+                          G_CALLBACK (on_photo_popup_unmap), um);
+
+        return um;
+}
+
+void
+um_photo_dialog_free (UmPhotoDialog *um)
+{
+        gtk_widget_destroy (um->photo_popup);
+
+        if (um->thumb_factory)
+                g_object_unref (um->thumb_factory);
+#ifdef HAVE_CHEESE
+        if (um->monitor)
+                g_object_unref (um->monitor);
+#endif
+        if (um->user)
+                g_object_unref (um->user);
+
+        g_free (um);
+}
+
+static void
+clear_tip (GtkMenuItem  *item,
+           gpointer      user_data)
+{
+        GList *children;
+        GtkWidget *image;
+        GIcon *icon, *icon2;
+        const char *filename;
+
+        /* Not a stock icon? */
+        filename = g_object_get_data (G_OBJECT (item), "filename");
+        if (filename == NULL)
+                return;
+
+        children = gtk_container_get_children (GTK_CONTAINER (item));
+        image = children->data;
+        g_assert (image != NULL);
+        g_list_free (children);
+
+        gtk_image_get_gicon (GTK_IMAGE (image), &icon, NULL);
+
+        if (G_IS_EMBLEMED_ICON (icon))
+                icon2 = g_emblemed_icon_get_icon (G_EMBLEMED_ICON (icon));
+        else
+                return;
+
+        gtk_image_set_from_gicon (GTK_IMAGE (image), icon2, GTK_ICON_SIZE_DIALOG);
+        g_object_unref (icon);
+}
+
+static void
+set_tip (GtkWidget  *item,
+         const char *tip,
+         GEmblem    *emblem)
+{
+        GList *children;
+        GtkWidget *image;
+        GIcon *icon, *icon2;
+
+        children = gtk_container_get_children (GTK_CONTAINER (item));
+        image = children->data;
+        g_assert (image != NULL);
+        g_list_free (children);
+
+        gtk_image_get_gicon (GTK_IMAGE (image), &icon, NULL);
+        if (G_IS_EMBLEMED_ICON (icon)) {
+                return;
+        }
+
+        icon2 = g_emblemed_icon_new (icon, emblem);
+        gtk_image_set_from_gicon (GTK_IMAGE (image), icon2, GTK_ICON_SIZE_DIALOG);
+
+        gtk_widget_set_tooltip_text (GTK_WIDGET (item), tip);
+}
+
+void
+um_photo_dialog_set_user (UmPhotoDialog *um,
+                          UmUser        *user)
+{
+        UmUserManager *manager;
+        GSList *list, *l;
+        UmUser *u;
+        GIcon *icon;
+        GEmblem *emblem;
+        GList *children, *c;
+
+        g_return_if_fail (um != NULL);
+
+        if (um->user) {
+                g_object_unref (um->user);
+                um->user = NULL;
+        }
+        um->user = user;
+
+        if (um->user) {
+                g_object_ref (um->user);
+
+                children = gtk_container_get_children (GTK_CONTAINER (um->photo_popup));
+                g_list_foreach (children, (GFunc) clear_tip, NULL);
+
+                manager = um_user_manager_ref_default ();
+                list = um_user_manager_list_users (manager);
+                g_object_unref (manager);
+
+                icon = g_themed_icon_new ("avatar-default");
+                emblem = g_emblem_new (icon);
+                g_object_unref (icon);
+
+                for (l = list; l; l = l->next) {
+                        const char *filename;
+
+                        u = l->data;
+                        if (u == user)
+                                continue;
+                        filename = um_user_get_icon_file (u);
+                        if (filename  == NULL)
+                                continue;
+                        for (c = children; c; c = c->next) {
+                                const char *f;
+
+                                f = g_object_get_data (G_OBJECT (c->data), "filename");
+                                if (f == NULL)
+                                        continue;
+                                if (strcmp (f, filename) == 0) {
+                                        char *tip;
+
+                                        tip = g_strdup_printf (_("Used by %s"),
+                                                               um_user_get_real_name (u));
+                                        set_tip (GTK_WIDGET (c->data), tip, emblem);
+                                        g_free (tip);
+                                        break;
+                                }
+                        }
+                }
+                g_slist_free (list);
+
+                g_object_unref (emblem);
+        }
+}
+
diff --git a/panels/user-accounts/um-photo-dialog.h b/panels/user-accounts/um-photo-dialog.h
new file mode 100644
index 0000000..3f0c404
--- /dev/null
+++ b/panels/user-accounts/um-photo-dialog.h
@@ -0,0 +1,39 @@
+/* -*- 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_PHOTO_DIALOG_H__
+#define __UM_PHOTO_DIALOG_H__
+
+#include <gtk/gtk.h>
+#include "um-user.h"
+
+G_BEGIN_DECLS
+
+typedef struct _UmPhotoDialog UmPhotoDialog;
+
+UmPhotoDialog *um_photo_dialog_new      (GtkWidget     *button);
+void           um_photo_dialog_free     (UmPhotoDialog *dialog);
+void           um_photo_dialog_set_user (UmPhotoDialog *dialog,
+                                         UmUser        *user);
+
+G_END_DECLS
+
+#endif
diff --git a/panels/user-accounts/um-strength-bar.c b/panels/user-accounts/um-strength-bar.c
new file mode 100644
index 0000000..64af45f
--- /dev/null
+++ b/panels/user-accounts/um-strength-bar.c
@@ -0,0 +1,261 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright 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 <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include "um-strength-bar.h"
+
+#define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), UM_TYPE_STRENGTH_BAR, UmStrengthBarPrivate))
+
+struct _UmStrengthBarPrivate {
+        gdouble strength;
+};
+
+enum {
+        PROP_0,
+        PROP_STRENGTH
+};
+
+G_DEFINE_TYPE (UmStrengthBar, um_strength_bar, GTK_TYPE_WIDGET);
+
+
+static void
+um_strength_bar_set_property (GObject      *object,
+                              guint         prop_id,
+                              const GValue *value,
+                              GParamSpec   *pspec)
+{
+        UmStrengthBar *bar = UM_STRENGTH_BAR (object);
+
+        switch (prop_id) {
+        case PROP_STRENGTH:
+                um_strength_bar_set_strength (bar, g_value_get_double (value));
+                break;
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+        }
+}
+
+static void
+um_strength_bar_get_property (GObject    *object,
+                              guint       prop_id,
+                              GValue     *value,
+                              GParamSpec *pspec)
+{
+        UmStrengthBar *bar = UM_STRENGTH_BAR (object);
+
+        switch (prop_id) {
+        case PROP_STRENGTH:
+                g_value_set_double (value, um_strength_bar_get_strength (bar));
+                break;
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+        }
+}
+
+static void
+curved_rectangle (cairo_t *cr,
+                  double   x0,
+                  double   y0,
+                  double   width,
+                  double   height,
+                  double   radius)
+{
+        double x1;
+        double y1;
+
+        x1 = x0 + width;
+        y1 = y0 + height;
+
+        if (!width || !height) {
+                return;
+        }
+
+        if (width / 2 < radius) {
+                if (height / 2 < radius) {
+                        cairo_move_to  (cr, x0, (y0 + y1) / 2);
+                        cairo_curve_to (cr, x0 ,y0, x0, y0, (x0 + x1) / 2, y0);
+                        cairo_curve_to (cr, x1, y0, x1, y0, x1, (y0 + y1) / 2);
+                        cairo_curve_to (cr, x1, y1, x1, y1, (x1 + x0) / 2, y1);
+                        cairo_curve_to (cr, x0, y1, x0, y1, x0, (y0 + y1) / 2);
+                } else {
+                        cairo_move_to  (cr, x0, y0 + radius);
+                        cairo_curve_to (cr, x0, y0, x0, y0, (x0 + x1) / 2, y0);
+                        cairo_curve_to (cr, x1, y0, x1, y0, x1, y0 + radius);
+                        cairo_line_to (cr, x1, y1 - radius);
+                        cairo_curve_to (cr, x1, y1, x1, y1, (x1 + x0) / 2, y1);
+                        cairo_curve_to (cr, x0, y1, x0, y1, x0, y1 - radius);
+                }
+        } else {
+                if (height / 2 < radius) {
+                        cairo_move_to  (cr, x0, (y0 + y1) / 2);
+                        cairo_curve_to (cr, x0, y0, x0 , y0, x0 + radius, y0);
+                        cairo_line_to (cr, x1 - radius, y0);
+                        cairo_curve_to (cr, x1, y0, x1, y0, x1, (y0 + y1) / 2);
+                        cairo_curve_to (cr, x1, y1, x1, y1, x1 - radius, y1);
+                        cairo_line_to (cr, x0 + radius, y1);
+                        cairo_curve_to (cr, x0, y1, x0, y1, x0, (y0 + y1) / 2);
+                } else {
+                        cairo_move_to  (cr, x0, y0 + radius);
+                        cairo_curve_to (cr, x0 , y0, x0 , y0, x0 + radius, y0);
+                        cairo_line_to (cr, x1 - radius, y0);
+                        cairo_curve_to (cr, x1, y0, x1, y0, x1, y0 + radius);
+                        cairo_line_to (cr, x1, y1 - radius);
+                        cairo_curve_to (cr, x1, y1, x1, y1, x1 - radius, y1);
+                        cairo_line_to (cr, x0 + radius, y1);
+                        cairo_curve_to (cr, x0, y1, x0, y1, x0, y1 - radius);
+                }
+        }
+
+        cairo_close_path (cr);
+}
+
+gdouble color1[3] = { 213.0/255.0, 4.0/255.0, 4.0/255.0 };
+gdouble color2[3] = { 234.0/255.0, 236.0/255.0, 31.0/255.0 };
+gdouble color3[3] = { 141.0/255.0, 133.0/255.0, 241.0/255.0 };
+gdouble color4[3] = { 99.0/255.0, 251.0/255.0, 107.0/255.0 };
+
+static void
+get_color (gdouble value, gdouble *r, gdouble *g, gdouble *b)
+{
+        gdouble *c;
+
+        if (value < 0.50) {
+                c = color1;
+        }
+        else if (value < 0.75) {
+                c = color2;
+        }
+        else if (value < 0.90) {
+                c = color3;
+        }
+        else {
+                c = color4;
+        }
+
+        *r = c[0];
+        *g = c[1];
+        *b = c[2];
+}
+
+static gboolean
+um_strength_bar_draw (GtkWidget      *widget,
+                      cairo_t        *cr)
+{
+        UmStrengthBar *bar = UM_STRENGTH_BAR (widget);
+        gdouble r, g, b;
+        GdkWindow *window;
+        GtkAllocation allocation;
+
+	window = gtk_widget_get_window (widget);
+	gtk_widget_get_allocation (widget, &allocation);
+	cr = gdk_cairo_create (window);
+	cairo_set_line_width (cr, 1);
+
+	cairo_rectangle (cr,
+			 allocation.x,
+			 allocation.y,
+			 bar->priv->strength * allocation.width,
+			 allocation.height);
+	cairo_clip (cr);
+
+	curved_rectangle (cr,
+			  allocation.x + 0.5,
+			  allocation.y + 0.5,
+			  allocation.width - 1,
+			  allocation.height - 1,
+			  4);
+	get_color (bar->priv->strength, &r, &g ,&b);
+	cairo_set_source_rgb (cr, r, g, b);
+	cairo_fill_preserve (cr);
+
+	cairo_reset_clip (cr);
+	cairo_set_source_rgb (cr, 0, 0, 0);
+	cairo_stroke (cr);
+
+        return FALSE;
+}
+
+static void
+um_strength_bar_class_init (UmStrengthBarClass *class)
+{
+        GObjectClass *gobject_class;
+        GtkWidgetClass *widget_class;
+
+        gobject_class = (GObjectClass*)class;
+        widget_class = (GtkWidgetClass*)class;
+
+        gobject_class->set_property = um_strength_bar_set_property;
+        gobject_class->get_property = um_strength_bar_get_property;
+
+        widget_class->draw = um_strength_bar_draw;
+
+         g_object_class_install_property (gobject_class,
+                                          PROP_STRENGTH,
+                                          g_param_spec_double ("strength",
+                                                               "Strength",
+                                                               "Strength",
+                                                               0.0, 1.0, 0.0,
+                                                               G_PARAM_READWRITE));
+
+        g_type_class_add_private (class, sizeof (UmStrengthBarPrivate));
+}
+
+static void
+um_strength_bar_init (UmStrengthBar *bar)
+{
+        gtk_widget_set_has_window (GTK_WIDGET (bar), FALSE);
+        gtk_widget_set_size_request (GTK_WIDGET (bar), 120, 8);
+
+        bar->priv = GET_PRIVATE (bar);
+        bar->priv->strength = 0.0;
+}
+
+GtkWidget *
+um_strength_bar_new (void)
+{
+        return (GtkWidget*) g_object_new (UM_TYPE_STRENGTH_BAR, NULL);
+}
+
+void
+um_strength_bar_set_strength (UmStrengthBar *bar,
+                              gdouble        strength)
+{
+        bar->priv->strength = strength;
+
+        g_object_notify (G_OBJECT (bar), "strength");
+
+        if (gtk_widget_is_drawable (GTK_WIDGET (bar))) {
+                gtk_widget_queue_draw (GTK_WIDGET (bar));
+        }
+}
+
+gdouble
+um_strength_bar_get_strength (UmStrengthBar *bar)
+{
+        return bar->priv->strength;
+}
diff --git a/panels/user-accounts/um-strength-bar.h b/panels/user-accounts/um-strength-bar.h
new file mode 100644
index 0000000..8bf0572
--- /dev/null
+++ b/panels/user-accounts/um-strength-bar.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright © 2010 Red Hat, Inc.
+ *
+ * Licensed under the GNU General Public License Version 3
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Matthias Clasen
+ */
+
+#ifndef _UM_STRENGTH_BAR_H_
+#define _UM_STRENGTH_BAR_H_
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define UM_TYPE_STRENGTH_BAR            (um_strength_bar_get_type ())
+#define UM_STRENGTH_BAR(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), UM_TYPE_STRENGTH_BAR, \
+                                                                           UmStrengthBar))
+#define UM_STRENGTH_BAR_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), UM_TYPE_STRENGTH_BAR, \
+                                                                        UmStrengthBarClass))
+#define UM_IS_STRENGTH_BAR(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UM_TYPE_STRENGTH_BAR))
+#define UM_IS_STRENGTH_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UM_TYPE_STRENGTH_BAR))
+#define UM_STRENGTH_BAR_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), UM_TYPE_STRENGTH_BAR, \
+                                                                          UmStrengthBarClass))
+
+typedef struct _UmStrengthBarClass UmStrengthBarClass;
+typedef struct _UmStrengthBar UmStrengthBar;
+typedef struct _UmStrengthBarPrivate UmStrengthBarPrivate;
+
+struct _UmStrengthBarClass {
+        GtkWidgetClass parent_class;
+};
+
+struct _UmStrengthBar {
+        GtkWidget parent_instance;
+        UmStrengthBarPrivate *priv;
+};
+
+GType      um_strength_bar_get_type             (void) G_GNUC_CONST;
+
+GtkWidget *um_strength_bar_new                  (void);
+void       um_strength_bar_set_strength         (UmStrengthBar *bar,
+                                                 gdouble        strength);
+gdouble    um_strength_bar_get_strength         (UmStrengthBar *bar);
+
+G_END_DECLS
+
+#endif /* _UM_STRENGTH_BAR_H_ */
diff --git a/panels/user-accounts/um-user-manager.c b/panels/user-accounts/um-user-manager.c
new file mode 100644
index 0000000..1e39018
--- /dev/null
+++ b/panels/user-accounts/um-user-manager.c
@@ -0,0 +1,624 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 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 <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <pwd.h>
+
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif /* HAVE_PATHS_H */
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+#include <glib-object.h>
+#include <gio/gio.h>
+
+#include "um-user-manager.h"
+
+enum {
+        USERS_LOADED,
+        USER_ADDED,
+        USER_REMOVED,
+        USER_CHANGED,
+        LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL] = { 0, };
+
+static void     um_user_manager_class_init (UmUserManagerClass *klass);
+static void     um_user_manager_init       (UmUserManager      *user_manager);
+static void     um_user_manager_finalize   (GObject            *object);
+
+static gpointer user_manager_object = NULL;
+
+G_DEFINE_TYPE (UmUserManager, um_user_manager, G_TYPE_OBJECT)
+
+static void
+um_user_manager_class_init (UmUserManagerClass *klass)
+{
+        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
+
+        object_class->finalize = um_user_manager_finalize;
+
+       signals [USERS_LOADED] =
+                g_signal_new ("users-loaded",
+                              G_TYPE_FROM_CLASS (klass),
+                              G_SIGNAL_RUN_LAST,
+                              G_STRUCT_OFFSET (UmUserManagerClass, users_loaded),
+                              NULL, NULL,
+                              g_cclosure_marshal_VOID__VOID,
+                              G_TYPE_NONE, 0);
+
+        signals [USER_ADDED] =
+                g_signal_new ("user-added",
+                              G_TYPE_FROM_CLASS (klass),
+                              G_SIGNAL_RUN_LAST,
+                              G_STRUCT_OFFSET (UmUserManagerClass, user_added),
+                              NULL, NULL,
+                              g_cclosure_marshal_VOID__OBJECT,
+                              G_TYPE_NONE, 1, UM_TYPE_USER);
+        signals [USER_REMOVED] =
+                g_signal_new ("user-removed",
+                              G_TYPE_FROM_CLASS (klass),
+                              G_SIGNAL_RUN_LAST,
+                              G_STRUCT_OFFSET (UmUserManagerClass, user_removed),
+                              NULL, NULL,
+                              g_cclosure_marshal_VOID__OBJECT,
+                              G_TYPE_NONE, 1, UM_TYPE_USER);
+        signals [USER_CHANGED] =
+                g_signal_new ("user-changed",
+                              G_TYPE_FROM_CLASS (klass),
+                              G_SIGNAL_RUN_LAST,
+                              G_STRUCT_OFFSET (UmUserManagerClass, user_changed),
+                              NULL, NULL,
+                              g_cclosure_marshal_VOID__OBJECT,
+                              G_TYPE_NONE, 1, UM_TYPE_USER);
+}
+
+
+/* We maintain a ring for each group of users with the same real name.
+ * We need this to pick the right display names.
+ */
+static void
+remove_user_from_dupe_ring (UmUserManager *manager,
+                            UmUser        *user)
+{
+        GList *dupes;
+        UmUser *dup;
+
+        um_user_show_short_display_name (user);
+
+        dupes = g_object_get_data (G_OBJECT (user), "dupes");
+
+        if (dupes == NULL) {
+                return;
+        }
+
+        if (dupes->next == dupes->prev) {
+                dup = dupes->next->data;
+                um_user_show_short_display_name (dup);
+                g_signal_emit (manager, signals[USER_CHANGED], 0, dup);
+
+                g_list_free_1 (dupes->next);
+                g_object_set_data (G_OBJECT (dup), "dupes", NULL);
+        }
+        else {
+                dupes->next->prev = dupes->prev;
+                dupes->prev->next = dupes->next;
+        }
+
+        g_list_free_1 (dupes);
+        g_object_set_data (G_OBJECT (user), "dupes", NULL);
+}
+
+static gboolean
+match_real_name_hrfunc (gpointer key,
+                        gpointer value,
+                        gpointer user)
+{
+        return (value != user && g_strcmp0 (um_user_get_real_name (user), um_user_get_real_name (value)) == 0);
+}
+
+static void
+add_user_to_dupe_ring (UmUserManager *manager,
+                       UmUser        *user)
+{
+        UmUser *dup;
+        GList *dupes;
+        GList *l;
+
+        dup = g_hash_table_find (manager->user_by_object_path,
+                                 match_real_name_hrfunc, user);
+
+        if (!dup) {
+                return;
+        }
+
+        um_user_show_full_display_name (user);
+
+        dupes = g_object_get_data (G_OBJECT (dup), "dupes");
+        if (!dupes) {
+                um_user_show_full_display_name (dup);
+                g_signal_emit (manager, signals[USER_CHANGED], 0, dup);
+                dupes = g_list_append (NULL, dup);
+                g_object_set_data (G_OBJECT (dup), "dupes", dupes);
+                dupes->next = dupes->prev = dupes;
+        }
+
+        l = g_list_append (NULL, user);
+        g_object_set_data (G_OBJECT (user), "dupes", l);
+        l->prev = dupes->prev;
+        dupes->prev->next = l;
+        l->next = dupes;
+        dupes->prev = l;
+}
+
+static void
+user_changed_handler (UmUser        *user,
+                      UmUserManager *manager)
+{
+        remove_user_from_dupe_ring (manager, user);
+        add_user_to_dupe_ring (manager, user);
+        g_signal_emit (manager, signals[USER_CHANGED], 0, user);
+}
+
+static void
+user_added_handler (DBusGProxy *proxy,
+                    const char *object_path,
+                    gpointer    user_data)
+{
+        UmUserManager *manager = UM_USER_MANAGER (user_data);
+        UmUser *user;
+ 
+        if (g_hash_table_lookup (manager->user_by_object_path, object_path))
+                return;
+
+        user = um_user_new_from_object_path (object_path);
+        if (!user)
+                return;
+
+        add_user_to_dupe_ring (manager, user);
+
+        g_signal_connect (user, "changed",
+                          G_CALLBACK (user_changed_handler), manager);
+        g_hash_table_insert (manager->user_by_object_path, g_strdup (um_user_get_object_path (user)), g_object_ref (user));
+        g_hash_table_insert (manager->user_by_name, g_strdup (um_user_get_user_name (user)), g_object_ref (user));
+
+        g_signal_emit (manager, signals[USER_ADDED], 0, user);
+        g_object_unref (user);
+}
+
+static void
+user_deleted_handler (DBusGProxy *proxy,
+                      const char *object_path,
+                      gpointer    user_data)
+{
+        UmUserManager *manager = UM_USER_MANAGER (user_data);
+        UmUser *user;
+
+        user = g_hash_table_lookup (manager->user_by_object_path, object_path);
+        g_object_ref (user);
+        g_signal_handlers_disconnect_by_func (user, user_changed_handler, manager);
+
+        remove_user_from_dupe_ring (manager, user);
+
+        g_hash_table_remove (manager->user_by_object_path, um_user_get_object_path (user));
+        g_hash_table_remove (manager->user_by_name, um_user_get_user_name (user));
+        g_signal_emit (manager, signals[USER_REMOVED], 0, user);
+        g_object_unref (user);
+}
+
+static void
+add_user (const gchar   *object_path,
+          UmUserManager *manager)
+{
+        user_added_handler (NULL, object_path, manager);
+}
+
+static void
+got_users (DBusGProxy     *proxy,
+           DBusGProxyCall *call_id,
+           gpointer        data)
+{
+        UmUserManager *manager = data;
+        GError *error = NULL;
+        GPtrArray *paths;
+
+        if (!dbus_g_proxy_end_call (proxy,
+                                    call_id,
+                                    &error,
+                                    dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH), &paths,
+                                    G_TYPE_INVALID)) {
+                manager->no_service = TRUE;
+                g_error_free (error);
+                goto done;
+        }
+
+        g_ptr_array_foreach (paths, (GFunc)add_user, manager);
+
+        g_ptr_array_foreach (paths, (GFunc)g_free, NULL);
+        g_ptr_array_free (paths, TRUE);
+
+ done:
+        g_signal_emit (G_OBJECT (manager), signals[USERS_LOADED], 0);
+}
+
+static void
+get_users (UmUserManager *manager)
+{
+        g_debug ("calling 'ListCachedUsers'");
+        dbus_g_proxy_begin_call (manager->proxy,
+                                 "ListCachedUsers",
+                                 got_users,
+                                 manager,
+                                 NULL,
+                                 G_TYPE_INVALID);
+}
+
+static void
+um_user_manager_init (UmUserManager *manager)
+{
+        GError *error = NULL;
+
+        manager->user_by_object_path = g_hash_table_new_full (g_str_hash,
+                                                              g_str_equal,
+                                                              g_free,
+                                                              g_object_unref);
+        manager->user_by_name = g_hash_table_new_full (g_str_hash,
+                                                       g_str_equal,
+                                                       g_free,
+                                                       g_object_unref);
+
+        manager->bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
+        if (manager->bus == NULL) {
+                g_warning ("Couldn't connect to system bus: %s", error->message);
+                g_error_free (error);
+                goto error;
+        }
+
+        manager->proxy = dbus_g_proxy_new_for_name (manager->bus,
+                                                    "org.freedesktop.Accounts",
+                                                    "/org/freedesktop/Accounts",
+                                                    "org.freedesktop.Accounts");
+
+        dbus_g_proxy_add_signal (manager->proxy, "UserAdded", DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
+        dbus_g_proxy_add_signal (manager->proxy, "UserDeleted", DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
+
+        dbus_g_proxy_connect_signal (manager->proxy, "UserAdded",
+                                     G_CALLBACK (user_added_handler), manager, NULL);
+        dbus_g_proxy_connect_signal (manager->proxy, "UserDeleted",
+                                     G_CALLBACK (user_deleted_handler), manager, NULL);
+
+        get_users (manager);
+
+ error: ;
+}
+
+static void
+clear_dup (gpointer key,
+           gpointer value,
+           gpointer data)
+{
+        GList *dupes;
+
+        /* don't bother maintaining the ring, we're destroying the
+         * entire hash table anyway
+         */
+        dupes = g_object_get_data (G_OBJECT (value), "dupes");
+
+        if (dupes) {
+                g_list_free_1 (dupes);
+                g_object_set_data (G_OBJECT (value), "dupes", NULL);
+        }
+}
+
+static void
+um_user_manager_finalize (GObject *object)
+{
+        UmUserManager *manager;
+
+        manager = UM_USER_MANAGER (object);
+
+        g_hash_table_foreach (manager->user_by_object_path, clear_dup, NULL);
+        g_hash_table_destroy (manager->user_by_object_path);
+        g_hash_table_destroy (manager->user_by_name);
+
+        G_OBJECT_CLASS (um_user_manager_parent_class)->finalize (object);
+}
+
+UmUserManager *
+um_user_manager_ref_default (void)
+{
+        if (user_manager_object != NULL) {
+                g_object_ref (user_manager_object);
+        } else {
+                user_manager_object = g_object_new (UM_TYPE_USER_MANAGER, NULL);
+                g_object_add_weak_pointer (user_manager_object,
+                                           (gpointer *) &user_manager_object);
+        }
+
+        return UM_USER_MANAGER (user_manager_object);
+}
+
+typedef struct {
+        UmUserManager       *manager;
+        gchar               *user_name;
+        GAsyncReadyCallback  callback;
+        gpointer             data;
+        GDestroyNotify       destroy;
+}  AsyncUserOpData;
+
+static void
+async_user_op_data_free (gpointer d)
+{
+        AsyncUserOpData *data = d;
+
+        g_object_unref (data->manager);
+
+        g_free (data->user_name);
+
+        if (data->destroy)
+                data->destroy (data->data);
+
+        g_free (data);
+}
+
+static void
+create_user_done (DBusGProxy     *proxy,
+                  DBusGProxyCall *call_id,
+                  gpointer        user_data)
+{
+        AsyncUserOpData *data = user_data;
+        gchar *path;
+        GError *error;
+        GSimpleAsyncResult *res;
+
+        res = g_simple_async_result_new (G_OBJECT (data->manager),
+                                         data->callback,
+                                         data->data,
+                                         um_user_manager_create_user);
+        error = NULL;
+        if (!dbus_g_proxy_end_call (proxy,
+                                    call_id,
+                                    &error,
+                                    DBUS_TYPE_G_OBJECT_PATH, &path,
+                                    G_TYPE_INVALID)) {
+                /* dbus-glib fail:
+                 * We have to translate the errors manually here, since
+                 * calling dbus_g_error_has_name on the error returned in
+                 * um_user_manager_create_user_finish doesn't work.
+                 */
+                if (dbus_g_error_has_name (error, "org.freedesktop.Accounts.Error.PermissionDenied")) {
+                        g_simple_async_result_set_error (res,
+                                                         UM_USER_MANAGER_ERROR,
+                                                         UM_USER_MANAGER_ERROR_PERMISSION_DENIED,
+                                                         "Not authorized");
+                }
+                else if (dbus_g_error_has_name (error, "org.freedesktop.Accounts.Error.UserExists")) {
+                        g_simple_async_result_set_error (res,
+                                                         UM_USER_MANAGER_ERROR,
+                                                         UM_USER_MANAGER_ERROR_USER_EXISTS,
+                                                         _("A user with name '%s' already exists."),
+                                                         data->user_name);
+                }
+                else {
+                        g_simple_async_result_set_from_error (res, error);
+                }
+                g_error_free (error);
+        }
+        else {
+                g_simple_async_result_set_op_res_gpointer (res, path, g_free);
+        }
+
+        data->callback (G_OBJECT (data->manager), G_ASYNC_RESULT (res), data->data);
+}
+
+gboolean
+um_user_manager_create_user_finish (UmUserManager  *manager,
+                                    GAsyncResult   *result,
+                                    UmUser        **user,
+                                    GError        **error)
+{
+        gchar *path;
+        GSimpleAsyncResult *res;
+
+        res = G_SIMPLE_ASYNC_RESULT (result);
+
+        *user = NULL;
+
+        if (g_simple_async_result_propagate_error (res, error)) {
+                return FALSE;
+        }
+
+        path = g_simple_async_result_get_op_res_gpointer (res);
+        *user = g_hash_table_lookup (manager->user_by_object_path, path);
+
+        return TRUE;
+}
+
+void
+um_user_manager_create_user (UmUserManager       *manager,
+                             const char          *user_name,
+                             const char          *real_name,
+                             gint                 account_type,
+                             GAsyncReadyCallback  done,
+                             gpointer             done_data,
+                             GDestroyNotify       destroy)
+{
+        AsyncUserOpData *data;
+
+        data = g_new0 (AsyncUserOpData, 1);
+        data->manager = g_object_ref (manager);
+        data->user_name = g_strdup (user_name);
+        data->callback = done;
+        data->data = done_data;
+        data->destroy = destroy;
+
+        dbus_g_proxy_begin_call (manager->proxy,
+                                 "CreateUser",
+                                 create_user_done,
+                                 data,
+                                 async_user_op_data_free,
+                                 G_TYPE_STRING, user_name,
+                                 G_TYPE_STRING, real_name,
+                                 G_TYPE_INT, account_type,
+                                 G_TYPE_INVALID);
+}
+
+static void
+delete_user_done (DBusGProxy     *proxy,
+                  DBusGProxyCall *call_id,
+                  gpointer        user_data)
+{
+        AsyncUserOpData *data = user_data;
+        GError *error;
+        GSimpleAsyncResult *res;
+
+        res = g_simple_async_result_new (G_OBJECT (data->manager),
+                                         data->callback,
+                                         data->data,
+                                         um_user_manager_delete_user);
+        error = NULL;
+        if (!dbus_g_proxy_end_call (proxy,
+                                    call_id,
+                                    &error,
+                                    G_TYPE_INVALID)) {
+                if (dbus_g_error_has_name (error, "org.freedesktop.Accounts.Error.PermissionDenied")) {
+                        g_simple_async_result_set_error (res,
+                                                         UM_USER_MANAGER_ERROR,
+                                                         UM_USER_MANAGER_ERROR_PERMISSION_DENIED,
+                                                         "Not authorized");
+                }
+                else if (dbus_g_error_has_name (error, "org.freedesktop.Accounts.Error.UserDoesntExists")) {
+                        g_simple_async_result_set_error (res,
+                                                         UM_USER_MANAGER_ERROR,
+                                                         UM_USER_MANAGER_ERROR_USER_DOES_NOT_EXIST,
+                                                         _("This user does not exist."));
+                }
+                else {
+                        g_simple_async_result_set_from_error (res, error);
+                        g_error_free (error);
+                }
+        }
+
+        data->callback (G_OBJECT (data->manager), G_ASYNC_RESULT (res), data->data);
+}
+
+gboolean
+um_user_manager_delete_user_finish (UmUserManager  *manager,
+                                    GAsyncResult   *result,
+                                    GError        **error)
+{
+        GSimpleAsyncResult *res;
+
+        res = G_SIMPLE_ASYNC_RESULT (result);
+
+        if (g_simple_async_result_propagate_error (res, error)) {
+                return FALSE;
+        }
+
+        return TRUE;
+}
+
+void
+um_user_manager_delete_user (UmUserManager       *manager,
+                             UmUser              *user,
+                             gboolean             remove_files,
+                             GAsyncReadyCallback  done,
+                             gpointer             done_data,
+                             GDestroyNotify       destroy)
+{
+        AsyncUserOpData *data;
+
+        data = g_new0 (AsyncUserOpData, 1);
+        data->manager = g_object_ref (manager);
+        data->callback = done;
+        data->data = done_data;
+        data->destroy = destroy;
+
+        dbus_g_proxy_begin_call (manager->proxy,
+                                 "DeleteUser",
+                                 delete_user_done,
+                                 data,
+                                 async_user_op_data_free,
+                                 G_TYPE_INT64, um_user_get_uid (user),
+                                 G_TYPE_BOOLEAN, remove_files,
+                                 G_TYPE_INVALID);
+}
+
+GSList *
+um_user_manager_list_users (UmUserManager *manager)
+{
+        GSList *list = NULL;
+        GHashTableIter iter;
+        gpointer value;
+
+        g_hash_table_iter_init (&iter, manager->user_by_name);
+        while (g_hash_table_iter_next (&iter, NULL, &value)) {
+                list = g_slist_prepend (list, value);
+        }
+
+        return g_slist_sort (list, (GCompareFunc) um_user_collate);
+}
+
+UmUser *
+um_user_manager_get_user (UmUserManager *manager,
+                          const gchar   *name)
+{
+        return g_hash_table_lookup (manager->user_by_name, name);
+}
+
+UmUser *
+um_user_manager_get_user_by_id (UmUserManager *manager,
+                                uid_t          uid)
+{
+        struct passwd *pwent;
+
+        pwent = getpwuid (uid);
+        if (!pwent) {
+                return NULL;
+        }
+
+        return um_user_manager_get_user (manager, pwent->pw_name);
+}
+
+gboolean
+um_user_manager_no_service (UmUserManager *manager)
+{
+        return manager->no_service;
+}
+
+GQuark
+um_user_manager_error_quark (void)
+{
+        return g_quark_from_static_string ("um-user-manager-error-quark");
+}
diff --git a/panels/user-accounts/um-user-manager.h b/panels/user-accounts/um-user-manager.h
new file mode 100644
index 0000000..b051a88
--- /dev/null
+++ b/panels/user-accounts/um-user-manager.h
@@ -0,0 +1,112 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 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.
+ *
+ */
+
+#ifndef __UM_USER_MANAGER__
+#define __UM_USER_MANAGER__
+
+#include <glib-object.h>
+#include <gio/gio.h>
+#include <dbus/dbus-glib.h>
+
+#include "um-user.h"
+
+G_BEGIN_DECLS
+
+#define UM_TYPE_USER_MANAGER         (um_user_manager_get_type ())
+#define UM_USER_MANAGER(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), UM_TYPE_USER_MANAGER, UmUserManager))
+#define UM_USER_MANAGER_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), UM_TYPE_USER_MANAGER, UmUserManagerClass))
+#define UM_IS_USER_MANAGER(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), UM_TYPE_USER_MANAGER))
+#define UM_IS_USER_MANAGER_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), UM_TYPE_USER_MANAGER))
+#define UM_USER_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), UM_TYPE_USER_MANAGER, UmUserManagerClass))
+
+typedef struct
+{
+        GObject parent;
+
+        DBusGConnection *bus;
+        DBusGProxy *proxy;
+
+        GHashTable *user_by_object_path;
+        GHashTable *user_by_name;
+
+        gboolean no_service;
+} UmUserManager;
+
+typedef struct
+{
+        GObjectClass   parent_class;
+
+        void          (* users_loaded)              (UmUserManager *user_managaer);
+        void          (* user_added)                (UmUserManager *user_manager,
+                                                     UmUser        *user);
+        void          (* user_removed)              (UmUserManager *user_manager,
+                                                     UmUser        *user);
+        void          (* user_changed)              (UmUserManager *user_manager,
+                                                     UmUser        *user);
+} UmUserManagerClass;
+
+
+typedef enum {
+        UM_USER_MANAGER_ERROR_FAILED,
+        UM_USER_MANAGER_ERROR_USER_EXISTS,
+        UM_USER_MANAGER_ERROR_USER_DOES_NOT_EXIST,
+        UM_USER_MANAGER_ERROR_PERMISSION_DENIED
+} UmUserManagerError;
+
+#define UM_USER_MANAGER_ERROR um_user_manager_error_quark ()
+
+GQuark             um_user_manager_error_quark (void);
+
+GType              um_user_manager_get_type              (void);
+
+UmUserManager *    um_user_manager_ref_default           (void);
+
+gboolean           um_user_manager_no_service            (UmUserManager *manager);
+
+GSList *           um_user_manager_list_users            (UmUserManager *manager);
+UmUser *           um_user_manager_get_user              (UmUserManager *manager,
+                                                          const char    *user_name);
+UmUser *           um_user_manager_get_user_by_id        (UmUserManager *manager,
+                                                          uid_t          uid);
+
+void               um_user_manager_create_user           (UmUserManager       *manager,
+                                                          const char          *user_name,
+                                                          const char          *real_name,
+                                                          gint                 account_type,
+                                                          GAsyncReadyCallback  done,
+                                                          gpointer             user_data,
+                                                          GDestroyNotify       destroy);
+gboolean           um_user_manager_create_user_finish    (UmUserManager       *manager,
+                                                          GAsyncResult        *result,
+                                                          UmUser             **user,
+                                                          GError             **error);
+void               um_user_manager_delete_user           (UmUserManager       *manager,
+                                                          UmUser              *user,
+                                                          gboolean             remove_files,
+                                                          GAsyncReadyCallback  done,
+                                                          gpointer             user_data,
+                                                          GDestroyNotify       destroy);
+gboolean           um_user_manager_delete_user_finish    (UmUserManager       *manager,
+                                                          GAsyncResult        *result,
+                                                          GError             **error);
+
+G_END_DECLS
+
+#endif /* __UM_USER_MANAGER__ */
diff --git a/panels/user-accounts/um-user-module.c b/panels/user-accounts/um-user-module.c
new file mode 100644
index 0000000..d96ed40
--- /dev/null
+++ b/panels/user-accounts/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/panels/user-accounts/um-user-panel.c b/panels/user-accounts/um-user-panel.c
new file mode 100644
index 0000000..4bb3d6e
--- /dev/null
+++ b/panels/user-accounts/um-user-panel.c
@@ -0,0 +1,1286 @@
+/* -*- 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 <unistd.h>
+#include <sys/types.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <polkit/polkit.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-strength-bar.h"
+#include "um-editable-button.h"
+#include "um-editable-entry.h"
+#include "um-editable-combo.h"
+#include "um-lockbutton.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 "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;
+        PolkitPermission *permission;
+        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 gchar *
+get_password_mode_text (UmUser *user)
+{
+        const gchar *text;
+
+        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:
+                        /* five bullets */
+                        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 ();
+                }
+        }
+
+        return text;
+}
+
+static void
+show_user (UmUser *user, UmUserPanelPrivate *d)
+{
+        GtkWidget *image;
+        GtkWidget *label;
+        GtkWidget *label2;
+        GtkWidget *label3;
+        GdkPixbuf *pixbuf;
+        gchar *lang;
+        GtkWidget *widget;
+        GtkTreeModel *model;
+        GtkTreeIter iter;
+
+        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);
+
+        widget = get_widget (d, "full-name-entry");
+        um_editable_entry_set_text (UM_EDITABLE_ENTRY (widget), um_user_get_real_name (user));
+        gtk_widget_set_tooltip_text (widget, um_user_get_user_name (user));
+
+        widget = get_widget (d, "account-type-combo");
+        um_editable_combo_set_active (UM_EDITABLE_COMBO (widget), um_user_get_account_type (user));
+
+        widget = get_widget (d, "account-password-button");
+        um_editable_button_set_text (UM_EDITABLE_BUTTON (widget), get_password_mode_text (user));
+
+        widget = get_widget (d, "account-email-entry");
+        um_editable_entry_set_text (UM_EDITABLE_ENTRY (widget), um_user_get_email (user));
+
+        widget = get_widget (d, "account-language-combo");
+        model = um_editable_combo_get_model (UM_EDITABLE_COMBO (widget));
+        um_add_user_languages (model);
+
+        lang = g_strdup (um_user_get_language (user));
+        if (!lang)
+                lang = um_get_current_language ();
+        um_get_iter_for_language (model, lang, &iter);
+        um_editable_combo_set_active_iter (UM_EDITABLE_COMBO (widget), &iter);
+        g_free (lang);
+
+        label = get_widget (d, "account-location-entry");
+        um_editable_entry_set_text (UM_EDITABLE_ENTRY (label), um_user_get_location (user));
+
+        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 (UmLockButton *button, gpointer data);
+
+static void
+selected_user_changed (GtkTreeSelection *selection, UmUserPanelPrivate *d)
+{
+        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 (UM_LOCK_BUTTON (d->lock_button), d);
+                g_object_unref (user);
+        }
+}
+
+static void
+change_name_done (GtkWidget          *entry,
+                  UmUserPanelPrivate *d)
+{
+        const gchar *text;
+        UmUser *user;
+
+        user = get_selected_user (d);
+
+        text = um_editable_entry_get_text (UM_EDITABLE_ENTRY (entry));
+
+        if (g_strcmp0 (text, um_user_get_location (user)) != 0) {
+                um_user_set_real_name (user, text);
+        }
+}
+
+static void
+account_type_changed (UmEditableCombo    *combo,
+                      UmUserPanelPrivate *d)
+{
+        UmUser *user;
+        GtkTreeModel *model;
+        GtkTreeIter iter;
+        gint account_type;
+
+        user = get_selected_user (d);
+        model = um_editable_combo_get_model (combo);
+        um_editable_combo_get_active_iter (combo, &iter);
+        gtk_tree_model_get (model, &iter, 1, &account_type, -1);
+
+        if (account_type != um_user_get_account_type (user)) {
+                um_user_set_account_type (user, account_type);
+        }
+}
+
+static void
+language_response (GtkDialog         *dialog,
+                   gint               response_id,
+                   UmUserPanelPrivate *d)
+{
+        GtkWidget *combo;
+        UmUser *user;
+        gchar *lang;
+        GtkTreeModel *model;
+        GtkTreeIter iter;
+
+        user = get_selected_user (d);
+        combo = get_widget (d, "account-language-combo");
+        model = um_editable_combo_get_model (UM_EDITABLE_COMBO (combo));
+
+        if (response_id == GTK_RESPONSE_OK) {
+                lang = um_language_chooser_get_language (GTK_WIDGET (dialog));
+                um_user_set_language (user, lang);
+        }
+        else {
+                lang = g_strdup (um_user_get_language (user));
+                if (!lang)
+                        lang = um_get_current_language ();
+        }
+        um_get_iter_for_language (model, lang, &iter);
+        um_editable_combo_set_active_iter (UM_EDITABLE_COMBO (combo), &iter);
+        g_free (lang);
+
+        gtk_widget_hide (GTK_WIDGET (dialog));
+        gtk_widget_set_sensitive (combo, TRUE);
+}
+
+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 (UmEditableCombo    *combo,
+                  UmUserPanelPrivate *d)
+{
+        GtkTreeModel *model;
+        GtkTreeIter iter;
+        gchar *lang;
+        UmUser *user;
+        GdkCursor *cursor;
+
+        if (!um_editable_combo_get_active_iter (combo, &iter))
+                 return;
+
+        user = get_selected_user (d);
+        model = um_editable_combo_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 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_done (UmEditableEntry    *e,
+                   UmUserPanelPrivate *d)
+{
+        const gchar *text;
+        UmUser *user;
+
+        user = get_selected_user (d);
+
+        text = um_editable_entry_get_text (e);
+
+        if (g_strcmp0 (text, um_user_get_email (user)) != 0) {
+                um_user_set_email (user, text);
+        }
+}
+
+static void
+change_location_done (GtkWidget         *entry,
+                      UmUserPanelPrivate *d)
+{
+        const gchar *text;
+        UmUser *user;
+
+        user = get_selected_user (d);
+
+        text = um_editable_entry_get_text (UM_EDITABLE_ENTRY (entry));
+
+        if (g_strcmp0 (text, um_user_get_location (user)) != 0) {
+                um_user_set_location (user, text);
+        }
+}
+
+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 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
+add_unlock_tooltip (GtkWidget *button)
+{
+        const gchar *names[3];
+        GIcon *icon;
+
+        names[0] = "changes-prevent-symbolic";
+        names[1] = "changes-prevent";
+        names[2] = NULL;
+        icon = g_themed_icon_new_from_names (names, -1);
+        setup_tooltip_with_embedded_icon (button,
+                                          _("To make changes,\nclick the * icon first"),
+                                          "*",
+                                          icon);
+        g_object_unref (icon);
+        g_signal_connect (button, "button-release-event",
+                           G_CALLBACK (show_tooltip_now), NULL);
+}
+
+static void
+remove_unlock_tooltip (GtkWidget *button)
+{
+        setup_tooltip_with_embedded_icon (button, NULL, NULL, NULL);
+        g_signal_handlers_disconnect_by_func (button,
+                                              G_CALLBACK (show_tooltip_now), NULL);
+}
+
+static void
+lockbutton_changed (UmLockButton *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 = g_permission_get_allowed (G_PERMISSION (d->permission));
+        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 {
+                const gchar *names[3];
+                GIcon *icon;
+
+                names[0] = "changes-prevent-symbolic";
+                names[1] = "changes-prevent";
+                names[2] = NULL;
+                icon = g_themed_icon_new_from_names (names, -1);
+                setup_tooltip_with_embedded_icon (widget,
+                                                  _("To create a user,\nclick the * icon first"),
+                                                  "*",
+                                                  icon);
+                g_object_unref (icon);
+        }
+
+        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 {
+                const gchar *names[3];
+                GIcon *icon;
+
+                names[0] = "changes-prevent-symbolic";
+                names[1] = "changes-prevent";
+                names[2] = NULL;
+                icon = g_themed_icon_new_from_names (names, -1);
+
+                setup_tooltip_with_embedded_icon (widget,
+                                                  _("To delete the selected user,\nclick the * icon first"),
+                                                  "*",
+                                                  icon);
+                g_object_unref (icon);
+        }
+
+        if (is_authorized) {
+                um_editable_combo_set_editable (UM_EDITABLE_COMBO (get_widget (d, "account-type-combo")), TRUE);
+                remove_unlock_tooltip (get_widget (d, "account-type-combo"));
+        }
+        else {
+                um_editable_combo_set_editable (UM_EDITABLE_COMBO (get_widget (d, "account-type-combo")), FALSE);
+                add_unlock_tooltip (get_widget (d, "account-type-combo"));
+        }
+
+        if (is_authorized || self_selected) {
+                gtk_widget_show (get_widget (d, "user-icon-button"));
+                gtk_widget_hide (get_widget (d, "user-icon-nonbutton"));
+
+                um_editable_entry_set_editable (UM_EDITABLE_ENTRY (get_widget (d, "full-name-entry")), TRUE);
+                remove_unlock_tooltip (get_widget (d, "full-name-entry"));
+
+                um_editable_entry_set_editable (UM_EDITABLE_ENTRY (get_widget (d, "account-email-entry")), TRUE);
+                remove_unlock_tooltip (get_widget (d, "account-email-entry"));
+
+                um_editable_entry_set_editable (UM_EDITABLE_ENTRY (get_widget (d, "account-location-entry")), TRUE);
+                remove_unlock_tooltip (get_widget (d, "account-location-entry"));
+
+                um_editable_combo_set_editable (UM_EDITABLE_COMBO (get_widget (d, "account-language-combo")), TRUE);
+                remove_unlock_tooltip (get_widget (d, "account-language-combo"));
+
+                um_editable_button_set_editable (UM_EDITABLE_BUTTON (get_widget (d, "account-password-button")), TRUE);
+                remove_unlock_tooltip (get_widget (d, "account-password-button"));
+
+                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"));
+
+                um_editable_entry_set_editable (UM_EDITABLE_ENTRY (get_widget (d, "full-name-entry")), FALSE);
+                add_unlock_tooltip (get_widget (d, "full-name-entry"));
+
+                um_editable_entry_set_editable (UM_EDITABLE_ENTRY (get_widget (d, "account-email-entry")), FALSE);
+                add_unlock_tooltip (get_widget (d, "account-email-entry"));
+
+                um_editable_entry_set_editable (UM_EDITABLE_ENTRY (get_widget (d, "account-location-entry")), FALSE);
+                add_unlock_tooltip (get_widget (d, "account-location-entry"));
+
+                um_editable_combo_set_editable (UM_EDITABLE_COMBO (get_widget (d, "account-language-combo")), FALSE);
+                add_unlock_tooltip (get_widget (d, "account-language-combo"));
+
+                um_editable_button_set_editable (UM_EDITABLE_BUTTON (get_widget (d, "account-password-button")), FALSE);
+                add_unlock_tooltip (get_widget (d, "account-password-button"));
+
+                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 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 *userlist;
+        GtkTreeModel *model;
+        GtkListStore *store;
+        GtkTreeViewColumn *column;
+        GtkCellRenderer *cell;
+        GtkTreeSelection *selection;
+        GtkWidget *button;
+        GtkTreeIter iter;
+        gint expander_size;
+        GtkWidget *box;
+        gchar *title;
+        GIcon *icon;
+        const gchar *names[3];
+
+        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));
+
+        title = g_strdup_printf ("<small><span foreground=\"#555555\">%s</span></small>", _("My Account"));
+        gtk_list_store_append (store, &iter);
+        gtk_list_store_set (store, &iter,
+                            TITLE_COL, title,
+                            HEADING_ROW_COL, TRUE,
+                            SORT_KEY_COL, 0,
+                            -1);
+        g_free (title);
+
+        title = g_strdup_printf ("<small><span foreground=\"#555555\">%s</span></small>", _("Other Accounts"));
+        gtk_list_store_append (store, &iter);
+        gtk_list_store_set (store, &iter,
+                            TITLE_COL, title,
+                            HEADING_ROW_COL, TRUE,
+                            SORT_KEY_COL, 2,
+                            -1);
+        g_free (title);
+
+        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");
+        add_unlock_tooltip (button);
+
+        button = get_widget (d, "full-name-entry");
+        g_signal_connect (button, "editing-done", G_CALLBACK (change_name_done), d);
+
+        button = get_widget (d, "account-type-combo");
+        g_signal_connect (button, "editing-done", G_CALLBACK (account_type_changed), d);
+
+        button = get_widget (d, "account-password-button");
+        g_signal_connect (button, "start-editing", G_CALLBACK (change_password), d);
+
+        button = get_widget (d, "account-email-entry");
+        g_signal_connect (button, "editing-done", G_CALLBACK (change_email_done), d);
+
+        button = get_widget (d, "account-language-combo");
+        g_signal_connect (button, "editing-done", G_CALLBACK (language_changed), d);
+
+        button = get_widget (d, "account-location-entry");
+        g_signal_connect (button, "editing-done", G_CALLBACK (change_location_done), d);
+
+        button = get_widget (d, "account-fingerprint-button");
+        g_signal_connect (button, "clicked",
+                          G_CALLBACK (change_fingerprint), d);
+
+        d->permission = polkit_permission_new_sync ("org.freedesktop.accounts.user-administration", NULL, NULL, NULL);
+        button = um_lock_button_new (d->permission);
+        gtk_widget_set_margin_top (button, 12);
+        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 (UM_LOCK_BUTTON (button), d);
+        d->lock_button = button;
+
+        button = get_widget (d, "add-user-button");
+        names[0] = "changes-prevent-symbolic";
+        names[1] = "changes-prevent";
+        names[2] = NULL;
+        icon = g_themed_icon_new_from_names (names, -1);
+        setup_tooltip_with_embedded_icon (button,
+                                          _("To create a user,\nclick the * icon first"),
+                                          "*",
+                                          icon);
+        button = get_widget (d, "delete-user-button");
+        setup_tooltip_with_embedded_icon (button,
+                                          _("To delete the selected user,\nclick the * icon first"),
+                                          "*",
+                                          icon);
+        g_object_unref (icon);
+}
+
+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 ();
+        type = um_editable_button_get_type ();
+        type = um_editable_entry_get_type ();
+        type = um_editable_combo_get_type ();
+
+        d->builder = gtk_builder_new ();
+        d->um = um_user_manager_ref_default ();
+        d->authority = polkit_authority_get_sync (NULL, NULL);
+
+        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);
+        }
+
+        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->photo_dialog = um_photo_dialog_new (button);
+        d->notebook = get_widget (d, "top-level-notebook");
+        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_class_init (UmUserPanelClass *klass)
+{
+        GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+        object_class->dispose = um_user_panel_dispose;
+
+        g_type_class_add_private (klass, sizeof (UmUserPanelPrivate));
+}
+
+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, "user-accounts", 0);
+}
diff --git a/panels/user-accounts/um-user-panel.h b/panels/user-accounts/um-user-panel.h
new file mode 100644
index 0000000..4f5aec0
--- /dev/null
+++ b/panels/user-accounts/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/panels/user-accounts/um-user.c b/panels/user-accounts/um-user.c
new file mode 100644
index 0000000..ce92b4e
--- /dev/null
+++ b/panels/user-accounts/um-user.c
@@ -0,0 +1,1093 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+  *
+  * Copyright (C) 2004-2005 James M. Cape <jcape ignore-your tv>.
+  * Copyright (C) 2007-2008 William Jon McCann <mccann jhu edu>
+  * Copyright (C) 2009 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, write to the Free Software
+  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+  */
+
+#define _XOPEN_SOURCE
+
+#include "config.h"
+
+#include <float.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+
+#include <gio/gunixoutputstream.h>
+
+#include <dbus/dbus-glib.h>
+
+#include "um-user.h"
+#include "um-account-type.h"
+#include "um-utils.h"
+
+
+ #define UM_USER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UM_TYPE_USER, UmUserClass))
+ #define UM_IS_USER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UM_TYPE_USER))
+#define UM_USER_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS ((object), UM_TYPE_USER, UmUserClass))
+
+#define MAX_FILE_SIZE     65536
+
+typedef struct {
+        uid_t           uid;
+        gchar          *user_name;
+        gchar          *real_name;
+        gint            account_type;
+        gint            password_mode;
+        gchar          *password_hint;
+        gchar          *email;
+        gchar          *language;
+        gchar          *location;
+        guint64         login_frequency;
+        gchar          *icon_file;
+        gboolean        locked;
+        gboolean        automatic_login;
+} UserProperties;
+
+static void
+collect_props (const gchar    *key,
+               const GValue   *value,
+               UserProperties *props)
+{
+        gboolean handled = TRUE;
+
+        if (strcmp (key, "Uid") == 0) {
+                props->uid = g_value_get_uint64 (value);
+        }
+        else if (strcmp (key, "UserName") == 0) {
+                props->user_name = g_value_dup_string (value);
+        }
+        else if (strcmp (key, "RealName") == 0) {
+                props->real_name = g_value_dup_string (value);
+        }
+        else if (strcmp (key, "AccountType") == 0) {
+                props->account_type = g_value_get_int (value);
+        }
+        else if (strcmp (key, "Email") == 0) {
+                props->email = g_value_dup_string (value);
+        }
+        else if (strcmp (key, "Language") == 0) {
+                props->language = g_value_dup_string (value);
+        }
+        else if (strcmp (key, "Location") == 0) {
+                props->location = g_value_dup_string (value);
+        }
+        else if (strcmp (key, "LoginFrequency") == 0) {
+                props->login_frequency = g_value_get_uint64 (value);
+        }
+        else if (strcmp (key, "IconFile") == 0) {
+                props->icon_file = g_value_dup_string (value);
+        }
+        else if (strcmp (key, "Locked") == 0) {
+                props->locked = g_value_get_boolean (value);
+        }
+        else if (strcmp (key, "AutomaticLogin") == 0) {
+                props->automatic_login = g_value_get_boolean (value);
+        }
+        else if (strcmp (key, "PasswordMode") == 0) {
+                props->password_mode = g_value_get_int (value);
+        }
+        else if (strcmp (key, "PasswordHint") == 0) {
+                props->password_hint = g_value_dup_string (value);
+        }
+        else if (strcmp (key, "HomeDirectory") == 0) {
+                /* ignore */
+        }
+        else if (strcmp (key, "Shell") == 0) {
+                /* ignore */
+        }
+        else {
+                handled = FALSE;
+        }
+
+        if (!handled)
+                g_debug ("unhandled property %s", key);
+}
+
+static void
+user_properties_free (UserProperties *props)
+{
+        g_free (props->user_name);
+        g_free (props->real_name);
+        g_free (props->password_hint);
+        g_free (props->email);
+        g_free (props->language);
+        g_free (props->location);
+        g_free (props->icon_file);
+        g_free (props);
+}
+
+static UserProperties *
+user_properties_get (DBusGConnection *bus,
+                     const gchar     *object_path)
+{
+        UserProperties *props;
+        GError *error;
+        DBusGProxy *proxy;
+        GHashTable *hash_table;
+
+        props = g_new0 (UserProperties, 1);
+
+        proxy = dbus_g_proxy_new_for_name (bus,
+                                           "org.freedesktop.Accounts",
+                                           object_path,
+                                           "org.freedesktop.DBus.Properties");
+        error = NULL;
+        if (!dbus_g_proxy_call (proxy,
+                                "GetAll",
+                                &error,
+                                G_TYPE_STRING,
+                                "org.freedesktop.Accounts.User",
+                                G_TYPE_INVALID,
+                                dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE),
+                                &hash_table,
+                                G_TYPE_INVALID)) {
+                g_debug ("Error calling GetAll() when retrieving properties for %s: %s", object_path, error->message);
+                g_error_free (error);
+                g_free (props);
+                props = NULL;
+                goto out;
+        }
+        g_hash_table_foreach (hash_table, (GHFunc) collect_props, props);
+        g_hash_table_unref (hash_table);
+
+ out:
+        g_object_unref (proxy);
+        return props;
+}
+
+
+struct _UmUser {
+        GObject         parent;
+
+        DBusGConnection *bus;
+        DBusGProxy      *proxy;
+        gchar           *object_path;
+
+        UserProperties  *props;
+
+        gchar           *display_name;
+};
+
+typedef struct _UmUserClass
+{
+        GObjectClass parent_class;
+} UmUserClass;
+
+enum {
+        CHANGED,
+        LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static void um_user_finalize (GObject *object);
+
+G_DEFINE_TYPE (UmUser, um_user, G_TYPE_OBJECT)
+
+static void
+um_user_class_init (UmUserClass *class)
+{
+        GObjectClass *gobject_class;
+
+        gobject_class = G_OBJECT_CLASS (class);
+
+        gobject_class->finalize = um_user_finalize;
+
+        signals[CHANGED] = g_signal_new ("changed",
+                                         G_TYPE_FROM_CLASS (class),
+                                         G_SIGNAL_RUN_LAST,
+                                         0,
+                                         NULL, NULL,
+                                         g_cclosure_marshal_VOID__VOID,
+                                         G_TYPE_NONE, 0);
+}
+
+
+static void
+um_user_init (UmUser *user)
+{
+}
+
+static void
+um_user_finalize (GObject *object)
+{
+        UmUser *user;
+
+        user = UM_USER (object);
+
+        dbus_g_connection_unref (user->bus);
+        g_free (user->object_path);
+
+        if (user->proxy != NULL)
+                g_object_unref (user->proxy);
+
+        if (user->props != NULL)
+                user_properties_free (user->props);
+
+        (*G_OBJECT_CLASS (um_user_parent_class)->finalize) (object);
+}
+
+uid_t
+um_user_get_uid (UmUser *user)
+{
+        g_return_val_if_fail (UM_IS_USER (user), -1);
+
+        return user->props->uid;
+}
+
+const gchar *
+um_user_get_real_name (UmUser *user)
+{
+        g_return_val_if_fail (UM_IS_USER (user), NULL);
+
+        return user->props->real_name;
+}
+
+const gchar *
+um_user_get_display_name (UmUser *user)
+{
+        g_return_val_if_fail (UM_IS_USER (user), NULL);
+
+       return user->display_name ? user->display_name
+                                 : user->props->real_name;
+}
+
+const gchar *
+um_user_get_user_name (UmUser *user)
+{
+        g_return_val_if_fail (UM_IS_USER (user), NULL);
+
+        return user->props->user_name;
+}
+
+gint
+um_user_get_account_type (UmUser *user)
+{
+        g_return_val_if_fail (UM_IS_USER (user), UM_ACCOUNT_TYPE_STANDARD);
+
+        return user->props->account_type;
+}
+
+gulong
+um_user_get_login_frequency (UmUser *user)
+{
+        g_return_val_if_fail (UM_IS_USER (user), 0);
+
+        return user->props->login_frequency;
+}
+
+gint
+um_user_collate (UmUser *user1,
+                  UmUser *user2)
+{
+        const char *str1;
+        const char *str2;
+        gulong      num1;
+        gulong      num2;
+
+        g_return_val_if_fail (UM_IS_USER (user1), 0);
+        g_return_val_if_fail (UM_IS_USER (user2), 0);
+
+        num1 = user1->props->login_frequency;
+        num2 = user2->props->login_frequency;
+        if (num1 > num2) {
+                return -1;
+        }
+
+        if (num1 < num2) {
+                return 1;
+        }
+
+        /* if login frequency is equal try names */
+        if (user1->props->real_name != NULL) {
+                str1 = user1->props->real_name;
+        } else {
+                str1 = user1->props->user_name;
+        }
+
+        if (user2->props->real_name != NULL) {
+                str2 = user2->props->real_name;
+        } else {
+                str2 = user2->props->user_name;
+        }
+
+        if (str1 == NULL && str2 != NULL) {
+                return -1;
+        }
+
+        if (str1 != NULL && str2 == NULL) {
+                return 1;
+        }
+
+        if (str1 == NULL && str2 == NULL) {
+                return 0;
+        }
+
+        return g_utf8_collate (str1, str2);
+}
+
+static gboolean
+check_user_file (const char *filename,
+                 gssize      max_file_size)
+{
+        struct stat fileinfo;
+
+        if (max_file_size < 0) {
+                max_file_size = G_MAXSIZE;
+        }
+
+        /* Exists/Readable? */
+        if (stat (filename, &fileinfo) < 0) {
+                g_debug ("File does not exist");
+                return FALSE;
+        }
+
+        /* Is a regular file */
+        if (G_UNLIKELY (!S_ISREG (fileinfo.st_mode))) {
+                g_debug ("File is not a regular file");
+                return FALSE;
+        }
+
+        /* Size is kosher? */
+        if (G_UNLIKELY (fileinfo.st_size > max_file_size)) {
+                g_debug ("File is too large");
+                return FALSE;
+        }
+
+        return TRUE;
+}
+
+static cairo_surface_t *
+surface_from_pixbuf (GdkPixbuf *pixbuf)
+{
+        cairo_surface_t *surface;
+        cairo_t         *cr;
+
+        surface = cairo_image_surface_create (gdk_pixbuf_get_has_alpha (pixbuf) ?
+                                              CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24,
+                                              gdk_pixbuf_get_width (pixbuf),
+                                              gdk_pixbuf_get_height (pixbuf));
+        cr = cairo_create (surface);
+        gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
+        cairo_paint (cr);
+        cairo_destroy (cr);
+
+        return surface;
+}
+
+/**
+ * go_cairo_convert_data_to_pixbuf:
+ * @src: a pointer to pixel data in cairo format
+ * @dst: a pointer to pixel data in pixbuf format
+ * @width: image width
+ * @height: image height
+ * @rowstride: data rowstride
+ *
+ * Converts the pixel data stored in @src in CAIRO_FORMAT_ARGB32 cairo format
+ * to GDK_COLORSPACE_RGB pixbuf format and move them
+ * to @dst. If @src == @dst, pixel are converted in place.
+ **/
+
+static void
+go_cairo_convert_data_to_pixbuf (unsigned char *dst,
+                                 unsigned char const *src,
+                                 int width,
+                                 int height,
+                                 int rowstride)
+{
+        int i,j;
+        unsigned int t;
+        unsigned char a, b, c;
+
+        g_return_if_fail (dst != NULL);
+
+#define MULT(d,c,a,t) G_STMT_START { t = (a)? c * 255 / a: 0; d = t;} G_STMT_END
+
+        if (src == dst || src == NULL) {
+                for (i = 0; i < height; i++) {
+                        for (j = 0; j < width; j++) {
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+                                MULT(a, dst[2], dst[3], t);
+                                MULT(b, dst[1], dst[3], t);
+                                MULT(c, dst[0], dst[3], t);
+                                dst[0] = a;
+                                dst[1] = b;
+                                dst[2] = c;
+#else
+                                MULT(a, dst[1], dst[0], t);
+                                MULT(b, dst[2], dst[0], t);
+                                MULT(c, dst[3], dst[0], t);
+                                dst[3] = dst[0];
+                                dst[0] = a;
+                                dst[1] = b;
+                                dst[2] = c;
+#endif
+                                dst += 4;
+                        }
+                        dst += rowstride - width * 4;
+                }
+        } else {
+                for (i = 0; i < height; i++) {
+                        for (j = 0; j < width; j++) {
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+                                MULT(dst[0], src[2], src[3], t);
+                                MULT(dst[1], src[1], src[3], t);
+                                MULT(dst[2], src[0], src[3], t);
+                                dst[3] = src[3];
+#else
+                                MULT(dst[0], src[1], src[0], t);
+                                MULT(dst[1], src[2], src[0], t);
+                                MULT(dst[2], src[3], src[0], t);
+                                dst[3] = src[0];
+#endif
+                                src += 4;
+                                dst += 4;
+                        }
+                        src += rowstride - width * 4;
+                        dst += rowstride - width * 4;
+                }
+        }
+#undef MULT
+}
+
+static void
+cairo_to_pixbuf (guint8    *src_data,
+                 GdkPixbuf *dst_pixbuf)
+{
+        unsigned char *src;
+        unsigned char *dst;
+        guint          w;
+        guint          h;
+        guint          rowstride;
+
+        w = gdk_pixbuf_get_width (dst_pixbuf);
+        h = gdk_pixbuf_get_height (dst_pixbuf);
+        rowstride = gdk_pixbuf_get_rowstride (dst_pixbuf);
+
+        dst = gdk_pixbuf_get_pixels (dst_pixbuf);
+        src = src_data;
+
+        go_cairo_convert_data_to_pixbuf (dst, src, w, h, rowstride);
+}
+
+static GdkPixbuf *
+frame_pixbuf (GdkPixbuf *source)
+{
+        GdkPixbuf       *dest;
+        cairo_t         *cr;
+        cairo_surface_t *surface;
+        guint            w;
+        guint            h;
+        guint            rowstride;
+        int              frame_width;
+        double           radius;
+        guint8          *data;
+
+        frame_width = 2;
+
+        w = gdk_pixbuf_get_width (source) + frame_width * 2;
+        h = gdk_pixbuf_get_height (source) + frame_width * 2;
+        radius = w / 10;
+
+        dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
+                               TRUE,
+                               8,
+                               w,
+                               h);
+        rowstride = gdk_pixbuf_get_rowstride (dest);
+
+
+        data = g_new0 (guint8, h * rowstride);
+
+        surface = cairo_image_surface_create_for_data (data,
+                                                       CAIRO_FORMAT_ARGB32,
+                                                       w,
+                                                       h,
+                                                       rowstride);
+        cr = cairo_create (surface);
+        cairo_surface_destroy (surface);
+
+        /* set up image */
+        cairo_rectangle (cr, 0, 0, w, h);
+        cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.0);
+        cairo_fill (cr);
+
+        rounded_rectangle (cr, 1.0, 0.5, 0.5, radius, w - 1, h - 1);
+        cairo_set_source_rgba (cr, 0.5, 0.5, 0.5, 0.3);
+        cairo_fill_preserve (cr);
+
+        surface = surface_from_pixbuf (source);
+        cairo_set_source_surface (cr, surface, frame_width, frame_width);
+        cairo_fill (cr);
+        cairo_surface_destroy (surface);
+
+        cairo_to_pixbuf (data, dest);
+
+        cairo_destroy (cr);
+        g_free (data);
+
+        return dest;
+}
+
+GdkPixbuf *
+um_user_render_icon (UmUser   *user,
+                     gboolean  with_frame,
+                     gint      icon_size)
+{
+        GdkPixbuf    *pixbuf;
+        GdkPixbuf    *framed;
+        gboolean      res;
+        GError       *error;
+
+        g_return_val_if_fail (UM_IS_USER (user), NULL);
+        g_return_val_if_fail (icon_size > 12, NULL);
+
+        pixbuf = NULL;
+        if (user->props->icon_file) {
+                res = check_user_file (user->props->icon_file,
+                                       MAX_FILE_SIZE);
+                if (res) {
+                        pixbuf = gdk_pixbuf_new_from_file_at_size (user->props->icon_file,
+                                                                   icon_size,
+                                                                   icon_size,
+                                                                   NULL);
+                }
+                else {
+                        pixbuf = NULL;
+                }
+        }
+
+        if (pixbuf != NULL) {
+                goto out;
+        }
+
+        error = NULL;
+        pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
+
+                                           "avatar-default",
+                                           icon_size,
+                                           GTK_ICON_LOOKUP_FORCE_SIZE,
+                                           &error);
+        if (error) {
+                g_warning ("%s", error->message);
+                g_error_free (error);
+        }
+
+ out:
+
+        if (pixbuf != NULL && with_frame) {
+                framed = frame_pixbuf (pixbuf);
+                if (framed != NULL) {
+                        g_object_unref (pixbuf);
+                        pixbuf = framed;
+                }
+        }
+
+        return pixbuf;
+}
+
+const gchar *
+um_user_get_email (UmUser *user)
+{
+        g_return_val_if_fail (UM_IS_USER (user), NULL);
+
+        return user->props->email;
+}
+
+const gchar *
+um_user_get_language (UmUser *user)
+{
+        g_return_val_if_fail (UM_IS_USER (user), NULL);
+
+        if (*user->props->language == '\0')
+                return NULL;
+        return user->props->language;
+}
+
+const gchar *
+um_user_get_location (UmUser *user)
+{
+        g_return_val_if_fail (UM_IS_USER (user), NULL);
+
+        return user->props->location;
+}
+
+gint
+um_user_get_password_mode (UmUser *user)
+{
+        g_return_val_if_fail (UM_IS_USER (user), UM_PASSWORD_MODE_NONE);
+
+        return user->props->password_mode;
+}
+
+const char *
+um_user_get_password_hint (UmUser *user)
+{
+        g_return_val_if_fail (UM_IS_USER (user), NULL);
+
+        return user->props->password_hint;
+}
+
+const char *
+um_user_get_icon_file (UmUser *user)
+{
+        g_return_val_if_fail (UM_IS_USER (user), NULL);
+
+        return user->props->icon_file;
+}
+
+gboolean
+um_user_get_locked (UmUser *user)
+{
+        g_return_val_if_fail (UM_IS_USER (user), FALSE);
+
+        return user->props->locked;
+}
+
+gboolean
+um_user_get_automatic_login (UmUser *user)
+{
+        g_return_val_if_fail (UM_IS_USER (user), FALSE);
+
+        return user->props->automatic_login;
+}
+
+const gchar *
+um_user_get_object_path (UmUser *user)
+{
+        g_return_val_if_fail (UM_IS_USER (user), NULL);
+
+        return user->object_path;
+}
+
+static gboolean
+update_info (UmUser *user)
+{
+        UserProperties *props;
+
+        props = user_properties_get (user->bus, user->object_path);
+        if (props != NULL) {
+                if (user->props != NULL)
+                        user_properties_free (user->props);
+                user->props = props;
+                return TRUE;
+        }
+        else {
+                return FALSE;
+        }
+}
+
+static void
+changed_handler (DBusGProxy *proxy,
+                 gpointer   *data)
+{
+        UmUser *user = UM_USER (data);
+
+        if (update_info (user)) {
+                if (user->display_name != NULL) {
+                        um_user_show_full_display_name (user);
+                }
+
+                g_signal_emit (user, signals[CHANGED], 0);
+        }
+}
+
+UmUser *
+um_user_new_from_object_path (const gchar *object_path)
+{
+        UmUser *user;
+        GError *error;
+
+        user = (UmUser *)g_object_new (UM_TYPE_USER, NULL);
+        user->object_path = g_strdup (object_path);
+
+        error = NULL;
+        user->bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
+        if (user->bus == NULL) {
+                g_warning ("Couldn't connect to system bus: %s", error->message);
+                goto error;
+        }
+
+        user->proxy = dbus_g_proxy_new_for_name (user->bus,
+                                                 "org.freedesktop.Accounts",
+                                                 user->object_path,
+                                                 "org.freedesktop.Accounts.User");
+        dbus_g_proxy_set_default_timeout (user->proxy, INT_MAX);
+        dbus_g_proxy_add_signal (user->proxy, "Changed", G_TYPE_INVALID);
+
+        dbus_g_proxy_connect_signal (user->proxy, "Changed",
+                                     G_CALLBACK (changed_handler), user, NULL);
+
+        if (!update_info (user))
+                goto error;
+
+        return user;
+
+ error:
+        g_object_unref (user);
+        return NULL;
+}
+
+void
+um_user_set_email (UmUser      *user,
+                   const gchar *email)
+{
+        GError *error = NULL;
+
+        if (!dbus_g_proxy_call (user->proxy,
+                                "SetEmail",
+                                &error,
+                                G_TYPE_STRING, email,
+                                G_TYPE_INVALID,
+                                G_TYPE_INVALID)) {
+                g_warning ("SetEmail call failed: %s", error->message);
+                g_error_free (error);
+                return;
+        }
+}
+
+void
+um_user_set_language (UmUser      *user,
+                      const gchar *language)
+{
+        GError *error = NULL;
+
+        if (!dbus_g_proxy_call (user->proxy,
+                                "SetLanguage",
+                                &error,
+                                G_TYPE_STRING, language,
+                                G_TYPE_INVALID,
+                                G_TYPE_INVALID)) {
+                g_warning ("SetLanguage call failed: %s", error->message);
+                g_error_free (error);
+                return;
+        }
+}
+
+void
+um_user_set_location (UmUser      *user,
+                      const gchar *location)
+{
+        GError *error = NULL;
+
+        if (!dbus_g_proxy_call (user->proxy,
+                                "SetLocation",
+                                &error,
+                                G_TYPE_STRING, location,
+                                G_TYPE_INVALID,
+                                G_TYPE_INVALID)) {
+                g_warning ("SetLocation call failed: %s", error->message);
+                g_error_free (error);
+                return;
+        }
+}
+
+void
+um_user_set_user_name (UmUser      *user,
+                       const gchar *user_name)
+{
+        GError *error = NULL;
+
+        if (!dbus_g_proxy_call (user->proxy,
+                                "SetUserName",
+                                &error,
+                                G_TYPE_STRING, user_name,
+                                G_TYPE_INVALID,
+                                G_TYPE_INVALID)) {
+                g_warning ("SetUserName call failed: %s", error->message);
+                g_error_free (error);
+                return;
+        }
+}
+
+void
+um_user_set_real_name (UmUser      *user,
+                       const gchar *real_name)
+{
+        GError *error = NULL;
+
+        if (!dbus_g_proxy_call (user->proxy,
+                                "SetRealName",
+                                &error,
+                                G_TYPE_STRING, real_name,
+                                G_TYPE_INVALID,
+                                G_TYPE_INVALID)) {
+                g_warning ("SetRealName call failed: %s", error->message);
+                g_error_free (error);
+                return;
+        }
+}
+
+void
+um_user_set_icon_file (UmUser      *user,
+                       const gchar *icon_file)
+{
+        GError *error = NULL;
+
+        if (!dbus_g_proxy_call (user->proxy,
+                                "SetIconFile",
+                                &error,
+                                G_TYPE_STRING, icon_file,
+                                G_TYPE_INVALID,
+                                G_TYPE_INVALID)) {
+                g_warning ("SetIconFile call failed: %s", error->message);
+                g_error_free (error);
+                return;
+        }
+}
+
+void
+um_user_set_icon_data (UmUser    *user,
+                       GdkPixbuf *pixbuf)
+{
+        gchar *path;
+        gint fd;
+        GOutputStream *stream;
+        GError *error;
+
+        path = g_build_filename (g_get_tmp_dir (), "usericonXXXXXX", NULL);
+        fd = g_mkstemp (path);
+
+        if (fd == -1) {
+                g_warning ("failed to create temporary file for image data");
+                g_free (path);
+                return;
+        }
+
+        stream = g_unix_output_stream_new (fd, TRUE);
+
+        error = NULL;
+        if (!gdk_pixbuf_save_to_stream (pixbuf, stream, "png", NULL, &error, NULL)) {
+                g_warning ("failed to save image: %s", error->message);
+                g_error_free (error);
+                g_object_unref (stream);
+                return;
+        }
+
+        g_object_unref (stream);
+
+        um_user_set_icon_file (user, path);
+
+        /* if we ever make the dbus call async, the g_remove call needs
+         * to wait for its completion
+         */
+        g_remove (path);
+
+        g_free (path);
+}
+
+void
+um_user_set_account_type (UmUser *user,
+                          gint    account_type)
+{
+        GError *error = NULL;
+
+        if (!dbus_g_proxy_call (user->proxy,
+                                "SetAccountType",
+                                &error,
+                                G_TYPE_INT, account_type,
+                                G_TYPE_INVALID,
+                                G_TYPE_INVALID)) {
+                g_warning ("SetAccountType call failed: %s", error->message);
+                g_error_free (error);
+                return;
+        }
+}
+
+static gchar
+salt_char (GRand *rand)
+{
+        gchar salt[] = "ABCDEFGHIJKLMNOPQRSTUVXYZ"
+                       "abcdefghijklmnopqrstuvxyz"
+                       "./0123456789";
+
+        return salt[g_rand_int_range (rand, 0, G_N_ELEMENTS (salt))];
+}
+
+static gchar *
+make_crypted (const gchar *plain)
+{
+        GString *salt;
+        gchar *result;
+        GRand *rand;
+        gint i;
+
+        rand = g_rand_new ();
+        salt = g_string_sized_new (21);
+
+        /* SHA 256 */
+        g_string_append (salt, "$6$");
+        for (i = 0; i < 16; i++) {
+                g_string_append_c (salt, salt_char (rand));
+        }
+        g_string_append_c (salt, '$');
+
+        result = g_strdup (crypt (plain, salt->str));
+
+        g_string_free (salt, TRUE);
+        g_rand_free (rand);
+
+        return result;
+}
+
+void
+um_user_set_password (UmUser      *user,
+                      gint         password_mode,
+                      const gchar *password,
+                      const gchar *hint)
+{
+        GError *error = NULL;
+        gchar *crypted;
+
+        if (password_mode == 0) {
+                crypted = make_crypted (password);
+                if (!dbus_g_proxy_call (user->proxy,
+                                        "SetPassword",
+                                        &error,
+                                        G_TYPE_STRING, crypted,
+                                        G_TYPE_STRING, hint,
+                                        G_TYPE_INVALID,
+                                        G_TYPE_INVALID)) {
+                        g_warning ("SetPassword call failed: %s", error->message);
+                        g_error_free (error);
+                }
+                memset (crypted, 0, strlen (crypted));
+                g_free (crypted);
+        }
+        else if (password_mode == 3 || password_mode == 4) {
+                if (!dbus_g_proxy_call (user->proxy,
+                                        "SetLocked",
+                                        &error,
+                                        G_TYPE_BOOLEAN, (password_mode == 3),
+                                        G_TYPE_INVALID,
+                                        G_TYPE_INVALID)) {
+                        g_warning ("SetLocked call failed: %s", error->message);
+                        g_error_free (error);
+                }
+        }
+        else {
+                if (!dbus_g_proxy_call (user->proxy,
+                                        "SetPasswordMode",
+                                        &error,
+                                        G_TYPE_INT, password_mode,
+                                        G_TYPE_INVALID,
+                                        G_TYPE_INVALID)) {
+                        g_warning ("SetPasswordMode call failed: %s", error->message);
+                        g_error_free (error);
+                }
+        }
+}
+
+gboolean
+um_user_is_logged_in (UmUser *user)
+{
+        DBusGProxy *proxy;
+        GPtrArray *array;
+        GError *error;
+        gint n_sessions;
+
+        proxy = dbus_g_proxy_new_for_name (user->bus,
+                                           "org.freedesktop.ConsoleKit",
+                                           "/org/freedesktop/ConsoleKit/Manager",
+                                           "org.freedesktop.ConsoleKit.Manager");
+
+        array = NULL;
+        error = NULL;
+        if (!dbus_g_proxy_call (proxy,
+                                "GetSessionsForUnixUser",
+                                &error,
+                                G_TYPE_UINT, um_user_get_uid (user),
+                                G_TYPE_INVALID,
+                                dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH), &array,
+                                G_TYPE_INVALID)) {
+                g_warning ("GetSessionsForUnixUser failed: %s", error->message);
+                g_error_free (error);
+                return FALSE;
+        }
+
+        n_sessions = array->len;
+
+        g_ptr_array_foreach (array, (GFunc)g_free, NULL);
+        g_ptr_array_free (array, TRUE);
+
+        g_object_unref (proxy);
+
+        return n_sessions > 0;
+}
+
+
+void
+um_user_set_automatic_login (UmUser   *user,
+                             gboolean  enabled)
+{
+        GError *error = NULL;
+
+        if (!dbus_g_proxy_call (user->proxy,
+                                "SetAutomaticLogin",
+                                &error,
+                                G_TYPE_BOOLEAN, enabled,
+                                G_TYPE_INVALID,
+                                G_TYPE_INVALID)) {
+                g_warning ("SetAutomaticLogin call failed: %s", error->message);
+                g_error_free (error);
+        }
+}
+
+void
+um_user_show_full_display_name (UmUser *user)
+{
+        char *uniq_name;
+
+        g_return_if_fail (UM_IS_USER (user));
+
+        if (user->props->real_name != NULL) {
+                uniq_name = g_strdup_printf ("%s (%s)",
+                                             user->props->real_name,
+                                             user->props->user_name);
+        } else {
+                uniq_name = NULL;
+        }
+
+        if (uniq_name && g_strcmp0 (uniq_name, user->display_name) != 0) {
+                g_free (user->display_name);
+                user->display_name = uniq_name;
+        }
+        else {
+                g_free (uniq_name);
+        }
+}
+
+void
+um_user_show_short_display_name (UmUser *user)
+{
+        g_return_if_fail (UM_IS_USER (user));
+
+        if (user->display_name) {
+                g_free (user->display_name);
+                user->display_name = NULL;
+        }
+}
+
diff --git a/panels/user-accounts/um-user.h b/panels/user-accounts/um-user.h
new file mode 100644
index 0000000..43a88b0
--- /dev/null
+++ b/panels/user-accounts/um-user.h
@@ -0,0 +1,107 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2004-2005 James M. Cape <jcape ignore-your tv>.
+ * Copyright (C) 2007-2008 William Jon McCann <mccann jhu edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ * Facade object for user data, owned by UmUserManager
+ */
+
+#ifndef __UM_USER__
+#define __UM_USER__
+
+#include <sys/types.h>
+#include <gtk/gtk.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#include "um-account-type.h"
+
+G_BEGIN_DECLS
+
+#define UM_TYPE_USER (um_user_get_type ())
+#define UM_USER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), UM_TYPE_USER, UmUser))
+#define UM_IS_USER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), UM_TYPE_USER))
+
+typedef enum {
+        UM_PASSWORD_MODE_REGULAR,
+        UM_PASSWORD_MODE_SET_AT_LOGIN,
+        UM_PASSWORD_MODE_NONE,
+        UM_PASSWORD_MODE_DISABLED,
+        UM_PASSWORD_MODE_ENABLED
+} UmPasswordMode;
+
+typedef struct _UmUser UmUser;
+
+GType          um_user_get_type            (void) G_GNUC_CONST;
+
+UmUser        *um_user_new_from_object_path (const gchar *path);
+const gchar   *um_user_get_object_path      (UmUser *user);
+
+uid_t          um_user_get_uid             (UmUser   *user);
+const gchar   *um_user_get_user_name       (UmUser   *user);
+const gchar   *um_user_get_real_name       (UmUser   *user);
+const gchar   *um_user_get_display_name    (UmUser   *user);
+gint           um_user_get_account_type    (UmUser   *user);
+const gchar   *um_user_get_email           (UmUser   *user);
+const gchar   *um_user_get_language        (UmUser   *user);
+const gchar   *um_user_get_location        (UmUser   *user);
+const gchar   *um_user_get_home_directory  (UmUser   *user);
+const gchar   *um_user_get_shell           (UmUser   *user);
+gulong         um_user_get_login_frequency (UmUser   *user);
+gint           um_user_get_password_mode   (UmUser   *user);
+const gchar   *um_user_get_password_hint   (UmUser   *user);
+const gchar   *um_user_get_icon_file       (UmUser   *user);
+gboolean       um_user_get_locked          (UmUser   *user);
+gboolean       um_user_get_automatic_login (UmUser   *user);
+
+void           um_user_set_user_name       (UmUser      *user,
+                                            const gchar *user_name);
+void           um_user_set_real_name       (UmUser      *user,
+                                            const gchar *real_name);
+void           um_user_set_email           (UmUser      *user,
+                                            const gchar *email);
+void           um_user_set_language        (UmUser      *user,
+                                            const gchar *language);
+void           um_user_set_location        (UmUser      *user,
+                                            const gchar *location);
+void           um_user_set_icon_file       (UmUser      *user,
+                                            const gchar *filename);
+void           um_user_set_icon_data       (UmUser      *user,
+                                            GdkPixbuf   *pixbuf);
+void           um_user_set_account_type    (UmUser      *user,
+                                            gint         account_type);
+void           um_user_set_automatic_login (UmUser      *user,
+                                            gboolean     enabled);
+void           um_user_set_password        (UmUser      *user,
+                                            int          password_mode,
+                                            const gchar *plain,
+                                            const gchar *password_hint);
+gboolean       um_user_is_logged_in        (UmUser   *user);
+
+GdkPixbuf     *um_user_render_icon         (UmUser   *user,
+                                            gboolean  framed,
+                                            gint      icon_size);
+gint           um_user_collate             (UmUser   *user1,
+                                            UmUser   *user2);
+
+void           um_user_show_short_display_name (UmUser *user);
+void           um_user_show_full_display_name  (UmUser *user);
+
+G_END_DECLS
+
+#endif
diff --git a/panels/user-accounts/um-utils.c b/panels/user-accounts/um-utils.c
new file mode 100644
index 0000000..86a8add
--- /dev/null
+++ b/panels/user-accounts/um-utils.c
@@ -0,0 +1,382 @@
+/* -*- 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 <glib.h>
+#include <glib/gi18n.h>
+
+#include "um-utils.h"
+
+typedef struct {
+        gchar *text;
+        gchar *placeholder_str;
+        GIcon *icon;
+        gunichar placeholder;
+        gulong query_id;
+} IconShapeData;
+
+static IconShapeData *
+icon_shape_data_new (const gchar *text,
+                     const gchar *placeholder,
+                     GIcon       *icon)
+{
+        IconShapeData *data;
+
+        data = g_new0 (IconShapeData, 1);
+
+        data->text = g_strdup (text);
+        data->placeholder_str = g_strdup (placeholder);
+        data->placeholder = g_utf8_get_char_validated (placeholder, -1);
+        data->icon = g_object_ref (icon);
+
+        return data;
+}
+
+static void
+icon_shape_data_free (gpointer user_data)
+{
+        IconShapeData *data = user_data;
+
+        g_free (data->text);
+        g_free (data->placeholder_str);
+        g_object_unref (data->icon);
+        g_free (data);
+}
+
+static void
+icon_shape_renderer (cairo_t        *cr,
+                     PangoAttrShape *attr,
+                     gboolean        do_path,
+                     gpointer        user_data)
+{
+        IconShapeData *data = user_data;
+        gdouble x, y;
+
+        cairo_get_current_point (cr, &x, &y);
+        if (GPOINTER_TO_UINT (attr->data) == data->placeholder) {
+                gdouble ascent;
+                gdouble height;
+                gdouble width;
+                GdkPixbuf *pixbuf;
+                GtkIconInfo *info;
+
+                ascent = pango_units_to_double (attr->ink_rect.y);
+                height = pango_units_to_double (attr->ink_rect.height);
+                width = pango_units_to_double (attr->ink_rect.width);
+                info = gtk_icon_theme_lookup_by_gicon (gtk_icon_theme_get_default (),
+                                                       data->icon,
+                                                       (gint)height,
+                                                       GTK_ICON_LOOKUP_FORCE_SIZE | GTK_ICON_LOOKUP_USE_BUILTIN);
+                pixbuf = gtk_icon_info_load_icon (info, NULL);
+                gtk_icon_info_free (info);
+
+                cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+                cairo_reset_clip (cr);
+                gdk_cairo_set_source_pixbuf (cr, pixbuf, x, y + ascent);
+                cairo_paint (cr);
+                g_object_unref (pixbuf);
+        }
+}
+
+static PangoAttrList *
+create_shape_attr_list_for_layout (PangoLayout   *layout,
+                                   IconShapeData *data)
+{
+        PangoAttrList *attrs;
+        PangoFontMetrics *metrics;
+        gint ascent, descent;
+        PangoRectangle ink_rect, logical_rect;
+        const gchar *p;
+        const gchar *text;
+        gint placeholder_len;
+
+        /* Get font metrics and prepare fancy shape size */
+        metrics = pango_context_get_metrics (pango_layout_get_context (layout),
+                                             pango_layout_get_font_description (layout),
+                                             NULL);
+        ascent = pango_font_metrics_get_ascent (metrics);
+        descent = pango_font_metrics_get_descent (metrics);
+        pango_font_metrics_unref (metrics);
+
+        logical_rect.x = 0;
+        logical_rect.y = - ascent;
+        logical_rect.width = ascent + descent;
+        logical_rect.height = ascent + descent;
+
+        ink_rect = logical_rect;
+
+        attrs = pango_attr_list_new ();
+        text = pango_layout_get_text (layout);
+        placeholder_len = strlen (data->placeholder_str);
+        for (p = text; (p = strstr (p, data->placeholder_str)); p += placeholder_len) {
+                PangoAttribute *attr;
+
+                attr = pango_attr_shape_new_with_data (&ink_rect,
+                                                       &logical_rect,
+                                                       GUINT_TO_POINTER (g_utf8_get_char (p)),
+                                                       NULL, NULL);
+
+                attr->start_index = p - text;
+                attr->end_index = attr->start_index + placeholder_len;
+
+                pango_attr_list_insert (attrs, attr);
+        }
+
+        return attrs;
+}
+
+static gboolean
+query_unlock_tooltip (GtkWidget  *widget,
+                      gint        x,
+                      gint        y,
+                      gboolean    keyboard_tooltip,
+                      GtkTooltip *tooltip,
+                      gpointer    user_data)
+{
+        GtkWidget *label;
+        PangoLayout *layout;
+        PangoAttrList *attrs;
+        IconShapeData *data;
+
+        data = g_object_get_data (G_OBJECT (widget), "icon-shape-data");
+        label = g_object_get_data (G_OBJECT (widget), "tooltip-label");
+        if (label == NULL) {
+                label = gtk_label_new (data->text);
+                g_object_ref_sink (label);
+                g_object_set_data_full (G_OBJECT (widget),
+                                        "tooltip-label", label, g_object_unref);
+        }
+
+        layout = gtk_label_get_layout (GTK_LABEL (label));
+        pango_cairo_context_set_shape_renderer (pango_layout_get_context (layout),
+                                                icon_shape_renderer,
+                                                data, NULL);
+
+        attrs = create_shape_attr_list_for_layout (layout, data);
+        gtk_label_set_attributes (GTK_LABEL (label), attrs);
+        pango_attr_list_unref (attrs);
+
+        gtk_tooltip_set_custom (tooltip, label);
+
+        return TRUE;
+}
+
+void
+setup_tooltip_with_embedded_icon (GtkWidget   *widget,
+                                  const gchar *text,
+                                  const gchar *placeholder,
+                                  GIcon       *icon)
+{
+        IconShapeData *data;
+
+        data = g_object_get_data (G_OBJECT (widget), "icon-shape-data");
+        if (data) {
+                gtk_widget_set_has_tooltip (widget, FALSE);
+                g_signal_handler_disconnect (widget, data->query_id);
+                g_object_set_data (G_OBJECT (widget), "icon-shape-data", NULL);
+                g_object_set_data (G_OBJECT (widget), "tooltip-label", NULL);
+        }
+
+        if (!placeholder) {
+                gtk_widget_set_tooltip_text (widget, text);
+                return;
+        }
+
+        data = icon_shape_data_new (text, placeholder, icon);
+        g_object_set_data_full (G_OBJECT (widget),
+                                "icon-shape-data",
+                                data,
+                                icon_shape_data_free);
+
+        gtk_widget_set_has_tooltip (widget, TRUE);
+        data->query_id = g_signal_connect (widget, "query-tooltip",
+                                           G_CALLBACK (query_unlock_tooltip), NULL);
+
+}
+
+gboolean
+show_tooltip_now (GtkWidget *widget,
+                  GdkEvent  *event)
+{
+        GtkSettings *settings;
+        gint timeout;
+
+        settings = gtk_widget_get_settings (widget);
+
+        g_object_get (settings, "gtk-tooltip-timeout", &timeout, NULL);
+        g_object_set (settings, "gtk-tooltip-timeout", 1, NULL);
+        gtk_tooltip_trigger_tooltip_query (gtk_widget_get_display (widget));
+        g_object_set (settings, "gtk-tooltip-timeout", timeout, NULL);
+
+        return FALSE;
+}
+
+static gboolean
+query_tooltip (GtkWidget  *widget,
+               gint        x,
+               gint        y,
+               gboolean    keyboard_mode,
+               GtkTooltip *tooltip,
+               gpointer    user_data)
+{
+        gchar *tip;
+
+        if (GTK_ENTRY_ICON_SECONDARY == gtk_entry_get_icon_at_pos (GTK_ENTRY (widget), x, y)) {
+                tip = gtk_entry_get_icon_tooltip_text (GTK_ENTRY (widget),
+                                                       GTK_ENTRY_ICON_SECONDARY);
+                gtk_tooltip_set_text (tooltip, tip);
+                g_free (tip);
+
+                return TRUE;
+        }
+        else {
+                return FALSE;
+        }
+}
+
+static void
+icon_released (GtkEntry             *entry,
+              GtkEntryIconPosition  pos,
+              GdkEvent             *event,
+              gpointer              user_data)
+{
+        GtkSettings *settings;
+        gint timeout;
+
+        settings = gtk_widget_get_settings (GTK_WIDGET (entry));
+
+        g_object_get (settings, "gtk-tooltip-timeout", &timeout, NULL);
+        g_object_set (settings, "gtk-tooltip-timeout", 1, NULL);
+        gtk_tooltip_trigger_tooltip_query (gtk_widget_get_display (GTK_WIDGET (entry)));
+        g_object_set (settings, "gtk-tooltip-timeout", timeout, NULL);
+}
+
+
+void
+set_entry_validation_error (GtkEntry    *entry,
+                            const gchar *text)
+{
+        g_object_set (entry, "caps-lock-warning", FALSE, NULL);
+        gtk_entry_set_icon_from_stock (entry,
+                                       GTK_ENTRY_ICON_SECONDARY,
+                                       GTK_STOCK_DIALOG_ERROR);
+        gtk_entry_set_icon_activatable (entry,
+                                        GTK_ENTRY_ICON_SECONDARY,
+                                        TRUE);
+        g_signal_connect (entry, "icon-release",
+                          G_CALLBACK (icon_released), FALSE);
+        g_signal_connect (entry, "query-tooltip",
+                          G_CALLBACK (query_tooltip), NULL);
+        g_object_set (entry, "has-tooltip", TRUE, NULL);
+        gtk_entry_set_icon_tooltip_text (entry,
+                                         GTK_ENTRY_ICON_SECONDARY,
+                                         text);
+}
+
+void
+clear_entry_validation_error (GtkEntry *entry)
+{
+        gboolean warning;
+
+        g_object_get (entry, "caps-lock-warning", &warning, NULL);
+
+        if (warning)
+                return;
+
+        g_object_set (entry, "has-tooltip", FALSE, NULL);
+        gtk_entry_set_icon_from_pixbuf (entry,
+                                        GTK_ENTRY_ICON_SECONDARY,
+                                        NULL);
+        g_object_set (entry, "caps-lock-warning", TRUE, NULL);
+}
+
+void
+popup_menu_below_button (GtkMenu   *menu,
+                         gint      *x,
+                         gint      *y,
+                         gboolean  *push_in,
+                         GtkWidget *button)
+{
+        GtkRequisition menu_req;
+        GtkTextDirection direction;
+        GtkAllocation allocation;
+
+        gtk_widget_size_request (GTK_WIDGET (menu), &menu_req);
+
+        direction = gtk_widget_get_direction (button);
+
+        gdk_window_get_origin (gtk_widget_get_window (button), x, y);
+        gtk_widget_get_allocation (button, &allocation);
+        *x += allocation.x;
+        *y += allocation.y + allocation.height;
+
+        if (direction == GTK_TEXT_DIR_LTR)
+                *x += MAX (allocation.width - menu_req.width, 0);
+        else if (menu_req.width > allocation.width)
+                *x -= menu_req.width - allocation.width;
+
+        *push_in = TRUE;
+}
+
+void
+rounded_rectangle (cairo_t *cr,
+                   gdouble  aspect,
+                   gdouble  x,
+                   gdouble  y,
+                   gdouble  corner_radius,
+                   gdouble  width,
+                   gdouble  height)
+{
+        gdouble radius;
+        gdouble degrees;
+
+        radius = corner_radius / aspect;
+        degrees = G_PI / 180.0;
+
+        cairo_new_sub_path (cr);
+        cairo_arc (cr,
+                   x + width - radius,
+                   y + radius,
+                   radius,
+                   -90 * degrees,
+                   0 * degrees);
+        cairo_arc (cr,
+                   x + width - radius,
+                   y + height - radius,
+                   radius,
+                   0 * degrees,
+                   90 * degrees);
+        cairo_arc (cr,
+                   x + radius,
+                   y + height - radius,
+                   radius,
+                   90 * degrees,
+                   180 * degrees);
+        cairo_arc (cr,
+                   x + radius,
+                   y + radius,
+                   radius,
+                   180 * degrees,
+                   270 * degrees);
+        cairo_close_path (cr);
+}
+
diff --git a/panels/user-accounts/um-utils.h b/panels/user-accounts/um-utils.h
new file mode 100644
index 0000000..d6a227e
--- /dev/null
+++ b/panels/user-accounts/um-utils.h
@@ -0,0 +1,56 @@
+/* -*- 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_UTILS_H__
+#define __UM_UTILS_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+void     setup_tooltip_with_embedded_icon (GtkWidget   *widget,
+                                           const gchar *text,
+                                           const gchar *placeholder,
+                                           GIcon       *icon);
+gboolean show_tooltip_now                 (GtkWidget   *widget,
+                                           GdkEvent    *event);
+
+void     set_entry_validation_error       (GtkEntry    *entry,
+                                           const gchar *text);
+void     clear_entry_validation_error     (GtkEntry    *entry);
+
+void     popup_menu_below_button          (GtkMenu     *menu,
+                                           gint        *x,
+                                           gint        *y,
+                                           gboolean    *push_in,
+                                           GtkWidget   *button);
+
+void     rounded_rectangle                (cairo_t     *cr,
+                                           gdouble      aspect,
+                                           gdouble      x,
+                                           gdouble      y,
+                                           gdouble      corner_radius,
+                                           gdouble      width,
+                                           gdouble      height);
+
+G_END_DECLS
+
+#endif
diff --git a/po/POTFILES.in b/po/POTFILES.in
index e3cdea4..186dbf2 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -64,6 +64,25 @@ panels/sound/data/gnome-sound-panel.desktop.in.in
 panels/sound/data/sounds/gnome-sounds-default.xml.in.in
 panels/universal-access/gnome-universal-access-panel.desktop.in.in
 [type: gettext/glade]panels/universal-access/uap.ui
+panels/user-accounts/gdm-languages.c
+panels/user-accounts/run-passwd.c
+panels/user-accounts/um-account-dialog.c
+panels/user-accounts/um-account-type.c
+panels/user-accounts/um-fingerprint-dialog.c
+panels/user-accounts/um-language-dialog.c
+panels/user-accounts/um-lockbutton.c
+panels/user-accounts/um-login-options.c
+panels/user-accounts/um-password-dialog.c
+panels/user-accounts/um-photo-dialog.c
+panels/user-accounts/um-user-manager.c
+panels/user-accounts/um-user-panel.c
+panels/user-accounts/data/gnome-user-accounts-panel.desktop.in.in
+[type: gettext/glade]panels/user-accounts/data/account-dialog.ui
+[type: gettext/glade]panels/user-accounts/data/language-chooser.ui
+[type: gettext/glade]panels/user-accounts/data/password-dialog.ui
+[type: gettext/glade]panels/user-accounts/data/photo-dialog.ui
+[type: gettext/glade]panels/user-accounts/data/user-accounts-dialog.ui
+[type: gettext/glade]panels/user-accounts/data/account-fingerprint.ui
 shell/control-center.c
 shell/gnome-control-center.desktop.in.in
 shell/gnomecc.directory.in
diff --git a/po/POTFILES.skip b/po/POTFILES.skip
index cb6a3a1..93aeda3 100644
--- a/po/POTFILES.skip
+++ b/po/POTFILES.skip
@@ -10,6 +10,8 @@ panels/keybindings/gnome-keybindings-panel.desktop.in
 panels/keyboard/gnome-keyboard-panel.desktop.in
 panels/sound/data/gnome-sound-panel.desktop.in
 panels/sound/data/sounds/gnome-sounds-default.xml.in
+panels/user-accounts/data/gnome-user-accounts-panel.desktop.in
+panels/user-accounts/fingerprint-strings.h
 capplets/localization/localization.desktop.in
 capplets/mouse/gnome-settings-mouse.desktop.in
 panels/network/gnome-network-panel.desktop.in



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