rpms/gdm/devel 2-new-chooser-widget.patch, NONE, 1.1 3-switch-user-chooser-over.patch, NONE, 1.1 4-switch-session-chooser-over.patch, NONE, 1.1 5-dont-shrink-in-test-program.patch, NONE, 1.1 6-session-chooser-in-login-window.patch, NONE, 1.1 7-login-window-animation.patch, NONE, 1.1 gdm.spec, 1.321, 1.322

Ray Strode (rstrode) fedora-extras-commits at redhat.com
Thu Dec 13 20:32:33 UTC 2007


Author: rstrode

Update of /cvs/pkgs/rpms/gdm/devel
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv10215

Modified Files:
	gdm.spec 
Added Files:
	2-new-chooser-widget.patch 3-switch-user-chooser-over.patch 
	4-switch-session-chooser-over.patch 
	5-dont-shrink-in-test-program.patch 
	6-session-chooser-in-login-window.patch 
	7-login-window-animation.patch 
Log Message:
- add session chooser to login screen
- add hoaky animations


2-new-chooser-widget.patch:

--- NEW FILE 2-new-chooser-widget.patch ---
>From 675a2a355ef15825b5998adc89a69d0958a0e2c0 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode at redhat.com>
Date: Thu, 13 Dec 2007 10:06:26 -0500
Subject: [PATCH] Add new chooser widget
 Since it takes a lot of code to deal with the whole model/view
 split of a tree view, it's probably better to abstract that
 work out into one unified "chooser" widget.

---
 gui/simple-greeter/gdm-chooser-widget.c | 1607 +++++++++++++++++++++++++++++++
 gui/simple-greeter/gdm-chooser-widget.h |  102 ++
 2 files changed, 1709 insertions(+), 0 deletions(-)
 create mode 100644 gui/simple-greeter/gdm-chooser-widget.c
 create mode 100644 gui/simple-greeter/gdm-chooser-widget.h

diff --git a/gui/simple-greeter/gdm-chooser-widget.c b/gui/simple-greeter/gdm-chooser-widget.c
new file mode 100644
index 0000000..64186a2
--- /dev/null
+++ b/gui/simple-greeter/gdm-chooser-widget.c
@@ -0,0 +1,1607 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Ray Strode <rstrode at redhat.com>
+ * Copyright (C) 2007 William Jon McCann <mccann at 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.
+ *
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <dirent.h>
+#include <sys/stat.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+#include <gtk/gtk.h>
+
+#include "gdm-chooser-widget.h"
+
+#define GDM_CHOOSER_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_CHOOSER_WIDGET, GdmChooserWidgetPrivate))
+
+#ifndef GDM_CHOOSER_WIDGET_DEFAULT_ICON_SIZE
+#define GDM_CHOOSER_WIDGET_DEFAULT_ICON_SIZE 64
+#endif
+
+typedef enum {
+        GDM_CHOOSER_WIDGET_STATE_GROWN = 0,
+        GDM_CHOOSER_WIDGET_STATE_GROWING,
+        GDM_CHOOSER_WIDGET_STATE_SHRINKING,
+        GDM_CHOOSER_WIDGET_STATE_SHRUNK,
+} GdmChooserWidgetState;
+
+struct GdmChooserWidgetPrivate
+{
+        GtkWidget                *frame;
+        GtkWidget                *frame_alignment;
+        GtkWidget                *scrolled_window;
+
+        GtkWidget                *items_view;
+        GtkListStore             *list_store;
+
+        GtkTreeModelFilter       *model_filter;
+        GtkTreeModelSort         *model_sorter;
+
+        GdkPixbuf                *is_in_use_pixbuf;
+
+        GtkTreeRowReference      *active_row;
+        GtkTreeRowReference      *separator_row;
+        GtkTreeRowReference      *top_edge_row;    /* Only around for shrink */
+        GtkTreeRowReference      *bottom_edge_row; /* animations */
+
+        GtkTreeViewColumn        *is_in_use_column;
+        GtkTreeViewColumn        *image_column;
+
+        char                     *inactive_text;
+        char                     *active_text;
+        char                     *in_use_message;
+
+        gint                     number_of_normal_rows;
+        gint                     number_of_separated_rows;
+        gint                     number_of_in_use_rows;
+        gint                     number_of_rows_with_images;
+
+        guint                    update_idle_id;
+        guint                    animation_timeout_id;
+
+        guint32                  should_hide_inactive_items : 1;
+
+        GdmChooserWidgetPosition separator_position;
+        GdmChooserWidgetState    state;
+
+};
+
+enum {
+        PROP_0,
+        PROP_INACTIVE_TEXT,
+        PROP_ACTIVE_TEXT
+};
+
+enum {
+        ACTIVATED = 0,
+        DEACTIVATED,
+        NUMBER_OF_SIGNALS
+};
+
+static guint    signals[NUMBER_OF_SIGNALS];
+
+static void     gdm_chooser_widget_class_init  (GdmChooserWidgetClass *klass);
+static void     gdm_chooser_widget_init        (GdmChooserWidget      *chooser_widget);
+static void     gdm_chooser_widget_finalize    (GObject                   *object);
+
+G_DEFINE_TYPE (GdmChooserWidget, gdm_chooser_widget, GTK_TYPE_ALIGNMENT)
+enum {
+        CHOOSER_IMAGE_COLUMN = 0,
+        CHOOSER_NAME_COLUMN,
+        CHOOSER_COMMENT_COLUMN,
+        CHOOSER_ITEM_IS_IN_USE_COLUMN,
+        CHOOSER_ITEM_IS_SEPARATED_COLUMN,
+        CHOOSER_ITEM_IS_VISIBLE_COLUMN,
+        CHOOSER_ID_COLUMN,
+        NUMBER_OF_CHOOSER_COLUMNS
+};
+
+static gboolean
+find_item (GdmChooserWidget *widget,
+           const char       *id,
+           GtkTreeIter      *iter)
+{
+        GtkTreeModel *model;
+        gboolean      found_item;
+
+        g_assert (GDM_IS_CHOOSER_WIDGET (widget));
+        g_assert (id != NULL);
+
+        found_item = FALSE;
+        model = GTK_TREE_MODEL (widget->priv->list_store);
+
+        if (!gtk_tree_model_get_iter_first (model, iter)) {
+                return FALSE;
+        }
+
+        do {
+                char *item_id;
+
+
+                gtk_tree_model_get (model, iter,
+                                    CHOOSER_ID_COLUMN, &item_id, -1);
+
+                g_assert (item_id != NULL);
+
+                if (strcmp (id, item_id) == 0) {
+                        found_item = TRUE;
+                }
+                g_free (item_id);
+
+        } while (!found_item && gtk_tree_model_iter_next (model, iter));
+
+        return found_item;
+}
+
+static char *
+get_active_item_id (GdmChooserWidget *widget,
+                    GtkTreeIter      *iter)
+{
+        char *item_id;
+        GtkTreeModel *model;
+        GtkTreePath *path;
+
+        g_return_val_if_fail (GDM_IS_CHOOSER_WIDGET (widget), NULL);
+
+        model = GTK_TREE_MODEL (widget->priv->list_store);
+        item_id = NULL;
+
+        if (widget->priv->active_row == NULL) {
+                return NULL;
+        }
+
+        path = gtk_tree_row_reference_get_path (widget->priv->active_row);
+        if (gtk_tree_model_get_iter (model, iter, path)) {
+                gtk_tree_model_get (model, iter,
+                                    CHOOSER_ID_COLUMN, &item_id, -1);
+        };
+        gtk_tree_path_free (path);
+
+        return item_id;
+}
+
+char *
+gdm_chooser_widget_get_active_item (GdmChooserWidget *widget)
+{
+        GtkTreeIter iter;
+
+        return get_active_item_id (widget, &iter);
+}
+
+static void
+activate_from_item_id (GdmChooserWidget *widget,
+                       const char       *item_id)
+{
+        GtkTreeModel *model;
+        GtkTreePath  *path;
+        GtkTreeIter   iter;
+
+        model = GTK_TREE_MODEL (widget->priv->list_store);
+        path = NULL;
+
+        if (find_item (widget, item_id, &iter)) {
+                GtkTreePath  *child_path;
+
+                child_path = gtk_tree_model_get_path (model, &iter);
+                path = gtk_tree_model_sort_convert_child_path_to_path (widget->priv->model_sorter, child_path);
+                gtk_tree_path_free (child_path);
+        }
+
+        if (path == NULL) {
+                return;
+        }
+
+        gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (widget->priv->items_view),
+                                      path,
+                                      NULL,
+                                      TRUE,
+                                      0.5,
+                                      0.0);
+
+        gtk_tree_view_set_cursor (GTK_TREE_VIEW (widget->priv->items_view),
+                                  path,
+                                  NULL,
+                                  FALSE);
+
+        gtk_tree_view_row_activated (GTK_TREE_VIEW (widget->priv->items_view),
+                                     path,
+                                     NULL);
+        gtk_tree_path_free (path);
+}
+
+static void
+set_frame_text (GdmChooserWidget *widget,
+                const char       *text)
+{
+        GtkWidget *label;
+
+        label = gtk_frame_get_label_widget (GTK_FRAME (widget->priv->frame));
+
+        if (text == NULL && label != NULL) {
+                gtk_frame_set_label_widget (GTK_FRAME (widget->priv->frame),
+                                            NULL);
+                gtk_alignment_set_padding (GTK_ALIGNMENT (widget->priv->frame_alignment),
+                                           0, 0, 0, 0);
+        } else if (text != NULL && label == NULL) {
+                label = gtk_label_new ("");
+                gtk_label_set_mnemonic_widget (GTK_LABEL (label),
+                                               widget->priv->items_view);
+                gtk_widget_show (label);
+                gtk_frame_set_label_widget (GTK_FRAME (widget->priv->frame),
+                                            label);
+                gtk_alignment_set_padding (GTK_ALIGNMENT (widget->priv->frame_alignment),
+                                           6, 0, 12, 0);
+        }
+
+        if (label != NULL && text != NULL) {
+                char *markup;
+                markup = g_strdup_printf ("<b>%s</b>", text);
+                gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), markup);
+                g_free (markup);
+        }
+}
+
+static void
+translate_base_path_to_sorted_path (GdmChooserWidget  *widget,
+                                    GtkTreePath      **path)
+{
+        GtkTreePath *filtered_path;
+        GtkTreePath *sorted_path;
+
+        filtered_path =
+            gtk_tree_model_filter_convert_child_path_to_path (widget->priv->model_filter, *path);
+        sorted_path = gtk_tree_model_sort_convert_child_path_to_path (widget->priv->model_sorter,
+                                                                      filtered_path);
+        gtk_tree_path_free (filtered_path);
+
+        gtk_tree_path_free (*path);
+        *path = sorted_path;
+}
+
+static gboolean
+shrink_edge_toward_active_row (GdmChooserWidget     *widget,
+                               GtkTreeRowReference **edge_row)
+{
+        GtkTreeModel *model;
+        GtkTreePath  *active_path;
+        GtkTreePath  *edge_path;
+        GtkTreeIter   edge_iter;
+        gboolean      edge_is_hidden;
+        int           relative_position;
+
+        model = GTK_TREE_MODEL (widget->priv->list_store);
+
+        active_path = gtk_tree_row_reference_get_path (widget->priv->active_row);
+        translate_base_path_to_sorted_path (widget, &active_path);
+
+        g_assert (*edge_row != NULL);
+        edge_path = gtk_tree_row_reference_get_path (*edge_row);
+        g_assert (edge_path != NULL);
+        relative_position = gtk_tree_path_compare (edge_path, active_path);
+        if (relative_position != 0 &&
+            gtk_tree_model_get_iter (GTK_TREE_MODEL (widget->priv->model_sorter),
+                                     &edge_iter, edge_path)) {
+                GtkTreeIter filtered_iter;
+                GtkTreeIter iter;
+
+                if (relative_position < 0) {
+                        gtk_tree_path_next (edge_path);
+                } else {
+                        gtk_tree_path_prev (edge_path);
+                }
+                gtk_tree_row_reference_free (*edge_row);
+
+                *edge_row = gtk_tree_row_reference_new (GTK_TREE_MODEL (widget->priv->model_sorter),
+                                                        edge_path);
+
+                gtk_tree_model_sort_convert_iter_to_child_iter (widget->priv->model_sorter,
+                                                                &filtered_iter, &edge_iter);
+                gtk_tree_model_filter_convert_iter_to_child_iter (widget->priv->model_filter,
+                                                                  &iter, &filtered_iter);
+                gtk_list_store_set (GTK_LIST_STORE (widget->priv->list_store),
+                                    &iter, CHOOSER_ITEM_IS_VISIBLE_COLUMN, FALSE, -1);
+
+                edge_is_hidden = FALSE;
+        } else {
+                edge_is_hidden = TRUE;
+        }
+        gtk_tree_path_free (active_path);
+        gtk_tree_path_free (edge_path);
+
+        return edge_is_hidden;
+}
+
+static gboolean
+iterate_animation (GdmChooserWidget *widget)
+{
+        gboolean is_done;
+
+        if (widget->priv->state == GDM_CHOOSER_WIDGET_STATE_SHRINKING) {
+                if (widget->priv->top_edge_row != NULL) {
+                        is_done = shrink_edge_toward_active_row (widget,
+                                                   &widget->priv->top_edge_row);
+                }
+
+                if (widget->priv->bottom_edge_row != NULL) {
+                        is_done = is_done &&
+                                shrink_edge_toward_active_row (widget,
+                                                 &widget->priv->bottom_edge_row);
+                }
+        } else {
+                GtkTreePath *path;
+                GtkTreeIter  iter;
+                gboolean     is_visible;
+
+                path = gtk_tree_path_new_first ();
+
+                do {
+                        if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (widget->priv->list_store),
+                                                 &iter, path)) {
+                                is_done = TRUE;
+                                break;
+                        }
+
+                        gtk_tree_model_get (GTK_TREE_MODEL (widget->priv->list_store),
+                                                 &iter, CHOOSER_ITEM_IS_VISIBLE_COLUMN,
+                                                 &is_visible, -1);
+
+                        if (is_visible) {
+                                gtk_tree_path_next (path);
+                        } else {
+                                gtk_list_store_set (GTK_LIST_STORE (widget->priv->list_store),
+                                                    &iter, CHOOSER_ITEM_IS_VISIBLE_COLUMN,
+                                                    TRUE, -1);
+                        }
+                } while (is_visible);
+
+                gtk_tree_path_free (path);
+        }
+
+        return is_done != TRUE;
+}
+
+static void
+stop_animation (GdmChooserWidget *widget)
+{
+        if (widget->priv->animation_timeout_id == 0) {
+                return;
+        }
+
+        gtk_tree_row_reference_free (widget->priv->top_edge_row);
+        widget->priv->top_edge_row = NULL;
+
+        gtk_tree_row_reference_free (widget->priv->bottom_edge_row);
+        widget->priv->bottom_edge_row = NULL;
+
+        widget->priv->animation_timeout_id = 0;
+        gtk_widget_set_sensitive (GTK_WIDGET (widget), TRUE);
+}
+
+static void
+start_animation (GdmChooserWidget *widget)
+{
+       GtkTreePath *edge_path;
+       int          number_of_visible_rows;
+       int          number_of_rows;
+
+       if (widget->priv->animation_timeout_id != 0) {
+                g_source_remove (widget->priv->animation_timeout_id);
+       }
+
+       number_of_visible_rows = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (widget->priv->model_sorter), NULL);
+       number_of_rows = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (widget->priv->list_store), NULL);
+
+       if (widget->priv->state == GDM_CHOOSER_WIDGET_STATE_SHRINKING) {
+               if (number_of_visible_rows <= 1) {
+                       widget->priv->state = GDM_CHOOSER_WIDGET_STATE_SHRUNK;
+                       return;
+               }
+
+               edge_path = gtk_tree_path_new_first ();
+               widget->priv->top_edge_row = gtk_tree_row_reference_new (GTK_TREE_MODEL (widget->priv->model_sorter),
+                                                                        edge_path);
+               gtk_tree_path_free (edge_path);
+
+               edge_path = gtk_tree_path_new_from_indices (number_of_visible_rows - 1, -1);
+
+               widget->priv->bottom_edge_row = gtk_tree_row_reference_new (GTK_TREE_MODEL (widget->priv->model_sorter),
+                                                                           edge_path);
+               gtk_tree_path_free (edge_path);
+
+               g_assert (widget->priv->top_edge_row != NULL && widget->priv->bottom_edge_row != NULL);
+       }
+
+       if (widget->priv->state == GDM_CHOOSER_WIDGET_STATE_GROWING) {
+               if (number_of_visible_rows >= number_of_rows) {
+                       widget->priv->state = GDM_CHOOSER_WIDGET_STATE_GROWN;
+                       return;
+               }
+       }
+
+       gtk_widget_set_sensitive (GTK_WIDGET (widget), FALSE);
+
+       /* FIXME: The 4 here is abitrary.  We should really keep track of the time we start and
+        * hide enough rows to catch up to where we should be each time through
+        */
+       widget->priv->animation_timeout_id =
+               g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE,
+                                   1000 / (4 * number_of_rows),
+                                   (GSourceFunc) iterate_animation,
+                                   widget, (GDestroyNotify) stop_animation);
+}
+
+static void
+gdm_chooser_widget_grow (GdmChooserWidget *widget)
+{
+        gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (widget->priv->scrolled_window),
+                                             GTK_SHADOW_ETCHED_IN);
+        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (widget->priv->scrolled_window),
+                                        GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+        gtk_alignment_set (GTK_ALIGNMENT (widget->priv->frame_alignment),
+                           0.0, 0.0, 1.0, 1.0);
+
+        set_frame_text (widget, widget->priv->inactive_text);
+
+        widget->priv->state = GDM_CHOOSER_WIDGET_STATE_GROWING;
+        start_animation (widget);
+}
+
+static void
+move_cursor_to_top (GdmChooserWidget *widget)
+{
+        GtkTreeModel *model;
+        GtkTreePath  *path;
+        GtkTreeIter   iter;
+
+        model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget->priv->items_view));
+        path = gtk_tree_path_new_first ();
+        if (gtk_tree_model_get_iter (model, &iter, path)) {
+                gtk_tree_view_set_cursor (GTK_TREE_VIEW (widget->priv->items_view),
+                                          path,
+                                          NULL,
+                                          FALSE);
+        }
+        gtk_tree_path_free (path);
+}
+
+static gboolean
+clear_selection (GdmChooserWidget *widget)
+{
+        GtkTreeSelection *selection;
+
+        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget->priv->items_view));
+        gtk_tree_selection_unselect_all (selection);
+
+        return FALSE;
+}
+
+static void
+gdm_chooser_widget_shrink (GdmChooserWidget *widget)
+{
+        g_assert (widget->priv->should_hide_inactive_items == TRUE);
+
+        set_frame_text (widget, widget->priv->active_text);
+
+        gtk_alignment_set (GTK_ALIGNMENT (widget->priv->frame_alignment),
+                           0.0, 0.0, 1.0, 0.0);
+
+        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (widget->priv->scrolled_window),
+                                        GTK_POLICY_NEVER, GTK_POLICY_NEVER);
+
+        gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (widget->priv->scrolled_window),
+                                             GTK_SHADOW_ETCHED_OUT);
+
+        clear_selection (widget);
+        widget->priv->state = GDM_CHOOSER_WIDGET_STATE_SHRINKING;
+        start_animation (widget);
+}
+
+static void
+activate_from_row (GdmChooserWidget    *widget,
+                   GtkTreeRowReference *row)
+{
+        g_assert (row != NULL);
+        g_assert (gtk_tree_row_reference_valid (row));
+
+        if (widget->priv->active_row != NULL) {
+                gtk_tree_row_reference_free (widget->priv->active_row);
+                widget->priv->active_row = NULL;
+        }
+
+        widget->priv->active_row = gtk_tree_row_reference_copy (row);
+        g_signal_emit (widget, signals[ACTIVATED], 0);
+
+        if (widget->priv->should_hide_inactive_items) {
+                gdm_chooser_widget_shrink (widget);
+        }
+}
+
+static void
+deactivate (GdmChooserWidget *widget)
+{
+        if (widget->priv->active_row == NULL) {
+                return;
+        }
+
+        gtk_tree_row_reference_free (widget->priv->active_row);
+        widget->priv->active_row = NULL;
+
+        g_signal_emit (widget, signals[DEACTIVATED], 0, NULL, NULL);
+
+        if (widget->priv->state != GDM_CHOOSER_WIDGET_STATE_GROWN) {
+                gdm_chooser_widget_grow (widget);
+        }
+}
+
+static void
+activate_selected_item (GdmChooserWidget *widget)
+{
+        GtkTreeRowReference *row;
+        GtkTreeSelection    *selection;
+        GtkTreeModel        *model;
+        GtkTreeModel        *sort_model;
+        GtkTreeIter          sorted_iter;
+        gboolean             is_already_active;
+
+        row = NULL;
+        model = GTK_TREE_MODEL (widget->priv->list_store);
+        is_already_active = FALSE;
+
+        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget->priv->items_view));
+        if (gtk_tree_selection_get_selected (selection, &sort_model, &sorted_iter)) {
+                GtkTreePath *sorted_path;
+                GtkTreePath *filtered_path;
+                GtkTreePath *base_path;
+
+                g_assert (sort_model == GTK_TREE_MODEL (widget->priv->model_sorter));
+
+                sorted_path = gtk_tree_model_get_path (sort_model, &sorted_iter);
+                filtered_path =
+                    gtk_tree_model_sort_convert_path_to_child_path (widget->priv->model_sorter,
+                                                                    sorted_path);
+                gtk_tree_path_free (sorted_path);
+                base_path =
+                    gtk_tree_model_filter_convert_path_to_child_path (widget->priv->model_filter,
+                                                                      filtered_path);
+
+                if (widget->priv->active_row != NULL) {
+                        GtkTreePath *active_path;
+
+                        active_path = gtk_tree_row_reference_get_path (widget->priv->active_row);
+
+                        if (gtk_tree_path_compare  (base_path, active_path) == 0) {
+                                is_already_active = TRUE;
+                        }
+                        gtk_tree_path_free (active_path);
+                }
+                g_assert (base_path != NULL);
+                row = gtk_tree_row_reference_new (model, base_path);
+                gtk_tree_path_free (base_path);
+        }
+
+        if (!is_already_active) {
+                activate_from_row (widget, row);
+        } else {
+                deactivate (widget);
+        }
+        gtk_tree_row_reference_free (row);
+}
+
+void
+gdm_chooser_widget_set_active_item (GdmChooserWidget *widget,
+                                    const char       *id)
+{
+        g_return_if_fail (GDM_IS_CHOOSER_WIDGET (widget));
+
+        if (id != NULL) {
+                activate_from_item_id (widget, id);
+        } else {
+                deactivate (widget);
+        }
+}
+
+static void
+gdm_chooser_widget_set_property (GObject        *object,
+                                 guint           prop_id,
+                                 const GValue   *value,
+                                 GParamSpec     *pspec)
+{
+        GdmChooserWidget *self;
+
+        self = GDM_CHOOSER_WIDGET (object);
+
+        switch (prop_id) {
+
+        case PROP_INACTIVE_TEXT:
+                g_free (self->priv->inactive_text);
+                self->priv->inactive_text = g_value_dup_string (value);
+
+                if (self->priv->active_row == NULL) {
+                        set_frame_text (self, self->priv->inactive_text);
+                }
+                break;
+
+        case PROP_ACTIVE_TEXT:
+                g_free (self->priv->active_text);
+                self->priv->active_text = g_value_dup_string (value);
+
+                if (self->priv->active_row != NULL) {
+                        set_frame_text (self, self->priv->active_text);
+                }
+                break;
+
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+        }
+}
+
+static void
+gdm_chooser_widget_get_property (GObject        *object,
+                                 guint           prop_id,
+                                 GValue         *value,
+                                 GParamSpec     *pspec)
+{
+        GdmChooserWidget *self;
+
+        self = GDM_CHOOSER_WIDGET (object);
+
+        switch (prop_id) {
+        case PROP_INACTIVE_TEXT:
+                g_value_set_string (value, self->priv->inactive_text);
+                break;
+
+        case PROP_ACTIVE_TEXT:
+                g_value_set_string (value, self->priv->active_text);
+                break;
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+        }
+}
+
+static GObject *
+gdm_chooser_widget_constructor (GType                  type,
+                                guint                  n_construct_properties,
+                                GObjectConstructParam *construct_properties)
+{
+        GdmChooserWidget      *chooser_widget;
+        GdmChooserWidgetClass *klass;
+
+        klass = GDM_CHOOSER_WIDGET_CLASS (g_type_class_peek (GDM_TYPE_CHOOSER_WIDGET));
+
+        chooser_widget = GDM_CHOOSER_WIDGET (G_OBJECT_CLASS (gdm_chooser_widget_parent_class)->constructor (type,
+                                                                                                            n_construct_properties,
+                                                                                                            construct_properties));
+
+        return G_OBJECT (chooser_widget);
+}
+
+static void
+gdm_chooser_widget_dispose (GObject *object)
+{
+        GdmChooserWidget *widget;
+
+        widget = GDM_CHOOSER_WIDGET (object);
+
+        if (widget->priv->separator_row != NULL) {
+                gtk_tree_row_reference_free (widget->priv->separator_row);
+                widget->priv->separator_row = NULL;
+        }
+
+        if (widget->priv->active_row != NULL) {
+                gtk_tree_row_reference_free (widget->priv->active_row);
+                widget->priv->active_row = NULL;
+        }
+
+        if (widget->priv->inactive_text != NULL) {
+                g_free (widget->priv->inactive_text);
+                widget->priv->inactive_text = NULL;
+        }
+
+        if (widget->priv->active_text != NULL) {
+                g_free (widget->priv->active_text);
+                widget->priv->active_text = NULL;
+        }
+
+        if (widget->priv->in_use_message != NULL) {
+                g_free (widget->priv->in_use_message);
+                widget->priv->in_use_message = NULL;
+        }
+
+        G_OBJECT_CLASS (gdm_chooser_widget_parent_class)->dispose (object);
+}
+
+static gboolean
+gdm_chooser_widget_focus_in (GtkWidget     *widget,
+                             GdkEventFocus *event)
+{
+        GdmChooserWidget *chooser;
+        chooser = GDM_CHOOSER_WIDGET (widget);
+
+        gtk_widget_grab_focus (chooser->priv->items_view);
+
+        return FALSE;
+}
+
+static void
+gdm_chooser_widget_size_request (GtkWidget      *widget,
+                                 GtkRequisition *requisition)
+{
+        GdmChooserWidget *chooser;
+
+        chooser = GDM_CHOOSER_WIDGET (widget);
+
+        GTK_WIDGET_CLASS (gdm_chooser_widget_parent_class)->size_request (widget, requisition);
+
+        /* XXX: this hack makes the scrolled window behave the way we want in
+         * the login window.  The login window is special because it always
+         * tries to hug the widgets as tightly as possible.  Normally, this
+         * "tight hug" makes the scrolled_window get squeezed into nothing (if
+         * POLICY_AUTOMATIC) If we use POLICY_NEVER then the scrolled window
+         * gets the right size but can't have a scrollbar (which sort of
+         * defeats the point I guess)
+         */
+        requisition->height -= chooser->priv->scrolled_window->requisition.height;
+        chooser->priv->scrolled_window->requisition.height = chooser->priv->items_view->requisition.height;
+        chooser->priv->scrolled_window->requisition.height += chooser->priv->scrolled_window->style->ythickness * 2;
+        chooser->priv->scrolled_window->requisition.height += GTK_CONTAINER (chooser->priv->scrolled_window)->border_width * 2;
+        requisition->height += chooser->priv->scrolled_window->requisition.height;
+}
+
+#ifdef BUILD_ALLOCATION_HACK
+static gint
+compare_allocation_height (GdmChooserWidget *widget_a,
+                           GdmChooserWidget *widget_b)
+{
+        return GTK_WIDGET (widget_a)->allocation.height - GTK_WIDGET (widget_b)->allocation.height;
+}
+
+static void
+renegotiate_allocation (GtkContainer          *container,
+                        GdmChooserWidgetClass *klass)
+{
+        GList *children;
+        GList *choosers;
+        GList *tmp;
+        int    total_allocation;
+        int    number_of_choosers;
+
+        if (klass->size_negotiation_handler == 0) {
+                return;
+        }
+        klass->size_negotiation_handler = 0;
+        g_signal_handlers_disconnect_by_func (container, renegotiate_allocation, klass);
+
+        children = gtk_container_get_children (container);
+
+        total_allocation = 0;
+        number_of_choosers = 0;
+        choosers = NULL;
+        for (tmp = children; tmp != NULL; tmp = tmp->next) {
+                GdmChooserWidget *widget;
+
+                if (!GDM_IS_CHOOSER_WIDGET (tmp->data)) {
+                        continue;
+                }
+
+                widget = GDM_CHOOSER_WIDGET (tmp->data);
+
+                total_allocation += GTK_WIDGET (widget)->allocation.height;
+                choosers = g_list_insert_sorted (choosers, widget, (GCompareFunc) compare_allocation_height);
+                number_of_choosers++;
+        }
+        total_allocation = MIN (total_allocation, GTK_WIDGET (container)->allocation.height);
+
+        for (tmp = choosers; tmp != NULL; tmp = tmp->next) {
+                GdmChooserWidget *widget;
+                GtkAllocation  allocation;
+
+                g_assert (GDM_IS_CHOOSER_WIDGET (tmp->data));
+
+                widget = GDM_CHOOSER_WIDGET (tmp->data);
+
+                allocation = GTK_WIDGET (widget)->allocation;
+
+                GTK_WIDGET (widget)->allocation.height = MIN (GTK_WIDGET (widget)->requisition.height,
+                                                              total_allocation / number_of_choosers);
+
+                total_allocation -= allocation.height;
+
+                number_of_choosers--;
+        }
+        g_list_free (children);
+}
+
+static void
+gdm_chooser_widget_size_allocate (GtkWidget        *widget,
+                                  GtkAllocation    *allocation)
+{
+        GdmChooserWidgetClass *klass;
+
+        klass = GDM_CHOOSER_WIDGET_GET_CLASS (widget);
+
+        GTK_WIDGET_CLASS (gdm_chooser_widget_parent_class)->size_allocate (widget, allocation);
+
+        /* XXX: Vbox isn't too smart about divving up allocations when there isn't enough room to go around.
+         * Since we may have more than one chooser widget in a vbox, we redistribute space between the choosers
+         * (if one chooser gets lots of space and another gets no space, give some up)
+         */
+        if (allocation->height == 1 && klass->size_negotiation_handler == 0) {
+                GtkWidget *parent;
+
+                parent = gtk_widget_get_parent (widget);
+                klass->size_negotiation_handler = g_signal_connect (parent, "size-allocate",
+                                                                    G_CALLBACK (renegotiate_allocation),
+                                                                    klass);
+        }
+}
+#endif
+
+static void
+gdm_chooser_widget_class_init (GdmChooserWidgetClass *klass)
+{
+        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
+        GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+        object_class->get_property = gdm_chooser_widget_get_property;
+        object_class->set_property = gdm_chooser_widget_set_property;
+        object_class->constructor = gdm_chooser_widget_constructor;
+        object_class->dispose = gdm_chooser_widget_dispose;
+        object_class->finalize = gdm_chooser_widget_finalize;
+        widget_class->focus_in_event = gdm_chooser_widget_focus_in;
+        widget_class->size_request = gdm_chooser_widget_size_request;
+#ifdef BUILD_ALLOCATION_HACK
+        widget_class->size_allocate = gdm_chooser_widget_size_allocate;
+#endif
+
+        signals [ACTIVATED] = g_signal_new ("activated",
+                                            G_TYPE_FROM_CLASS (object_class),
+                                            G_SIGNAL_RUN_LAST,
+                                            G_STRUCT_OFFSET (GdmChooserWidgetClass, activated),
+                                            NULL,
+                                            NULL,
+                                            g_cclosure_marshal_VOID__VOID,
+                                            G_TYPE_NONE,
+                                            0);
+
+        signals [DEACTIVATED] = g_signal_new ("deactivated",
+                                              G_TYPE_FROM_CLASS (object_class),
+                                              G_SIGNAL_RUN_LAST,
+                                              G_STRUCT_OFFSET (GdmChooserWidgetClass, deactivated),
+                                              NULL,
+                                              NULL,
+                                              g_cclosure_marshal_VOID__VOID,
+                                              G_TYPE_NONE,
+                                              0);
+
+        g_object_class_install_property (object_class,
+                                         PROP_INACTIVE_TEXT,
+                                         g_param_spec_string ("inactive-text",
+                                                              _("Inactive Text"),
+                                                              _("The text to use in the label if the "
+                                                                "user hasn't picked an item yet"),
+                                                              NULL,
+                                                              (G_PARAM_READWRITE |
+                                                               G_PARAM_CONSTRUCT)));
+        g_object_class_install_property (object_class,
+                                         PROP_ACTIVE_TEXT,
+                                         g_param_spec_string ("active-text",
+                                                              _("Active Text"),
+                                                              _("The text to use in the label if the "
+                                                                "user has picked an item"),
+                                                              NULL,
+                                                              (G_PARAM_READWRITE |
+                                                               G_PARAM_CONSTRUCT)));
+
+        g_type_class_add_private (klass, sizeof (GdmChooserWidgetPrivate));
+}
+
+static void
+on_row_activated (GtkTreeView          *tree_view,
+                  GtkTreePath          *tree_path,
+                  GtkTreeViewColumn    *tree_column,
+                  GdmChooserWidget     *widget)
+{
+        activate_selected_item (widget);
+}
+
+static gboolean
+path_is_separator (GdmChooserWidget *widget,
+                   GtkTreeModel     *model,
+                   GtkTreePath      *path)
+{
+        GtkTreePath      *base_path;
+        GtkTreePath      *filtered_path;
+        GtkTreePath      *sorted_path;
+        GtkTreePath      *separator_path;
+        gboolean          is_separator;
+
+        if (widget->priv->separator_row == NULL) {
+                return FALSE;
+        }
+
+        base_path = gtk_tree_row_reference_get_path (widget->priv->separator_row);
+        separator_path = base_path;
+        filtered_path = NULL;
+        sorted_path = NULL;
+
+        if (model != GTK_TREE_MODEL (widget->priv->list_store)) {
+                filtered_path = gtk_tree_model_filter_convert_child_path_to_path (widget->priv->model_filter, base_path);
+                separator_path = filtered_path;
+
+                gtk_tree_path_free (base_path);
+                base_path = NULL;
+        }
+
+        if (filtered_path != NULL && model != GTK_TREE_MODEL (widget->priv->model_filter)) {
+                sorted_path = gtk_tree_model_sort_convert_child_path_to_path (widget->priv->model_sorter, filtered_path);
+                separator_path = sorted_path;
+
+                gtk_tree_path_free (filtered_path);
+                filtered_path = NULL;
+        }
+
+        if ((separator_path != NULL) &&
+            gtk_tree_path_compare (path, separator_path) == 0) {
+                is_separator = TRUE;
+        } else {
+                is_separator = FALSE;
+        }
+        gtk_tree_path_free (separator_path);
+
+        return is_separator;
+}
+
+static int
+compare_item  (GtkTreeModel *model,
+               GtkTreeIter  *a,
+               GtkTreeIter  *b,
+               gpointer      data)
+{
+        GdmChooserWidget *widget;
+        char             *name_a;
+        char             *name_b;
+        gboolean          is_separate_a;
+        gboolean          is_separate_b;
+        int               result;
+        int               direction;
+        GtkTreeIter      *separator_iter;
+
+        g_assert (GDM_IS_CHOOSER_WIDGET (data));
+
+        widget = GDM_CHOOSER_WIDGET (data);
+
+        separator_iter = NULL;
+        if (widget->priv->separator_row != NULL) {
+
+                GtkTreePath      *path_a;
+                GtkTreePath      *path_b;
+
+                path_a = gtk_tree_model_get_path (model, a);
+                path_b = gtk_tree_model_get_path (model, b);
+
+                if (path_is_separator (widget, model, path_a)) {
+                        separator_iter = a;
+                } else if (path_is_separator (widget, model, path_b)) {
+                        separator_iter = b;
+                }
+
+                gtk_tree_path_free (path_a);
+                gtk_tree_path_free (path_b);
+        }
+
+        name_a = NULL;
+        is_separate_a = FALSE;
+        if (separator_iter != a) {
+                gtk_tree_model_get (model, a,
+                                    CHOOSER_NAME_COLUMN, &name_a,
+                                    CHOOSER_ITEM_IS_SEPARATED_COLUMN, &is_separate_a,
+                                    -1);
+        }
+
+        char *id;
+        name_b = NULL;
+        is_separate_b = FALSE;
+        if (separator_iter != b) {
+                gtk_tree_model_get (model, b,
+                                    CHOOSER_NAME_COLUMN, &name_b,
+                                    CHOOSER_ID_COLUMN, &id,
+                                    CHOOSER_ITEM_IS_SEPARATED_COLUMN, &is_separate_b,
+                                    -1);
+        }
+
+        if (widget->priv->separator_position == GDM_CHOOSER_WIDGET_POSITION_TOP) {
+                direction = -1;
+        } else {
+                direction = 1;
+        }
+
+        if (separator_iter == b) {
+                result = is_separate_a? 1 : -1;
+                result *= direction;
+        } else if (separator_iter == a) {
+                result = is_separate_b? -1 : 1;
+                result *= direction;
+        } else if (is_separate_b == is_separate_a) {
+                result = g_utf8_collate (name_a, name_b);
+        } else {
+                result = is_separate_a - is_separate_b;
+                result *= direction;
+        }
+
+        g_free (name_a);
+        g_free (name_b);
+
+        return result;
+}
+
+static void
+name_cell_data_func (GtkTreeViewColumn  *tree_column,
+                     GtkCellRenderer    *cell,
+                     GtkTreeModel       *model,
+                     GtkTreeIter        *iter,
+                     GdmChooserWidget   *widget)
+{
+        gboolean is_in_use;
+        char    *name;
+        char    *markup;
+
+        name = NULL;
+        gtk_tree_model_get (model,
+                            iter,
+                            CHOOSER_ITEM_IS_IN_USE_COLUMN, &is_in_use,
+                            CHOOSER_NAME_COLUMN, &name,
+                            -1);
+
+        if (is_in_use) {
+                markup = g_strdup_printf ("<b>%s</b>\n"
+                                          "<i><span size=\"x-small\">%s</span></i>",
+                                          name, widget->priv->in_use_message);
+        } else {
+                markup = g_strdup_printf ("<b>%s</b>", name);
+        }
+        g_free (name);
+
+        g_object_set (cell, "markup", markup, NULL);
+        g_free (markup);
+}
+
+static void
+check_cell_data_func (GtkTreeViewColumn    *tree_column,
+                      GtkCellRenderer      *cell,
+                      GtkTreeModel         *model,
+                      GtkTreeIter          *iter,
+                      GdmChooserWidget     *widget)
+{
+        gboolean   is_in_use;
+        GdkPixbuf *pixbuf;
+
+        gtk_tree_model_get (model,
+                            iter,
+                            CHOOSER_ITEM_IS_IN_USE_COLUMN, &is_in_use,
+                            -1);
+
+        if (is_in_use) {
+                pixbuf = widget->priv->is_in_use_pixbuf;
+        } else {
+                pixbuf = NULL;
+        }
+
+        g_object_set (cell, "pixbuf", pixbuf, NULL);
+}
+
+static GdkPixbuf *
+get_is_in_use_pixbuf (GdmChooserWidget *widget)
+{
+        GtkIconTheme *theme;
+        GdkPixbuf    *pixbuf;
+
+        theme = gtk_icon_theme_get_default ();
+        pixbuf = gtk_icon_theme_load_icon (theme,
+                                           "emblem-default",
+                                           GDM_CHOOSER_WIDGET_DEFAULT_ICON_SIZE / 3,
+                                           0,
+                                           NULL);
+
+        return pixbuf;
+}
+
+static gboolean
+separator_func (GtkTreeModel *model,
+                GtkTreeIter  *iter,
+                gpointer      data)
+{
+        GdmChooserWidget *widget;
+        GtkTreePath      *path;
+        gboolean          is_separator;
+
+        g_assert (GDM_IS_CHOOSER_WIDGET (data));
+
+        widget = GDM_CHOOSER_WIDGET (data);
+
+        g_assert (widget->priv->separator_row != NULL);
+
+        path = gtk_tree_model_get_path (model, iter);
+
+        is_separator = path_is_separator (widget, model, path);
+
+        gtk_tree_path_free (path);
+
+        return is_separator;
+}
+
+static void
+add_separator (GdmChooserWidget *widget)
+{
+        GtkTreeIter   iter;
+        GtkTreeModel *model;
+        GtkTreePath  *path;
+
+        g_assert (widget->priv->separator_row == NULL);
+
+        model = GTK_TREE_MODEL (widget->priv->list_store);
+
+        gtk_list_store_insert_with_values (widget->priv->list_store,
+                                           &iter, 0,
+                                           CHOOSER_ID_COLUMN, "-", -1);
+        path = gtk_tree_model_get_path (model, &iter);
+        widget->priv->separator_row =
+            gtk_tree_row_reference_new (model, path);
+        gtk_tree_path_free (path);
+}
+
+static gboolean
+update_column_visibility (GdmChooserWidget *widget)
+{
+        if (widget->priv->number_of_rows_with_images > 0) {
+                gtk_tree_view_column_set_visible (widget->priv->image_column,
+                                                  TRUE);
+        } else {
+                gtk_tree_view_column_set_visible (widget->priv->image_column,
+                                                  FALSE);
+        }
+        if (widget->priv->number_of_in_use_rows > 0) {
+                gtk_tree_view_column_set_visible (widget->priv->is_in_use_column,
+                                                  TRUE);
+        } else {
+                gtk_tree_view_column_set_visible (widget->priv->is_in_use_column,
+                                                  FALSE);
+        }
+
+        return FALSE;
+}
+
+static void
+clear_canceled_visibility_update (GdmChooserWidget *widget)
+{
+        widget->priv->update_idle_id = 0;
+}
+
+static void
+queue_column_visibility_update (GdmChooserWidget *widget)
+{
+        if (widget->priv->update_idle_id == 0) {
+                widget->priv->update_idle_id =
+                        g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
+                                         (GSourceFunc)
+                                         update_column_visibility, widget,
+                                         (GDestroyNotify)
+                                         clear_canceled_visibility_update);
+        }
+}
+
+static void
+on_row_changed (GtkTreeModel     *model,
+                GtkTreePath      *path,
+                GtkTreeIter      *iter,
+                GdmChooserWidget *widget)
+{
+        queue_column_visibility_update (widget);
+}
+
+static void
+add_frame (GdmChooserWidget *widget)
+{
+        widget->priv->frame = gtk_frame_new (NULL);
+        gtk_frame_set_shadow_type (GTK_FRAME (widget->priv->frame),
+                                   GTK_SHADOW_NONE);
+        gtk_widget_show (widget->priv->frame);
+        gtk_container_add (GTK_CONTAINER (widget), widget->priv->frame);
+
+        widget->priv->frame_alignment = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
+        gtk_widget_show (widget->priv->frame_alignment);
+        gtk_container_add (GTK_CONTAINER (widget->priv->frame),
+                           widget->priv->frame_alignment);
+}
+
+static gboolean
+on_button_release (GtkTreeView      *items_view,
+                   GdkEventButton   *event,
+                   GdmChooserWidget *widget)
+{
+        GtkTreeModel     *model;
+        GtkTreeIter       iter;
+        GtkTreeSelection *selection;
+
+        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget->priv->items_view));
+        if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
+                GtkTreePath *path;
+
+                path = gtk_tree_model_get_path (model, &iter);
+                gtk_tree_view_row_activated (GTK_TREE_VIEW (items_view),
+                                             path, NULL);
+                gtk_tree_path_free (path);
+        }
+
+        return FALSE;
+}
+
+static void
+gdm_chooser_widget_init (GdmChooserWidget *widget)
+{
+        GtkTreeViewColumn *column;
+        GtkTreeSelection  *selection;
+        GtkCellRenderer   *renderer;
+
+        widget->priv = GDM_CHOOSER_WIDGET_GET_PRIVATE (widget);
+
+        gtk_alignment_set_padding (GTK_ALIGNMENT (widget), 6, 0, 12, 0);
+
+        add_frame (widget);
+
+        widget->priv->scrolled_window = gtk_scrolled_window_new (NULL, NULL);
+
+        gtk_scrolled_window_set_vadjustment (GTK_SCROLLED_WINDOW (widget->priv->scrolled_window),
+                                             NULL);
+        gtk_scrolled_window_set_hadjustment (GTK_SCROLLED_WINDOW (widget->priv->scrolled_window),
+                                             NULL);
+        gtk_widget_show (widget->priv->scrolled_window);
+        gtk_container_add (GTK_CONTAINER (widget->priv->frame_alignment),
+                           widget->priv->scrolled_window);
+
+        widget->priv->items_view = gtk_tree_view_new ();
+        gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (widget->priv->items_view),
+                                           FALSE);
+        g_signal_connect (widget->priv->items_view,
+                          "row-activated",
+                          G_CALLBACK (on_row_activated),
+                          widget);
+
+        /* hack to make single-click activate work
+         */
+        g_signal_connect_after (widget->priv->items_view,
+                               "button-release-event",
+                               G_CALLBACK (on_button_release),
+                               widget);
+
+        gtk_widget_show (widget->priv->items_view);
+        gtk_container_add (GTK_CONTAINER (widget->priv->scrolled_window),
+                           widget->priv->items_view);
+
+        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget->priv->items_view));
+        gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
+
+        g_assert (NUMBER_OF_CHOOSER_COLUMNS == 7);
+        widget->priv->list_store = gtk_list_store_new (NUMBER_OF_CHOOSER_COLUMNS,
+                                                       GDK_TYPE_PIXBUF,
+                                                       G_TYPE_STRING,
+                                                       G_TYPE_STRING,
+                                                       G_TYPE_BOOLEAN,
+                                                       G_TYPE_BOOLEAN,
+                                                       G_TYPE_BOOLEAN,
+                                                       G_TYPE_STRING);
+
+        widget->priv->model_filter = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (GTK_TREE_MODEL (widget->priv->list_store), NULL));
+
+        gtk_tree_model_filter_set_visible_column (widget->priv->model_filter,
+                                                  CHOOSER_ITEM_IS_VISIBLE_COLUMN);
+        g_signal_connect (G_OBJECT (widget->priv->model_filter), "row-changed",
+                          G_CALLBACK (on_row_changed), widget);
+
+        widget->priv->model_sorter = GTK_TREE_MODEL_SORT (gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (widget->priv->model_filter)));
+
+        gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (widget->priv->model_sorter),
+                                         CHOOSER_ID_COLUMN,
+                                         compare_item,
+                                         widget, NULL);
+
+        gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (widget->priv->model_sorter),
+                                              CHOOSER_ID_COLUMN,
+                                              GTK_SORT_ASCENDING);
+        gtk_tree_view_set_model (GTK_TREE_VIEW (widget->priv->items_view),
+                                 GTK_TREE_MODEL (widget->priv->model_sorter));
+        gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (widget->priv->items_view),
+                                              separator_func,
+                                              widget, NULL);
+
+        /* IMAGE COLUMN */
+        renderer = gtk_cell_renderer_pixbuf_new ();
+        column = gtk_tree_view_column_new ();
+        gtk_tree_view_column_pack_start (column, renderer, FALSE);
+        gtk_tree_view_append_column (GTK_TREE_VIEW (widget->priv->items_view), column);
+        widget->priv->image_column = column;
+
+        gtk_tree_view_column_set_attributes (column,
+                                             renderer,
+                                             "pixbuf", CHOOSER_IMAGE_COLUMN,
+                                             NULL);
+
+        g_object_set (renderer,
+                      "width", GDM_CHOOSER_WIDGET_DEFAULT_ICON_SIZE,
+                      "xalign", 1.0,
+                      NULL);
+
+        /* NAME COLUMN */
+        renderer = gtk_cell_renderer_text_new ();
+        column = gtk_tree_view_column_new ();
+        gtk_tree_view_column_pack_start (column, renderer, FALSE);
+        gtk_tree_view_append_column (GTK_TREE_VIEW (widget->priv->items_view), column);
+        gtk_tree_view_column_set_cell_data_func (column,
+                                                 renderer,
+                                                 (GtkTreeCellDataFunc) name_cell_data_func,
+                                                 widget,
+                                                 NULL);
+
+        gtk_tree_view_set_tooltip_column (GTK_TREE_VIEW (widget->priv->items_view),
+                                          CHOOSER_COMMENT_COLUMN);
+
+        /* IN USE COLUMN */
+        renderer = gtk_cell_renderer_pixbuf_new ();
+        column = gtk_tree_view_column_new ();
+        gtk_tree_view_column_pack_start (column, renderer, FALSE);
+        gtk_tree_view_append_column (GTK_TREE_VIEW (widget->priv->items_view), column);
+        widget->priv->is_in_use_column = column;
+
+        gtk_tree_view_column_set_cell_data_func (column,
+                                                 renderer,
+                                                 (GtkTreeCellDataFunc) check_cell_data_func,
+                                                 widget,
+                                                 NULL);
+        widget->priv->is_in_use_pixbuf = get_is_in_use_pixbuf (widget);
+
+        g_object_set (renderer,
+                      "width", GDM_CHOOSER_WIDGET_DEFAULT_ICON_SIZE,
+                      NULL);
+
+        add_separator (widget);
+
+        queue_column_visibility_update (widget);
+        gdm_chooser_widget_grow (widget);
+}
+
+static void
+gdm_chooser_widget_finalize (GObject *object)
+{
+        GdmChooserWidget *widget;
+
+        g_return_if_fail (object != NULL);
+        g_return_if_fail (GDM_IS_CHOOSER_WIDGET (object));
+
+        widget = GDM_CHOOSER_WIDGET (object);
+
+        g_return_if_fail (widget->priv != NULL);
+
+        G_OBJECT_CLASS (gdm_chooser_widget_parent_class)->finalize (object);
+}
+
+GtkWidget *
+gdm_chooser_widget_new (const char *inactive_text,
+                        const char *active_text)
+{
+        GObject *object;
+
+        object = g_object_new (GDM_TYPE_CHOOSER_WIDGET,
+                               "inactive-text", inactive_text,
+                               "active-text", active_text, NULL);
+
+        return GTK_WIDGET (object);
+}
+
+void
+gdm_chooser_widget_add_item (GdmChooserWidget *widget,
+                             const char       *id,
+                             GdkPixbuf        *image,
+                             const char       *name,
+                             const char       *comment,
+                             gboolean          in_use,
+                             gboolean          keep_separate)
+{
+        gboolean is_visible;
+
+        g_return_if_fail (GDM_IS_CHOOSER_WIDGET (widget));
+
+        if (keep_separate) {
+                widget->priv->number_of_separated_rows++;
+        } else {
+                widget->priv->number_of_normal_rows++;
+        }
+
+        if (in_use) {
+                widget->priv->number_of_in_use_rows++;
+        }
+
+        if (image != NULL) {
+                widget->priv->number_of_rows_with_images++;
+        }
+
+        is_visible = widget->priv->active_row == NULL;
+
+        gtk_list_store_insert_with_values (widget->priv->list_store,
+                                           NULL, 0,
+                                           CHOOSER_IMAGE_COLUMN, image,
+                                           CHOOSER_NAME_COLUMN, name,
+                                           CHOOSER_COMMENT_COLUMN, comment,
+                                           CHOOSER_ITEM_IS_IN_USE_COLUMN, in_use,
+                                           CHOOSER_ITEM_IS_SEPARATED_COLUMN, keep_separate,
+                                           CHOOSER_ITEM_IS_VISIBLE_COLUMN, is_visible,
+                                           CHOOSER_ID_COLUMN, id,
+                                           -1);
+
+        move_cursor_to_top (widget);
+}
+
+void
+gdm_chooser_widget_remove_item (GdmChooserWidget *widget,
+                                const char       *id)
+{
+        GtkTreeModel *model;
+        GtkTreeIter   iter;
+        GdkPixbuf    *image;
+        gboolean      is_separate;
+        gboolean      is_in_use;
+
+        g_return_if_fail (GDM_IS_CHOOSER_WIDGET (widget));
+
+        model = GTK_TREE_MODEL (widget->priv->list_store);
+
+        if (!find_item (widget, id, &iter)) {
+                g_critical ("Tried to remove non-existing item from chooser");
+                return;
+        }
+
+        is_separate = FALSE;
+        gtk_tree_model_get (model, &iter,
+                            CHOOSER_IMAGE_COLUMN, &image,
+                            CHOOSER_ITEM_IS_IN_USE_COLUMN, &is_in_use,
+                            CHOOSER_ITEM_IS_SEPARATED_COLUMN, &is_separate,
+                            -1);
+
+        if (image != NULL) {
+                widget->priv->number_of_rows_with_images--;
+                g_object_unref (image);
+        }
+
+        if (is_in_use) {
+                widget->priv->number_of_in_use_rows--;
+        }
+
+        if (is_separate) {
+                widget->priv->number_of_separated_rows--;
+        } else {
+                widget->priv->number_of_normal_rows--;
+        }
+
+        gtk_list_store_remove (widget->priv->list_store, &iter);
+
+        move_cursor_to_top (widget);
+}
+
+gboolean
+gdm_chooser_widget_lookup_item (GdmChooserWidget *widget,
+                                const char       *id,
+                                GdkPixbuf       **image,
+                                char            **name,
+                                char            **comment,
+                                gboolean         *is_in_use,
+                                gboolean         *is_separate)
+{
+        GtkTreeModel *model;
+        GtkTreeIter   iter;
+        char         *active_item_id;
+
+        g_return_val_if_fail (GDM_IS_CHOOSER_WIDGET (widget), FALSE);
+        g_return_val_if_fail (id != NULL, FALSE);
+
+        active_item_id = get_active_item_id (widget, &iter);
+
+        if (active_item_id == NULL || strcmp (active_item_id, id) != 0) {
+                g_free (active_item_id);
+
+                if (!find_item (widget, id, &iter)) {
+                        return FALSE;
+                }
+        }
+        g_free (active_item_id);
+
+        gtk_tree_model_get (model, &iter,
+                            CHOOSER_IMAGE_COLUMN, image,
+                            CHOOSER_NAME_COLUMN, name,
+                            CHOOSER_ITEM_IS_IN_USE_COLUMN, is_in_use,
+                            CHOOSER_ITEM_IS_SEPARATED_COLUMN, is_separate,
+                            -1);
+
+        return TRUE;
+}
+
+void
+gdm_chooser_widget_set_item_in_use (GdmChooserWidget *widget,
+                                    const char       *id,
+                                    gboolean          is_in_use)
+{
+        GtkTreeIter   iter;
+
+        g_return_if_fail (GDM_IS_CHOOSER_WIDGET (widget));
+
+        if (!find_item (widget, id, &iter)) {
+                return;
+        }
+
+        gtk_list_store_set (widget->priv->list_store, &iter,
+                            CHOOSER_ITEM_IS_IN_USE_COLUMN, is_in_use, -1);
+}
+
+void
+gdm_chooser_widget_set_in_use_message (GdmChooserWidget *widget,
+                                       const char       *message)
+{
+        g_return_if_fail (GDM_IS_CHOOSER_WIDGET (widget));
+
+        g_free (widget->priv->in_use_message);
+        widget->priv->in_use_message = g_strdup (message);
+}
+
+void
+gdm_chooser_widget_set_separator_position (GdmChooserWidget         *widget,
+                                           GdmChooserWidgetPosition  position)
+{
+        g_return_if_fail (GDM_IS_CHOOSER_WIDGET (widget));
+
+        if (widget->priv->separator_position != position) {
+                widget->priv->separator_position = position;
+        }
+
+        gtk_tree_model_filter_refilter (widget->priv->model_filter);
+}
+
+void
+gdm_chooser_widget_set_hide_inactive_items (GdmChooserWidget  *widget,
+                                            gboolean           should_hide)
+{
+        widget->priv->should_hide_inactive_items = should_hide;
+
+        if (should_hide &&
+            (widget->priv->state != GDM_CHOOSER_WIDGET_STATE_SHRUNK
+             || widget->priv->state != GDM_CHOOSER_WIDGET_STATE_SHRINKING) &&
+            widget->priv->active_row != NULL) {
+                gdm_chooser_widget_shrink (widget);
+        } else if (!should_hide &&
+              (widget->priv->state != GDM_CHOOSER_WIDGET_STATE_GROWN
+               || widget->priv->state != GDM_CHOOSER_WIDGET_STATE_GROWING)) {
+                gdm_chooser_widget_grow (widget);
+        }
+}
diff --git a/gui/simple-greeter/gdm-chooser-widget.h b/gui/simple-greeter/gdm-chooser-widget.h
new file mode 100644
index 0000000..9a5581f
--- /dev/null
+++ b/gui/simple-greeter/gdm-chooser-widget.h
@@ -0,0 +1,102 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Ray Strode <rstrode at redhat.com>
+ * Copyright (C) 2007 William Jon McCann <mccann at 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.
+ *
+ */
+
+#ifndef __GDM_CHOOSER_WIDGET_H
+#define __GDM_CHOOSER_WIDGET_H
+
+#include <glib-object.h>
+#include <gtk/gtkalignment.h>
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_CHOOSER_WIDGET         (gdm_chooser_widget_get_type ())
+#define GDM_CHOOSER_WIDGET(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_CHOOSER_WIDGET, GdmChooserWidget))
+#define GDM_CHOOSER_WIDGET_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_CHOOSER_WIDGET, GdmChooserWidgetClass))
+#define GDM_IS_CHOOSER_WIDGET(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_CHOOSER_WIDGET))
+#define GDM_IS_CHOOSER_WIDGET_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_CHOOSER_WIDGET))
+#define GDM_CHOOSER_WIDGET_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_CHOOSER_WIDGET, GdmChooserWidgetClass))
+
+typedef struct GdmChooserWidgetPrivate GdmChooserWidgetPrivate;
+
+typedef struct
+{
+        GtkAlignment             parent;
+        GdmChooserWidgetPrivate *priv;
+} GdmChooserWidget;
+
+typedef struct
+{
+        GtkAlignmentClass       parent_class;
+
+        void (* activated)      (GdmChooserWidget *widget);
+        void (* deactivated)    (GdmChooserWidget *widget);
+
+#ifdef BUILD_ALLOCATION_HACK
+        gulong size_negotiation_handler;
+#endif
+} GdmChooserWidgetClass;
+
+typedef enum {
+        GDM_CHOOSER_WIDGET_POSITION_TOP = 0,
+        GDM_CHOOSER_WIDGET_POSITION_BOTTOM,
+} GdmChooserWidgetPosition;
+
+GType                  gdm_chooser_widget_get_type               (void);
+GtkWidget *            gdm_chooser_widget_new                    (const char *unactive_label,
+                                                                  const char *active_label);
+
+void                   gdm_chooser_widget_add_item               (GdmChooserWidget *widget,
+                                                                  const char       *id,
+                                                                  GdkPixbuf        *image,
+                                                                  const char       *name,
+                                                                  const char       *comment,
+                                                                  gboolean          is_in_use,
+                                                                  gboolean          keep_separate);
+
+void                   gdm_chooser_widget_remove_item            (GdmChooserWidget *widget,
+                                                                  const char       *id);
+
+gboolean               gdm_chooser_widget_lookup_item            (GdmChooserWidget *widget,
+                                                                  const char       *id,
+                                                                  GdkPixbuf       **image,
+                                                                  char            **name,
+                                                                  char            **comment,
+                                                                  gboolean         *is_in_use,
+                                                                  gboolean         *is_separate);
+
+char *                 gdm_chooser_widget_get_active_item        (GdmChooserWidget *widget);
+void                   gdm_chooser_widget_set_active_item        (GdmChooserWidget *widget,
+                                                                  const char       *item);
+
+void                   gdm_chooser_widget_set_item_in_use        (GdmChooserWidget *widget,
+                                                                  const char       *id,
+                                                                  gboolean          is_in_use);
+
+void                   gdm_chooser_widget_set_in_use_message     (GdmChooserWidget *widget,
+                                                                  const char       *message);
+
+void                   gdm_chooser_widget_set_separator_position  (GdmChooserWidget         *widget,
+                                                                   GdmChooserWidgetPosition  position);
+void                   gdm_chooser_widget_set_hide_inactive_items (GdmChooserWidget         *widget,
+                                                                   gboolean                  should_hide);
+G_END_DECLS
+
+#endif /* __GDM_CHOOSER_WIDGET_H */
-- 
1.5.3.6


3-switch-user-chooser-over.patch:

--- NEW FILE 3-switch-user-chooser-over.patch ---
>From 1a8e5634ea780869574072ce5d4b33048fb35698 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode at redhat.com>
Date: Thu, 13 Dec 2007 10:12:30 -0500
Subject: [PATCH] Change user-chooser-widget over to use new chooser widget

---
 gui/simple-greeter/Makefile.am               |   10 +
 gui/simple-greeter/gdm-user-chooser-widget.c |  600 ++------------------------
 gui/simple-greeter/gdm-user-chooser-widget.h |   11 +-
 3 files changed, 59 insertions(+), 562 deletions(-)

diff --git a/gui/simple-greeter/Makefile.am b/gui/simple-greeter/Makefile.am
index a403f24..836c620 100644
--- a/gui/simple-greeter/Makefile.am
+++ b/gui/simple-greeter/Makefile.am
@@ -45,6 +45,8 @@ test_greeter_login_window_SOURCES = 	\
 	test-greeter-login-window.c	\
 	gdm-greeter-login-window.h	\
 	gdm-greeter-login-window.c	\
+	gdm-chooser-widget.h		\
+	gdm-chooser-widget.c		\
 	gdm-user-chooser-widget.h	\
 	gdm-user-chooser-widget.c	\
 	gdm-user-chooser-dialog.h	\
@@ -86,6 +88,8 @@ test_language_chooser_LDADD =	\
 
 test_session_chooser_SOURCES = 	\
 	test-session-chooser.c		\
+	gdm-chooser-widget.h		\
+	gdm-chooser-widget.c		\
 	gdm-session-chooser-widget.h	\
 	gdm-session-chooser-widget.c	\
 	gdm-session-chooser-dialog.h	\
@@ -98,6 +102,8 @@ test_session_chooser_LDADD =		\
 
 test_user_chooser_SOURCES = 		\
 	test-user-chooser.c		\
+	gdm-chooser-widget.h		\
+	gdm-chooser-widget.c		\
 	gdm-user-chooser-widget.h	\
 	gdm-user-chooser-widget.c	\
 	gdm-user-chooser-dialog.h	\
@@ -131,6 +137,8 @@ libexec_PROGRAMS =			\
 
 gdm_simple_greeter_SOURCES =  		\
 	greeter-main.c 			\
+	gdm-chooser-widget.h		\
+	gdm-chooser-widget.c		\
 	gdm-greeter-client.h		\
 	gdm-greeter-client.c		\
 	gdm-greeter-session.h		\
@@ -145,6 +153,8 @@ gdm_simple_greeter_SOURCES =  		\
 	gdm-greeter-panel.c		\
 	gdm-greeter-background.h	\
 	gdm-greeter-background.c	\
+	gdm-session-chooser-widget.h	\
+	gdm-session-chooser-widget.c	\
 	gdm-user-chooser-widget.h	\
 	gdm-user-chooser-widget.c	\
 	gdm-user-manager.h		\
diff --git a/gui/simple-greeter/gdm-user-chooser-widget.c b/gui/simple-greeter/gdm-user-chooser-widget.c
index e8c0cdc..b8a9bb7 100644
--- a/gui/simple-greeter/gdm-user-chooser-widget.c
+++ b/gui/simple-greeter/gdm-user-chooser-widget.c
@@ -1,6 +1,7 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
  *
  * Copyright (C) 2007 William Jon McCann <mccann at jhu.edu>
+ * Copyright (C) 2007 Ray Strode <rstrode at redhat.com>
  *
  * 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
@@ -47,61 +48,23 @@ enum {
 
 struct GdmUserChooserWidgetPrivate
 {
-        GtkWidget          *treeview;
-
-        GtkTreeModel       *real_model;
-        GtkTreeModel       *filter_model;
-        GtkTreeModel       *sort_model;
-
         GdmUserManager     *manager;
 
         GdkPixbuf          *logged_in_pixbuf;
-        char               *chosen_user;
-        gboolean            show_only_chosen;
-        gboolean            show_other_user;
-        gboolean            show_guest_user;
 
-        guint               populate_id;
+        guint               show_other_user : 1;
+        guint               show_guest_user : 1;
 };
 
 enum {
         PROP_0,
 };
 
-enum {
-        USER_CHOSEN,
-        LAST_SIGNAL
-};
-
-static guint signals [LAST_SIGNAL] = { 0, };
-
 static void     gdm_user_chooser_widget_class_init  (GdmUserChooserWidgetClass *klass);
 static void     gdm_user_chooser_widget_init        (GdmUserChooserWidget      *user_chooser_widget);
 static void     gdm_user_chooser_widget_finalize    (GObject                   *object);
 
-G_DEFINE_TYPE (GdmUserChooserWidget, gdm_user_chooser_widget, GTK_TYPE_VBOX)
-
-enum {
-        CHOOSER_LIST_PIXBUF_COLUMN = 0,
-        CHOOSER_LIST_NAME_COLUMN,
-        CHOOSER_LIST_TOOLTIP_COLUMN,
-        CHOOSER_LIST_IS_LOGGED_IN_COLUMN,
-        CHOOSER_LIST_ID_COLUMN
-};
-
-void
-gdm_user_chooser_widget_set_show_only_chosen (GdmUserChooserWidget *widget,
-                                              gboolean              show_only)
-{
-        g_return_if_fail (GDM_IS_USER_CHOOSER_WIDGET (widget));
-
-        if (widget->priv->show_only_chosen != show_only) {
-                widget->priv->show_only_chosen = show_only;
-                if (widget->priv->filter_model != NULL) {
-                        gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (widget->priv->filter_model));
-                }
-        }
-}
+G_DEFINE_TYPE (GdmUserChooserWidget, gdm_user_chooser_widget, GDM_TYPE_CHOOSER_WIDGET)
 
 void
 gdm_user_chooser_widget_set_show_other_user (GdmUserChooserWidget *widget,
@@ -111,9 +74,6 @@ gdm_user_chooser_widget_set_show_other_user (GdmUserChooserWidget *widget,
 
         if (widget->priv->show_other_user != show_user) {
                 widget->priv->show_other_user = show_user;
-                if (widget->priv->filter_model != NULL) {
-                        gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (widget->priv->filter_model));
-                }
         }
 }
 
@@ -125,122 +85,15 @@ gdm_user_chooser_widget_set_show_guest_user (GdmUserChooserWidget *widget,
 
         if (widget->priv->show_guest_user != show_user) {
                 widget->priv->show_guest_user = show_user;
-                if (widget->priv->filter_model != NULL) {
-                        gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (widget->priv->filter_model));
-                }
         }
 }
 
 char *
 gdm_user_chooser_widget_get_chosen_user_name (GdmUserChooserWidget *widget)
 {
-        char *user_name;
-
         g_return_val_if_fail (GDM_IS_USER_CHOOSER_WIDGET (widget), NULL);
 
-        user_name = NULL;
-        if (widget->priv->chosen_user != NULL) {
-                user_name = g_strdup (widget->priv->chosen_user);
-        }
-
-        return user_name;
-}
-
-static void
-activate_name (GdmUserChooserWidget *widget,
-               const char           *name)
-{
-        GtkTreeModel *model;
-        GtkTreeIter   iter;
-        GtkTreePath  *path;
-
-        path = NULL;
-
-        model = widget->priv->real_model;
-
-        if (name != NULL && gtk_tree_model_get_iter_first (model, &iter)) {
-
-                do {
-                        char           *id;
-                        gboolean        found;
-
-                        id = NULL;
-                        gtk_tree_model_get (model,
-                                            &iter,
-                                            CHOOSER_LIST_ID_COLUMN, &id,
-                                            -1);
-                        if (id == NULL) {
-                                continue;
-                        }
-
-                        found = (strcmp (id, name) == 0);
-
-                        if (found) {
-                                path = gtk_tree_model_get_path (model, &iter);
-                                break;
-                        }
-
-                } while (gtk_tree_model_iter_next (model, &iter));
-        }
-
-        if (path != NULL) {
-                gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (widget->priv->treeview),
-                                              path,
-                                              NULL,
-                                              TRUE,
-                                              0.5,
-                                              0.0);
-                gtk_tree_view_set_cursor (GTK_TREE_VIEW (widget->priv->treeview),
-                                          path,
-                                          NULL,
-                                          FALSE);
-
-                gtk_tree_view_row_activated (GTK_TREE_VIEW (widget->priv->treeview),
-                                             path,
-                                             NULL);
-                gtk_tree_path_free (path);
-        }
-}
-
-static void
-choose_user_id (GdmUserChooserWidget *widget,
-                const char           *id)
-{
-
-        g_debug ("GdmUserChooserWidget: Selection changed from:'%s' to:'%s'",
-                 widget->priv->chosen_user ? widget->priv->chosen_user : "",
-                 id ? id : "");
-
-        g_free (widget->priv->chosen_user);
-        widget->priv->chosen_user = g_strdup (id);
-
-        gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (widget->priv->filter_model));
-}
-
-static void
-choose_selected_user (GdmUserChooserWidget *widget)
-{
-        char             *id;
-        GtkTreeSelection *selection;
-        GtkTreeModel     *model;
-        GtkTreeIter       iter;
-
-        id = NULL;
-
-        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget->priv->treeview));
-        if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
-                gtk_tree_model_get (model, &iter, CHOOSER_LIST_ID_COLUMN, &id, -1);
-        }
-
-        choose_user_id (widget, id);
-}
-
-static void
-clear_selection (GdmUserChooserWidget *widget)
-{
-        GtkTreeSelection *selection;
-        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget->priv->treeview));
-        gtk_tree_selection_unselect_all (selection);
+        return gdm_chooser_widget_get_active_item (GDM_CHOOSER_WIDGET (widget));
 }
 
 void
@@ -249,14 +102,18 @@ gdm_user_chooser_widget_set_chosen_user_name (GdmUserChooserWidget *widget,
 {
         g_return_if_fail (GDM_IS_USER_CHOOSER_WIDGET (widget));
 
-        if (name == NULL) {
-                clear_selection (widget);
-                choose_user_id (widget, NULL);
-        } else {
-                activate_name (widget, name);
-        }
+        gdm_chooser_widget_set_active_item (GDM_CHOOSER_WIDGET (widget), name);
 }
 
+void
+gdm_user_chooser_widget_set_show_only_chosen (GdmUserChooserWidget *widget,
+                                              gboolean              show_only) {
+        g_return_if_fail (GDM_IS_USER_CHOOSER_WIDGET (widget));
+
+        gdm_chooser_widget_set_hide_inactive_items (GDM_CHOOSER_WIDGET (widget),
+                                                    show_only);
+
+}
 static void
 gdm_user_chooser_widget_set_property (GObject        *object,
                                       guint           prop_id,
@@ -315,55 +172,22 @@ gdm_user_chooser_widget_dispose (GObject *object)
 
         widget = GDM_USER_CHOOSER_WIDGET (object);
 
-        g_free (widget->priv->chosen_user);
-        widget->priv->chosen_user = NULL;
-
         G_OBJECT_CLASS (gdm_user_chooser_widget_parent_class)->dispose (object);
 }
 
 static void
 gdm_user_chooser_widget_class_init (GdmUserChooserWidgetClass *klass)
 {
-        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
-
+        GObjectClass          *object_class = G_OBJECT_CLASS (klass);
         object_class->get_property = gdm_user_chooser_widget_get_property;
         object_class->set_property = gdm_user_chooser_widget_set_property;
         object_class->constructor = gdm_user_chooser_widget_constructor;
         object_class->dispose = gdm_user_chooser_widget_dispose;
         object_class->finalize = gdm_user_chooser_widget_finalize;
 
-        signals [USER_CHOSEN] = g_signal_new ("user-chosen",
-                                              G_TYPE_FROM_CLASS (object_class),
-                                              G_SIGNAL_RUN_LAST,
-                                              G_STRUCT_OFFSET (GdmUserChooserWidgetClass, user_chosen),
-                                              NULL,
-                                              NULL,
-                                              g_cclosure_marshal_VOID__VOID,
-                                              G_TYPE_NONE,
-                                              0);
-
         g_type_class_add_private (klass, sizeof (GdmUserChooserWidgetPrivate));
 }
 
-static void
-on_selection_changed (GtkTreeSelection     *selection,
-                      GdmUserChooserWidget *widget)
-{
-}
-
-static void
-on_row_activated (GtkTreeView          *tree_view,
-                  GtkTreePath          *tree_path,
-                  GtkTreeViewColumn    *tree_column,
-                  GdmUserChooserWidget *widget)
-{
-        choose_selected_user (widget);
-
-        g_signal_emit (widget, signals[USER_CHOSEN], 0);
-
-        clear_selection (widget);
-}
-
 static GdkPixbuf *
 get_pixbuf_for_user (GdmUserChooserWidget *widget,
                      const char           *username)
@@ -394,107 +218,37 @@ get_logged_in_pixbuf (GdmUserChooserWidget *widget)
 }
 
 static gboolean
-populate_model (GdmUserChooserWidget *widget)
+add_special_users (GdmUserChooserWidget *widget)
 {
-        GtkTreeIter iter;
         GdkPixbuf  *pixbuf;
 
         widget->priv->logged_in_pixbuf = get_logged_in_pixbuf (widget);
 
         pixbuf = get_pixbuf_for_user (widget, NULL);
 
-        /* Add some fake entries */
-        gtk_list_store_append (GTK_LIST_STORE (widget->priv->real_model), &iter);
-        gtk_list_store_set (GTK_LIST_STORE (widget->priv->real_model), &iter,
-                            CHOOSER_LIST_PIXBUF_COLUMN, pixbuf,
-                            CHOOSER_LIST_NAME_COLUMN, _("Other..."),
-                            CHOOSER_LIST_TOOLTIP_COLUMN, _("Choose a different account"),
-                            CHOOSER_LIST_IS_LOGGED_IN_COLUMN, FALSE,
-                            CHOOSER_LIST_ID_COLUMN, GDM_USER_CHOOSER_USER_OTHER,
-                            -1);
-
-        gtk_list_store_append (GTK_LIST_STORE (widget->priv->real_model), &iter);
-        gtk_list_store_set (GTK_LIST_STORE (widget->priv->real_model), &iter,
-                            CHOOSER_LIST_PIXBUF_COLUMN, pixbuf,
-                            CHOOSER_LIST_NAME_COLUMN, _("Guest"),
-                            CHOOSER_LIST_TOOLTIP_COLUMN, _("Login as a temporary guest"),
-                            CHOOSER_LIST_IS_LOGGED_IN_COLUMN, FALSE,
-                            CHOOSER_LIST_ID_COLUMN, GDM_USER_CHOOSER_USER_GUEST,
-                            -1);
-
+        gdm_chooser_widget_add_item (GDM_CHOOSER_WIDGET (widget),
+                                     GDM_USER_CHOOSER_USER_OTHER,
+                                     pixbuf, _("Other..."),
+                                     _("Choose a different account"), FALSE,
+                                     TRUE);
+
+        gdm_chooser_widget_add_item (GDM_CHOOSER_WIDGET (widget),
+                                     GDM_USER_CHOOSER_USER_GUEST,
+                                     pixbuf, _("Guest"),
+                                     _("Login as a temporary guest"), FALSE,
+                                     TRUE);
         if (pixbuf != NULL) {
                 g_object_unref (pixbuf);
         }
 
-        widget->priv->populate_id = 0;
         return FALSE;
 }
 
-static int
-compare_user_names (char *name_a,
-                    char *name_b,
-                    char *id_a,
-                    char *id_b)
-{
-
-        if (id_a == NULL) {
-                return 1;
-        } else if (id_b == NULL) {
-                return -1;
-        }
-
-        if (strcmp (id_a, "__other") == 0) {
-                return 1;
-        } else if (strcmp (id_b, "__other") == 0) {
-                return -1;
-        } else if (strcmp (id_a, "__guest") == 0) {
-                return 1;
-        } else if (strcmp (id_b, "__guest") == 0) {
-                return -1;
-        }
-
-        if (name_a == NULL) {
-                return 1;
-        } else if (name_b == NULL) {
-                return -1;
-        }
-
-        return g_utf8_collate (name_a, name_b);
-}
-
-static int
-compare_user  (GtkTreeModel *model,
-                  GtkTreeIter  *a,
-                  GtkTreeIter  *b,
-                  gpointer      user_data)
-{
-        char *name_a;
-        char *name_b;
-        char *id_a;
-        char *id_b;
-        int   result;
-
-        gtk_tree_model_get (model, a, CHOOSER_LIST_NAME_COLUMN, &name_a, -1);
-        gtk_tree_model_get (model, b, CHOOSER_LIST_NAME_COLUMN, &name_b, -1);
-        gtk_tree_model_get (model, a, CHOOSER_LIST_ID_COLUMN, &id_a, -1);
-        gtk_tree_model_get (model, b, CHOOSER_LIST_ID_COLUMN, &id_b, -1);
-
-        result = compare_user_names (name_a, name_b, id_a, id_b);
-
-        g_free (name_a);
-        g_free (name_b);
-        g_free (id_a);
-        g_free (id_b);
-
-        return result;
-}
-
 static void
 on_user_added (GdmUserManager       *manager,
                GdmUser              *user,
                GdmUserChooserWidget *widget)
 {
-        GtkTreeIter   iter;
         GdkPixbuf    *pixbuf;
         char         *tooltip;
 
@@ -502,18 +256,13 @@ on_user_added (GdmUserManager       *manager,
 
         pixbuf = gdm_user_render_icon (user, GTK_WIDGET (widget), ICON_SIZE);
 
-        tooltip = g_strdup_printf ("%s: %s",
-                                   _("Short Name"),
+        tooltip = g_strdup_printf (_("Log in as %s"),
                                    gdm_user_get_user_name (user));
 
-        gtk_list_store_append (GTK_LIST_STORE (widget->priv->real_model), &iter);
-        gtk_list_store_set (GTK_LIST_STORE (widget->priv->real_model), &iter,
-                            CHOOSER_LIST_PIXBUF_COLUMN, pixbuf,
-                            CHOOSER_LIST_NAME_COLUMN, gdm_user_get_real_name (user),
-                            CHOOSER_LIST_TOOLTIP_COLUMN, tooltip,
-                            CHOOSER_LIST_IS_LOGGED_IN_COLUMN, gdm_user_get_num_sessions (user) > 0,
-                            CHOOSER_LIST_ID_COLUMN, gdm_user_get_user_name (user),
-                            -1);
+        gdm_chooser_widget_add_item (GDM_CHOOSER_WIDGET (widget),
+                                     gdm_user_get_user_name (user),
+                                     pixbuf, gdm_user_get_real_name (user),
+                                     tooltip, FALSE, FALSE);
         g_free (tooltip);
 
         if (pixbuf != NULL) {
@@ -526,41 +275,14 @@ on_user_removed (GdmUserManager       *manager,
                  GdmUser              *user,
                  GdmUserChooserWidget *widget)
 {
-        GtkTreeIter iter;
-        gboolean    found;
         const char *user_name;
 
         g_debug ("GdmUserChooserWidget: User removed: %s", gdm_user_get_user_name (user));
 
-        found = FALSE;
-
         user_name = gdm_user_get_user_name (user);
 
-        if (gtk_tree_model_get_iter_first (widget->priv->real_model, &iter)) {
-
-                do {
-                        char *id;
-
-                        id = NULL;
-                        gtk_tree_model_get (widget->priv->real_model,
-                                            &iter,
-                                            CHOOSER_LIST_ID_COLUMN, &id,
-                                            -1);
-                        if (id == NULL) {
-                                continue;
-                        }
-
-                        found = (strcmp (id, user_name) == 0);
-
-                        if (found) {
-                                break;
-                        }
-
-                } while (gtk_tree_model_iter_next (widget->priv->real_model, &iter));
-        }
-        if (found) {
-                gtk_list_store_remove (GTK_LIST_STORE (widget->priv->real_model), &iter);
-        }
+        gdm_chooser_widget_remove_item (GDM_CHOOSER_WIDGET (widget),
+                                        user_name);
 }
 
 static void
@@ -568,162 +290,28 @@ on_user_is_logged_in_changed (GdmUserManager       *manager,
                               GdmUser              *user,
                               GdmUserChooserWidget *widget)
 {
-        GtkTreeIter iter;
-        gboolean    found;
         const char *user_name;
         gboolean    is_logged_in;
 
         g_debug ("GdmUserChooserWidget: User logged in changed: %s", gdm_user_get_user_name (user));
 
-        found = FALSE;
-
         user_name = gdm_user_get_user_name (user);
         is_logged_in = gdm_user_get_num_sessions (user) > 0;
 
-        if (gtk_tree_model_get_iter_first (widget->priv->real_model, &iter)) {
-
-                do {
-                        char *id;
-
-                        id = NULL;
-                        gtk_tree_model_get (widget->priv->real_model,
-                                            &iter,
-                                            CHOOSER_LIST_ID_COLUMN, &id,
-                                            -1);
-                        if (id == NULL) {
-                                continue;
-                        }
-
-                        found = (strcmp (id, user_name) == 0);
-
-                        if (found) {
-                                break;
-                        }
-
-                } while (gtk_tree_model_iter_next (widget->priv->real_model, &iter));
-        }
-
-        if (found) {
-                gtk_list_store_set (GTK_LIST_STORE (widget->priv->real_model),
-                                    &iter,
-                                    CHOOSER_LIST_IS_LOGGED_IN_COLUMN, is_logged_in,
-                                    -1);
-        }
-}
-
-static gboolean
-user_visible_cb (GtkTreeModel         *model,
-                 GtkTreeIter          *iter,
-                 GdmUserChooserWidget *widget)
-{
-        char    *id;
-        gboolean ret;
-
-        ret = FALSE;
-
-        id = NULL;
-        gtk_tree_model_get (model, iter, CHOOSER_LIST_ID_COLUMN, &id, -1);
-        if (id == NULL) {
-                goto out;
-        }
-
-        /* if a user is chosen */
-        if (widget->priv->chosen_user != NULL
-            && widget->priv->show_only_chosen) {
-
-                ret = (strcmp (id, widget->priv->chosen_user) == 0);
-                goto out;
-        }
-
-        if (! widget->priv->show_other_user
-            && strcmp (id, GDM_USER_CHOOSER_USER_OTHER) == 0) {
-                ret = FALSE;
-                goto out;
-        }
-        if (! widget->priv->show_guest_user
-            && strcmp (id, GDM_USER_CHOOSER_USER_GUEST) == 0) {
-                ret = FALSE;
-                goto out;
-        }
-
-        ret = TRUE;
-
- out:
-        g_free (id);
-
-        return ret;
-}
-
-static void
-name_cell_data_func (GtkTreeViewColumn    *tree_column,
-                     GtkCellRenderer      *cell,
-                     GtkTreeModel         *model,
-                     GtkTreeIter          *iter,
-                     GdmUserChooserWidget *widget)
-{
-        gboolean logged_in;
-        char    *name;
-        char    *markup;
-
-        name = NULL;
-        gtk_tree_model_get (model,
-                            iter,
-                            CHOOSER_LIST_IS_LOGGED_IN_COLUMN, &logged_in,
-                            CHOOSER_LIST_NAME_COLUMN, &name,
-                            -1);
-
-        if (logged_in) {
-                markup = g_strdup_printf ("<b>%s</b>\n<i><span size=\"x-small\">%s</span></i>",
-                                          name,
-                                          _("Currently logged in"));
-        } else {
-                markup = g_strdup_printf ("<b>%s</b>", name);
-        }
-
-        g_object_set (cell,
-                      "markup", markup,
-                      NULL);
-
-        g_free (markup);
-        g_free (name);
-}
-
-static void
-check_cell_data_func (GtkTreeViewColumn    *tree_column,
-                      GtkCellRenderer      *cell,
-                      GtkTreeModel         *model,
-                      GtkTreeIter          *iter,
-                      GdmUserChooserWidget *widget)
-{
-        gboolean   logged_in;
-        GdkPixbuf *pixbuf;
-
-        gtk_tree_model_get (model,
-                            iter,
-                            CHOOSER_LIST_IS_LOGGED_IN_COLUMN, &logged_in,
-                            -1);
-
-        if (logged_in) {
-                pixbuf = widget->priv->logged_in_pixbuf;
-        } else {
-                pixbuf = NULL;
-        }
-
-        g_object_set (cell,
-                      "pixbuf", pixbuf,
-                      NULL);
+        gdm_chooser_widget_set_item_in_use (GDM_CHOOSER_WIDGET (widget),
+                                            user_name, is_logged_in);
 }
 
 static void
 gdm_user_chooser_widget_init (GdmUserChooserWidget *widget)
 {
-        GtkWidget         *scrolled;
-        GtkTreeViewColumn *column;
-        GtkTreeSelection  *selection;
-        GtkCellRenderer   *renderer;
-
         widget->priv = GDM_USER_CHOOSER_WIDGET_GET_PRIVATE (widget);
 
+        gdm_chooser_widget_set_separator_position (GDM_CHOOSER_WIDGET (widget),
+                                                   GDM_CHOOSER_WIDGET_POSITION_BOTTOM);
+        gdm_chooser_widget_set_in_use_message (GDM_CHOOSER_WIDGET (widget),
+                                               _("Currently logged in"));
+
         widget->priv->manager = gdm_user_manager_ref_default ();
         g_signal_connect (widget->priv->manager,
                           "user-added",
@@ -738,103 +326,7 @@ gdm_user_chooser_widget_init (GdmUserChooserWidget *widget)
                           G_CALLBACK (on_user_is_logged_in_changed),
                           widget);
 
-        scrolled = gtk_scrolled_window_new (NULL, NULL);
-        gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
-                                             GTK_SHADOW_IN);
-        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
-                                        GTK_POLICY_NEVER,
-                                        GTK_POLICY_AUTOMATIC);
-        gtk_box_pack_start (GTK_BOX (widget), scrolled, TRUE, TRUE, 0);
-
-        widget->priv->treeview = gtk_tree_view_new ();
-        gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (widget->priv->treeview), FALSE);
-
-        g_signal_connect (widget->priv->treeview,
-                          "row-activated",
-                          G_CALLBACK (on_row_activated),
-                          widget);
-        gtk_container_add (GTK_CONTAINER (scrolled), widget->priv->treeview);
-
-        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget->priv->treeview));
-        gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
-        g_signal_connect (selection, "changed",
-                          G_CALLBACK (on_selection_changed),
-                          widget);
-
-        widget->priv->real_model = (GtkTreeModel *)gtk_list_store_new (5,
-                                                                       GDK_TYPE_PIXBUF,
-                                                                       G_TYPE_STRING,
-                                                                       G_TYPE_STRING,
-                                                                       G_TYPE_BOOLEAN,
-                                                                       G_TYPE_STRING);
-
-        widget->priv->filter_model = gtk_tree_model_filter_new (widget->priv->real_model, NULL);
-
-        gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (widget->priv->filter_model),
-                                                (GtkTreeModelFilterVisibleFunc) user_visible_cb,
-                                                widget,
-                                                NULL);
-
-        widget->priv->sort_model = gtk_tree_model_sort_new_with_model (widget->priv->filter_model);
-
-        gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (widget->priv->sort_model),
-                                         CHOOSER_LIST_NAME_COLUMN,
-                                         compare_user,
-                                         NULL, NULL);
-
-        gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (widget->priv->sort_model),
-                                              CHOOSER_LIST_NAME_COLUMN,
-                                              GTK_SORT_ASCENDING);
-
-        gtk_tree_view_set_model (GTK_TREE_VIEW (widget->priv->treeview), widget->priv->sort_model);
-
-        /* CHECK COLUMN */
-        renderer = gtk_cell_renderer_pixbuf_new ();
-        column = gtk_tree_view_column_new ();
-        gtk_tree_view_column_pack_start (column, renderer, FALSE);
-        gtk_tree_view_append_column (GTK_TREE_VIEW (widget->priv->treeview), column);
-        gtk_tree_view_column_set_cell_data_func (column,
-                                                 renderer,
-                                                 (GtkTreeCellDataFunc) check_cell_data_func,
-                                                 widget,
-                                                 NULL);
-        g_object_set (renderer,
-                      "width", 96,
-                      "yalign", 0.5,
-                      "xalign", 0.5,
-                      NULL);
-
-        /* FACE COLUMN */
-        renderer = gtk_cell_renderer_pixbuf_new ();
-        column = gtk_tree_view_column_new ();
-        gtk_tree_view_column_pack_start (column, renderer, FALSE);
-        gtk_tree_view_append_column (GTK_TREE_VIEW (widget->priv->treeview), column);
-
-        gtk_tree_view_column_set_attributes (column,
-                                             renderer,
-                                             "pixbuf", CHOOSER_LIST_PIXBUF_COLUMN,
-                                             NULL);
-
-        g_object_set (renderer,
-                      "width", 64,
-                      "yalign", 0.5,
-                      "xalign", 1.0,
-                      NULL);
-
-        /* NAME COLUMN */
-        renderer = gtk_cell_renderer_text_new ();
-        column = gtk_tree_view_column_new ();
-        gtk_tree_view_column_pack_start (column, renderer, FALSE);
-        gtk_tree_view_append_column (GTK_TREE_VIEW (widget->priv->treeview), column);
-        gtk_tree_view_column_set_cell_data_func (column,
-                                                 renderer,
-                                                 (GtkTreeCellDataFunc) name_cell_data_func,
-                                                 widget,
-                                                 NULL);
-
-        gtk_tree_view_set_tooltip_column (GTK_TREE_VIEW (widget->priv->treeview), CHOOSER_LIST_TOOLTIP_COLUMN);
-
-        widget->priv->populate_id = g_idle_add ((GSourceFunc)populate_model, widget);
+        add_special_users (widget);
 }
 
 static void
@@ -849,10 +341,6 @@ gdm_user_chooser_widget_finalize (GObject *object)
 
         g_return_if_fail (widget->priv != NULL);
 
-        if (widget->priv->populate_id > 0) {
-                g_source_remove (widget->priv->populate_id);
-        }
-
         G_OBJECT_CLASS (gdm_user_chooser_widget_parent_class)->finalize (object);
 }
 
@@ -862,6 +350,8 @@ gdm_user_chooser_widget_new (void)
         GObject *object;
 
         object = g_object_new (GDM_TYPE_USER_CHOOSER_WIDGET,
+                               "inactive-text", _("_Users:"),
+                               "active-text", _("_User:"),
                                NULL);
 
         return GTK_WIDGET (object);
diff --git a/gui/simple-greeter/gdm-user-chooser-widget.h b/gui/simple-greeter/gdm-user-chooser-widget.h
index 9c1ef6f..a117fb3 100644
--- a/gui/simple-greeter/gdm-user-chooser-widget.h
+++ b/gui/simple-greeter/gdm-user-chooser-widget.h
@@ -22,7 +22,8 @@
 #define __GDM_USER_CHOOSER_WIDGET_H
 
 #include <glib-object.h>
-#include <gtk/gtkvbox.h>
+
+#include "gdm-chooser-widget.h"
 
 G_BEGIN_DECLS
 
@@ -37,16 +38,13 @@ typedef struct GdmUserChooserWidgetPrivate GdmUserChooserWidgetPrivate;
 
 typedef struct
 {
-        GtkVBox                      parent;
+        GdmChooserWidget            parent;
         GdmUserChooserWidgetPrivate *priv;
 } GdmUserChooserWidget;
 
 typedef struct
 {
-        GtkVBoxClass   parent_class;
-
-        /* signals */
-        void (* user_chosen)        (GdmUserChooserWidget *widget);
+        GdmChooserWidgetClass   parent_class;
 } GdmUserChooserWidgetClass;
 
 #define GDM_USER_CHOOSER_USER_OTHER "__other"
@@ -64,7 +62,6 @@ void                   gdm_user_chooser_widget_set_show_other_user        (GdmUs
                                                                            gboolean              show_other);
 void                   gdm_user_chooser_widget_set_show_guest_user        (GdmUserChooserWidget *widget,
                                                                            gboolean              show_other);
-
 G_END_DECLS
 
 #endif /* __GDM_USER_CHOOSER_WIDGET_H */
-- 
1.5.3.6


4-switch-session-chooser-over.patch:

--- NEW FILE 4-switch-session-chooser-over.patch ---
>From 62276dc527e60a27f951cf73ad8de3fb1c8ced8a Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode at redhat.com>
Date: Thu, 13 Dec 2007 10:14:33 -0500
Subject: [PATCH] Change session-chooser-widget over to use new chooser widget

---
 gui/simple-greeter/gdm-session-chooser-widget.c |  352 +++--------------------
 gui/simple-greeter/gdm-session-chooser-widget.h |   15 +-
 2 files changed, 50 insertions(+), 317 deletions(-)

diff --git a/gui/simple-greeter/gdm-session-chooser-widget.c b/gui/simple-greeter/gdm-session-chooser-widget.c
index 7763da7..849be94 100644
--- a/gui/simple-greeter/gdm-session-chooser-widget.c
+++ b/gui/simple-greeter/gdm-session-chooser-widget.c
@@ -1,6 +1,7 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
  *
  * Copyright (C) 2007 William Jon McCann <mccann at jhu.edu>
+ * Copyright (C) 2007 Ray Strode <rstrode at redhat.com>
  *
  * 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
@@ -34,6 +35,7 @@
 #include <gtk/gtk.h>
 
 #include "gdm-session-chooser-widget.h"
+#include "gdm-chooser-widget.h"
 
 enum {
         DESKTOP_ENTRY_NO_DISPLAY     = 1 << 0,
@@ -54,34 +56,18 @@ typedef struct _GdmChooserSession {
 
 struct GdmSessionChooserWidgetPrivate
 {
-        GtkWidget          *treeview;
-
         GHashTable         *available_sessions;
-        char               *current_session;
 };
 
 enum {
         PROP_0,
 };
 
-enum {
-        SESSION_ACTIVATED,
-        LAST_SIGNAL
-};
-
-static guint signals [LAST_SIGNAL] = { 0, };
-
 static void     gdm_session_chooser_widget_class_init  (GdmSessionChooserWidgetClass *klass);
 static void     gdm_session_chooser_widget_init        (GdmSessionChooserWidget      *session_chooser_widget);
 static void     gdm_session_chooser_widget_finalize    (GObject                       *object);
 
-G_DEFINE_TYPE (GdmSessionChooserWidget, gdm_session_chooser_widget, GTK_TYPE_VBOX)
-
-enum {
-        CHOOSER_LIST_NAME_COLUMN = 0,
-        CHOOSER_LIST_COMMENT_COLUMN,
-        CHOOSER_LIST_ID_COLUMN
-};
+G_DEFINE_TYPE (GdmSessionChooserWidget, gdm_session_chooser_widget, GDM_TYPE_CHOOSER_WIDGET)
 
 static void
 chooser_session_free (GdmChooserSession *session)
@@ -101,89 +87,28 @@ chooser_session_free (GdmChooserSession *session)
 char *
 gdm_session_chooser_widget_get_current_session_name (GdmSessionChooserWidget *widget)
 {
-        char *session_name;
-
         g_return_val_if_fail (GDM_IS_SESSION_CHOOSER_WIDGET (widget), NULL);
-
-        session_name = NULL;
-        if (widget->priv->current_session != NULL) {
-                session_name = g_strdup (widget->priv->current_session);
-        }
-
-        return session_name;
+        return gdm_chooser_widget_get_active_item (GDM_CHOOSER_WIDGET (widget));
 }
 
-static void
-select_name (GdmSessionChooserWidget *widget,
-             const char               *name)
+void
+gdm_session_chooser_widget_set_current_session_name (GdmSessionChooserWidget *widget,
+                                                     const char              *name)
 {
-        GtkTreeModel *model;
-        GtkTreeIter   iter;
-        GtkTreePath  *path;
-
-        path = NULL;
-
-        model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget->priv->treeview));
-
-        if (name != NULL && gtk_tree_model_get_iter_first (model, &iter)) {
-
-                do {
-                        GdmChooserSession *session;
-                        char              *id;
-                        gboolean          found;
-
-                        session = NULL;
-                        id = NULL;
-                        gtk_tree_model_get (model,
-                                            &iter,
-                                            CHOOSER_LIST_ID_COLUMN, &id,
-                                            -1);
-                        if (id != NULL) {
-                                session = g_hash_table_lookup (widget->priv->available_sessions, id);
-                                g_free (id);
-                        }
-
-                        found = (session != NULL
-                                 && session->filename != NULL
-                                 && strcmp (session->filename, name) == 0);
-
-                        if (found) {
-                                path = gtk_tree_model_get_path (model, &iter);
-                                break;
-                        }
-
-                } while (gtk_tree_model_iter_next (model, &iter));
-        }
+        g_return_if_fail (GDM_IS_SESSION_CHOOSER_WIDGET (widget));
 
-        if (path != NULL) {
-                gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (widget->priv->treeview),
-                                              path,
-                                              gtk_tree_view_get_column (GTK_TREE_VIEW (widget->priv->treeview), 0),
-                                              TRUE, 0.5, 0.0);
-                gtk_tree_view_set_cursor (GTK_TREE_VIEW (widget->priv->treeview),
-                                          path,
-                                          NULL,
-                                          FALSE);
-
-                gtk_tree_path_free (path);
-        }
+        gdm_chooser_widget_set_active_item (GDM_CHOOSER_WIDGET (widget),
+                                            name);
 }
 
 void
-gdm_session_chooser_widget_set_current_session_name (GdmSessionChooserWidget *widget,
-                                                     const char              *name)
+gdm_session_chooser_widget_set_show_only_chosen (GdmSessionChooserWidget *widget,
+                                                 gboolean                 show_only)
 {
-        GtkTreeSelection *selection;
-
         g_return_if_fail (GDM_IS_SESSION_CHOOSER_WIDGET (widget));
 
-        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget->priv->treeview));
-
-        if (name == NULL) {
-                gtk_tree_selection_unselect_all (selection);
-        } else {
-                select_name (widget, name);
-        }
+        gdm_chooser_widget_set_hide_inactive_items (GDM_CHOOSER_WIDGET (widget),
+                                                    show_only);
 }
 
 static void
@@ -249,9 +174,6 @@ gdm_session_chooser_widget_dispose (GObject *object)
                 widget->priv->available_sessions = NULL;
         }
 
-        g_free (widget->priv->current_session);
-        widget->priv->current_session = NULL;
-
         G_OBJECT_CLASS (gdm_session_chooser_widget_parent_class)->dispose (object);
 }
 
@@ -266,39 +188,9 @@ gdm_session_chooser_widget_class_init (GdmSessionChooserWidgetClass *klass)
         object_class->dispose = gdm_session_chooser_widget_dispose;
         object_class->finalize = gdm_session_chooser_widget_finalize;
 
-        signals [SESSION_ACTIVATED] = g_signal_new ("session-activated",
-                                                     G_TYPE_FROM_CLASS (object_class),
-                                                     G_SIGNAL_RUN_LAST,
-                                                     G_STRUCT_OFFSET (GdmSessionChooserWidgetClass, session_activated),
-                                                     NULL,
-                                                     NULL,
-                                                     g_cclosure_marshal_VOID__VOID,
-                                                     G_TYPE_NONE,
-                                                     0);
-
         g_type_class_add_private (klass, sizeof (GdmSessionChooserWidgetPrivate));
 }
 
-static void
-on_session_selected (GtkTreeSelection        *selection,
-                     GdmSessionChooserWidget *widget)
-{
-        GtkTreeModel      *model = NULL;
-        GtkTreeIter        iter = {0};
-        char              *id;
-
-        id = NULL;
-
-        if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
-                gtk_tree_model_get (model, &iter, CHOOSER_LIST_ID_COLUMN, &id, -1);
-        }
-
-        g_free (widget->priv->current_session);
-        widget->priv->current_session = g_strdup (id);
-
-        g_free (id);
-}
-
 /* adapted from gnome-menus desktop-entries.c */
 static guint
 get_flags_from_key_file (GKeyFile     *key_file,
@@ -460,21 +352,13 @@ collect_sessions (GdmSessionChooserWidget *widget)
 }
 
 static void
-on_row_activated (GtkTreeView          *tree_view,
-                  GtkTreePath          *tree_path,
-                  GtkTreeViewColumn    *tree_column,
-                  GdmSessionChooserWidget *widget)
-{
-        g_signal_emit (widget, signals[SESSION_ACTIVATED], 0);
-}
-
-static void
-add_session_to_model (const char              *name,
-                      GdmChooserSession       *session,
-                      GdmSessionChooserWidget *widget)
+add_session (const char              *name,
+             GdmChooserSession       *session,
+             GdmSessionChooserWidget *widget)
 {
-        GtkTreeModel *model;
-        GtkTreeIter   iter;
+        g_assert (name != NULL);
+        g_assert (session != NULL);
+        g_assert (GDM_IS_SESSION_CHOOSER_WIDGET (widget));
 
         if (session->flags & DESKTOP_ENTRY_NO_DISPLAY
             || session->flags & DESKTOP_ENTRY_HIDDEN
@@ -483,197 +367,43 @@ add_session_to_model (const char              *name,
                 g_debug ("Not adding session to list: %s", session->filename);
         }
 
-        model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget->priv->treeview));
-
-        gtk_list_store_append (GTK_LIST_STORE (model), &iter);
-        gtk_list_store_set (GTK_LIST_STORE (model),
-                            &iter,
-                            CHOOSER_LIST_NAME_COLUMN, session->translated_name,
-                            CHOOSER_LIST_COMMENT_COLUMN, session->translated_comment,
-                            CHOOSER_LIST_ID_COLUMN, name,
-                            -1);
+        gdm_chooser_widget_add_item (GDM_CHOOSER_WIDGET (widget), name,
+                                     NULL, session->translated_name,
+                                     session->translated_comment, FALSE, FALSE);
 }
 
 static void
-populate_model (GdmSessionChooserWidget *widget,
-                GtkTreeModel            *model)
+add_available_sessions (GdmSessionChooserWidget *widget)
 {
-        GtkTreeIter iter;
-
-        /* Add some fake entries */
-        gtk_list_store_append (GTK_LIST_STORE (model), &iter);
-        gtk_list_store_set (GTK_LIST_STORE (model), &iter,
-                            CHOOSER_LIST_NAME_COLUMN, _("Previous Session"),
-                            CHOOSER_LIST_ID_COLUMN, "__previous-session",
-                            -1);
-
-        gtk_list_store_append (GTK_LIST_STORE (model), &iter);
-        gtk_list_store_set (GTK_LIST_STORE (model), &iter,
-                            CHOOSER_LIST_NAME_COLUMN, _("System Default"),
-                            CHOOSER_LIST_ID_COLUMN, "__default-session",
-                            -1);
-
-        gtk_list_store_append (GTK_LIST_STORE (model), &iter);
-        gtk_list_store_set (GTK_LIST_STORE (model), &iter,
-                            CHOOSER_LIST_NAME_COLUMN, NULL,
-                            CHOOSER_LIST_ID_COLUMN, "__separator",
-                            -1);
+        gdm_chooser_widget_add_item (GDM_CHOOSER_WIDGET (widget),
+                                     GDM_SESSION_CHOOSER_SESSION_PREVIOUS,
+                                     NULL, _("Default"),
+                                     _("Login with the same session as "
+                                       "last time."),
+                                     FALSE, TRUE);
+        gdm_chooser_widget_add_item (GDM_CHOOSER_WIDGET (widget),
+                                     GDM_SESSION_CHOOSER_SESSION_DEFAULT,
+                                     NULL, _("Legacy"),
+                                     _("Login based on preset legacy configuration"),
+                                     FALSE, TRUE);
 
         g_hash_table_foreach (widget->priv->available_sessions,
-                              (GHFunc)add_session_to_model,
+                              (GHFunc) add_session,
                               widget);
 }
 
-static gboolean
-separator_func (GtkTreeModel *model,
-                GtkTreeIter  *iter,
-                gpointer      data)
-{
-        int   column = GPOINTER_TO_INT (data);
-        char *text;
-
-        gtk_tree_model_get (model, iter, column, &text, -1);
-
-        if (text != NULL && strcmp (text, "__separator") == 0) {
-                return TRUE;
-        }
-
-        g_free (text);
-
-        return FALSE;
-}
-
-static int
-compare_session_names (char *name_a,
-                       char *name_b,
-                       char *id_a,
-                       char *id_b)
-{
-
-        if (id_a == NULL) {
-                return 1;
-        } else if (id_b == NULL) {
-                return -1;
-        }
-
-        if (strcmp (id_a, "__previous-session") == 0) {
-                return -1;
-        } else if (strcmp (id_b, "__previous-session") == 0) {
-                return 1;
-        } else if (strcmp (id_a, "__default-session") == 0) {
-                return -1;
-        } else if (strcmp (id_b, "__default-session") == 0) {
-                return 1;
-        } else if (strcmp (id_a, "__separator") == 0) {
-                return -1;
-        } else if (strcmp (id_b, "__separator") == 0) {
-                return 1;
-        }
-
-        if (name_a == NULL) {
-                return 1;
-        } else if (name_b == NULL) {
-                return -1;
-        }
-
-        return g_utf8_collate (name_a, name_b);
-}
-
-static int
-compare_session  (GtkTreeModel *model,
-                  GtkTreeIter  *a,
-                  GtkTreeIter  *b,
-                  gpointer      user_data)
-{
-        char *name_a;
-        char *name_b;
-        char *id_a;
-        char *id_b;
-        int   result;
-
-        gtk_tree_model_get (model, a, CHOOSER_LIST_NAME_COLUMN, &name_a, -1);
-        gtk_tree_model_get (model, b, CHOOSER_LIST_NAME_COLUMN, &name_b, -1);
-        gtk_tree_model_get (model, a, CHOOSER_LIST_ID_COLUMN, &id_a, -1);
-        gtk_tree_model_get (model, b, CHOOSER_LIST_ID_COLUMN, &id_b, -1);
-
-        result = compare_session_names (name_a, name_b, id_a, id_b);
-
-        g_free (name_a);
-        g_free (name_b);
-        g_free (id_a);
-        g_free (id_b);
-
-        return result;
-}
-
 static void
 gdm_session_chooser_widget_init (GdmSessionChooserWidget *widget)
 {
-        GtkWidget         *scrolled;
-        GtkTreeSelection  *selection;
-        GtkTreeViewColumn *column;
-        GtkTreeModel      *model;
-
         widget->priv = GDM_SESSION_CHOOSER_WIDGET_GET_PRIVATE (widget);
 
+        gdm_chooser_widget_set_separator_position (GDM_CHOOSER_WIDGET (widget),
+                                                   GDM_CHOOSER_WIDGET_POSITION_TOP);
         widget->priv->available_sessions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)chooser_session_free);
 
-        scrolled = gtk_scrolled_window_new (NULL, NULL);
-        gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
-                                             GTK_SHADOW_IN);
-        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
-                                        GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
-        gtk_box_pack_start (GTK_BOX (widget), scrolled, TRUE, TRUE, 0);
-
-        widget->priv->treeview = gtk_tree_view_new ();
-        gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (widget->priv->treeview), FALSE);
-        g_signal_connect (widget->priv->treeview,
-                          "row-activated",
-                          G_CALLBACK (on_row_activated),
-                          widget);
-        gtk_container_add (GTK_CONTAINER (scrolled), widget->priv->treeview);
-
-        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget->priv->treeview));
-        gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
-        g_signal_connect (selection, "changed",
-                          G_CALLBACK (on_session_selected),
-                          widget);
-
-        model = (GtkTreeModel *)gtk_list_store_new (3,
-                                                    G_TYPE_STRING,
-                                                    G_TYPE_STRING,
-                                                    G_TYPE_STRING);
-        gtk_tree_view_set_model (GTK_TREE_VIEW (widget->priv->treeview), model);
-
-        column = gtk_tree_view_column_new_with_attributes ("Session",
-                                                           gtk_cell_renderer_text_new (),
-                                                           "text", CHOOSER_LIST_NAME_COLUMN,
-                                                           NULL);
-        gtk_tree_view_append_column (GTK_TREE_VIEW (widget->priv->treeview), column);
-
-        column = gtk_tree_view_column_new_with_attributes ("Comment",
-                                                           gtk_cell_renderer_text_new (),
-                                                           "text", CHOOSER_LIST_COMMENT_COLUMN,
-                                                           NULL);
-        gtk_tree_view_append_column (GTK_TREE_VIEW (widget->priv->treeview), column);
-
-        gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (model),
-                                         CHOOSER_LIST_NAME_COLUMN,
-                                         compare_session,
-                                         NULL, NULL);
-
-        gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model),
-                                              CHOOSER_LIST_NAME_COLUMN,
-                                              GTK_SORT_ASCENDING);
-
-        gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (widget->priv->treeview),
-                                              separator_func,
-                                              GINT_TO_POINTER (CHOOSER_LIST_ID_COLUMN),
-                                              NULL);
-
         collect_sessions (widget);
 
-        populate_model (widget, model);
+        add_available_sessions (widget);
 }
 
 static void
@@ -696,7 +426,9 @@ gdm_session_chooser_widget_new (void)
 {
         GObject *object;
 
-        object = g_object_new (GDM_TYPE_SESSION_CHOOSER_WIDGET,
+        object = g_object_new (GDM_TYPE_SESSION_CHOOSER_WIDGET, 
+                               "inactive-text", _("_Sessions:"),
+                               "active-text", _("_Session:"),
                                NULL);
 
         return GTK_WIDGET (object);
diff --git a/gui/simple-greeter/gdm-session-chooser-widget.h b/gui/simple-greeter/gdm-session-chooser-widget.h
index ec32b23..63ea466 100644
--- a/gui/simple-greeter/gdm-session-chooser-widget.h
+++ b/gui/simple-greeter/gdm-session-chooser-widget.h
@@ -22,7 +22,7 @@
 #define __GDM_SESSION_CHOOSER_WIDGET_H
 
 #include <glib-object.h>
-#include <gtk/gtkvbox.h>
+#include "gdm-chooser-widget.h"
 
 G_BEGIN_DECLS
 
@@ -37,25 +37,26 @@ typedef struct GdmSessionChooserWidgetPrivate GdmSessionChooserWidgetPrivate;
 
 typedef struct
 {
-        GtkVBox                         parent;
+        GdmChooserWidget                parent;
         GdmSessionChooserWidgetPrivate *priv;
 } GdmSessionChooserWidget;
 
 typedef struct
 {
-        GtkVBoxClass   parent_class;
-
-        /* signals */
-        void (* session_activated)        (GdmSessionChooserWidget *widget);
+        GdmChooserWidgetClass   parent_class;
 } GdmSessionChooserWidgetClass;
 
+#define GDM_SESSION_CHOOSER_SESSION_PREVIOUS "__previous-session"
+#define GDM_SESSION_CHOOSER_SESSION_DEFAULT "__default-session"
+
 GType                  gdm_session_chooser_widget_get_type                      (void);
 GtkWidget *            gdm_session_chooser_widget_new                           (void);
 
 char *                 gdm_session_chooser_widget_get_current_session_name      (GdmSessionChooserWidget *widget);
 void                   gdm_session_chooser_widget_set_current_session_name      (GdmSessionChooserWidget *widget,
                                                                                  const char              *session_name);
-
+void                   gdm_session_chooser_widget_set_show_only_chosen          (GdmSessionChooserWidget *widget,
+                                                                                 gboolean                 show_only);
 G_END_DECLS
 
 #endif /* __GDM_SESSION_CHOOSER_WIDGET_H */
-- 
1.5.3.6


5-dont-shrink-in-test-program.patch:

--- NEW FILE 5-dont-shrink-in-test-program.patch ---
>From ed5e63fbb8cf281f8e7bfd8062b3f453fcb3d279 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode at redhat.com>
Date: Thu, 13 Dec 2007 10:16:37 -0500
Subject: [PATCH] Don't shrink to chosen item by by default for dialog

---
 gui/simple-greeter/gdm-user-chooser-dialog.c |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/gui/simple-greeter/gdm-user-chooser-dialog.c b/gui/simple-greeter/gdm-user-chooser-dialog.c
index f3e83a2..4848177 100644
--- a/gui/simple-greeter/gdm-user-chooser-dialog.c
+++ b/gui/simple-greeter/gdm-user-chooser-dialog.c
@@ -154,7 +154,6 @@ gdm_user_chooser_dialog_init (GdmUserChooserDialog *dialog)
         dialog->priv = GDM_USER_CHOOSER_DIALOG_GET_PRIVATE (dialog);
 
         dialog->priv->chooser_widget = gdm_user_chooser_widget_new ();
-        gdm_user_chooser_widget_set_show_only_chosen (GDM_USER_CHOOSER_WIDGET (dialog->priv->chooser_widget), TRUE);
         gdm_user_chooser_widget_set_show_other_user (GDM_USER_CHOOSER_WIDGET (dialog->priv->chooser_widget), TRUE);
         gdm_user_chooser_widget_set_show_guest_user (GDM_USER_CHOOSER_WIDGET (dialog->priv->chooser_widget), TRUE);
         gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), dialog->priv->chooser_widget);
-- 
1.5.3.6


6-session-chooser-in-login-window.patch:

--- NEW FILE 6-session-chooser-in-login-window.patch ---
>From 755e5e94e6f06ff688497fe876e243836480a2c0 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode at redhat.com>
Date: Thu, 13 Dec 2007 10:59:21 -0500
Subject: [PATCH] Add session chooser and greeter-login-window
 This change adds the session chooser to the login window.
 It changes the mechanism by the choosers are specified in
 the glade file to use custom widgets.

---
 gui/simple-greeter/Makefile.am                    |    2 +
 gui/simple-greeter/gdm-greeter-login-window.c     |  148 ++-
 gui/simple-greeter/gdm-greeter-login-window.glade | 1279 +++++++++++++--------
 3 files changed, 929 insertions(+), 500 deletions(-)

diff --git a/gui/simple-greeter/Makefile.am b/gui/simple-greeter/Makefile.am
index 836c620..e64f9fb 100644
--- a/gui/simple-greeter/Makefile.am
+++ b/gui/simple-greeter/Makefile.am
@@ -47,6 +47,8 @@ test_greeter_login_window_SOURCES = 	\
 	gdm-greeter-login-window.c	\
 	gdm-chooser-widget.h		\
 	gdm-chooser-widget.c		\
+	gdm-session-chooser-widget.h	\
+	gdm-session-chooser-widget.c	\
 	gdm-user-chooser-widget.h	\
 	gdm-user-chooser-widget.c	\
 	gdm-user-chooser-dialog.h	\
diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
index efc341e..ca14b38 100644
--- a/gui/simple-greeter/gdm-greeter-login-window.c
+++ b/gui/simple-greeter/gdm-greeter-login-window.c
@@ -36,12 +36,16 @@
 #include <glib/gi18n.h>
 #include <glib/gstdio.h>
 #include <glib-object.h>
+
+#include <gdk/gdkx.h>
+
 #include <gtk/gtk.h>
 
 #include <glade/glade-xml.h>
 
 #include "gdm-greeter-login-window.h"
 #include "gdm-user-chooser-widget.h"
+#include "gdm-session-chooser-widget.h"
 
 #if HAVE_PAM
 #include <security/pam_appl.h>
@@ -62,6 +66,7 @@ enum {
 struct GdmGreeterLoginWindowPrivate
 {
         GladeXML        *xml;
+        GtkWidget       *session_chooser;
         GtkWidget       *user_chooser;
         gboolean         display_is_local;
         char            *timeformat;
@@ -177,7 +182,7 @@ switch_mode (GdmGreeterLoginWindow *login_window,
              int                    number)
 {
         const char *default_name;
-        GtkWidget  *user_list;
+        GtkWidget  *user_chooser;
         GtkWidget  *box;
 
         /* FIXME: do animation */
@@ -191,6 +196,7 @@ switch_mode (GdmGreeterLoginWindow *login_window,
                 show_widget (login_window, "suspend-button", login_window->priv->display_is_local);
                 show_widget (login_window, "disconnect-button", ! login_window->priv->display_is_local);
                 show_widget (login_window, "auth-input-box", FALSE);
+                show_widget (login_window, "session-chooser", FALSE);
                 default_name = NULL;
                 break;
         case MODE_AUTHENTICATION:
@@ -201,6 +207,7 @@ switch_mode (GdmGreeterLoginWindow *login_window,
                 show_widget (login_window, "suspend-button", FALSE);
                 show_widget (login_window, "disconnect-button", FALSE);
                 show_widget (login_window, "auth-input-box", TRUE);
+                show_widget (login_window, "session-chooser", TRUE);
                 default_name = "log-in-button";
                 break;
         default:
@@ -211,14 +218,21 @@ switch_mode (GdmGreeterLoginWindow *login_window,
         gtk_button_box_set_layout (GTK_BUTTON_BOX (box),
                                    (number == MODE_SELECTION) ? GTK_BUTTONBOX_SPREAD : GTK_BUTTONBOX_END );
 
-        box = glade_xml_get_widget (login_window->priv->xml, "selection-box");
-        user_list = glade_xml_get_widget (login_window->priv->xml, "userlist-box");
-        gtk_box_set_child_packing (GTK_BOX (box),
-                                   user_list,
-                                   number == MODE_SELECTION,
-                                   number == MODE_SELECTION,
-                                   10,
-                                   GTK_PACK_START);
+        user_chooser = glade_xml_get_widget (login_window->priv->xml, "user-chooser");
+        box = gtk_widget_get_parent (user_chooser);
+        if (GTK_IS_BOX (box)) {
+            guint padding;
+            GtkPackType pack_type;
+
+            gtk_box_query_child_packing (GTK_BOX (box), user_chooser,
+                                         NULL, NULL, &padding, &pack_type);
+            gtk_box_set_child_packing (GTK_BOX (box),
+                                       user_chooser,
+                                       number == MODE_SELECTION,
+                                       number == MODE_SELECTION,
+                                       padding, pack_type);
+        }
+
         if (default_name != NULL) {
                 GtkWidget *widget;
 
@@ -230,7 +244,10 @@ switch_mode (GdmGreeterLoginWindow *login_window,
 static void
 do_cancel (GdmGreeterLoginWindow *login_window)
 {
+
         gdm_user_chooser_widget_set_chosen_user_name (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser), NULL);
+        gdm_session_chooser_widget_set_current_session_name (GDM_SESSION_CHOOSER_WIDGET (login_window->priv->session_chooser),
+                                                             GDM_SESSION_CHOOSER_SESSION_PREVIOUS);
 
         switch_mode (login_window, MODE_SELECTION);
         set_busy (login_window);
@@ -259,6 +276,8 @@ reset_dialog (GdmGreeterLoginWindow *login_window)
         set_message (login_window, "");
 
         gdm_user_chooser_widget_set_chosen_user_name (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser), NULL);
+        gdm_session_chooser_widget_set_current_session_name (GDM_SESSION_CHOOSER_WIDGET (login_window->priv->session_chooser),
+                                                             GDM_SESSION_CHOOSER_SESSION_PREVIOUS);
 
         switch_mode (login_window, MODE_SELECTION);
 
@@ -458,6 +477,29 @@ on_user_chosen (GdmUserChooserWidget  *user_chooser,
 }
 
 static void
+on_user_unchosen (GdmUserChooserWidget  *user_chooser,
+                     GdmGreeterLoginWindow *login_window)
+{
+        do_cancel (login_window);
+}
+
+static void
+on_session_activated (GdmSessionChooserWidget *session_chooser,
+                      GdmGreeterLoginWindow   *login_window)
+{
+        char *session;
+
+        session = gdm_session_chooser_widget_get_current_session_name (GDM_SESSION_CHOOSER_WIDGET (login_window->priv->session_chooser));
+        if (session == NULL) {
+                return;
+        }
+
+        g_signal_emit (login_window, signals[SESSION_SELECTED], 0, session);
+
+        g_free (session);
+}
+
+static void
 update_clock (GtkLabel   *label,
               const char *format)
 {
@@ -706,6 +748,37 @@ create_computer_info (GdmGreeterLoginWindow *login_window)
 #define INVISIBLE_CHAR_BULLET        0x2022
 #define INVISIBLE_CHAR_NONE          0
 
+static GtkWidget *
+custom_widget_constructor (GladeXML              *xml,
+                           char                  *func_name,
+                           char                  *name,
+                           char                  *string1,
+                           char                  *string2,
+                           int                    int1,
+                           int                    int2,
+                           GdmGreeterLoginWindow *login_window)
+{
+        GtkWidget *widget;
+
+        g_assert (GLADE_IS_XML (xml));
+        g_assert (name != NULL);
+        g_assert (GDM_IS_GREETER_LOGIN_WINDOW (login_window));
+
+        widget = NULL;
+
+        if (strcmp (name, "user-chooser") == 0) {
+               widget = gdm_user_chooser_widget_new ();
+        } else if (strcmp (name, "session-chooser") == 0) {
+               widget = gdm_session_chooser_widget_new ();
+        }
+
+        if (widget != NULL) {
+                gtk_widget_show (widget);
+        }
+
+        return widget;
+}
+
 static void
 load_theme (GdmGreeterLoginWindow *login_window)
 {
@@ -713,6 +786,8 @@ load_theme (GdmGreeterLoginWindow *login_window)
         GtkWidget *button;
         GtkWidget *box;
 
+        glade_set_custom_handler ((GladeXMLCustomWidgetHandler) custom_widget_constructor,
+                                  login_window);
         login_window->priv->xml = glade_xml_new (GLADEDIR "/" GLADE_XML_FILE,
                                                  "window-box",
                                                  PACKAGE);
@@ -722,11 +797,45 @@ load_theme (GdmGreeterLoginWindow *login_window)
         box = glade_xml_get_widget (login_window->priv->xml, "window-box");
         gtk_container_add (GTK_CONTAINER (login_window), box);
 
-        box = glade_xml_get_widget (login_window->priv->xml, "userlist-box");
-        if (box == NULL) {
+        login_window->priv->user_chooser =
+                glade_xml_get_widget (login_window->priv->xml, "user-chooser");
+
+        if (login_window->priv->user_chooser == NULL) {
                 g_critical ("Userlist box not found");
         }
-        gtk_container_add (GTK_CONTAINER (box), login_window->priv->user_chooser);
+
+        gdm_user_chooser_widget_set_show_only_chosen (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser), TRUE);
+
+        /* FIXME: set from gconf */
+        gdm_user_chooser_widget_set_show_other_user (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser), TRUE);
+        gdm_user_chooser_widget_set_show_guest_user (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser), TRUE);
+
+        g_signal_connect (login_window->priv->user_chooser,
+                          "activated",
+                          G_CALLBACK (on_user_chosen),
+                          login_window);
+        g_signal_connect (login_window->priv->user_chooser,
+                          "deactivated",
+                          G_CALLBACK (on_user_unchosen),
+                          login_window);
+
+        login_window->priv->session_chooser =
+                glade_xml_get_widget (login_window->priv->xml, "session-chooser");
+
+        if (login_window->priv->session_chooser == NULL) {
+                g_critical ("Session chooser not found in greeter theme");
+        }
+
+        gdm_session_chooser_widget_set_show_only_chosen (GDM_SESSION_CHOOSER_WIDGET (login_window->priv->session_chooser), TRUE);
+
+        g_signal_connect (login_window->priv->session_chooser,
+                          "activated",
+                          G_CALLBACK (on_session_activated),
+                          login_window);
+
+        gdm_session_chooser_widget_set_current_session_name (GDM_SESSION_CHOOSER_WIDGET (login_window->priv->session_chooser),
+                                                             GDM_SESSION_CHOOSER_SESSION_PREVIOUS);
+
 
         button = glade_xml_get_widget (login_window->priv->xml, "log-in-button");
         gtk_widget_grab_default (button);
@@ -910,21 +1019,6 @@ gdm_greeter_login_window_init (GdmGreeterLoginWindow *login_window)
 
         login_window->priv->clock_show_seconds = TRUE;
 
-        login_window->priv->user_chooser = gdm_user_chooser_widget_new ();
-        gdm_user_chooser_widget_set_show_only_chosen (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser), TRUE);
-
-        /* FIXME: set from gconf */
-        gdm_user_chooser_widget_set_show_other_user (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser), TRUE);
-        gdm_user_chooser_widget_set_show_guest_user (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser), TRUE);
-
-        g_signal_connect (login_window->priv->user_chooser,
-                          "user-chosen",
-                          G_CALLBACK (on_user_chosen),
-                          login_window);
-
-        gtk_widget_show_all (login_window->priv->user_chooser);
-
-        gtk_window_set_keep_above (GTK_WINDOW (login_window), TRUE);
         gtk_window_set_opacity (GTK_WINDOW (login_window), 0.85);
         gtk_window_set_position (GTK_WINDOW (login_window), GTK_WIN_POS_CENTER_ALWAYS);
         gtk_window_set_deletable (GTK_WINDOW (login_window), FALSE);
diff --git a/gui/simple-greeter/gdm-greeter-login-window.glade b/gui/simple-greeter/gdm-greeter-login-window.glade
index 2d1d61a..d30000e 100644
--- a/gui/simple-greeter/gdm-greeter-login-window.glade
+++ b/gui/simple-greeter/gdm-greeter-login-window.glade
@@ -1,475 +1,808 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
-<!--*- mode: xml -*-->
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
 <glade-interface>
-  <widget class="GtkWindow" id="window1">
-    <property name="height_request">400</property>
-    <property name="visible">True</property>
-    <property name="border_width">12</property>
-    <property name="title" translatable="yes">Authentication Dialog</property>
-    <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
-    <child>
-      <widget class="GtkVBox" id="window-box">
-        <property name="visible">True</property>
-        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-        <property name="spacing">10</property>
-        <child>
-          <widget class="GtkAlignment" id="alignment1">
-            <property name="visible">True</property>
-            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-            <child>
-              <widget class="GtkImage" id="logo-image">
-                <property name="visible">True</property>
-                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                <property name="pixel_size">64</property>
-                <property name="icon_name">computer</property>
-              </widget>
-            </child>
-          </widget>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">False</property>
-          </packing>
-        </child>
-        <child>
-          <widget class="GtkEventBox" id="computer-info-event-box">
-            <property name="visible">True</property>
-            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-            <child>
-              <widget class="GtkNotebook" id="computer-info-notebook">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                <property name="show_tabs">False</property>
-                <property name="show_border">False</property>
-                <child>
-                  <widget class="GtkLabel" id="computer-info-name-label">
-                    <property name="visible">True</property>
-                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                    <property name="label" translatable="yes">Computer Name</property>
-                  </widget>
-                  <packing>
-                    <property name="tab_expand">False</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkLabel" id="label5">
-                    <property name="visible">True</property>
-                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                    <property name="label" translatable="yes">page 1</property>
-                  </widget>
-                  <packing>
-                    <property name="type">tab</property>
-                    <property name="tab_expand">False</property>
-                    <property name="tab_fill">False</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkLabel" id="computer-info-version-label">
-                    <property name="visible">True</property>
-                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                    <property name="label" translatable="yes">Version</property>
-                  </widget>
-                  <packing>
-                    <property name="position">1</property>
-                    <property name="tab_expand">False</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkLabel" id="label6">
-                    <property name="visible">True</property>
-                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                    <property name="label" translatable="yes">page 2</property>
-                  </widget>
-                  <packing>
-                    <property name="type">tab</property>
-                    <property name="position">1</property>
-                    <property name="tab_expand">False</property>
-                    <property name="tab_fill">False</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkLabel" id="computer-info-ip-label">
-                    <property name="visible">True</property>
-                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                    <property name="label" translatable="yes">IP Address</property>
-                  </widget>
-                  <packing>
-                    <property name="position">2</property>
-                    <property name="tab_expand">False</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkLabel" id="label7">
-                    <property name="visible">True</property>
-                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                    <property name="label" translatable="yes">page 3</property>
-                  </widget>
-                  <packing>
-                    <property name="type">tab</property>
-                    <property name="position">2</property>
-                    <property name="tab_expand">False</property>
-                    <property name="tab_fill">False</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkLabel" id="computer-info-network-label">
-                    <property name="visible">True</property>
-                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                    <property name="label" translatable="yes">Network status</property>
-                  </widget>
-                  <packing>
-                    <property name="position">3</property>
-                    <property name="tab_expand">False</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkLabel" id="label8">
-                    <property name="visible">True</property>
-                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                    <property name="label" translatable="yes">page 4</property>
-                  </widget>
-                  <packing>
-                    <property name="type">tab</property>
-                    <property name="position">3</property>
-                    <property name="tab_expand">False</property>
-                    <property name="tab_fill">False</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkLabel" id="computer-info-time-label">
-                    <property name="visible">True</property>
-                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                    <property name="label" translatable="yes">Tue Oct 23 21:16:50 EDT 2007</property>
-                  </widget>
-                  <packing>
-                    <property name="position">4</property>
-                    <property name="tab_expand">False</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkLabel" id="label9">
-                    <property name="visible">True</property>
-                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                    <property name="label" translatable="yes">page 5</property>
-                  </widget>
-                  <packing>
-                    <property name="type">tab</property>
-                    <property name="position">4</property>
-                    <property name="tab_expand">False</property>
-                    <property name="tab_fill">False</property>
-                  </packing>
-                </child>
-              </widget>
-            </child>
-          </widget>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">False</property>
-            <property name="position">1</property>
-          </packing>
-        </child>
-        <child>
-          <widget class="GtkAlignment" id="alignment2">
-            <property name="visible">True</property>
-            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-            <property name="left_padding">10</property>
-            <property name="right_padding">10</property>
-            <child>
-              <widget class="GtkVBox" id="selection-box">
-                <property name="visible">True</property>
-                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                <property name="spacing">10</property>
-                <child>
-                  <widget class="GtkVBox" id="userlist-box">
-                    <property name="visible">True</property>
-                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                    <child>
-                      <placeholder/>
-                    </child>
-                  </widget>
-                </child>
-                <child>
-                  <widget class="GtkHBox" id="auth-input-box">
-                    <property name="visible">True</property>
-                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                    <property name="spacing">6</property>
-                    <child>
-                      <widget class="GtkLabel" id="auth-prompt-label">
-                        <property name="visible">True</property>
-                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                        <property name="label" translatable="yes">Prompt:</property>
-                      </widget>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">False</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <widget class="GtkEntry" id="auth-prompt-entry">
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                        <property name="activates_default">True</property>
-                      </widget>
-                      <packing>
-                        <property name="position">1</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <placeholder/>
-                    </child>
-                  </widget>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">False</property>
-                    <property name="position">1</property>
-                  </packing>
-                </child>
-                <child>
-                  <widget class="GtkHBox" id="auth-message-box">
-                    <property name="visible">True</property>
-                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                    <child>
-                      <widget class="GtkLabel" id="auth-message-label">
-                        <property name="visible">True</property>
-                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                      </widget>
-                    </child>
-                  </widget>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">False</property>
-                    <property name="position">2</property>
-                  </packing>
-                </child>
-              </widget>
-            </child>
-          </widget>
-          <packing>
-            <property name="position">2</property>
-          </packing>
-        </child>
-        <child>
-          <widget class="GtkHButtonBox" id="buttonbox">
-            <property name="visible">True</property>
-            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-            <property name="spacing">6</property>
-            <property name="homogeneous">True</property>
-            <property name="layout_style">GTK_BUTTONBOX_END</property>
-            <child>
-              <widget class="GtkButton" id="disconnect-button">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="can_default">True</property>
-                <property name="has_default">True</property>
-                <property name="receives_default">True</property>
-                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                <property name="response_id">0</property>
-                <child>
-                  <widget class="GtkHBox" id="hbox2">
-                    <property name="visible">True</property>
-                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                    <child>
-                      <widget class="GtkImage" id="image10">
-                        <property name="visible">True</property>
-                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                        <property name="pixel_size">16</property>
-                        <property name="icon_name">window-close</property>
-                      </widget>
-                    </child>
-                    <child>
-                      <widget class="GtkLabel" id="label3">
-                        <property name="visible">True</property>
-                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                        <property name="label" translatable="yes">Disconnect</property>
-                      </widget>
-                      <packing>
-                        <property name="position">1</property>
-                      </packing>
-                    </child>
-                  </widget>
-                </child>
-              </widget>
-            </child>
-            <child>
-              <widget class="GtkButton" id="suspend-button">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="can_default">True</property>
-                <property name="has_default">True</property>
-                <property name="receives_default">True</property>
-                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                <property name="response_id">0</property>
-                <child>
-                  <widget class="GtkHBox" id="hbox3">
-                    <property name="visible">True</property>
-                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                    <child>
-                      <widget class="GtkImage" id="image9">
-                        <property name="visible">True</property>
-                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                        <property name="pixel_size">16</property>
-                        <property name="icon_name">media-playback-pause</property>
-                      </widget>
-                    </child>
-                    <child>
-                      <widget class="GtkLabel" id="label4">
-                        <property name="visible">True</property>
-                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                        <property name="xalign">0</property>
-                        <property name="label" translatable="yes">Suspend</property>
-                      </widget>
-                      <packing>
-                        <property name="position">1</property>
-                      </packing>
-                    </child>
-                  </widget>
-                </child>
-              </widget>
-              <packing>
-                <property name="position">1</property>
-              </packing>
-            </child>
-            <child>
-              <widget class="GtkButton" id="restart-button">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="can_default">True</property>
-                <property name="has_default">True</property>
-                <property name="receives_default">True</property>
-                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                <property name="response_id">0</property>
-                <child>
-                  <widget class="GtkHBox" id="hbox1">
-                    <property name="visible">True</property>
-                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                    <child>
-                      <widget class="GtkImage" id="image7">
-                        <property name="visible">True</property>
-                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                        <property name="pixel_size">16</property>
-                        <property name="icon_name">view-refresh</property>
-                      </widget>
-                    </child>
-                    <child>
-                      <widget class="GtkLabel" id="label2">
-                        <property name="visible">True</property>
-                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                        <property name="xalign">0</property>
-                        <property name="label" translatable="yes">Restart</property>
-                      </widget>
-                      <packing>
-                        <property name="position">1</property>
-                      </packing>
-                    </child>
-                  </widget>
-                </child>
-              </widget>
-              <packing>
-                <property name="position">2</property>
-              </packing>
-            </child>
-            <child>
-              <widget class="GtkButton" id="shutdown-button">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="can_default">True</property>
-                <property name="has_default">True</property>
-                <property name="receives_default">True</property>
-                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                <property name="response_id">0</property>
-                <child>
-                  <widget class="GtkHBox" id="hbox4">
-                    <property name="visible">True</property>
-                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                    <child>
-                      <widget class="GtkImage" id="image5">
-                        <property name="visible">True</property>
-                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                        <property name="pixel_size">16</property>
-                        <property name="icon_name">gnome-shutdown</property>
-                      </widget>
-                    </child>
-                    <child>
-                      <widget class="GtkLabel" id="label10">
-                        <property name="visible">True</property>
-                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                        <property name="label" translatable="yes">Shut Down</property>
-                      </widget>
-                      <packing>
-                        <property name="position">1</property>
-                      </packing>
-                    </child>
-                  </widget>
-                </child>
-              </widget>
-              <packing>
-                <property name="position">3</property>
-              </packing>
-            </child>
-            <child>
-              <widget class="GtkButton" id="cancel-button">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="receives_default">True</property>
-                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                <property name="label" translatable="yes">gtk-cancel</property>
-                <property name="use_stock">True</property>
-                <property name="response_id">0</property>
-              </widget>
-              <packing>
-                <property name="position">4</property>
-              </packing>
-            </child>
-            <child>
-              <widget class="GtkButton" id="log-in-button">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="can_default">True</property>
-                <property name="has_default">True</property>
-                <property name="receives_default">True</property>
-                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                <property name="response_id">0</property>
-                <child>
-                  <widget class="GtkHBox" id="hbox5">
-                    <property name="visible">True</property>
-                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                    <child>
-                      <widget class="GtkImage" id="image1">
-                        <property name="visible">True</property>
-                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                        <property name="pixel_size">16</property>
-                        <property name="icon_name">go-home</property>
-                      </widget>
-                    </child>
-                    <child>
-                      <widget class="GtkLabel" id="label1">
-                        <property name="visible">True</property>
-                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                        <property name="xalign">0</property>
-                        <property name="label" translatable="yes">Log In</property>
-                      </widget>
-                      <packing>
-                        <property name="position">1</property>
-                      </packing>
-                    </child>
-                  </widget>
-                </child>
-              </widget>
-              <packing>
-                <property name="position">5</property>
-              </packing>
-            </child>
-          </widget>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">False</property>
-            <property name="pack_type">GTK_PACK_END</property>
-            <property name="position">3</property>
-          </packing>
-        </child>
-      </widget>
-    </child>
-  </widget>
+
+<widget class="GtkWindow" id="window1">
+  <property name="border_width">12</property>
+  <property name="height_request">400</property>
+  <property name="visible">True</property>
+  <property name="title" translatable="yes">Authentication Dialog</property>
+  <property name="type">GTK_WINDOW_TOPLEVEL</property>
+  <property name="window_position">GTK_WIN_POS_NONE</property>
+  <property name="modal">False</property>
+  <property name="resizable">True</property>
+  <property name="destroy_with_parent">False</property>
+  <property name="decorated">True</property>
+  <property name="skip_taskbar_hint">False</property>
+  <property name="skip_pager_hint">False</property>
+  <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+  <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+  <property name="focus_on_map">True</property>
+  <property name="urgency_hint">False</property>
+
+  <child>
+    <widget class="GtkVBox" id="window-box">
+      <property name="visible">True</property>
+      <property name="homogeneous">False</property>
+      <property name="spacing">10</property>
+
+      <child>
+	<widget class="GtkAlignment" id="alignment1">
+	  <property name="visible">True</property>
+	  <property name="xalign">0.5</property>
+	  <property name="yalign">0.5</property>
+	  <property name="xscale">1</property>
+	  <property name="yscale">1</property>
+	  <property name="top_padding">0</property>
+	  <property name="bottom_padding">0</property>
+	  <property name="left_padding">0</property>
+	  <property name="right_padding">0</property>
+
+	  <child>
+	    <widget class="GtkImage" id="logo-image">
+	      <property name="visible">True</property>
+	      <property name="icon_name">computer</property>
+	      <property name="pixel_size">64</property>
+	      <property name="xalign">0.5</property>
+	      <property name="yalign">0.5</property>
+	      <property name="xpad">0</property>
+	      <property name="ypad">0</property>
+	    </widget>
+	  </child>
+	</widget>
+	<packing>
+	  <property name="padding">0</property>
+	  <property name="expand">False</property>
+	  <property name="fill">False</property>
+	</packing>
+      </child>
+
+      <child>
+	<widget class="GtkEventBox" id="computer-info-event-box">
+	  <property name="visible">True</property>
+	  <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+	  <property name="visible_window">True</property>
+	  <property name="above_child">False</property>
+
+	  <child>
+	    <widget class="GtkNotebook" id="computer-info-notebook">
+	      <property name="visible">True</property>
+	      <property name="show_tabs">False</property>
+	      <property name="show_border">False</property>
+	      <property name="tab_pos">GTK_POS_TOP</property>
+	      <property name="scrollable">False</property>
+	      <property name="enable_popup">False</property>
+
+	      <child>
+		<widget class="GtkLabel" id="computer-info-name-label">
+		  <property name="visible">True</property>
+		  <property name="label" translatable="yes">Computer Name</property>
+		  <property name="use_underline">False</property>
+		  <property name="use_markup">False</property>
+		  <property name="justify">GTK_JUSTIFY_LEFT</property>
+		  <property name="wrap">False</property>
+		  <property name="selectable">False</property>
+		  <property name="xalign">0.5</property>
+		  <property name="yalign">0.5</property>
+		  <property name="xpad">0</property>
+		  <property name="ypad">0</property>
+		  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		  <property name="width_chars">-1</property>
+		  <property name="single_line_mode">False</property>
+		  <property name="angle">0</property>
+		</widget>
+		<packing>
+		  <property name="tab_expand">False</property>
+		  <property name="tab_fill">True</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkLabel" id="label5">
+		  <property name="visible">True</property>
+		  <property name="label" translatable="yes">page 1</property>
+		  <property name="use_underline">False</property>
+		  <property name="use_markup">False</property>
+		  <property name="justify">GTK_JUSTIFY_LEFT</property>
+		  <property name="wrap">False</property>
+		  <property name="selectable">False</property>
+		  <property name="xalign">0.5</property>
+		  <property name="yalign">0.5</property>
+		  <property name="xpad">0</property>
+		  <property name="ypad">0</property>
+		  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		  <property name="width_chars">-1</property>
+		  <property name="single_line_mode">False</property>
+		  <property name="angle">0</property>
+		</widget>
+		<packing>
+		  <property name="type">tab</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkLabel" id="computer-info-version-label">
+		  <property name="visible">True</property>
+		  <property name="label" translatable="yes">Version</property>
+		  <property name="use_underline">False</property>
+		  <property name="use_markup">False</property>
+		  <property name="justify">GTK_JUSTIFY_LEFT</property>
+		  <property name="wrap">False</property>
+		  <property name="selectable">False</property>
+		  <property name="xalign">0.5</property>
+		  <property name="yalign">0.5</property>
+		  <property name="xpad">0</property>
+		  <property name="ypad">0</property>
+		  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		  <property name="width_chars">-1</property>
+		  <property name="single_line_mode">False</property>
+		  <property name="angle">0</property>
+		</widget>
+		<packing>
+		  <property name="tab_expand">False</property>
+		  <property name="tab_fill">True</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkLabel" id="label6">
+		  <property name="visible">True</property>
+		  <property name="label" translatable="yes">page 2</property>
+		  <property name="use_underline">False</property>
+		  <property name="use_markup">False</property>
+		  <property name="justify">GTK_JUSTIFY_LEFT</property>
+		  <property name="wrap">False</property>
+		  <property name="selectable">False</property>
+		  <property name="xalign">0.5</property>
+		  <property name="yalign">0.5</property>
+		  <property name="xpad">0</property>
+		  <property name="ypad">0</property>
+		  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		  <property name="width_chars">-1</property>
+		  <property name="single_line_mode">False</property>
+		  <property name="angle">0</property>
+		</widget>
+		<packing>
+		  <property name="type">tab</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkLabel" id="computer-info-ip-label">
+		  <property name="visible">True</property>
+		  <property name="label" translatable="yes">IP Address</property>
+		  <property name="use_underline">False</property>
+		  <property name="use_markup">False</property>
+		  <property name="justify">GTK_JUSTIFY_LEFT</property>
+		  <property name="wrap">False</property>
+		  <property name="selectable">False</property>
+		  <property name="xalign">0.5</property>
+		  <property name="yalign">0.5</property>
+		  <property name="xpad">0</property>
+		  <property name="ypad">0</property>
+		  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		  <property name="width_chars">-1</property>
+		  <property name="single_line_mode">False</property>
+		  <property name="angle">0</property>
+		</widget>
+		<packing>
+		  <property name="tab_expand">False</property>
+		  <property name="tab_fill">True</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkLabel" id="label7">
+		  <property name="visible">True</property>
+		  <property name="label" translatable="yes">page 3</property>
+		  <property name="use_underline">False</property>
+		  <property name="use_markup">False</property>
+		  <property name="justify">GTK_JUSTIFY_LEFT</property>
+		  <property name="wrap">False</property>
+		  <property name="selectable">False</property>
+		  <property name="xalign">0.5</property>
+		  <property name="yalign">0.5</property>
+		  <property name="xpad">0</property>
+		  <property name="ypad">0</property>
+		  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		  <property name="width_chars">-1</property>
+		  <property name="single_line_mode">False</property>
+		  <property name="angle">0</property>
+		</widget>
+		<packing>
+		  <property name="type">tab</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkLabel" id="computer-info-network-label">
+		  <property name="visible">True</property>
+		  <property name="label" translatable="yes">Network status</property>
+		  <property name="use_underline">False</property>
+		  <property name="use_markup">False</property>
+		  <property name="justify">GTK_JUSTIFY_LEFT</property>
+		  <property name="wrap">False</property>
+		  <property name="selectable">False</property>
+		  <property name="xalign">0.5</property>
+		  <property name="yalign">0.5</property>
+		  <property name="xpad">0</property>
+		  <property name="ypad">0</property>
+		  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		  <property name="width_chars">-1</property>
+		  <property name="single_line_mode">False</property>
+		  <property name="angle">0</property>
+		</widget>
+		<packing>
+		  <property name="tab_expand">False</property>
+		  <property name="tab_fill">True</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkLabel" id="label8">
+		  <property name="visible">True</property>
+		  <property name="label" translatable="yes">page 4</property>
+		  <property name="use_underline">False</property>
+		  <property name="use_markup">False</property>
+		  <property name="justify">GTK_JUSTIFY_LEFT</property>
+		  <property name="wrap">False</property>
+		  <property name="selectable">False</property>
+		  <property name="xalign">0.5</property>
+		  <property name="yalign">0.5</property>
+		  <property name="xpad">0</property>
+		  <property name="ypad">0</property>
+		  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		  <property name="width_chars">-1</property>
+		  <property name="single_line_mode">False</property>
+		  <property name="angle">0</property>
+		</widget>
+		<packing>
+		  <property name="type">tab</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkLabel" id="computer-info-time-label">
+		  <property name="visible">True</property>
+		  <property name="label" translatable="yes">Tue Oct 23 21:16:50 EDT 2007</property>
+		  <property name="use_underline">False</property>
+		  <property name="use_markup">False</property>
+		  <property name="justify">GTK_JUSTIFY_LEFT</property>
+		  <property name="wrap">False</property>
+		  <property name="selectable">False</property>
+		  <property name="xalign">0.5</property>
+		  <property name="yalign">0.5</property>
+		  <property name="xpad">0</property>
+		  <property name="ypad">0</property>
+		  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		  <property name="width_chars">-1</property>
+		  <property name="single_line_mode">False</property>
+		  <property name="angle">0</property>
+		</widget>
+		<packing>
+		  <property name="tab_expand">False</property>
+		  <property name="tab_fill">True</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkLabel" id="label9">
+		  <property name="visible">True</property>
+		  <property name="label" translatable="yes">page 5</property>
+		  <property name="use_underline">False</property>
+		  <property name="use_markup">False</property>
+		  <property name="justify">GTK_JUSTIFY_LEFT</property>
+		  <property name="wrap">False</property>
+		  <property name="selectable">False</property>
+		  <property name="xalign">0.5</property>
+		  <property name="yalign">0.5</property>
+		  <property name="xpad">0</property>
+		  <property name="ypad">0</property>
+		  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		  <property name="width_chars">-1</property>
+		  <property name="single_line_mode">False</property>
+		  <property name="angle">0</property>
+		</widget>
+		<packing>
+		  <property name="type">tab</property>
+		</packing>
+	      </child>
+	    </widget>
+	  </child>
+	</widget>
+	<packing>
+	  <property name="padding">0</property>
+	  <property name="expand">False</property>
+	  <property name="fill">False</property>
+	</packing>
+      </child>
+
+      <child>
+	<widget class="GtkAlignment" id="alignment2">
+	  <property name="visible">True</property>
+	  <property name="xalign">0.5</property>
+	  <property name="yalign">0.5</property>
+	  <property name="xscale">1</property>
+	  <property name="yscale">1</property>
+	  <property name="top_padding">0</property>
+	  <property name="bottom_padding">0</property>
+	  <property name="left_padding">10</property>
+	  <property name="right_padding">10</property>
+
+	  <child>
+	    <widget class="GtkVBox" id="selection-box">
+	      <property name="visible">True</property>
+	      <property name="homogeneous">False</property>
+	      <property name="spacing">10</property>
+
+	      <child>
+		<widget class="Custom" id="user-chooser">
+		  <property name="visible">True</property>
+		  <property name="int1">0</property>
+		  <property name="int2">0</property>
+		  <property name="last_modification_time">Tue, 04 Dec 2007 23:50:30 GMT</property>
+		</widget>
+		<packing>
+		  <property name="padding">0</property>
+		  <property name="expand">True</property>
+		  <property name="fill">True</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkHBox" id="auth-input-box">
+		  <property name="visible">True</property>
+		  <property name="homogeneous">False</property>
+		  <property name="spacing">6</property>
+
+		  <child>
+		    <widget class="GtkLabel" id="auth-prompt-label">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes">Prompt:</property>
+		      <property name="use_underline">False</property>
+		      <property name="use_markup">False</property>
+		      <property name="justify">GTK_JUSTIFY_LEFT</property>
+		      <property name="wrap">False</property>
+		      <property name="selectable">False</property>
+		      <property name="xalign">0.5</property>
+		      <property name="yalign">0.5</property>
+		      <property name="xpad">0</property>
+		      <property name="ypad">0</property>
+		      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		      <property name="width_chars">-1</property>
+		      <property name="single_line_mode">False</property>
+		      <property name="angle">0</property>
+		    </widget>
+		    <packing>
+		      <property name="padding">0</property>
+		      <property name="expand">False</property>
+		      <property name="fill">False</property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <widget class="GtkEntry" id="auth-prompt-entry">
+		      <property name="visible">True</property>
+		      <property name="can_focus">True</property>
+		      <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+		      <property name="editable">True</property>
+		      <property name="visibility">True</property>
+		      <property name="max_length">0</property>
+		      <property name="text" translatable="yes"></property>
+		      <property name="has_frame">True</property>
+		      <property name="invisible_char">•</property>
+		      <property name="activates_default">True</property>
+		    </widget>
+		    <packing>
+		      <property name="padding">0</property>
+		      <property name="expand">True</property>
+		      <property name="fill">True</property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <placeholder/>
+		  </child>
+		</widget>
+		<packing>
+		  <property name="padding">0</property>
+		  <property name="expand">False</property>
+		  <property name="fill">False</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkHBox" id="auth-message-box">
+		  <property name="visible">True</property>
+		  <property name="homogeneous">False</property>
+		  <property name="spacing">0</property>
+
+		  <child>
+		    <widget class="GtkLabel" id="auth-message-label">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes"></property>
+		      <property name="use_underline">False</property>
+		      <property name="use_markup">False</property>
+		      <property name="justify">GTK_JUSTIFY_LEFT</property>
+		      <property name="wrap">False</property>
+		      <property name="selectable">False</property>
+		      <property name="xalign">0.5</property>
+		      <property name="yalign">0.5</property>
+		      <property name="xpad">0</property>
+		      <property name="ypad">0</property>
+		      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		      <property name="width_chars">-1</property>
+		      <property name="single_line_mode">False</property>
+		      <property name="angle">0</property>
+		    </widget>
+		    <packing>
+		      <property name="padding">0</property>
+		      <property name="expand">True</property>
+		      <property name="fill">True</property>
+		    </packing>
+		  </child>
+		</widget>
+		<packing>
+		  <property name="padding">0</property>
+		  <property name="expand">False</property>
+		  <property name="fill">False</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="Custom" id="session-chooser">
+		  <property name="int1">0</property>
+		  <property name="int2">0</property>
+		  <property name="last_modification_time">Tue, 04 Dec 2007 23:26:50 GMT</property>
+		</widget>
+		<packing>
+		  <property name="padding">0</property>
+		  <property name="expand">True</property>
+		  <property name="fill">True</property>
+		</packing>
+	      </child>
+	    </widget>
+	  </child>
+	</widget>
+	<packing>
+	  <property name="padding">0</property>
+	  <property name="expand">True</property>
+	  <property name="fill">True</property>
+	</packing>
+      </child>
+
+      <child>
+	<widget class="GtkHButtonBox" id="buttonbox">
+	  <property name="visible">True</property>
+	  <property name="layout_style">GTK_BUTTONBOX_END</property>
+	  <property name="spacing">6</property>
+
+	  <child>
+	    <widget class="GtkButton" id="disconnect-button">
+	      <property name="visible">True</property>
+	      <property name="can_default">True</property>
+	      <property name="has_default">True</property>
+	      <property name="can_focus">True</property>
+	      <property name="relief">GTK_RELIEF_NORMAL</property>
+	      <property name="focus_on_click">True</property>
+
+	      <child>
+		<widget class="GtkHBox" id="hbox2">
+		  <property name="visible">True</property>
+		  <property name="homogeneous">False</property>
+		  <property name="spacing">0</property>
+
+		  <child>
+		    <widget class="GtkImage" id="image10">
+		      <property name="visible">True</property>
+		      <property name="icon_name">window-close</property>
+		      <property name="pixel_size">16</property>
+		      <property name="xalign">0.5</property>
+		      <property name="yalign">0.5</property>
+		      <property name="xpad">0</property>
+		      <property name="ypad">0</property>
+		    </widget>
+		    <packing>
+		      <property name="padding">0</property>
+		      <property name="expand">True</property>
+		      <property name="fill">True</property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <widget class="GtkLabel" id="label3">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes">Disconnect</property>
+		      <property name="use_underline">False</property>
+		      <property name="use_markup">False</property>
+		      <property name="justify">GTK_JUSTIFY_LEFT</property>
+		      <property name="wrap">False</property>
+		      <property name="selectable">False</property>
+		      <property name="xalign">0.5</property>
+		      <property name="yalign">0.5</property>
+		      <property name="xpad">0</property>
+		      <property name="ypad">0</property>
+		      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		      <property name="width_chars">-1</property>
+		      <property name="single_line_mode">False</property>
+		      <property name="angle">0</property>
+		    </widget>
+		    <packing>
+		      <property name="padding">0</property>
+		      <property name="expand">True</property>
+		      <property name="fill">True</property>
+		    </packing>
+		  </child>
+		</widget>
+	      </child>
+	    </widget>
+	  </child>
+
+	  <child>
+	    <widget class="GtkButton" id="suspend-button">
+	      <property name="visible">True</property>
+	      <property name="can_default">True</property>
+	      <property name="has_default">True</property>
+	      <property name="can_focus">True</property>
+	      <property name="relief">GTK_RELIEF_NORMAL</property>
+	      <property name="focus_on_click">True</property>
+
+	      <child>
+		<widget class="GtkHBox" id="hbox3">
+		  <property name="visible">True</property>
+		  <property name="homogeneous">False</property>
+		  <property name="spacing">0</property>
+
+		  <child>
+		    <widget class="GtkImage" id="image9">
+		      <property name="visible">True</property>
+		      <property name="icon_name">media-playback-pause</property>
+		      <property name="pixel_size">16</property>
+		      <property name="xalign">0.5</property>
+		      <property name="yalign">0.5</property>
+		      <property name="xpad">0</property>
+		      <property name="ypad">0</property>
+		    </widget>
+		    <packing>
+		      <property name="padding">0</property>
+		      <property name="expand">True</property>
+		      <property name="fill">True</property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <widget class="GtkLabel" id="label4">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes">Suspend</property>
+		      <property name="use_underline">False</property>
+		      <property name="use_markup">False</property>
+		      <property name="justify">GTK_JUSTIFY_LEFT</property>
+		      <property name="wrap">False</property>
+		      <property name="selectable">False</property>
+		      <property name="xalign">0</property>
+		      <property name="yalign">0.5</property>
+		      <property name="xpad">0</property>
+		      <property name="ypad">0</property>
+		      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		      <property name="width_chars">-1</property>
+		      <property name="single_line_mode">False</property>
+		      <property name="angle">0</property>
+		    </widget>
+		    <packing>
+		      <property name="padding">0</property>
+		      <property name="expand">True</property>
+		      <property name="fill">True</property>
+		    </packing>
+		  </child>
+		</widget>
+	      </child>
+	    </widget>
+	  </child>
+
+	  <child>
+	    <widget class="GtkButton" id="restart-button">
+	      <property name="visible">True</property>
+	      <property name="can_default">True</property>
+	      <property name="has_default">True</property>
+	      <property name="can_focus">True</property>
+	      <property name="relief">GTK_RELIEF_NORMAL</property>
+	      <property name="focus_on_click">True</property>
+
+	      <child>
+		<widget class="GtkHBox" id="hbox1">
+		  <property name="visible">True</property>
+		  <property name="homogeneous">False</property>
+		  <property name="spacing">0</property>
+
+		  <child>
+		    <widget class="GtkImage" id="image7">
+		      <property name="visible">True</property>
+		      <property name="icon_name">view-refresh</property>
+		      <property name="pixel_size">16</property>
+		      <property name="xalign">0.5</property>
+		      <property name="yalign">0.5</property>
+		      <property name="xpad">0</property>
+		      <property name="ypad">0</property>
+		    </widget>
+		    <packing>
+		      <property name="padding">0</property>
+		      <property name="expand">True</property>
+		      <property name="fill">True</property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <widget class="GtkLabel" id="label2">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes">Restart</property>
+		      <property name="use_underline">False</property>
+		      <property name="use_markup">False</property>
+		      <property name="justify">GTK_JUSTIFY_LEFT</property>
+		      <property name="wrap">False</property>
+		      <property name="selectable">False</property>
+		      <property name="xalign">0</property>
+		      <property name="yalign">0.5</property>
+		      <property name="xpad">0</property>
+		      <property name="ypad">0</property>
+		      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		      <property name="width_chars">-1</property>
+		      <property name="single_line_mode">False</property>
+		      <property name="angle">0</property>
+		    </widget>
+		    <packing>
+		      <property name="padding">0</property>
+		      <property name="expand">True</property>
+		      <property name="fill">True</property>
+		    </packing>
+		  </child>
+		</widget>
+	      </child>
+	    </widget>
+	  </child>
+
+	  <child>
+	    <widget class="GtkButton" id="shutdown-button">
+	      <property name="visible">True</property>
+	      <property name="can_default">True</property>
+	      <property name="has_default">True</property>
+	      <property name="can_focus">True</property>
+	      <property name="relief">GTK_RELIEF_NORMAL</property>
+	      <property name="focus_on_click">True</property>
+
+	      <child>
+		<widget class="GtkHBox" id="hbox4">
+		  <property name="visible">True</property>
+		  <property name="homogeneous">False</property>
+		  <property name="spacing">0</property>
+
+		  <child>
+		    <widget class="GtkImage" id="image5">
+		      <property name="visible">True</property>
+		      <property name="icon_name">gnome-shutdown</property>
+		      <property name="pixel_size">16</property>
+		      <property name="xalign">0.5</property>
+		      <property name="yalign">0.5</property>
+		      <property name="xpad">0</property>
+		      <property name="ypad">0</property>
+		    </widget>
+		    <packing>
+		      <property name="padding">0</property>
+		      <property name="expand">True</property>
+		      <property name="fill">True</property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <widget class="GtkLabel" id="label10">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes">Shut Down</property>
+		      <property name="use_underline">False</property>
+		      <property name="use_markup">False</property>
+		      <property name="justify">GTK_JUSTIFY_LEFT</property>
+		      <property name="wrap">False</property>
+		      <property name="selectable">False</property>
+		      <property name="xalign">0.5</property>
+		      <property name="yalign">0.5</property>
+		      <property name="xpad">0</property>
+		      <property name="ypad">0</property>
+		      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		      <property name="width_chars">-1</property>
+		      <property name="single_line_mode">False</property>
+		      <property name="angle">0</property>
+		    </widget>
+		    <packing>
+		      <property name="padding">0</property>
+		      <property name="expand">True</property>
+		      <property name="fill">True</property>
+		    </packing>
+		  </child>
+		</widget>
+	      </child>
+	    </widget>
+	  </child>
+
+	  <child>
+	    <widget class="GtkButton" id="cancel-button">
+	      <property name="visible">True</property>
+	      <property name="can_focus">True</property>
+	      <property name="label">gtk-cancel</property>
+	      <property name="use_stock">True</property>
+	      <property name="relief">GTK_RELIEF_NORMAL</property>
+	      <property name="focus_on_click">True</property>
+	    </widget>
+	  </child>
+
+	  <child>
+	    <widget class="GtkButton" id="log-in-button">
+	      <property name="visible">True</property>
+	      <property name="can_default">True</property>
+	      <property name="has_default">True</property>
+	      <property name="can_focus">True</property>
+	      <property name="relief">GTK_RELIEF_NORMAL</property>
+	      <property name="focus_on_click">True</property>
+
+	      <child>
+		<widget class="GtkHBox" id="hbox5">
+		  <property name="visible">True</property>
+		  <property name="homogeneous">False</property>
+		  <property name="spacing">0</property>
+
+		  <child>
+		    <widget class="GtkImage" id="image1">
+		      <property name="visible">True</property>
+		      <property name="icon_name">go-home</property>
+		      <property name="pixel_size">16</property>
+		      <property name="xalign">0.5</property>
+		      <property name="yalign">0.5</property>
+		      <property name="xpad">0</property>
+		      <property name="ypad">0</property>
+		    </widget>
+		    <packing>
+		      <property name="padding">0</property>
+		      <property name="expand">True</property>
+		      <property name="fill">True</property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <widget class="GtkLabel" id="label1">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes">Log In</property>
+		      <property name="use_underline">False</property>
+		      <property name="use_markup">False</property>
+		      <property name="justify">GTK_JUSTIFY_LEFT</property>
+		      <property name="wrap">False</property>
+		      <property name="selectable">False</property>
+		      <property name="xalign">0</property>
+		      <property name="yalign">0.5</property>
+		      <property name="xpad">0</property>
+		      <property name="ypad">0</property>
+		      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		      <property name="width_chars">-1</property>
+		      <property name="single_line_mode">False</property>
+		      <property name="angle">0</property>
+		    </widget>
+		    <packing>
+		      <property name="padding">0</property>
+		      <property name="expand">True</property>
+		      <property name="fill">True</property>
+		    </packing>
+		  </child>
+		</widget>
+	      </child>
+	    </widget>
+	  </child>
+	</widget>
+	<packing>
+	  <property name="padding">0</property>
+	  <property name="expand">False</property>
+	  <property name="fill">False</property>
+	  <property name="pack_type">GTK_PACK_END</property>
+	</packing>
+      </child>
+    </widget>
+  </child>
+</widget>
+
 </glade-interface>
-- 
1.5.3.6


7-login-window-animation.patch:

--- NEW FILE 7-login-window-animation.patch ---
>From 33c2ba849b1f752deb38cf8715571eadbc4b323b Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode at redhat.com>
Date: Thu, 13 Dec 2007 14:38:16 -0500
Subject: [PATCH] add lame animation to greeter login window

---
 gui/simple-greeter/gdm-greeter-login-window.c |   90 +++++++++++++++++++++++-
 1 files changed, 86 insertions(+), 4 deletions(-)

diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
index ca14b38..ceb9e88 100644
--- a/gui/simple-greeter/gdm-greeter-login-window.c
+++ b/gui/simple-greeter/gdm-greeter-login-window.c
@@ -72,6 +72,8 @@ struct GdmGreeterLoginWindowPrivate
         char            *timeformat;
         guint            update_clock_id;
         gboolean         clock_show_seconds;
+
+        guint            animation_timeout_id;
 };
 
 enum {
@@ -860,12 +862,60 @@ load_theme (GdmGreeterLoginWindow *login_window)
         switch_mode (login_window, MODE_SELECTION);
 }
 
+static gboolean
+fit_window_to_children (GdmGreeterLoginWindow *window)
+{
+        int x;
+        int y;
+        int width;
+        int height;
+        int height_step;
+        int width_step;
+
+        /* FIXME: this animation logic is really dumb
+         */
+
+        if (!GTK_WIDGET_REALIZED (GTK_WIDGET (window))) {
+                return FALSE;
+        }
+
+        gdk_window_get_geometry (GTK_WIDGET (window)->window,
+                                 &x, &y, &width, &height, NULL);
+
+        if (height == GTK_WIDGET (window)->requisition.height) {
+                return FALSE;
+        }
+
+        if (width < GTK_WIDGET (window)->requisition.width) {
+                width_step = MIN (1, GTK_WIDGET (window)->requisition.width - width);
+        } else if (width > GTK_WIDGET (window)->requisition.width) {
+                width_step = -1 * MIN (1, width - GTK_WIDGET (window)->requisition.width);
+        } else {
+                width_step = 0;
+        }
+
+        if (height < GTK_WIDGET (window)->requisition.height) {
+                height_step = MIN ((int) 25, GTK_WIDGET (window)->requisition.height - height);
+        } else if (height > GTK_WIDGET (window)->requisition.height) {
+                height_step = -1 * MIN ((int) 25, height - GTK_WIDGET (window)->requisition.height);
+        } else {
+                height_step = 0;
+        }
+
+        gdk_window_resize (GTK_WIDGET (window)->window,
+                           width + width_step,
+                           height + height_step);
+
+        return TRUE;
+}
+
 static void
 gdm_greeter_login_window_size_request (GtkWidget      *widget,
                                        GtkRequisition *requisition)
 {
-        int screen_w;
-        int screen_h;
+        int            screen_w;
+        int            screen_h;
+        GtkRequisition child_requisition;
 
         if (GTK_WIDGET_CLASS (gdm_greeter_login_window_parent_class)->size_request) {
                 GTK_WIDGET_CLASS (gdm_greeter_login_window_parent_class)->size_request (widget, requisition);
@@ -874,8 +924,39 @@ gdm_greeter_login_window_size_request (GtkWidget      *widget,
         screen_w = gdk_screen_get_width (gtk_widget_get_screen (widget));
         screen_h = gdk_screen_get_height (gtk_widget_get_screen (widget));
 
-        requisition->height = screen_h * 0.5;
-        requisition->width = screen_w * 0.3;
+        gtk_widget_size_request (GTK_BIN (widget)->child, &child_requisition);
+        *requisition = child_requisition;
+
+        requisition->width += 2 * GTK_CONTAINER (widget)->border_width;
+        requisition->height += 2 * GTK_CONTAINER (widget)->border_width;
+
+        requisition->width = MIN (requisition->width, .50 * screen_w);
+        requisition->height = MIN (requisition->height, .80 * screen_h);
+}
+
+static void
+clear_animation_timeout_id (GdmGreeterLoginWindow *window)
+{
+        window->priv->animation_timeout_id = 0;
+}
+
+static void
+gdm_greeter_login_window_size_allocate (GtkWidget      *widget,
+                                        GtkAllocation  *allocation)
+{
+        GdmGreeterLoginWindow *window;
+
+        window = GDM_GREETER_LOGIN_WINDOW (widget);
+
+        if (window->priv->animation_timeout_id == 0) {
+                window->priv->animation_timeout_id =
+                    g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE, 20,
+                                        (GSourceFunc) fit_window_to_children,
+                                        widget,
+                                        (GDestroyNotify) clear_animation_timeout_id);
+        }
+
+        GTK_WIDGET_CLASS (gdm_greeter_login_window_parent_class)->size_allocate (widget, allocation);
 }
 
 static GObject *
@@ -910,6 +991,7 @@ gdm_greeter_login_window_class_init (GdmGreeterLoginWindowClass *klass)
         object_class->finalize = gdm_greeter_login_window_finalize;
 
         widget_class->size_request = gdm_greeter_login_window_size_request;
+        widget_class->size_allocate = gdm_greeter_login_window_size_allocate;
 
         signals [BEGIN_VERIFICATION] =
                 g_signal_new ("begin-verification",
-- 
1.5.3.6



Index: gdm.spec
===================================================================
RCS file: /cvs/pkgs/rpms/gdm/devel/gdm.spec,v
retrieving revision 1.321
retrieving revision 1.322
diff -u -r1.321 -r1.322
--- gdm.spec	30 Nov 2007 15:07:05 -0000	1.321
+++ gdm.spec	13 Dec 2007 20:31:53 -0000	1.322
@@ -16,7 +16,7 @@
 Summary: The GNOME Display Manager
 Name: gdm
 Version: 2.21.2
-Release: 0.2007.11.20.4%{?dist}
+Release: 0.2007.11.20.5%{?dist}
 Epoch: 1
 License: GPLv2+
 Group: User Interface/X
@@ -82,6 +82,13 @@
 
 Patch0: gdm-2.21.2-use-metacity.patch
 Patch1: gdm-2.21.2-fix-background.patch
+Patch2: 2-new-chooser-widget.patch
+Patch3: 3-switch-user-chooser-over.patch
+Patch4: 4-switch-session-chooser-over.patch
+Patch5: 5-dont-shrink-in-test-program.patch
+Patch6: 6-session-chooser-in-login-window.patch
+Patch7: 7-login-window-animation.patch
+
 
 %description
 Gdm (the GNOME Display Manager) is a highly configurable
@@ -93,6 +100,12 @@
 %setup -q
 %patch0 -p1 -b .use-metacity
 %patch1 -p1 -b .fix-background
+%patch2 -p1 -b .new-chooser-widget
+%patch3 -p1 -b .switch-user-chooser-over
+%patch4 -p1 -b .switch-session-chooser-over
+%patch5 -p1 -b .dont-shrink-in-test-program
+%patch6 -p1 -b .session-chooser-in-login-window
+%patch7 -p1 -b .login-window-animation
 
 %build
 cp -f %{SOURCE1} data/gdm
@@ -280,6 +293,10 @@
 %attr(1770, root, gdm) %dir %{_localstatedir}/lib/gdm
 
 %changelog
+* Thu Dec 13 2007 Ray Strode <rstrode at redhat.com> - 1:2.21.2-0.2007.11.20.5
+- add session chooser to login screen
+- add hoaky animations
+
 * Fri Nov 30 2007 Matthias Clasen <mclasen at redhat.com> - 1:2.21.2-0.2007.11.20.4
 - Use the new "substack" support in pam to make keyring unlocking work
  




More information about the fedora-extras-commits mailing list