[gdm/f14/master] Update to 2.31.90

Ray Strode rstrode at fedoraproject.org
Tue Aug 17 21:55:07 UTC 2010


commit 4e70be422a09af6be611582ac69b5bf95218c60a
Author: Ray Strode <rstrode at redhat.com>
Date:   Tue Aug 17 17:53:41 2010 -0400

    Update to 2.31.90
    
    This update means we get to drop the accounts service patch, which
    has been upstreamed now.
    
    It also means the multi-stack patch has been substantially rebased.
    This could incur certain unknown regressions.

 gdm-multistack.patch |11620 ++++++++++++++++++++++++++------------------------
 gdm.spec             |   19 +-
 2 files changed, 6096 insertions(+), 5543 deletions(-)
---
diff --git a/gdm-multistack.patch b/gdm-multistack.patch
index e120df5..871c21d 100644
--- a/gdm-multistack.patch
+++ b/gdm-multistack.patch
@@ -1,7 +1,386 @@
-From 5df4d8024ef0126a524892fb714351134bf727da Mon Sep 17 00:00:00 2001
+From bfe236555216f30e82c562ad0393a1762afdfab2 Mon Sep 17 00:00:00 2001
+From: Ray Strode <rstrode at redhat.com>
+Date: Thu, 22 Jul 2010 13:38:09 -0400
+Subject: [PATCH 01/35] Revert "Don't wait a mandatory 2 seconds when resetting greeter"
+
+This reverts commit 83552f19154bf5689b395a76c1a9931b2558f41b.
+
+This is a temporary fix so that error messages are displayed for
+long enough.  A better fix would belong in the greeter.
+---
+ daemon/gdm-simple-slave.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/daemon/gdm-simple-slave.c b/daemon/gdm-simple-slave.c
+index 2994014..6b9159a 100644
+--- a/daemon/gdm-simple-slave.c
++++ b/daemon/gdm-simple-slave.c
+@@ -227,7 +227,7 @@ queue_greeter_reset (GdmSimpleSlave *slave)
+                 return;
+         }
+ 
+-        slave->priv->greeter_reset_id = g_idle_add ((GSourceFunc)greeter_reset_timeout, slave);
++        slave->priv->greeter_reset_id = g_timeout_add_seconds (2, (GSourceFunc)greeter_reset_timeout, slave);
+ }
+ 
+ static void
+-- 
+1.7.2.1
+
+
+From 7ced60d18d4aed59060e260550bf7e1837018c93 Mon Sep 17 00:00:00 2001
+From: Ray Strode <rstrode at redhat.com>
+Date: Wed, 7 Jul 2010 17:16:38 -0400
+Subject: [PATCH 02/35] Don't set list-visible unless the widget is visible
+
+list-visible is a special property that means the
+list part of the chooser widget is visible.  We need
+to make sure we only report it visible when the
+chooser itself is visible otherwise the property is
+a lie.
+
+This fixes focus handling when the conversation list
+isn't visible to begin with.
+---
+ gui/simple-greeter/gdm-chooser-widget.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/gui/simple-greeter/gdm-chooser-widget.c b/gui/simple-greeter/gdm-chooser-widget.c
+index 9e3ae73..28c8404 100644
+--- a/gui/simple-greeter/gdm-chooser-widget.c
++++ b/gui/simple-greeter/gdm-chooser-widget.c
+@@ -698,7 +698,7 @@ update_chooser_visibility (GdmChooserWidget *widget)
+ 
+         if (gdm_chooser_widget_get_number_of_items (widget) > 0) {
+                 gtk_widget_show (widget->priv->frame);
+-                set_chooser_list_visible (widget, TRUE);
++                set_chooser_list_visible (widget, GTK_WIDGET_VISIBLE (widget));
+         } else {
+                 gtk_widget_hide (widget->priv->frame);
+                 set_chooser_list_visible (widget, FALSE);
+-- 
+1.7.2.1
+
+
+From 686cfe7fc5d691f31323751b57aa24f3034231aa Mon Sep 17 00:00:00 2001
+From: Ray Strode <rstrode at redhat.com>
+Date: Mon, 28 Jun 2010 14:35:35 -0400
+Subject: [PATCH 03/35] Add user chooser to ui file
+
+Before it was getting added manually from the source code.
+
+This way is a lot cleaner.
+---
+ gui/simple-greeter/gdm-greeter-login-window.c  |   20 ++++++++++++++------
+ gui/simple-greeter/gdm-greeter-login-window.ui |    9 ++++++++-
+ 2 files changed, 22 insertions(+), 7 deletions(-)
+
+diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
+index 96e6fce..95371b8 100644
+--- a/gui/simple-greeter/gdm-greeter-login-window.c
++++ b/gui/simple-greeter/gdm-greeter-login-window.c
+@@ -1208,6 +1208,17 @@ create_computer_info (GdmGreeterLoginWindow *login_window)
+ 
+ 
+ static void
++register_custom_types (GdmGreeterLoginWindow *login_window)
++{
++        GType types[] = { GDM_TYPE_USER_CHOOSER_WIDGET };
++        int i;
++
++        for (i = 0; i < G_N_ELEMENTS (types); i++) {
++                g_debug ("Registering type '%s'", g_type_name (types[i]));
++        }
++}
++
++static void
+ load_theme (GdmGreeterLoginWindow *login_window)
+ {
+         GtkWidget *entry;
+@@ -1218,6 +1229,8 @@ load_theme (GdmGreeterLoginWindow *login_window)
+ 
+         gdm_profile_start (NULL);
+ 
++        register_custom_types (login_window);
++
+         login_window->priv->builder = gtk_builder_new ();
+         if (!gtk_builder_add_from_file (login_window->priv->builder, UIDIR "/" UI_XML_FILE, &error)) {
+                 g_warning ("Couldn't load builder file: %s", error->message);
+@@ -1251,12 +1264,7 @@ load_theme (GdmGreeterLoginWindow *login_window)
+         box = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "window-frame"));
+         gtk_container_add (GTK_CONTAINER (login_window), box);
+ 
+-        /* FIXME: user chooser should implement GtkBuildable and this should get dropped
+-         */
+-        login_window->priv->user_chooser = gdm_user_chooser_widget_new ();
+-        box = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "selection-box"));
+-        gtk_box_pack_start (GTK_BOX (box), login_window->priv->user_chooser, TRUE, TRUE, 0);
+-        gtk_box_reorder_child (GTK_BOX (box), login_window->priv->user_chooser, 0);
++        login_window->priv->user_chooser = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "user-chooser"));
+ 
+         gdm_user_chooser_widget_set_show_only_chosen (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser), TRUE);
+ 
+diff --git a/gui/simple-greeter/gdm-greeter-login-window.ui b/gui/simple-greeter/gdm-greeter-login-window.ui
+index d8cf1cc..83375ed 100644
+--- a/gui/simple-greeter/gdm-greeter-login-window.ui
++++ b/gui/simple-greeter/gdm-greeter-login-window.ui
+@@ -160,7 +160,14 @@
+                         <property name="visible">True</property>
+                         <property name="spacing">10</property>
+                         <child>
+-                          <placeholder/>
++                          <object class="GdmUserChooserWidget" id="user-chooser">
++                            <property name="visible">False</property>
++                          </object>
++                          <packing>
++                            <property name="expand">True</property>
++                            <property name="fill">True</property>
++                            <property name="position">0</property>
++                          </packing>
+                         </child>
+                         <child>
+                           <object class="GtkHBox" id="auth-input-box">
+-- 
+1.7.2.1
+
+
+From e2b84e687b0fd3ccd5e53b6dca5c24689c42ffcd Mon Sep 17 00:00:00 2001
+From: Ray Strode <rstrode at redhat.com>
+Date: Fri, 20 Feb 2009 14:05:20 -0500
+Subject: [PATCH 04/35] Add new api to ask when chooser widget is done loading items
+
+---
+ gui/simple-greeter/gdm-chooser-widget.c |    8 ++++++++
+ gui/simple-greeter/gdm-chooser-widget.h |    2 ++
+ 2 files changed, 10 insertions(+), 0 deletions(-)
+
+diff --git a/gui/simple-greeter/gdm-chooser-widget.c b/gui/simple-greeter/gdm-chooser-widget.c
+index 28c8404..4fa7175 100644
+--- a/gui/simple-greeter/gdm-chooser-widget.c
++++ b/gui/simple-greeter/gdm-chooser-widget.c
+@@ -98,6 +98,7 @@ struct GdmChooserWidgetPrivate
+ 
+         guint32                  should_hide_inactive_items : 1;
+         guint32                  emit_activated_after_resize_animation : 1;
++        guint32                  is_loaded : 1;
+ 
+         GdmChooserWidgetPosition separator_position;
+         GdmChooserWidgetState    state;
+@@ -2741,9 +2742,16 @@ gdm_chooser_widget_propagate_pending_key_events (GdmChooserWidget *widget)
+         gdm_scrollable_widget_replay_queued_key_events (GDM_SCROLLABLE_WIDGET (widget->priv->scrollable_widget));
+ }
+ 
++gboolean
++gdm_chooser_widget_is_loaded (GdmChooserWidget *widget)
++{
++        return widget->priv->is_loaded;
++}
++
+ void
+ gdm_chooser_widget_loaded (GdmChooserWidget *widget)
+ {
++        widget->priv->is_loaded = TRUE;
+         g_signal_emit (widget, signals[LOADED], 0);
+         update_chooser_visibility (widget);
+         queue_move_cursor_to_top (widget);
+diff --git a/gui/simple-greeter/gdm-chooser-widget.h b/gui/simple-greeter/gdm-chooser-widget.h
+index 11a6456..3f6fea3 100644
+--- a/gui/simple-greeter/gdm-chooser-widget.h
++++ b/gui/simple-greeter/gdm-chooser-widget.h
+@@ -142,6 +142,8 @@ int            gdm_chooser_widget_get_number_of_items          (GdmChooserWidget
+ void           gdm_chooser_widget_activate_if_one_item         (GdmChooserWidget          *widget);
+ void           gdm_chooser_widget_propagate_pending_key_events (GdmChooserWidget          *widget);
+ 
++gboolean       gdm_chooser_widget_is_loaded                    (GdmChooserWidget          *widget);
++
+ /* Protected
+  */
+ void           gdm_chooser_widget_loaded                       (GdmChooserWidget          *widget);
+-- 
+1.7.2.1
+
+
+From 19f14037c4e503c21d205e45cc3a3b3354a7c198 Mon Sep 17 00:00:00 2001
+From: Ray Strode <rstrode at redhat.com>
+Date: Fri, 6 Mar 2009 11:19:40 -0500
+Subject: [PATCH 05/35] Create session settings object up front
+
+This allows us to set language, session, etc,
+before the PAM conversation is started.
+---
+ daemon/gdm-session-worker.c |    3 +--
+ 1 files changed, 1 insertions(+), 2 deletions(-)
+
+diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c
+index 3715396..775f99b 100644
+--- a/daemon/gdm-session-worker.c
++++ b/daemon/gdm-session-worker.c
+@@ -2334,8 +2334,6 @@ do_setup (GdmSessionWorker *worker)
+         GError  *error;
+         gboolean res;
+ 
+-        worker->priv->user_settings = gdm_session_settings_new ();
+-
+         g_signal_connect_swapped (worker->priv->user_settings,
+                                   "notify::language-name",
+                                   G_CALLBACK (on_saved_language_name_read),
+@@ -2961,6 +2959,7 @@ gdm_session_worker_init (GdmSessionWorker *worker)
+                                                            g_str_equal,
+                                                            (GDestroyNotify) g_free,
+                                                            (GDestroyNotify) g_free);
++        worker->priv->user_settings = gdm_session_settings_new ();
+ }
+ 
+ static void
+-- 
+1.7.2.1
+
+
+From f03a89dc0782aff6173b95ebc8e0ded678bcbb00 Mon Sep 17 00:00:00 2001
+From: Ray Strode <rstrode at redhat.com>
+Date: Tue, 13 Jul 2010 22:42:43 -0400
+Subject: [PATCH 06/35] disconnect signal handlers in destroy session
+
+We don't want them firing as part of object destruction
+---
+ daemon/gdm-simple-slave.c |  102 ++++++++++++++++++++++++++++++++++++++++----
+ 1 files changed, 92 insertions(+), 10 deletions(-)
+
+diff --git a/daemon/gdm-simple-slave.c b/daemon/gdm-simple-slave.c
+index 6b9159a..7187ea1 100644
+--- a/daemon/gdm-simple-slave.c
++++ b/daemon/gdm-simple-slave.c
+@@ -97,6 +97,7 @@ static void     gdm_simple_slave_finalize       (GObject             *object);
+ G_DEFINE_TYPE (GdmSimpleSlave, gdm_simple_slave, GDM_TYPE_SLAVE)
+ 
+ static void create_new_session (GdmSimpleSlave *slave);
++static void destroy_session    (GdmSimpleSlave *slave);
+ static void start_greeter      (GdmSimpleSlave *slave);
+ 
+ static void
+@@ -171,16 +172,6 @@ add_user_authorization (GdmSimpleSlave *slave,
+ }
+ 
+ static void
+-destroy_session (GdmSimpleSlave *slave)
+-{
+-        if (slave->priv->session != NULL) {
+-                gdm_session_close (GDM_SESSION (slave->priv->session));
+-                g_object_unref (slave->priv->session);
+-                slave->priv->session = NULL;
+-        }
+-}
+-
+-static void
+ reset_session (GdmSimpleSlave *slave)
+ {
+         destroy_session (slave);
+@@ -780,6 +771,97 @@ create_new_session (GdmSimpleSlave *slave)
+ }
+ 
+ static void
++destroy_session (GdmSimpleSlave *slave)
++{
++        g_signal_handlers_disconnect_by_func (slave->priv->session,
++                                              G_CALLBACK (on_session_conversation_started),
++                                              slave);
++        g_signal_handlers_disconnect_by_func (slave->priv->session,
++                                              G_CALLBACK (on_session_setup_complete),
++                                              slave);
++        g_signal_handlers_disconnect_by_func (slave->priv->session,
++                                              G_CALLBACK (on_session_setup_failed),
++                                              slave);
++        g_signal_handlers_disconnect_by_func (slave->priv->session,
++                                              G_CALLBACK (on_session_reset_complete),
++                                              slave);
++        g_signal_handlers_disconnect_by_func (slave->priv->session,
++                                              G_CALLBACK (on_session_reset_failed),
++                                              slave);
++        g_signal_handlers_disconnect_by_func (slave->priv->session,
++                                              G_CALLBACK (on_session_authenticated),
++                                              slave);
++        g_signal_handlers_disconnect_by_func (slave->priv->session,
++                                              G_CALLBACK (on_session_authentication_failed),
++                                              slave);
++        g_signal_handlers_disconnect_by_func (slave->priv->session,
++                                              G_CALLBACK (on_session_authorized),
++                                              slave);
++        g_signal_handlers_disconnect_by_func (slave->priv->session,
++                                              G_CALLBACK (on_session_authorization_failed),
++                                              slave);
++        g_signal_handlers_disconnect_by_func (slave->priv->session,
++                                              G_CALLBACK (on_session_accredited),
++                                              slave);
++        g_signal_handlers_disconnect_by_func (slave->priv->session,
++                                              G_CALLBACK (on_session_accreditation_failed),
++                                              slave);
++        g_signal_handlers_disconnect_by_func (slave->priv->session,
++                                              G_CALLBACK (on_session_opened),
++                                              slave);
++        g_signal_handlers_disconnect_by_func (slave->priv->session,
++                                              G_CALLBACK (on_session_open_failed),
++                                              slave);
++        g_signal_handlers_disconnect_by_func (slave->priv->session,
++                                              G_CALLBACK (on_session_info),
++                                              slave);
++        g_signal_handlers_disconnect_by_func (slave->priv->session,
++                                              G_CALLBACK (on_session_problem),
++                                              slave);
++        g_signal_handlers_disconnect_by_func (slave->priv->session,
++                                              G_CALLBACK (on_session_info_query),
++                                              slave);
++        g_signal_handlers_disconnect_by_func (slave->priv->session,
++                                              G_CALLBACK (on_session_secret_info_query),
++                                              slave);
++        g_signal_handlers_disconnect_by_func (slave->priv->session,
++                                              G_CALLBACK (on_session_started),
++                                              slave);
++        g_signal_handlers_disconnect_by_func (slave->priv->session,
++                                              G_CALLBACK (on_session_exited),
++                                              slave);
++        g_signal_handlers_disconnect_by_func (slave->priv->session,
++                                              G_CALLBACK (on_session_died),
++                                              slave);
++#if 0
++        g_signal_handlers_disconnect_by_func (slave->priv->session,
++                                              G_CALLBACK (on_session_closed),
++                                              slave);
++#endif
++        g_signal_handlers_disconnect_by_func (slave->priv->session,
++                                              G_CALLBACK (on_session_selected_user_changed),
++                                              slave);
++
++        g_signal_handlers_disconnect_by_func (slave->priv->session,
++                                              G_CALLBACK (on_default_language_name_changed),
++                                              slave);
++
++        g_signal_handlers_disconnect_by_func (slave->priv->session,
++                                              G_CALLBACK (on_default_layout_name_changed),
++                                              slave);
++
++        g_signal_handlers_disconnect_by_func (slave->priv->session,
++                                              G_CALLBACK (on_default_session_name_changed),
++                                              slave);
++
++        if (slave->priv->session != NULL) {
++                gdm_session_close (GDM_SESSION (slave->priv->session));
++                g_object_unref (slave->priv->session);
++                slave->priv->session = NULL;
++        }
++}
++
++static void
+ on_greeter_session_start (GdmGreeterSession *greeter,
+                           GdmSimpleSlave    *slave)
+ {
+-- 
+1.7.2.1
+
+
+From 211c78dbb4e45660da5e44c1c030661423d261ba Mon Sep 17 00:00:00 2001
 From: Ray Strode <rstrode at redhat.com>
 Date: Fri, 16 Jan 2009 11:00:08 -0500
-Subject: [PATCH 01/45] Introduce new Conversation object
+Subject: [PATCH 07/35] Introduce new Conversation object
 
 We want to eventually support having multiple
 simultaneous PAM conversations in one login
@@ -29,7 +408,7 @@ screen is talking to.
  11 files changed, 263 insertions(+), 145 deletions(-)
 
 diff --git a/daemon/gdm-factory-slave.c b/daemon/gdm-factory-slave.c
-index 606c995..bd98445 100644
+index b413497..0151ab2 100644
 --- a/daemon/gdm-factory-slave.c
 +++ b/daemon/gdm-factory-slave.c
 @@ -181,7 +181,8 @@ on_session_secret_info_query (GdmSession      *session,
@@ -42,7 +421,7 @@ index 606c995..bd98445 100644
  {
          g_debug ("GdmFactorySlave: session conversation started");
  
-@@ -388,7 +389,7 @@ on_session_relay_connected (GdmSessionRelay *session,
+@@ -389,7 +390,7 @@ on_session_relay_connected (GdmSessionRelay *session,
  {
          g_debug ("GdmFactorySlave: Relay Connected");
  
@@ -52,7 +431,7 @@ index 606c995..bd98445 100644
  
  static void
 diff --git a/daemon/gdm-product-slave.c b/daemon/gdm-product-slave.c
-index 1fff780..ec6300d 100644
+index a423965..9be89b4 100644
 --- a/daemon/gdm-product-slave.c
 +++ b/daemon/gdm-product-slave.c
 @@ -246,19 +246,21 @@ relay_session_started (GdmProductSlave *slave,
@@ -108,10 +487,10 @@ index 1fff780..ec6300d 100644
  
  static void
 diff --git a/daemon/gdm-session-direct.c b/daemon/gdm-session-direct.c
-index 031ae33..66e4e0e 100644
+index 0282ab7..f9621a2 100644
 --- a/daemon/gdm-session-direct.c
 +++ b/daemon/gdm-session-direct.c
-@@ -66,6 +66,16 @@
+@@ -67,6 +67,16 @@
  #define GDM_SESSION_DEFAULT_PATH "/usr/local/bin:/usr/bin:/bin"
  #endif
  
@@ -128,7 +507,7 @@ index 031ae33..66e4e0e 100644
  struct _GdmSessionDirectPrivate
  {
          /* per open scope */
-@@ -78,8 +88,7 @@ struct _GdmSessionDirectPrivate
+@@ -79,8 +89,7 @@ struct _GdmSessionDirectPrivate
          char                *selected_user;
          char                *user_x11_authority_file;
  
@@ -138,7 +517,7 @@ index 031ae33..66e4e0e 100644
  
          GdmSessionWorkerJob *job;
          GPid                 session_pid;
-@@ -120,39 +129,39 @@ G_DEFINE_TYPE_WITH_CODE (GdmSessionDirect,
+@@ -123,39 +132,39 @@ G_DEFINE_TYPE_WITH_CODE (GdmSessionDirect,
                                                  gdm_session_iface_init))
  
  static gboolean
@@ -185,7 +564,7 @@ index 031ae33..66e4e0e 100644
  
          message = dbus_message_new_signal (GDM_SESSION_DBUS_PATH,
                                             GDM_SESSION_DBUS_INTERFACE,
-@@ -161,7 +170,7 @@ send_dbus_string_signal (GdmSessionDirect *session,
+@@ -164,7 +173,7 @@ send_dbus_string_signal (GdmSessionDirect *session,
          dbus_message_iter_init_append (message, &iter);
          dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &text);
  
@@ -194,7 +573,7 @@ index 031ae33..66e4e0e 100644
                  g_debug ("GdmSessionDirect: Could not send %s signal",
                           name ? name : "(null)");
          }
-@@ -170,18 +179,18 @@ send_dbus_string_signal (GdmSessionDirect *session,
+@@ -173,18 +182,18 @@ send_dbus_string_signal (GdmSessionDirect *session,
  }
  
  static void
@@ -217,7 +596,7 @@ index 031ae33..66e4e0e 100644
                  g_debug ("GdmSessionDirect: Could not send %s signal", name);
          }
  
-@@ -193,22 +202,32 @@ on_authentication_failed (GdmSession *session,
+@@ -196,22 +205,32 @@ on_authentication_failed (GdmSession *session,
                            const char *message)
  {
          GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
@@ -260,7 +639,7 @@ index 031ae33..66e4e0e 100644
  }
  
  static void
-@@ -216,11 +235,16 @@ on_session_start_failed (GdmSession *session,
+@@ -219,11 +238,16 @@ on_session_start_failed (GdmSession *session,
                           const char *message)
  {
          GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
@@ -282,7 +661,7 @@ index 031ae33..66e4e0e 100644
  }
  
  static void
-@@ -228,6 +252,7 @@ on_session_exited (GdmSession *session,
+@@ -231,6 +255,7 @@ on_session_exited (GdmSession *session,
                     int        exit_code)
  {
          GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
@@ -290,7 +669,7 @@ index 031ae33..66e4e0e 100644
          gdm_session_record_logout (impl->priv->session_pid,
                                     impl->priv->selected_user,
                                     impl->priv->display_hostname,
-@@ -770,54 +795,52 @@ gdm_session_direct_handle_username_changed (GdmSessionDirect *session,
+@@ -815,54 +840,52 @@ gdm_session_direct_handle_username_changed (GdmSessionDirect *session,
  }
  
  static void
@@ -362,7 +741,7 @@ index 031ae33..66e4e0e 100644
  }
  
  static DBusHandlerResult
-@@ -827,6 +850,9 @@ gdm_session_direct_handle_info_query (GdmSessionDirect *session,
+@@ -872,6 +895,9 @@ gdm_session_direct_handle_info_query (GdmSessionDirect *session,
  {
          DBusError    error;
          const char  *text;
@@ -372,7 +751,7 @@ index 031ae33..66e4e0e 100644
  
          dbus_error_init (&error);
          if (! dbus_message_get_args (message, &error,
-@@ -835,7 +861,7 @@ gdm_session_direct_handle_info_query (GdmSessionDirect *session,
+@@ -880,7 +906,7 @@ gdm_session_direct_handle_info_query (GdmSessionDirect *session,
                  g_warning ("ERROR: %s", error.message);
          }
  
@@ -381,7 +760,7 @@ index 031ae33..66e4e0e 100644
  
          g_debug ("GdmSessionDirect: Emitting 'info-query' signal");
          _gdm_session_info_query (GDM_SESSION (session), text);
-@@ -850,6 +876,9 @@ gdm_session_direct_handle_secret_info_query (GdmSessionDirect *session,
+@@ -895,6 +921,9 @@ gdm_session_direct_handle_secret_info_query (GdmSessionDirect *session,
  {
          DBusError    error;
          const char  *text;
@@ -391,7 +770,7 @@ index 031ae33..66e4e0e 100644
  
          dbus_error_init (&error);
          if (! dbus_message_get_args (message, &error,
-@@ -858,7 +887,7 @@ gdm_session_direct_handle_secret_info_query (GdmSessionDirect *session,
+@@ -903,7 +932,7 @@ gdm_session_direct_handle_secret_info_query (GdmSessionDirect *session,
                  g_warning ("ERROR: %s", error.message);
          }
  
@@ -400,7 +779,7 @@ index 031ae33..66e4e0e 100644
  
          g_debug ("GdmSessionDirect: Emitting 'secret-info-query' signal");
          _gdm_session_secret_info_query (GDM_SESSION (session), text);
-@@ -898,9 +927,13 @@ gdm_session_direct_handle_cancel_pending_query (GdmSessionDirect *session,
+@@ -943,9 +972,13 @@ gdm_session_direct_handle_cancel_pending_query (GdmSessionDirect *session,
                                                  DBusMessage      *message)
  {
          DBusMessage *reply;
@@ -415,7 +794,7 @@ index 031ae33..66e4e0e 100644
  
          reply = dbus_message_new_method_return (message);
          dbus_connection_send (connection, reply, NULL);
-@@ -1522,16 +1555,18 @@ handle_connection (DBusServer      *server,
+@@ -1567,16 +1600,18 @@ handle_connection (DBusServer      *server,
                     void            *user_data)
  {
          GdmSessionDirect *session = GDM_SESSION_DIRECT (user_data);
@@ -436,7 +815,7 @@ index 031ae33..66e4e0e 100644
                  dbus_connection_ref (new_connection);
                  dbus_connection_setup_with_g_main (new_connection, NULL);
  
-@@ -1549,7 +1584,8 @@ handle_connection (DBusServer      *server,
+@@ -1594,7 +1629,8 @@ handle_connection (DBusServer      *server,
                                                        session);
  
                  g_debug ("GdmSessionDirect: Emitting conversation-started signal");
@@ -446,7 +825,7 @@ index 031ae33..66e4e0e 100644
          }
  }
  
-@@ -1619,8 +1655,6 @@ gdm_session_direct_init (GdmSessionDirect *session)
+@@ -1664,8 +1700,6 @@ gdm_session_direct_init (GdmSessionDirect *session)
                            G_CALLBACK (on_session_exited),
                            NULL);
  
@@ -455,7 +834,7 @@ index 031ae33..66e4e0e 100644
          session->priv->environment = g_hash_table_new_full (g_str_hash,
                                                              g_str_equal,
                                                              (GDestroyNotify) g_free,
-@@ -1632,7 +1666,7 @@ gdm_session_direct_init (GdmSessionDirect *session)
+@@ -1677,7 +1711,7 @@ gdm_session_direct_init (GdmSessionDirect *session)
  
  static void
  worker_started (GdmSessionWorkerJob *job,
@@ -464,7 +843,7 @@ index 031ae33..66e4e0e 100644
  {
          g_debug ("GdmSessionDirect: Worker job started");
  }
-@@ -1640,87 +1674,105 @@ worker_started (GdmSessionWorkerJob *job,
+@@ -1685,87 +1719,105 @@ worker_started (GdmSessionWorkerJob *job,
  static void
  worker_exited (GdmSessionWorkerJob *job,
                 int                  code,
@@ -606,7 +985,7 @@ index 031ae33..66e4e0e 100644
  }
  
  static void
-@@ -1733,6 +1785,7 @@ send_setup (GdmSessionDirect *session,
+@@ -1778,6 +1830,7 @@ send_setup (GdmSessionDirect *session,
          const char     *display_device;
          const char     *display_hostname;
          const char     *display_x11_authority_file;
@@ -614,7 +993,7 @@ index 031ae33..66e4e0e 100644
  
          g_assert (service_name != NULL);
  
-@@ -1770,7 +1823,8 @@ send_setup (GdmSessionDirect *session,
+@@ -1815,7 +1868,8 @@ send_setup (GdmSessionDirect *session,
          dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &display_hostname);
          dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &display_x11_authority_file);
  
@@ -624,7 +1003,7 @@ index 031ae33..66e4e0e 100644
                  g_debug ("GdmSessionDirect: Could not send %s signal", "Setup");
          }
  
-@@ -1788,6 +1842,7 @@ send_setup_for_user (GdmSessionDirect *session,
+@@ -1833,6 +1887,7 @@ send_setup_for_user (GdmSessionDirect *session,
          const char     *display_hostname;
          const char     *display_x11_authority_file;
          const char     *selected_user;
@@ -632,7 +1011,7 @@ index 031ae33..66e4e0e 100644
  
          g_assert (service_name != NULL);
  
-@@ -1831,7 +1886,8 @@ send_setup_for_user (GdmSessionDirect *session,
+@@ -1876,7 +1931,8 @@ send_setup_for_user (GdmSessionDirect *session,
          dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &display_x11_authority_file);
          dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &selected_user);
  
@@ -642,7 +1021,7 @@ index 031ae33..66e4e0e 100644
                  g_debug ("GdmSessionDirect: Could not send %s signal", "SetupForUser");
          }
  
-@@ -1845,7 +1901,8 @@ gdm_session_direct_setup (GdmSession *session,
+@@ -1890,7 +1946,8 @@ gdm_session_direct_setup (GdmSession *session,
          GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
  
          g_return_if_fail (session != NULL);
@@ -652,7 +1031,7 @@ index 031ae33..66e4e0e 100644
  
          send_setup (impl, service_name);
          gdm_session_direct_defaults_changed (impl);
-@@ -1859,7 +1916,8 @@ gdm_session_direct_setup_for_user (GdmSession *session,
+@@ -1904,7 +1961,8 @@ gdm_session_direct_setup_for_user (GdmSession *session,
          GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
  
          g_return_if_fail (session != NULL);
@@ -662,7 +1041,7 @@ index 031ae33..66e4e0e 100644
          g_return_if_fail (username != NULL);
  
          gdm_session_direct_select_user (session, username);
-@@ -1872,22 +1930,28 @@ static void
+@@ -1917,22 +1975,28 @@ static void
  gdm_session_direct_authenticate (GdmSession *session)
  {
          GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
@@ -695,7 +1074,7 @@ index 031ae33..66e4e0e 100644
  }
  
  static void
-@@ -1895,16 +1959,19 @@ gdm_session_direct_accredit (GdmSession *session,
+@@ -1940,16 +2004,19 @@ gdm_session_direct_accredit (GdmSession *session,
                               int         cred_flag)
  {
          GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
@@ -718,7 +1097,7 @@ index 031ae33..66e4e0e 100644
                  break;
          default:
                  g_assert_not_reached ();
-@@ -1918,6 +1985,7 @@ send_environment_variable (const char       *key,
+@@ -1963,6 +2030,7 @@ send_environment_variable (const char       *key,
  {
          DBusMessage    *message;
          DBusMessageIter iter;
@@ -726,7 +1105,7 @@ index 031ae33..66e4e0e 100644
  
          message = dbus_message_new_signal (GDM_SESSION_DBUS_PATH,
                                             GDM_SESSION_DBUS_INTERFACE,
-@@ -1927,7 +1995,8 @@ send_environment_variable (const char       *key,
+@@ -1972,7 +2040,8 @@ send_environment_variable (const char       *key,
          dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key);
          dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &value);
  
@@ -736,7 +1115,7 @@ index 031ae33..66e4e0e 100644
                  g_debug ("GdmSessionDirect: Could not send %s signal", "SetEnvironmentVariable");
          }
  
-@@ -2075,6 +2144,7 @@ static void
+@@ -2120,6 +2189,7 @@ static void
  gdm_session_direct_start_session (GdmSession *session)
  {
          GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
@@ -744,7 +1123,7 @@ index 031ae33..66e4e0e 100644
          char             *command;
          char             *program;
  
-@@ -2094,7 +2164,8 @@ gdm_session_direct_start_session (GdmSession *session)
+@@ -2139,7 +2209,8 @@ gdm_session_direct_start_session (GdmSession *session)
          setup_session_environment (impl);
          send_environment (impl);
  
@@ -754,7 +1133,7 @@ index 031ae33..66e4e0e 100644
          g_free (program);
  }
  
-@@ -2107,16 +2178,12 @@ gdm_session_direct_close (GdmSession *session)
+@@ -2152,16 +2223,12 @@ gdm_session_direct_close (GdmSession *session)
  
          g_debug ("GdmSessionDirect: Closing session");
  
@@ -777,7 +1156,7 @@ index 031ae33..66e4e0e 100644
          }
  
          g_free (impl->priv->selected_user);
-@@ -2154,10 +2221,13 @@ gdm_session_direct_answer_query  (GdmSession *session,
+@@ -2199,10 +2266,13 @@ gdm_session_direct_answer_query  (GdmSession *session,
                                    const char *text)
  {
          GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
@@ -792,7 +1171,7 @@ index 031ae33..66e4e0e 100644
  }
  
  static void
-@@ -2167,7 +2237,7 @@ gdm_session_direct_cancel  (GdmSession *session)
+@@ -2212,7 +2282,7 @@ gdm_session_direct_cancel  (GdmSession *session)
  
          g_return_if_fail (session != NULL);
  
@@ -801,7 +1180,7 @@ index 031ae33..66e4e0e 100644
  }
  
  char *
-@@ -2232,6 +2302,7 @@ gdm_session_direct_select_session (GdmSession *session,
+@@ -2276,6 +2346,7 @@ gdm_session_direct_select_session (GdmSession *session,
                                     const char *text)
  {
          GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
@@ -809,7 +1188,7 @@ index 031ae33..66e4e0e 100644
  
          g_free (impl->priv->selected_session);
  
-@@ -2241,7 +2312,8 @@ gdm_session_direct_select_session (GdmSession *session,
+@@ -2285,7 +2356,8 @@ gdm_session_direct_select_session (GdmSession *session,
                  impl->priv->selected_session = g_strdup (text);
          }
  
@@ -819,7 +1198,7 @@ index 031ae33..66e4e0e 100644
                                   get_session_name (impl));
  }
  
-@@ -2250,6 +2322,7 @@ gdm_session_direct_select_language (GdmSession *session,
+@@ -2294,6 +2366,7 @@ gdm_session_direct_select_language (GdmSession *session,
                                      const char *text)
  {
          GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
@@ -827,7 +1206,7 @@ index 031ae33..66e4e0e 100644
  
          g_free (impl->priv->selected_language);
  
-@@ -2259,7 +2332,8 @@ gdm_session_direct_select_language (GdmSession *session,
+@@ -2303,7 +2376,8 @@ gdm_session_direct_select_language (GdmSession *session,
                  impl->priv->selected_language = g_strdup (text);
          }
  
@@ -837,7 +1216,7 @@ index 031ae33..66e4e0e 100644
                                   get_language_name (impl));
  }
  
-@@ -2268,6 +2342,7 @@ gdm_session_direct_select_layout (GdmSession *session,
+@@ -2312,6 +2386,7 @@ gdm_session_direct_select_layout (GdmSession *session,
                                    const char *text)
  {
          GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
@@ -845,7 +1224,7 @@ index 031ae33..66e4e0e 100644
  
          g_free (impl->priv->selected_layout);
  
-@@ -2277,7 +2352,8 @@ gdm_session_direct_select_layout (GdmSession *session,
+@@ -2321,7 +2396,8 @@ gdm_session_direct_select_layout (GdmSession *session,
                  impl->priv->selected_layout = g_strdup (text);
          }
  
@@ -928,10 +1307,10 @@ index da0ecb3..a0b4cbf 100644
                                 "    <signal name=\"Close\">\n"
                                 "    </signal>\n"
 diff --git a/daemon/gdm-session-worker-job.c b/daemon/gdm-session-worker-job.c
-index 633d6e2..9c020fa 100644
+index 50bf4c0..f686002 100644
 --- a/daemon/gdm-session-worker-job.c
 +++ b/daemon/gdm-session-worker-job.c
-@@ -296,6 +296,13 @@ gdm_session_worker_job_stop (GdmSessionWorkerJob *session_worker_job)
+@@ -303,6 +303,13 @@ gdm_session_worker_job_stop (GdmSessionWorkerJob *session_worker_job)
          return TRUE;
  }
  
@@ -1035,10 +1414,10 @@ index fb199d3..00c2fa4 100644
                                                    const char *service_name);
  void     gdm_session_setup_for_user              (GdmSession *session,
 diff --git a/daemon/gdm-simple-slave.c b/daemon/gdm-simple-slave.c
-index 2910366..b3367fa 100644
+index 7187ea1..bd1ecad 100644
 --- a/daemon/gdm-simple-slave.c
 +++ b/daemon/gdm-simple-slave.c
-@@ -179,7 +179,6 @@ reset_session (GdmSimpleSlave *slave)
+@@ -176,7 +176,6 @@ reset_session (GdmSimpleSlave *slave)
  {
          destroy_session (slave);
          create_new_session (slave);
@@ -1046,7 +1425,7 @@ index 2910366..b3367fa 100644
  }
  
  static gboolean
-@@ -862,8 +861,6 @@ on_greeter_connected (GdmGreeterServer *greeter_server,
+@@ -981,8 +980,6 @@ on_greeter_connected (GdmGreeterServer *greeter_server,
  
          g_debug ("GdmSimpleSlave: Greeter connected");
  
@@ -1056,7 +1435,7 @@ index 2910366..b3367fa 100644
                        "display-is-local", &display_is_local,
                        NULL);
 diff --git a/daemon/test-session.c b/daemon/test-session.c
-index 9a4d7cf..ed13ff7 100644
+index 8bed085..9bfda86 100644
 --- a/daemon/test-session.c
 +++ b/daemon/test-session.c
 @@ -34,11 +34,12 @@ static GMainLoop *loop;
@@ -1073,7 +1452,7 @@ index 9a4d7cf..ed13ff7 100644
  }
  
  static void
-@@ -256,7 +257,7 @@ main (int   argc,
+@@ -267,7 +268,7 @@ main (int   argc,
                          username = argv[1];
                  }
  
@@ -1083,13 +1462,13 @@ index 9a4d7cf..ed13ff7 100644
                  g_signal_connect (session,
                                    "conversation-started",
 -- 
-1.6.5.2
+1.7.2.1
 
 
-From e408070a9096fc33bcbc95a231c6971ff70db5db Mon Sep 17 00:00:00 2001
+From d6e02a0b140b831adb0c7509eccb0e9039616b29 Mon Sep 17 00:00:00 2001
 From: Ray Strode <rstrode at redhat.com>
 Date: Wed, 4 Feb 2009 10:55:03 -0500
-Subject: [PATCH 02/45] Rename session worker to the service it's managing
+Subject: [PATCH 08/35] Rename session worker to the service it's managing
 
 This way when we're running multiple PAM conversations at once
 it will be obvious which worker is managing which conversation.
@@ -1100,10 +1479,10 @@ it will be obvious which worker is managing which conversation.
  3 files changed, 57 insertions(+), 16 deletions(-)
 
 diff --git a/daemon/gdm-session-direct.c b/daemon/gdm-session-direct.c
-index 66e4e0e..3a89871 100644
+index f9621a2..cfbaa15 100644
 --- a/daemon/gdm-session-direct.c
 +++ b/daemon/gdm-session-direct.c
-@@ -1700,6 +1700,7 @@ start_conversation (GdmSessionDirect *session,
+@@ -1745,6 +1745,7 @@ start_conversation (GdmSessionDirect *session,
                      const char       *service_name)
  {
          GdmSessionConversation *conversation;
@@ -1111,7 +1490,7 @@ index 66e4e0e..3a89871 100644
  
          conversation = g_new0 (GdmSessionConversation, 1);
          conversation->session = session;
-@@ -1720,12 +1721,16 @@ start_conversation (GdmSessionDirect *session,
+@@ -1765,12 +1766,16 @@ start_conversation (GdmSessionDirect *session,
                            G_CALLBACK (worker_died),
                            conversation);
  
@@ -1130,10 +1509,10 @@ index 66e4e0e..3a89871 100644
          conversation->worker_pid = gdm_session_worker_job_get_pid (conversation->job);
  
 diff --git a/daemon/gdm-session-worker-job.c b/daemon/gdm-session-worker-job.c
-index 9c020fa..0327d77 100644
+index f686002..be85f30 100644
 --- a/daemon/gdm-session-worker-job.c
 +++ b/daemon/gdm-session-worker-job.c
-@@ -149,6 +149,37 @@ copy_environment_to_hash (GHashTable *hash)
+@@ -156,6 +156,37 @@ copy_environment_to_hash (GHashTable *hash)
  }
  
  static GPtrArray *
@@ -1171,7 +1550,7 @@ index 9c020fa..0327d77 100644
  get_job_environment (GdmSessionWorkerJob *job)
  {
          GPtrArray     *env;
-@@ -171,31 +202,31 @@ get_job_environment (GdmSessionWorkerJob *job)
+@@ -178,31 +209,31 @@ get_job_environment (GdmSessionWorkerJob *job)
  }
  
  static gboolean
@@ -1214,7 +1593,7 @@ index 9c020fa..0327d77 100644
                                          (GSpawnChildSetupFunc)session_worker_job_child_setup,
                                          session_worker_job,
                                          &session_worker_job->priv->pid,
-@@ -204,6 +235,9 @@ gdm_session_worker_job_spawn (GdmSessionWorkerJob *session_worker_job)
+@@ -211,6 +242,9 @@ gdm_session_worker_job_spawn (GdmSessionWorkerJob *session_worker_job)
                                          NULL,
                                          &error);
  
@@ -1224,7 +1603,7 @@ index 9c020fa..0327d77 100644
          g_ptr_array_foreach (env, (GFunc)g_free, NULL);
          g_ptr_array_free (env, TRUE);
  
-@@ -220,7 +254,6 @@ gdm_session_worker_job_spawn (GdmSessionWorkerJob *session_worker_job)
+@@ -227,7 +261,6 @@ gdm_session_worker_job_spawn (GdmSessionWorkerJob *session_worker_job)
                                                                        (GChildWatchFunc)session_worker_job_child_watch,
                                                                        session_worker_job);
  
@@ -1232,7 +1611,7 @@ index 9c020fa..0327d77 100644
   out:
  
          return ret;
-@@ -233,13 +266,14 @@ gdm_session_worker_job_spawn (GdmSessionWorkerJob *session_worker_job)
+@@ -240,13 +273,14 @@ gdm_session_worker_job_spawn (GdmSessionWorkerJob *session_worker_job)
   * Starts a local X session_worker_job. Handles retries and fatal errors properly.
   */
  gboolean
@@ -1249,7 +1628,7 @@ index 9c020fa..0327d77 100644
  
          if (res) {
  
-@@ -287,6 +321,7 @@ gdm_session_worker_job_stop (GdmSessionWorkerJob *session_worker_job)
+@@ -294,6 +328,7 @@ gdm_session_worker_job_stop (GdmSessionWorkerJob *session_worker_job)
          g_debug ("GdmSessionWorkerJob: Stopping job pid:%d", session_worker_job->priv->pid);
  
          res = gdm_signal_pid (session_worker_job->priv->pid, SIGTERM);
@@ -1272,18 +1651,19 @@ index d24f025..4833f23 100644
  
  GPid                    gdm_session_worker_job_get_pid            (GdmSessionWorkerJob *session_worker_job);
 -- 
-1.6.5.2
+1.7.2.1
 
 
-From a914187b5f2efb214ca2a41b1fe087d9d9833a32 Mon Sep 17 00:00:00 2001
+From 23a4e811a336f275dd50536599ed9336b0c6a55b Mon Sep 17 00:00:00 2001
 From: Ray Strode <rstrode at redhat.com>
 Date: Fri, 16 Jan 2009 13:01:48 -0500
-Subject: [PATCH 03/45] Make greeter explicitly request PAM conversation
+Subject: [PATCH 09/35] Make greeter/autologin session explicitly request PAM conversation
 
-Now the greeter has to say what PAM stack it wants the slave to
-run.  When that stack is ready, we emit the Ready signal as
-before, but now the Ready signal carries a string argument
-saying which service is ready to converse.
+Now the greeter (and also the autologin code) has to say what
+PAM stack it wants the slave to run.  When that stack is ready,
+we emit the Ready signal as before, but now the Ready signal
+carries a string argument saying which service is ready to
+converse.
 
 When we support multiple PAM stacks, the greeter will call
 StartConversation for each stack, and will keep the UI
@@ -1293,14 +1673,14 @@ come back one-by-one.
  daemon/gdm-factory-slave.c               |    3 +-
  daemon/gdm-greeter-server.c              |   53 ++++++++++++++++++++++++++++--
  daemon/gdm-greeter-server.h              |    5 ++-
- daemon/gdm-simple-slave.c                |   22 +++++++++++-
+ daemon/gdm-simple-slave.c                |   39 +++++++++++++++++++++-
  gui/simple-greeter/gdm-greeter-client.c  |   18 ++++++----
  gui/simple-greeter/gdm-greeter-client.h  |    4 ++-
  gui/simple-greeter/gdm-greeter-session.c |    4 ++
- 7 files changed, 94 insertions(+), 15 deletions(-)
+ 7 files changed, 111 insertions(+), 15 deletions(-)
 
 diff --git a/daemon/gdm-factory-slave.c b/daemon/gdm-factory-slave.c
-index bd98445..ca3ba48 100644
+index 0151ab2..f30664f 100644
 --- a/daemon/gdm-factory-slave.c
 +++ b/daemon/gdm-factory-slave.c
 @@ -186,7 +186,8 @@ on_session_conversation_started (GdmSession      *session,
@@ -1314,10 +1694,10 @@ index bd98445..ca3ba48 100644
  
  static void
 diff --git a/daemon/gdm-greeter-server.c b/daemon/gdm-greeter-server.c
-index cecce83..ffca7ec 100644
+index 1ab01e4..03ecfca 100644
 --- a/daemon/gdm-greeter-server.c
 +++ b/daemon/gdm-greeter-server.c
-@@ -69,6 +69,7 @@ enum {
+@@ -70,6 +70,7 @@ enum {
  };
  
  enum {
@@ -1325,7 +1705,7 @@ index cecce83..ffca7ec 100644
          BEGIN_AUTO_LOGIN,
          BEGIN_VERIFICATION,
          BEGIN_VERIFICATION_FOR_USER,
-@@ -246,9 +247,10 @@ gdm_greeter_server_reset (GdmGreeterServer *greeter_server)
+@@ -254,9 +255,10 @@ gdm_greeter_server_reset (GdmGreeterServer *greeter_server)
  }
  
  gboolean
@@ -1338,7 +1718,7 @@ index cecce83..ffca7ec 100644
          return TRUE;
  }
  
-@@ -323,6 +325,34 @@ generate_address (void)
+@@ -331,6 +333,34 @@ generate_address (void)
  }
  
  static DBusHandlerResult
@@ -1373,7 +1753,7 @@ index cecce83..ffca7ec 100644
  handle_begin_verification (GdmGreeterServer *greeter_server,
                             DBusConnection   *connection,
                             DBusMessage      *message)
-@@ -645,7 +675,9 @@ greeter_handle_child_message (DBusConnection *connection,
+@@ -653,7 +683,9 @@ greeter_handle_child_message (DBusConnection *connection,
  {
          GdmGreeterServer *greeter_server = GDM_GREETER_SERVER (user_data);
  
@@ -1384,7 +1764,7 @@ index cecce83..ffca7ec 100644
                  return handle_begin_verification (greeter_server, connection, message);
          } else if (dbus_message_is_method_call (message, GDM_GREETER_SERVER_DBUS_INTERFACE, "BeginVerificationForUser")) {
                  return handle_begin_verification_for_user (greeter_server, connection, message);
-@@ -699,7 +731,11 @@ do_introspect (DBusConnection *connection,
+@@ -707,7 +739,11 @@ do_introspect (DBusConnection *connection,
          /* interface */
          xml = g_string_append (xml,
                                 "  <interface name=\"org.gnome.DisplayManager.GreeterServer\">\n"
@@ -1396,7 +1776,7 @@ index cecce83..ffca7ec 100644
                                 "    <method name=\"BeginTimedLogin\">\n"
                                 "    </method>\n"
                                 "    <method name=\"BeginVerificationForUser\">\n"
-@@ -759,6 +795,7 @@ do_introspect (DBusConnection *connection,
+@@ -767,6 +803,7 @@ do_introspect (DBusConnection *connection,
                                 "      <arg name=\"delay\" type=\"i\"/>\n"
                                 "    </signal>\n"
                                 "    <signal name=\"Ready\">\n"
@@ -1404,7 +1784,7 @@ index cecce83..ffca7ec 100644
                                 "    </signal>\n"
                                 "    <signal name=\"Reset\">\n"
                                 "    </signal>\n"
-@@ -1121,6 +1158,16 @@ gdm_greeter_server_class_init (GdmGreeterServerClass *klass)
+@@ -1131,6 +1168,16 @@ gdm_greeter_server_class_init (GdmGreeterServerClass *klass)
                                                                "group name",
                                                                GDM_GROUPNAME,
                                                                G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
@@ -1422,7 +1802,7 @@ index cecce83..ffca7ec 100644
                  g_signal_new ("begin-verification",
                                G_OBJECT_CLASS_TYPE (object_class),
 diff --git a/daemon/gdm-greeter-server.h b/daemon/gdm-greeter-server.h
-index 6e92100..7333db1 100644
+index f9c157f..7e2424a 100644
 --- a/daemon/gdm-greeter-server.h
 +++ b/daemon/gdm-greeter-server.h
 @@ -45,6 +45,8 @@ typedef struct
@@ -1434,9 +1814,9 @@ index 6e92100..7333db1 100644
          void (* begin_auto_login)           (GdmGreeterServer  *greeter_server);
          void (* begin_verification)         (GdmGreeterServer  *greeter_server);
          void (* begin_verification_for_user)(GdmGreeterServer  *greeter_server,
-@@ -85,7 +87,8 @@ gboolean            gdm_greeter_server_info                  (GdmGreeterServer *
- gboolean            gdm_greeter_server_problem               (GdmGreeterServer *greeter_server,
+@@ -86,7 +88,8 @@ gboolean            gdm_greeter_server_problem               (GdmGreeterServer *
                                                                const char       *text);
+ gboolean            gdm_greeter_server_authentication_failed (GdmGreeterServer *greeter_server);
  gboolean            gdm_greeter_server_reset                 (GdmGreeterServer *greeter_server);
 -gboolean            gdm_greeter_server_ready                 (GdmGreeterServer *greeter_server);
 +gboolean            gdm_greeter_server_ready                 (GdmGreeterServer *greeter_server,
@@ -1445,10 +1825,10 @@ index 6e92100..7333db1 100644
                                                                const char       *text);
  void                gdm_greeter_server_default_language_name_changed (GdmGreeterServer *greeter_server,
 diff --git a/daemon/gdm-simple-slave.c b/daemon/gdm-simple-slave.c
-index b3367fa..1a64bbb 100644
+index bd1ecad..dc7b437 100644
 --- a/daemon/gdm-simple-slave.c
 +++ b/daemon/gdm-simple-slave.c
-@@ -517,6 +517,7 @@ on_session_secret_info_query (GdmSession     *session,
+@@ -545,6 +545,7 @@ on_session_secret_info_query (GdmSession     *session,
  
  static void
  on_session_conversation_started (GdmSession     *session,
@@ -1456,7 +1836,7 @@ index b3367fa..1a64bbb 100644
                                   GdmSimpleSlave *slave)
  {
          gboolean res;
-@@ -526,7 +527,8 @@ on_session_conversation_started (GdmSession     *session,
+@@ -554,7 +555,8 @@ on_session_conversation_started (GdmSession     *session,
  
          g_debug ("GdmSimpleSlave: session conversation started");
          if (slave->priv->greeter_server != NULL) {
@@ -1466,7 +1846,7 @@ index b3367fa..1a64bbb 100644
                  if (! res) {
                          g_warning ("Unable to send ready");
                  }
-@@ -542,8 +544,10 @@ on_session_conversation_started (GdmSession     *session,
+@@ -570,8 +572,10 @@ on_session_conversation_started (GdmSession     *session,
                  gdm_greeter_server_request_timed_login (slave->priv->greeter_server, username, delay);
          } else {
                  g_debug ("GdmSimpleSlave: begin auto login for user '%s'", username);
@@ -1478,7 +1858,38 @@ index b3367fa..1a64bbb 100644
                                              username);
          }
  
-@@ -775,6 +779,16 @@ on_greeter_session_died (GdmGreeterSession    *greeter,
+@@ -627,6 +631,21 @@ on_default_session_name_changed (GdmSession     *session,
+ }
+ 
+ static void
++start_autologin_conversation_if_necessary (GdmSimpleSlave *slave)
++{
++        gboolean enabled;
++        gdm_slave_get_timed_login_details (GDM_SLAVE (slave), &enabled, NULL, NULL);
++
++        if (!enabled) {
++                return;
++        }
++
++        g_debug ("GdmSimpleSlave: Starting automatic login conversation");
++        gdm_session_start_conversation (GDM_SESSION (slave->priv->session),
++                                        "gdm-autologin");
++}
++
++static void
+ create_new_session (GdmSimpleSlave *slave)
+ {
+         gboolean       display_is_local;
+@@ -767,6 +786,8 @@ create_new_session (GdmSimpleSlave *slave)
+                           "default-session-name-changed",
+                           G_CALLBACK (on_default_session_name_changed),
+                           slave);
++
++        start_autologin_conversation_if_necessary (slave);
+ }
+ 
+ static void
+@@ -894,6 +915,16 @@ on_greeter_session_died (GdmGreeterSession    *greeter,
  }
  
  static void
@@ -1495,7 +1906,7 @@ index b3367fa..1a64bbb 100644
  on_greeter_begin_verification (GdmGreeterServer *greeter_server,
                                 GdmSimpleSlave   *slave)
  {
-@@ -949,6 +963,10 @@ start_greeter (GdmSimpleSlave *slave)
+@@ -1071,6 +1102,10 @@ start_greeter (GdmSimpleSlave *slave)
  
          slave->priv->greeter_server = gdm_greeter_server_new (display_id);
          g_signal_connect (slave->priv->greeter_server,
@@ -1507,10 +1918,10 @@ index b3367fa..1a64bbb 100644
                            G_CALLBACK (on_greeter_begin_auto_login),
                            slave);
 diff --git a/gui/simple-greeter/gdm-greeter-client.c b/gui/simple-greeter/gdm-greeter-client.c
-index ed4dd95..8d061a4 100644
+index d02b3d1..b175fc9 100644
 --- a/gui/simple-greeter/gdm-greeter-client.c
 +++ b/gui/simple-greeter/gdm-greeter-client.c
-@@ -237,11 +237,7 @@ static void
+@@ -238,11 +238,7 @@ static void
  on_ready (GdmGreeterClient *client,
            DBusMessage      *message)
  {
@@ -1523,7 +1934,7 @@ index ed4dd95..8d061a4 100644
  }
  
  static void
-@@ -400,6 +396,14 @@ send_dbus_void_method (DBusConnection *connection,
+@@ -412,6 +408,14 @@ send_dbus_void_method (DBusConnection *connection,
  }
  
  void
@@ -1538,7 +1949,7 @@ index ed4dd95..8d061a4 100644
  gdm_greeter_client_call_begin_auto_login (GdmGreeterClient *client,
                                            const char       *username)
  {
-@@ -879,9 +883,9 @@ gdm_greeter_client_class_init (GdmGreeterClientClass *klass)
+@@ -893,9 +897,9 @@ gdm_greeter_client_class_init (GdmGreeterClientClass *klass)
                                G_STRUCT_OFFSET (GdmGreeterClientClass, ready),
                                NULL,
                                NULL,
@@ -1551,10 +1962,10 @@ index ed4dd95..8d061a4 100644
          gdm_greeter_client_signals[RESET] =
                  g_signal_new ("reset",
 diff --git a/gui/simple-greeter/gdm-greeter-client.h b/gui/simple-greeter/gdm-greeter-client.h
-index 08deabd..88b0281 100644
+index 16ccef9..e08aaa5 100644
 --- a/gui/simple-greeter/gdm-greeter-client.h
 +++ b/gui/simple-greeter/gdm-greeter-client.h
-@@ -84,13 +84,15 @@ GQuark             gdm_greeter_client_error_quark                    (void);
+@@ -85,13 +85,15 @@ GQuark             gdm_greeter_client_error_quark                    (void);
  GdmGreeterClient * gdm_greeter_client_new                            (void);
  
  gboolean           gdm_greeter_client_start                          (GdmGreeterClient *client,
@@ -1572,10 +1983,10 @@ index 08deabd..88b0281 100644
                                                                        const char       *username);
  void               gdm_greeter_client_call_begin_verification        (GdmGreeterClient *client);
 diff --git a/gui/simple-greeter/gdm-greeter-session.c b/gui/simple-greeter/gdm-greeter-session.c
-index e7d206a..cd0cbdf 100644
+index d4ef77f..63de620 100644
 --- a/gui/simple-greeter/gdm-greeter-session.c
 +++ b/gui/simple-greeter/gdm-greeter-session.c
-@@ -85,6 +85,7 @@ on_problem (GdmGreeterClient  *client,
+@@ -89,6 +89,7 @@ on_problem (GdmGreeterClient  *client,
  
  static void
  on_ready (GdmGreeterClient  *client,
@@ -1583,7 +1994,7 @@ index e7d206a..cd0cbdf 100644
            GdmGreeterSession *session)
  {
          g_debug ("GdmGreeterSession: Ready");
-@@ -270,6 +271,7 @@ on_cancelled (GdmGreeterLoginWindow *login_window,
+@@ -293,6 +294,7 @@ on_cancelled (GdmGreeterLoginWindow *login_window,
  {
          gdm_greeter_panel_hide_user_options (GDM_GREETER_PANEL (session->priv->panel));
          gdm_greeter_client_call_cancel (session->priv->client);
@@ -1591,7 +2002,7 @@ index e7d206a..cd0cbdf 100644
  }
  
  static void
-@@ -439,6 +441,8 @@ gdm_greeter_session_start (GdmGreeterSession *session,
+@@ -457,6 +459,8 @@ gdm_greeter_session_start (GdmGreeterSession *session,
          toggle_panel (session, TRUE);
          toggle_login_window (session, TRUE);
  
@@ -1601,358 +2012,61 @@ index e7d206a..cd0cbdf 100644
  
          return res;
 -- 
-1.6.5.2
-
-
-From 32e86b62e22d0f25c73ec904674dac1924b54014 Mon Sep 17 00:00:00 2001
-From: Ray Strode <rstrode at redhat.com>
-Date: Wed, 4 Mar 2009 22:09:21 -0500
-Subject: [PATCH 04/45] start autologin conversation when creating session if necessary
-
-Without this autologin breaks, since when it comes time to
-autologin, there's no worker to do it.
----
- daemon/gdm-simple-slave.c |   10 ++++++++++
- 1 files changed, 10 insertions(+), 0 deletions(-)
-
-diff --git a/daemon/gdm-simple-slave.c b/daemon/gdm-simple-slave.c
-index 1a64bbb..a0b01e2 100644
---- a/daemon/gdm-simple-slave.c
-+++ b/daemon/gdm-simple-slave.c
-@@ -1076,10 +1076,20 @@ idle_connect_to_display (GdmSimpleSlave *slave)
-                 if (! enabled || delay > 0) {
-                         start_greeter (slave);
-                         create_new_session (slave);
-+
-+                        if (enabled) {
-+                                g_debug ("GdmSimpleSlave: Starting timed login conversation");
-+                                gdm_session_start_conversation (GDM_SESSION (slave->priv->session),
-+                                                                "gdm-autologin");
-+                        }
-                 } else {
-                         /* Run the init script. gdmslave suspends until script has terminated */
-                         gdm_slave_run_script (GDM_SLAVE (slave), GDMCONFDIR "/Init", GDM_USERNAME);
-                         reset_session (slave);
-+
-+                        g_debug ("GdmSimpleSlave: Starting automatic login conversation");
-+                        gdm_session_start_conversation (GDM_SESSION (slave->priv->session),
-+                                                        "gdm-autologin");
-                 }
-         } else {
-                 if (slave->priv->connection_attempts >= MAX_CONNECT_ATTEMPTS) {
--- 
-1.6.5.2
+1.7.2.1
 
 
-From ea122f625f448995fcf609d183cf62f35c13160f Mon Sep 17 00:00:00 2001
+From 501504483329a0ddc74acb39456860f381b0e54e Mon Sep 17 00:00:00 2001
 From: Ray Strode <rstrode at redhat.com>
 Date: Fri, 16 Jan 2009 15:18:31 -0500
-Subject: [PATCH 05/45] Store multiple conversations in the session
+Subject: [PATCH 10/35] Store multiple conversations in the session
 
 We keep multiple conversations in the session now, keyed off of
 PAM service is at the other end.  Much of the guts still
 only operate on the first conversation added though.
 ---
- daemon/gdm-session-direct.c |  123 +++++++++++++++++++++++++++++++++++++------
- 1 files changed, 106 insertions(+), 17 deletions(-)
+ daemon/gdm-factory-slave.c               |   69 +++-
+ daemon/gdm-greeter-server.c              |  134 ++++++--
+ daemon/gdm-greeter-server.h              |   19 +-
+ daemon/gdm-product-slave.c               |  264 +++++++++++---
+ daemon/gdm-session-direct.c              |  585 ++++++++++++++++++++----------
+ daemon/gdm-session-private.h             |   28 ++-
+ daemon/gdm-session-relay.c               |  135 ++++++--
+ daemon/gdm-session-worker.c              |   27 ++
+ daemon/gdm-session.c                     |  203 +++++++----
+ daemon/gdm-session.h                     |   60 +++-
+ daemon/gdm-simple-slave.c                |  114 +++++--
+ daemon/test-session.c                    |   22 +-
+ gui/simple-greeter/gdm-greeter-client.c  |  188 ++++++++--
+ gui/simple-greeter/gdm-greeter-client.h  |   16 +-
+ gui/simple-greeter/gdm-greeter-session.c |   11 +-
+ 15 files changed, 1394 insertions(+), 481 deletions(-)
 
-diff --git a/daemon/gdm-session-direct.c b/daemon/gdm-session-direct.c
-index 3a89871..8171b4e 100644
---- a/daemon/gdm-session-direct.c
-+++ b/daemon/gdm-session-direct.c
-@@ -89,6 +89,7 @@ struct _GdmSessionDirectPrivate
-         char                *user_x11_authority_file;
+diff --git a/daemon/gdm-factory-slave.c b/daemon/gdm-factory-slave.c
+index f30664f..653cb18 100644
+--- a/daemon/gdm-factory-slave.c
++++ b/daemon/gdm-factory-slave.c
+@@ -144,45 +144,49 @@ on_greeter_session_died (GdmGreeterSession    *greeter,
  
-         GdmSessionConversation *conversation;
-+        GHashTable          *conversations;
+ static void
+ on_session_info (GdmSession      *session,
++                 const char      *service_name,
+                  const char      *text,
+                  GdmFactorySlave *slave)
+ {
+         g_debug ("GdmFactorySlave: Info: %s", text);
+-        gdm_greeter_server_info (slave->priv->greeter_server, text);
++        gdm_greeter_server_info (slave->priv->greeter_server, service_name, text);
+ }
  
-         GdmSessionWorkerJob *job;
-         GPid                 session_pid;
-@@ -1549,6 +1550,42 @@ allow_user_function (DBusConnection *connection,
-         return FALSE;
- }
- 
-+static GdmSessionConversation *
-+find_conversation_by_name (GdmSessionDirect *session,
-+                           const char       *service_name)
-+{
-+        GdmSessionConversation *conversation;
-+
-+        conversation = g_hash_table_lookup (session->priv->conversations, service_name);
-+
-+        if (conversation == NULL) {
-+                g_warning ("Tried to look up non-existant conversation");
-+        }
-+
-+        return conversation;
-+}
-+
-+static GdmSessionConversation *
-+find_conversation_by_pid (GdmSessionDirect *session,
-+                          GPid              pid)
-+{
-+        GHashTableIter iter;
-+        gpointer key, value;
-+
-+        g_hash_table_iter_init (&iter, session->priv->conversations);
-+        while (g_hash_table_iter_next (&iter, &key, &value)) {
-+                GdmSessionConversation *conversation;
-+
-+                conversation = (GdmSessionConversation *) value;
-+
-+                if (conversation->worker_pid == pid) {
-+                        return conversation;
-+                }
-+        }
-+
-+        return NULL;
-+}
-+
- static void
- handle_connection (DBusServer      *server,
-                    DBusConnection  *new_connection,
-@@ -1556,10 +1593,22 @@ handle_connection (DBusServer      *server,
- {
-         GdmSessionDirect *session = GDM_SESSION_DIRECT (user_data);
-         GdmSessionConversation *conversation;
-+        gulong pid;
- 
-         g_debug ("GdmSessionDirect: Handing new connection");
- 
--        conversation = session->priv->conversation;
-+        if (!dbus_connection_get_unix_process_id (new_connection, &pid)) {
-+                g_warning ("Unable to read pid on new worker connection");
-+                return;
-+        }
-+
-+        conversation = find_conversation_by_pid (session, (GPid) pid);
-+
-+        if (conversation == NULL) {
-+                g_warning ("New worker connection is from unknown source");
-+                return;
-+        }
-+
-         if (conversation->worker_connection == NULL) {
-                 DBusObjectPathVTable vtable = { &session_unregister_handler,
-                                                 &session_message_handler,
-@@ -1632,6 +1681,17 @@ setup_server (GdmSessionDirect *session)
- }
- 
- static void
-+free_conversation (GdmSessionConversation *conversation)
-+{
-+        if (conversation->job != NULL) {
-+                g_warning ("Freeing conversation with active job");
-+        }
-+
-+        g_free (conversation->service_name);
-+        g_free (conversation);
-+}
-+
-+static void
- gdm_session_direct_init (GdmSessionDirect *session)
- {
-         session->priv = G_TYPE_INSTANCE_GET_PRIVATE (session,
-@@ -1655,6 +1715,11 @@ gdm_session_direct_init (GdmSessionDirect *session)
-                           G_CALLBACK (on_session_exited),
-                           NULL);
- 
-+        session->priv->conversations = g_hash_table_new_full (g_str_hash,
-+                                                              g_str_equal,
-+                                                              (GDestroyNotify) g_free,
-+                                                              (GDestroyNotify)
-+                                                              free_conversation);
-         session->priv->environment = g_hash_table_new_full (g_str_hash,
-                                                             g_str_equal,
-                                                             (GDestroyNotify) g_free,
-@@ -1754,17 +1819,15 @@ stop_conversation (GdmSessionConversation *conversation)
-                                               G_CALLBACK (worker_died),
-                                               conversation);
- 
--        cancel_pending_query (conversation);
--
-         if (conversation->worker_connection != NULL) {
-                 dbus_connection_close (conversation->worker_connection);
-                 conversation->worker_connection = NULL;
-         }
- 
-         gdm_session_worker_job_stop (conversation->job);
-+
-         g_object_unref (conversation->job);
--        g_free (conversation->service_name);
--        g_free (conversation);
-+        conversation->job = NULL;
- }
- 
- static void
-@@ -1772,12 +1835,20 @@ gdm_session_direct_start_conversation (GdmSession *session,
-                                        const char *service_name)
- {
-         GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
-+        GdmSessionConversation *conversation;
- 
-         g_return_if_fail (session != NULL);
- 
-         g_debug ("GdmSessionDirect: starting conversation");
- 
--        impl->priv->conversation = start_conversation (impl, service_name);
-+        conversation = start_conversation (impl, service_name);
-+
-+        g_hash_table_insert (impl->priv->conversations,
-+                             g_strdup (service_name), conversation);
-+
-+        if (impl->priv->conversation != NULL) {
-+                impl->priv->conversation = conversation;
-+        }
- }
- 
- static void
-@@ -1828,8 +1899,8 @@ send_setup (GdmSessionDirect *session,
-         dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &display_hostname);
-         dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &display_x11_authority_file);
- 
--        conversation = session->priv->conversation;
--        if (! send_dbus_message (conversation, message)) {
-+        conversation = find_conversation_by_name (session, service_name);
-+        if (conversation != NULL && ! send_dbus_message (conversation, message)) {
-                 g_debug ("GdmSessionDirect: Could not send %s signal", "Setup");
-         }
- 
-@@ -1891,8 +1962,8 @@ send_setup_for_user (GdmSessionDirect *session,
-         dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &display_x11_authority_file);
-         dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &selected_user);
- 
--        conversation = session->priv->conversation;
--        if (! send_dbus_message (conversation, message)) {
-+        conversation = find_conversation_by_name (session, service_name);
-+        if (conversation != NULL && ! send_dbus_message (conversation, message)) {
-                 g_debug ("GdmSessionDirect: Could not send %s signal", "SetupForUser");
-         }
- 
-@@ -1906,8 +1977,6 @@ gdm_session_direct_setup (GdmSession *session,
-         GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
- 
-         g_return_if_fail (session != NULL);
--        g_return_if_fail (impl->priv->conversation != NULL);
--        g_return_if_fail (dbus_connection_get_is_connected (impl->priv->conversation->worker_connection));
- 
-         send_setup (impl, service_name);
-         gdm_session_direct_defaults_changed (impl);
-@@ -1921,8 +1990,6 @@ gdm_session_direct_setup_for_user (GdmSession *session,
-         GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
- 
-         g_return_if_fail (session != NULL);
--        g_return_if_fail (impl->priv->conversation != NULL);
--        g_return_if_fail (dbus_connection_get_is_connected (impl->priv->conversation->worker_connection));
-         g_return_if_fail (username != NULL);
- 
-         gdm_session_direct_select_user (session, username);
-@@ -2175,6 +2242,28 @@ gdm_session_direct_start_session (GdmSession *session)
- }
- 
- static void
-+stop_all_conversations (GdmSessionDirect *session)
-+{
-+        GHashTableIter iter;
-+        gpointer key, value;
-+
-+        if (session->priv->conversations == NULL) {
-+                return;
-+        }
-+
-+        g_hash_table_iter_init (&iter, session->priv->conversations);
-+        while (g_hash_table_iter_next (&iter, &key, &value)) {
-+                GdmSessionConversation *conversation;
-+
-+                conversation = (GdmSessionConversation *) value;
-+
-+                stop_conversation (conversation);
-+        }
-+
-+        g_hash_table_remove_all (session->priv->conversations);
-+}
-+
-+static void
- gdm_session_direct_close (GdmSession *session)
- {
-         GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
-@@ -2191,6 +2280,8 @@ gdm_session_direct_close (GdmSession *session)
-                                            impl->priv->display_device);
-         }
- 
-+        stop_all_conversations (impl);
-+
-         g_free (impl->priv->selected_user);
-         impl->priv->selected_user = NULL;
- 
-@@ -2238,11 +2329,9 @@ gdm_session_direct_answer_query  (GdmSession *session,
- static void
- gdm_session_direct_cancel  (GdmSession *session)
- {
--        GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
--
-         g_return_if_fail (session != NULL);
- 
--        cancel_pending_query (impl->priv->conversation);
-+        stop_all_conversations (GDM_SESSION_DIRECT (session));
- }
- 
- char *
--- 
-1.6.5.2
-
-
-From f7108150aeab14a890652f8f0d24be3ef6bc9647 Mon Sep 17 00:00:00 2001
-From: Ray Strode <rstrode at redhat.com>
-Date: Thu, 22 Jan 2009 08:52:01 -0500
-Subject: [PATCH 06/45] Propagate service name to more layers
-
-This is more prep work to get multiple concurrent
-PAM stacks going.
----
- daemon/gdm-factory-slave.c               |   69 +++--
- daemon/gdm-greeter-server.c              |  120 ++++++--
- daemon/gdm-greeter-server.h              |   17 +-
- daemon/gdm-product-slave.c               |  246 ++++++++++++---
- daemon/gdm-session-direct.c              |  498 +++++++++++++++++------------
- daemon/gdm-session-private.h             |   26 ++-
- daemon/gdm-session-relay.c               |  135 +++++++--
- daemon/gdm-session-worker.c              |   27 ++
- daemon/gdm-session.c                     |  175 ++++++-----
- daemon/gdm-session.h                     |   54 +++-
- daemon/gdm-simple-slave.c                |   78 ++++--
- daemon/test-session.c                    |   22 +-
- gui/simple-greeter/gdm-greeter-client.c  |  188 +++++++++---
- gui/simple-greeter/gdm-greeter-client.h  |   16 +-
- gui/simple-greeter/gdm-greeter-session.c |   11 +-
- 15 files changed, 1191 insertions(+), 491 deletions(-)
-
-diff --git a/daemon/gdm-factory-slave.c b/daemon/gdm-factory-slave.c
-index ca3ba48..553ae3a 100644
---- a/daemon/gdm-factory-slave.c
-+++ b/daemon/gdm-factory-slave.c
-@@ -144,45 +144,49 @@ on_greeter_session_died (GdmGreeterSession    *greeter,
- 
- static void
- on_session_info (GdmSession      *session,
-+                 const char      *service_name,
-                  const char      *text,
-                  GdmFactorySlave *slave)
- {
-         g_debug ("GdmFactorySlave: Info: %s", text);
--        gdm_greeter_server_info (slave->priv->greeter_server, text);
-+        gdm_greeter_server_info (slave->priv->greeter_server, service_name, text);
- }
- 
- static void
- on_session_problem (GdmSession      *session,
-+                    const char      *service_name,
-                     const char      *text,
-                     GdmFactorySlave *slave)
- {
-         g_debug ("GdmFactorySlave: Problem: %s", text);
--        gdm_greeter_server_problem (slave->priv->greeter_server, text);
-+        gdm_greeter_server_problem (slave->priv->greeter_server, service_name, text);
+ static void
+ on_session_problem (GdmSession      *session,
++                    const char      *service_name,
+                     const char      *text,
+                     GdmFactorySlave *slave)
+ {
+         g_debug ("GdmFactorySlave: Problem: %s", text);
+-        gdm_greeter_server_problem (slave->priv->greeter_server, text);
++        gdm_greeter_server_problem (slave->priv->greeter_server, service_name, text);
  }
  
  static void
@@ -2110,7 +2224,7 @@ index ca3ba48..553ae3a 100644
  
          queue_greeter_reset (slave);
  }
-@@ -389,37 +403,48 @@ on_session_relay_connected (GdmSessionRelay *session,
+@@ -390,37 +404,48 @@ on_session_relay_connected (GdmSessionRelay *session,
                              GdmFactorySlave *slave)
  {
          g_debug ("GdmFactorySlave: Relay Connected");
@@ -2163,7 +2277,7 @@ index ca3ba48..553ae3a 100644
  }
  
  static void
-@@ -516,6 +541,10 @@ run_greeter (GdmFactorySlave *slave)
+@@ -520,6 +545,10 @@ run_greeter (GdmFactorySlave *slave)
  
          slave->priv->greeter_server = gdm_greeter_server_new (display_id);
          g_signal_connect (slave->priv->greeter_server,
@@ -2175,18 +2289,18 @@ index ca3ba48..553ae3a 100644
                            G_CALLBACK (on_greeter_begin_verification),
                            slave);
 diff --git a/daemon/gdm-greeter-server.c b/daemon/gdm-greeter-server.c
-index ffca7ec..dae34c5 100644
+index 03ecfca..50e4193 100644
 --- a/daemon/gdm-greeter-server.c
 +++ b/daemon/gdm-greeter-server.c
-@@ -43,6 +43,7 @@
- #include <dbus/dbus-glib.h>
+@@ -44,6 +44,7 @@
  #include <dbus/dbus-glib-lowlevel.h>
  
+ #include "gdm-common.h"
 +#include "gdm-marshal.h"
  #include "gdm-greeter-server.h"
  
  #define GDM_GREETER_SERVER_DBUS_PATH      "/org/gnome/DisplayManager/GreeterServer"
-@@ -156,6 +157,46 @@ send_dbus_string_and_int_signal (GdmGreeterServer *greeter_server,
+@@ -157,6 +158,46 @@ send_dbus_string_and_int_signal (GdmGreeterServer *greeter_server,
  }
  
  static void
@@ -2233,7 +2347,7 @@ index ffca7ec..dae34c5 100644
  send_dbus_string_signal (GdmGreeterServer *greeter_server,
                           const char       *name,
                           const char       *text)
-@@ -208,34 +249,38 @@ send_dbus_void_signal (GdmGreeterServer *greeter_server,
+@@ -209,34 +250,38 @@ send_dbus_void_signal (GdmGreeterServer *greeter_server,
  
  gboolean
  gdm_greeter_server_info_query (GdmGreeterServer *greeter_server,
@@ -2276,7 +2390,22 @@ index ffca7ec..dae34c5 100644
          return TRUE;
  }
  
-@@ -291,9 +336,10 @@ gdm_greeter_server_request_timed_login (GdmGreeterServer *greeter_server,
+@@ -262,6 +307,14 @@ gdm_greeter_server_ready (GdmGreeterServer *greeter_server,
+         return TRUE;
+ }
+ 
++gboolean
++gdm_greeter_server_conversation_stopped (GdmGreeterServer *greeter_server,
++                                         const char       *service_name)
++{
++        send_dbus_string_signal (greeter_server, "ConversationStopped", service_name);
++        return TRUE;
++}
++
+ void
+ gdm_greeter_server_selected_user_changed (GdmGreeterServer *greeter_server,
+                                           const char       *username)
+@@ -299,9 +352,10 @@ gdm_greeter_server_request_timed_login (GdmGreeterServer *greeter_server,
  }
  
  void
@@ -2289,7 +2418,7 @@ index ffca7ec..dae34c5 100644
  }
  
  /* Note: Use abstract sockets like dbus does by default on Linux. Abstract
-@@ -358,6 +404,16 @@ handle_begin_verification (GdmGreeterServer *greeter_server,
+@@ -366,6 +420,16 @@ handle_begin_verification (GdmGreeterServer *greeter_server,
                             DBusMessage      *message)
  {
          DBusMessage *reply;
@@ -2306,7 +2435,7 @@ index ffca7ec..dae34c5 100644
  
          g_debug ("GreeterServer: BeginVerification");
  
-@@ -365,7 +421,7 @@ handle_begin_verification (GdmGreeterServer *greeter_server,
+@@ -373,7 +437,7 @@ handle_begin_verification (GdmGreeterServer *greeter_server,
          dbus_connection_send (connection, reply, NULL);
          dbus_message_unref (reply);
  
@@ -2315,7 +2444,7 @@ index ffca7ec..dae34c5 100644
  
          return DBUS_HANDLER_RESULT_HANDLED;
  }
-@@ -379,7 +435,6 @@ handle_begin_auto_login (GdmGreeterServer *greeter_server,
+@@ -387,7 +451,6 @@ handle_begin_auto_login (GdmGreeterServer *greeter_server,
          DBusError    error;
          const char  *text;
  
@@ -2323,7 +2452,7 @@ index ffca7ec..dae34c5 100644
          dbus_error_init (&error);
          if (! dbus_message_get_args (message, &error,
                                       DBUS_TYPE_STRING, &text,
-@@ -406,13 +461,16 @@ handle_begin_verification_for_user (GdmGreeterServer *greeter_server,
+@@ -414,13 +477,16 @@ handle_begin_verification_for_user (GdmGreeterServer *greeter_server,
          DBusMessage *reply;
          DBusError    error;
          const char  *text;
@@ -2340,7 +2469,7 @@ index ffca7ec..dae34c5 100644
  
          g_debug ("GreeterServer: BeginVerificationForUser for '%s'", text);
  
-@@ -420,7 +478,7 @@ handle_begin_verification_for_user (GdmGreeterServer *greeter_server,
+@@ -428,7 +494,7 @@ handle_begin_verification_for_user (GdmGreeterServer *greeter_server,
          dbus_connection_send (connection, reply, NULL);
          dbus_message_unref (reply);
  
@@ -2349,7 +2478,7 @@ index ffca7ec..dae34c5 100644
  
          return DBUS_HANDLER_RESULT_HANDLED;
  }
-@@ -433,13 +491,16 @@ handle_answer_query (GdmGreeterServer *greeter_server,
+@@ -441,13 +507,16 @@ handle_answer_query (GdmGreeterServer *greeter_server,
          DBusMessage *reply;
          DBusError    error;
          const char  *text;
@@ -2366,7 +2495,7 @@ index ffca7ec..dae34c5 100644
  
          g_debug ("GreeterServer: AnswerQuery");
  
-@@ -447,7 +508,7 @@ handle_answer_query (GdmGreeterServer *greeter_server,
+@@ -455,7 +524,7 @@ handle_answer_query (GdmGreeterServer *greeter_server,
          dbus_connection_send (connection, reply, NULL);
          dbus_message_unref (reply);
  
@@ -2375,7 +2504,7 @@ index ffca7ec..dae34c5 100644
  
          return DBUS_HANDLER_RESULT_HANDLED;
  }
-@@ -644,9 +705,11 @@ handle_start_session_when_ready (GdmGreeterServer *greeter_server,
+@@ -652,9 +721,11 @@ handle_start_session_when_ready (GdmGreeterServer *greeter_server,
          DBusMessage *reply;
          DBusError    error;
          gboolean     should_start_session;
@@ -2387,7 +2516,7 @@ index ffca7ec..dae34c5 100644
                                       DBUS_TYPE_BOOLEAN, &should_start_session,
                                       DBUS_TYPE_INVALID)) {
                  g_warning ("ERROR: %s", error.message);
-@@ -660,9 +723,9 @@ handle_start_session_when_ready (GdmGreeterServer *greeter_server,
+@@ -668,9 +739,9 @@ handle_start_session_when_ready (GdmGreeterServer *greeter_server,
          dbus_message_unref (reply);
  
          if (should_start_session) {
@@ -2399,9 +2528,13 @@ index ffca7ec..dae34c5 100644
          }
  
          return DBUS_HANDLER_RESULT_HANDLED;
-@@ -735,13 +798,16 @@ do_introspect (DBusConnection *connection,
+@@ -742,14 +813,20 @@ do_introspect (DBusConnection *connection,
+                                "    <method name=\"StartConversation\">\n"
                                 "      <arg name=\"service_name\" direction=\"in\" type=\"s\"/>\n"
                                 "    </method>\n"
++                               "    <method name=\"StopConversation\">\n"
++                               "      <arg name=\"service_name\" direction=\"in\" type=\"s\"/>\n"
++                               "    </method>\n"
                                 "    <method name=\"BeginVerification\">\n"
 +                               "      <arg name=\"service_name\" direction=\"in\" type=\"s\"/>\n"
                                 "    </method>\n"
@@ -2416,7 +2549,7 @@ index ffca7ec..dae34c5 100644
                                 "      <arg name=\"text\" direction=\"in\" type=\"s\"/>\n"
                                 "    </method>\n"
                                 "    <method name=\"SelectSession\">\n"
-@@ -764,18 +830,23 @@ do_introspect (DBusConnection *connection,
+@@ -772,18 +849,23 @@ do_introspect (DBusConnection *connection,
                                 "      <arg name=\"id\" direction=\"out\" type=\"o\"/>\n"
                                 "    </method>\n"
                                 "    <method name=\"StartSessionWhenReady\">\n"
@@ -2440,15 +2573,23 @@ index ffca7ec..dae34c5 100644
                                 "      <arg name=\"text\" type=\"s\"/>\n"
                                 "    </signal>\n"
                                 "    <signal name=\"SelectedUserChanged\">\n"
-@@ -800,6 +871,7 @@ do_introspect (DBusConnection *connection,
-                                "    <signal name=\"Reset\">\n"
+@@ -805,11 +887,15 @@ do_introspect (DBusConnection *connection,
+                                "    <signal name=\"Ready\">\n"
+                                "      <arg name=\"service-name\" type=\"s\"/>\n"
                                 "    </signal>\n"
-                                "    <signal name=\"UserAuthorized\">\n"
-+                               "      <arg name=\"service_name\" direction=\"in\" type=\"s\"/>\n"
++                               "    <signal name=\"ConversationStopped\">\n"
++                               "      <arg name=\"service-name\" type=\"s\"/>\n"
++                               "    </signal>\n"
+                                "    <signal name=\"Reset\">\n"
+                                "    </signal>\n"
+                                "    <signal name=\"AuthenticationFailed\">\n"
+                                "    </signal>\n"
+                                "    <signal name=\"UserAuthorized\">\n"
++                               "      <arg name=\"service_name\" direction=\"in\" type=\"s\"/>\n"
                                 "    </signal>\n"
                                 "  </interface>\n");
  
-@@ -1175,9 +1247,9 @@ gdm_greeter_server_class_init (GdmGreeterServerClass *klass)
+@@ -1185,9 +1271,9 @@ gdm_greeter_server_class_init (GdmGreeterServerClass *klass)
                                G_STRUCT_OFFSET (GdmGreeterServerClass, begin_verification),
                                NULL,
                                NULL,
@@ -2460,7 +2601,7 @@ index ffca7ec..dae34c5 100644
          signals [BEGIN_AUTO_LOGIN] =
                  g_signal_new ("begin-auto-login",
                                G_OBJECT_CLASS_TYPE (object_class),
-@@ -1196,10 +1268,10 @@ gdm_greeter_server_class_init (GdmGreeterServerClass *klass)
+@@ -1206,10 +1292,10 @@ gdm_greeter_server_class_init (GdmGreeterServerClass *klass)
                                G_STRUCT_OFFSET (GdmGreeterServerClass, begin_verification_for_user),
                                NULL,
                                NULL,
@@ -2474,7 +2615,7 @@ index ffca7ec..dae34c5 100644
          signals [QUERY_ANSWER] =
                  g_signal_new ("query-answer",
                                G_OBJECT_CLASS_TYPE (object_class),
-@@ -1207,10 +1279,10 @@ gdm_greeter_server_class_init (GdmGreeterServerClass *klass)
+@@ -1217,10 +1303,10 @@ gdm_greeter_server_class_init (GdmGreeterServerClass *klass)
                                G_STRUCT_OFFSET (GdmGreeterServerClass, query_answer),
                                NULL,
                                NULL,
@@ -2488,7 +2629,7 @@ index ffca7ec..dae34c5 100644
          signals [SESSION_SELECTED] =
                  g_signal_new ("session-selected",
                                G_OBJECT_CLASS_TYPE (object_class),
-@@ -1304,9 +1376,9 @@ gdm_greeter_server_class_init (GdmGreeterServerClass *klass)
+@@ -1314,9 +1400,9 @@ gdm_greeter_server_class_init (GdmGreeterServerClass *klass)
                                G_STRUCT_OFFSET (GdmGreeterServerClass, start_session_when_ready),
                                NULL,
                                NULL,
@@ -2500,7 +2641,7 @@ index ffca7ec..dae34c5 100644
  
          signals [START_SESSION_LATER] =
                  g_signal_new ("start-session-later",
-@@ -1315,9 +1387,9 @@ gdm_greeter_server_class_init (GdmGreeterServerClass *klass)
+@@ -1325,9 +1411,9 @@ gdm_greeter_server_class_init (GdmGreeterServerClass *klass)
                                G_STRUCT_OFFSET (GdmGreeterServerClass, start_session_later),
                                NULL,
                                NULL,
@@ -2513,7 +2654,7 @@ index ffca7ec..dae34c5 100644
  
  static void
 diff --git a/daemon/gdm-greeter-server.h b/daemon/gdm-greeter-server.h
-index 7333db1..6d0dd87 100644
+index 7e2424a..5af32fd 100644
 --- a/daemon/gdm-greeter-server.h
 +++ b/daemon/gdm-greeter-server.h
 @@ -48,10 +48,13 @@ typedef struct
@@ -2541,7 +2682,7 @@ index 7333db1..6d0dd87 100644
          void (* start_session_later)        (GdmGreeterServer  *greeter_server);
  } GdmGreeterServerClass;
  
-@@ -77,14 +81,17 @@ gboolean            gdm_greeter_server_start                 (GdmGreeterServer *
+@@ -77,19 +81,24 @@ gboolean            gdm_greeter_server_start                 (GdmGreeterServer *
  gboolean            gdm_greeter_server_stop                  (GdmGreeterServer *greeter_server);
  char *              gdm_greeter_server_get_address           (GdmGreeterServer *greeter_server);
  
@@ -2558,9 +2699,16 @@ index 7333db1..6d0dd87 100644
  gboolean            gdm_greeter_server_problem               (GdmGreeterServer *greeter_server,
 +                                                              const char       *service_name,
                                                                const char       *text);
+ gboolean            gdm_greeter_server_authentication_failed (GdmGreeterServer *greeter_server);
  gboolean            gdm_greeter_server_reset                 (GdmGreeterServer *greeter_server);
  gboolean            gdm_greeter_server_ready                 (GdmGreeterServer *greeter_server,
-@@ -101,8 +108,8 @@ void                gdm_greeter_server_default_session_name_changed (GdmGreeterS
+                                                               const char       *service_name);
++gboolean            gdm_greeter_server_conversation_stopped  (GdmGreeterServer *greeter_server,
++                                                              const char       *service_name);
+ void                gdm_greeter_server_selected_user_changed (GdmGreeterServer *greeter_server,
+                                                               const char       *text);
+ void                gdm_greeter_server_default_language_name_changed (GdmGreeterServer *greeter_server,
+@@ -102,8 +111,8 @@ void                gdm_greeter_server_default_session_name_changed (GdmGreeterS
  void                gdm_greeter_server_request_timed_login   (GdmGreeterServer *greeter_server,
                                                                const char       *username,
                                                                int               delay);
@@ -2572,7 +2720,7 @@ index 7333db1..6d0dd87 100644
  G_END_DECLS
  
 diff --git a/daemon/gdm-product-slave.c b/daemon/gdm-product-slave.c
-index ec6300d..93d83a1 100644
+index 9be89b4..607bbc6 100644
 --- a/daemon/gdm-product-slave.c
 +++ b/daemon/gdm-product-slave.c
 @@ -79,6 +79,8 @@ struct GdmProductSlavePrivate
@@ -2950,7 +3098,31 @@ index ec6300d..93d83a1 100644
          } else {
                  g_warning ("Unable to get arguments: %s", error.message);
                  dbus_error_free (&error);
-@@ -831,7 +973,25 @@ static void
+@@ -831,14 +973,48 @@ static void
+ on_relay_open_session (GdmProductSlave *slave,
+                         DBusMessage     *message)
+ {
+-        gdm_session_open_session (GDM_SESSION (slave->priv->session));
++        DBusError   error;
++        const char *text;
++        dbus_bool_t res;
++
++        dbus_error_init (&error);
++        res = dbus_message_get_args (message,
++                                     &error,
++                                     DBUS_TYPE_STRING, &text,
++                                     DBUS_TYPE_INVALID);
++        if (res) {
++                g_debug ("GdmProductSlave: open session %s", text);
++                gdm_session_open_session (GDM_SESSION (slave->priv->session),
++                                          text);
++        } else {
++                g_warning ("Unable to get arguments: %s", error.message);
++                dbus_error_free (&error);
++        }
+ }
+ 
+ static void
  on_relay_start_session (GdmProductSlave *slave,
                          DBusMessage     *message)
  {
@@ -2978,23 +3150,23 @@ index ec6300d..93d83a1 100644
  
  static void
 diff --git a/daemon/gdm-session-direct.c b/daemon/gdm-session-direct.c
-index 8171b4e..9d6a6b9 100644
+index cfbaa15..13c8974 100644
 --- a/daemon/gdm-session-direct.c
 +++ b/daemon/gdm-session-direct.c
-@@ -88,10 +88,10 @@ struct _GdmSessionDirectPrivate
+@@ -89,9 +89,10 @@ struct _GdmSessionDirectPrivate
          char                *selected_user;
          char                *user_x11_authority_file;
  
 -        GdmSessionConversation *conversation;
-         GHashTable          *conversations;
++        GHashTable          *conversations;
++
++        GList               *pending_connections;
  
 -        GdmSessionWorkerJob *job;
-+        GList               *pending_connections;
-+
          GPid                 session_pid;
          guint32              is_running : 1;
  
-@@ -198,14 +198,30 @@ send_dbus_void_signal (GdmSessionConversation *conversation,
+@@ -200,14 +201,30 @@ send_dbus_void_signal (GdmSessionConversation *conversation,
          dbus_message_unref (message);
  }
  
@@ -3026,7 +3198,7 @@ index 8171b4e..9d6a6b9 100644
          if (conversation != NULL) {
                  gdm_session_record_failed (conversation->worker_pid,
                                             impl->priv->selected_user,
-@@ -216,12 +232,13 @@ on_authentication_failed (GdmSession *session,
+@@ -218,12 +235,13 @@ on_authentication_failed (GdmSession *session,
  }
  
  static void
@@ -3042,7 +3214,7 @@ index 8171b4e..9d6a6b9 100644
          if (conversation != NULL) {
                  gdm_session_record_login (conversation->worker_pid,
                                            impl->priv->selected_user,
-@@ -233,12 +250,13 @@ on_session_started (GdmSession *session)
+@@ -235,12 +253,13 @@ on_session_started (GdmSession *session)
  
  static void
  on_session_start_failed (GdmSession *session,
@@ -3057,7 +3229,7 @@ index 8171b4e..9d6a6b9 100644
          if (conversation != NULL) {
                  gdm_session_record_login (conversation->worker_pid,
                                            impl->priv->selected_user,
-@@ -263,7 +281,7 @@ on_session_exited (GdmSession *session,
+@@ -265,7 +284,7 @@ on_session_exited (GdmSession *session,
  
  static DBusHandlerResult
  gdm_session_direct_handle_setup_complete (GdmSessionDirect *session,
@@ -3066,7 +3238,7 @@ index 8171b4e..9d6a6b9 100644
                                            DBusMessage      *message)
  {
          DBusMessage *reply;
-@@ -271,17 +289,17 @@ gdm_session_direct_handle_setup_complete (GdmSessionDirect *session,
+@@ -273,17 +292,17 @@ gdm_session_direct_handle_setup_complete (GdmSessionDirect *session,
          g_debug ("GdmSessionDirect: Emitting 'setup-complete' signal");
  
          reply = dbus_message_new_method_return (message);
@@ -3087,7 +3259,7 @@ index 8171b4e..9d6a6b9 100644
                                          DBusMessage      *message)
  {
          DBusMessage *reply;
-@@ -296,12 +314,12 @@ gdm_session_direct_handle_setup_failed (GdmSessionDirect *session,
+@@ -298,12 +317,12 @@ gdm_session_direct_handle_setup_failed (GdmSessionDirect *session,
          }
  
          reply = dbus_message_new_method_return (message);
@@ -3102,7 +3274,7 @@ index 8171b4e..9d6a6b9 100644
  
          return DBUS_HANDLER_RESULT_HANDLED;
  }
-@@ -309,7 +327,7 @@ gdm_session_direct_handle_setup_failed (GdmSessionDirect *session,
+@@ -311,7 +330,7 @@ gdm_session_direct_handle_setup_failed (GdmSessionDirect *session,
  
  static DBusHandlerResult
  gdm_session_direct_handle_reset_complete (GdmSessionDirect *session,
@@ -3111,7 +3283,7 @@ index 8171b4e..9d6a6b9 100644
                                            DBusMessage      *message)
  {
          DBusMessage *reply;
-@@ -317,7 +335,7 @@ gdm_session_direct_handle_reset_complete (GdmSessionDirect *session,
+@@ -319,7 +338,7 @@ gdm_session_direct_handle_reset_complete (GdmSessionDirect *session,
          g_debug ("GdmSessionDirect: Emitting 'reset-complete' signal");
  
          reply = dbus_message_new_method_return (message);
@@ -3120,7 +3292,7 @@ index 8171b4e..9d6a6b9 100644
          dbus_message_unref (reply);
  
          _gdm_session_reset_complete (GDM_SESSION (session));
-@@ -327,7 +345,7 @@ gdm_session_direct_handle_reset_complete (GdmSessionDirect *session,
+@@ -329,7 +348,7 @@ gdm_session_direct_handle_reset_complete (GdmSessionDirect *session,
  
  static DBusHandlerResult
  gdm_session_direct_handle_reset_failed (GdmSessionDirect *session,
@@ -3129,7 +3301,7 @@ index 8171b4e..9d6a6b9 100644
                                          DBusMessage      *message)
  {
          DBusMessage *reply;
-@@ -342,7 +360,7 @@ gdm_session_direct_handle_reset_failed (GdmSessionDirect *session,
+@@ -344,7 +363,7 @@ gdm_session_direct_handle_reset_failed (GdmSessionDirect *session,
          }
  
          reply = dbus_message_new_method_return (message);
@@ -3138,7 +3310,7 @@ index 8171b4e..9d6a6b9 100644
          dbus_message_unref (reply);
  
          g_debug ("GdmSessionDirect: Emitting 'reset-failed' signal");
-@@ -354,7 +372,7 @@ gdm_session_direct_handle_reset_failed (GdmSessionDirect *session,
+@@ -356,7 +375,7 @@ gdm_session_direct_handle_reset_failed (GdmSessionDirect *session,
  
  static DBusHandlerResult
  gdm_session_direct_handle_authenticated (GdmSessionDirect *session,
@@ -3147,7 +3319,7 @@ index 8171b4e..9d6a6b9 100644
                                           DBusMessage      *message)
  {
          DBusMessage *reply;
-@@ -362,17 +380,17 @@ gdm_session_direct_handle_authenticated (GdmSessionDirect *session,
+@@ -364,17 +383,17 @@ gdm_session_direct_handle_authenticated (GdmSessionDirect *session,
          g_debug ("GdmSessionDirect: Emitting 'authenticated' signal");
  
          reply = dbus_message_new_method_return (message);
@@ -3168,7 +3340,7 @@ index 8171b4e..9d6a6b9 100644
                                                   DBusMessage      *message)
  {
          DBusMessage *reply;
-@@ -387,19 +405,19 @@ gdm_session_direct_handle_authentication_failed (GdmSessionDirect *session,
+@@ -389,19 +408,19 @@ gdm_session_direct_handle_authentication_failed (GdmSessionDirect *session,
          }
  
          reply = dbus_message_new_method_return (message);
@@ -3191,7 +3363,7 @@ index 8171b4e..9d6a6b9 100644
                                        DBusMessage      *message)
  {
          DBusMessage *reply;
-@@ -407,17 +425,17 @@ gdm_session_direct_handle_authorized (GdmSessionDirect *session,
+@@ -409,17 +428,17 @@ gdm_session_direct_handle_authorized (GdmSessionDirect *session,
          g_debug ("GdmSessionDirect: Emitting 'authorized' signal");
  
          reply = dbus_message_new_method_return (message);
@@ -3212,7 +3384,7 @@ index 8171b4e..9d6a6b9 100644
                                                  DBusMessage      *message)
  {
          DBusMessage *reply;
-@@ -432,19 +450,19 @@ gdm_session_direct_handle_authorization_failed (GdmSessionDirect *session,
+@@ -434,19 +453,19 @@ gdm_session_direct_handle_authorization_failed (GdmSessionDirect *session,
          }
  
          reply = dbus_message_new_method_return (message);
@@ -3235,7 +3407,7 @@ index 8171b4e..9d6a6b9 100644
                                        DBusMessage      *message)
  {
          DBusMessage *reply;
-@@ -452,17 +470,17 @@ gdm_session_direct_handle_accredited (GdmSessionDirect *session,
+@@ -454,17 +473,17 @@ gdm_session_direct_handle_accredited (GdmSessionDirect *session,
          g_debug ("GdmSessionDirect: Emitting 'accredited' signal");
  
          reply = dbus_message_new_method_return (message);
@@ -3256,7 +3428,7 @@ index 8171b4e..9d6a6b9 100644
                                                  DBusMessage      *message)
  {
          DBusMessage *reply;
-@@ -477,12 +495,12 @@ gdm_session_direct_handle_accreditation_failed (GdmSessionDirect *session,
+@@ -479,12 +498,12 @@ gdm_session_direct_handle_accreditation_failed (GdmSessionDirect *session,
          }
  
          reply = dbus_message_new_method_return (message);
@@ -3271,7 +3443,7 @@ index 8171b4e..9d6a6b9 100644
  
          return DBUS_HANDLER_RESULT_HANDLED;
  }
-@@ -764,7 +782,7 @@ gdm_session_direct_select_user (GdmSession *session,
+@@ -808,7 +827,7 @@ gdm_session_direct_select_user (GdmSession *session,
  
  static DBusHandlerResult
  gdm_session_direct_handle_username_changed (GdmSessionDirect *session,
@@ -3280,7 +3452,7 @@ index 8171b4e..9d6a6b9 100644
                                              DBusMessage      *message)
  {
          DBusMessage *reply;
-@@ -779,7 +797,7 @@ gdm_session_direct_handle_username_changed (GdmSessionDirect *session,
+@@ -823,7 +842,7 @@ gdm_session_direct_handle_username_changed (GdmSessionDirect *session,
          }
  
          reply = dbus_message_new_method_return (message);
@@ -3289,7 +3461,7 @@ index 8171b4e..9d6a6b9 100644
          dbus_message_unref (reply);
  
          g_debug ("GdmSessionDirect: changing username from '%s' to '%s'",
-@@ -846,14 +864,11 @@ set_pending_query (GdmSessionConversation *conversation,
+@@ -890,14 +909,11 @@ set_pending_query (GdmSessionConversation *conversation,
  
  static DBusHandlerResult
  gdm_session_direct_handle_info_query (GdmSessionDirect *session,
@@ -3305,7 +3477,7 @@ index 8171b4e..9d6a6b9 100644
  
          dbus_error_init (&error);
          if (! dbus_message_get_args (message, &error,
-@@ -865,21 +880,18 @@ gdm_session_direct_handle_info_query (GdmSessionDirect *session,
+@@ -909,21 +925,18 @@ gdm_session_direct_handle_info_query (GdmSessionDirect *session,
          set_pending_query (conversation, message);
  
          g_debug ("GdmSessionDirect: Emitting 'info-query' signal");
@@ -3329,7 +3501,7 @@ index 8171b4e..9d6a6b9 100644
  
          dbus_error_init (&error);
          if (! dbus_message_get_args (message, &error,
-@@ -891,14 +903,14 @@ gdm_session_direct_handle_secret_info_query (GdmSessionDirect *session,
+@@ -935,14 +948,14 @@ gdm_session_direct_handle_secret_info_query (GdmSessionDirect *session,
          set_pending_query (conversation, message);
  
          g_debug ("GdmSessionDirect: Emitting 'secret-info-query' signal");
@@ -3346,7 +3518,7 @@ index 8171b4e..9d6a6b9 100644
                                  DBusMessage      *message)
  {
          DBusMessage *reply;
-@@ -913,31 +925,28 @@ gdm_session_direct_handle_info (GdmSessionDirect *session,
+@@ -957,31 +970,28 @@ gdm_session_direct_handle_info (GdmSessionDirect *session,
          }
  
          reply = dbus_message_new_method_return (message);
@@ -3382,7 +3554,7 @@ index 8171b4e..9d6a6b9 100644
          dbus_message_unref (reply);
  
          return DBUS_HANDLER_RESULT_HANDLED;
-@@ -945,7 +954,7 @@ gdm_session_direct_handle_cancel_pending_query (GdmSessionDirect *session,
+@@ -989,7 +999,7 @@ gdm_session_direct_handle_cancel_pending_query (GdmSessionDirect *session,
  
  static DBusHandlerResult
  gdm_session_direct_handle_problem (GdmSessionDirect *session,
@@ -3391,7 +3563,7 @@ index 8171b4e..9d6a6b9 100644
                                     DBusMessage      *message)
  {
          DBusMessage *reply;
-@@ -960,18 +969,18 @@ gdm_session_direct_handle_problem (GdmSessionDirect *session,
+@@ -1004,18 +1014,18 @@ gdm_session_direct_handle_problem (GdmSessionDirect *session,
          }
  
          reply = dbus_message_new_method_return (message);
@@ -3413,7 +3585,7 @@ index 8171b4e..9d6a6b9 100644
                                            DBusMessage      *message)
  {
          DBusMessage *reply;
-@@ -986,10 +995,10 @@ gdm_session_direct_handle_session_opened (GdmSessionDirect *session,
+@@ -1030,10 +1040,10 @@ gdm_session_direct_handle_session_opened (GdmSessionDirect *session,
  
          g_debug ("GdmSessionDirect: Emitting 'session-opened' signal");
  
@@ -3426,7 +3598,7 @@ index 8171b4e..9d6a6b9 100644
          dbus_message_unref (reply);
  
          return DBUS_HANDLER_RESULT_HANDLED;
-@@ -997,7 +1006,7 @@ gdm_session_direct_handle_session_opened (GdmSessionDirect *session,
+@@ -1041,7 +1051,7 @@ gdm_session_direct_handle_session_opened (GdmSessionDirect *session,
  
  static DBusHandlerResult
  gdm_session_direct_handle_open_failed (GdmSessionDirect *session,
@@ -3435,7 +3607,7 @@ index 8171b4e..9d6a6b9 100644
                                         DBusMessage      *message)
  {
          DBusMessage *reply;
-@@ -1012,18 +1021,18 @@ gdm_session_direct_handle_open_failed (GdmSessionDirect *session,
+@@ -1056,18 +1066,18 @@ gdm_session_direct_handle_open_failed (GdmSessionDirect *session,
          }
  
          reply = dbus_message_new_method_return (message);
@@ -3457,7 +3629,7 @@ index 8171b4e..9d6a6b9 100644
                                             DBusMessage      *message)
  {
          DBusMessage *reply;
-@@ -1042,7 +1051,7 @@ gdm_session_direct_handle_session_started (GdmSessionDirect *session,
+@@ -1086,7 +1096,7 @@ gdm_session_direct_handle_session_started (GdmSessionDirect *session,
          }
  
          reply = dbus_message_new_method_return (message);
@@ -3466,7 +3638,7 @@ index 8171b4e..9d6a6b9 100644
          dbus_message_unref (reply);
  
          g_debug ("GdmSessionDirect: Emitting 'session-started' signal with pid '%d'",
-@@ -1051,14 +1060,14 @@ gdm_session_direct_handle_session_started (GdmSessionDirect *session,
+@@ -1095,14 +1105,14 @@ gdm_session_direct_handle_session_started (GdmSessionDirect *session,
          session->priv->session_pid = pid;
          session->priv->is_running = TRUE;
  
@@ -3483,7 +3655,7 @@ index 8171b4e..9d6a6b9 100644
                                          DBusMessage      *message)
  {
          DBusMessage *reply;
-@@ -1073,18 +1082,18 @@ gdm_session_direct_handle_start_failed (GdmSessionDirect *session,
+@@ -1117,18 +1127,18 @@ gdm_session_direct_handle_start_failed (GdmSessionDirect *session,
          }
  
          reply = dbus_message_new_method_return (message);
@@ -3505,7 +3677,7 @@ index 8171b4e..9d6a6b9 100644
                                            DBusMessage      *message)
  {
          DBusMessage *reply;
-@@ -1099,7 +1108,7 @@ gdm_session_direct_handle_session_exited (GdmSessionDirect *session,
+@@ -1143,7 +1153,7 @@ gdm_session_direct_handle_session_exited (GdmSessionDirect *session,
          }
  
          reply = dbus_message_new_method_return (message);
@@ -3514,7 +3686,7 @@ index 8171b4e..9d6a6b9 100644
          dbus_message_unref (reply);
  
          g_debug ("GdmSessionDirect: Emitting 'session-exited' signal with exit code '%d'",
-@@ -1113,7 +1122,7 @@ gdm_session_direct_handle_session_exited (GdmSessionDirect *session,
+@@ -1157,7 +1167,7 @@ gdm_session_direct_handle_session_exited (GdmSessionDirect *session,
  
  static DBusHandlerResult
  gdm_session_direct_handle_session_died (GdmSessionDirect *session,
@@ -3523,7 +3695,7 @@ index 8171b4e..9d6a6b9 100644
                                          DBusMessage      *message)
  {
          DBusMessage *reply;
-@@ -1128,7 +1137,7 @@ gdm_session_direct_handle_session_died (GdmSessionDirect *session,
+@@ -1172,7 +1182,7 @@ gdm_session_direct_handle_session_died (GdmSessionDirect *session,
          }
  
          reply = dbus_message_new_method_return (message);
@@ -3532,7 +3704,7 @@ index 8171b4e..9d6a6b9 100644
          dbus_message_unref (reply);
  
          g_debug ("GdmSessionDirect: Emitting 'session-died' signal with signal number '%d'",
-@@ -1142,7 +1151,7 @@ gdm_session_direct_handle_session_died (GdmSessionDirect *session,
+@@ -1186,7 +1196,7 @@ gdm_session_direct_handle_session_died (GdmSessionDirect *session,
  
  static DBusHandlerResult
  gdm_session_direct_handle_saved_language_name_read (GdmSessionDirect *session,
@@ -3541,7 +3713,7 @@ index 8171b4e..9d6a6b9 100644
                                                      DBusMessage      *message)
  {
          DBusMessage *reply;
-@@ -1157,7 +1166,7 @@ gdm_session_direct_handle_saved_language_name_read (GdmSessionDirect *session,
+@@ -1201,7 +1211,7 @@ gdm_session_direct_handle_saved_language_name_read (GdmSessionDirect *session,
          }
  
          reply = dbus_message_new_method_return (message);
@@ -3550,7 +3722,7 @@ index 8171b4e..9d6a6b9 100644
          dbus_message_unref (reply);
  
          if (strcmp (language_name,
-@@ -1175,7 +1184,7 @@ gdm_session_direct_handle_saved_language_name_read (GdmSessionDirect *session,
+@@ -1219,7 +1229,7 @@ gdm_session_direct_handle_saved_language_name_read (GdmSessionDirect *session,
  
  static DBusHandlerResult
  gdm_session_direct_handle_saved_layout_name_read (GdmSessionDirect *session,
@@ -3559,7 +3731,7 @@ index 8171b4e..9d6a6b9 100644
                                                    DBusMessage      *message)
  {
          DBusMessage *reply;
-@@ -1190,7 +1199,7 @@ gdm_session_direct_handle_saved_layout_name_read (GdmSessionDirect *session,
+@@ -1234,7 +1244,7 @@ gdm_session_direct_handle_saved_layout_name_read (GdmSessionDirect *session,
          }
  
          reply = dbus_message_new_method_return (message);
@@ -3568,7 +3740,7 @@ index 8171b4e..9d6a6b9 100644
          dbus_message_unref (reply);
  
          if (strcmp (layout_name,
-@@ -1208,7 +1217,7 @@ gdm_session_direct_handle_saved_layout_name_read (GdmSessionDirect *session,
+@@ -1252,7 +1262,7 @@ gdm_session_direct_handle_saved_layout_name_read (GdmSessionDirect *session,
  
  static DBusHandlerResult
  gdm_session_direct_handle_saved_session_name_read (GdmSessionDirect *session,
@@ -3577,7 +3749,7 @@ index 8171b4e..9d6a6b9 100644
                                                     DBusMessage      *message)
  {
          DBusMessage *reply;
-@@ -1223,7 +1232,7 @@ gdm_session_direct_handle_saved_session_name_read (GdmSessionDirect *session,
+@@ -1267,7 +1277,7 @@ gdm_session_direct_handle_saved_session_name_read (GdmSessionDirect *session,
          }
  
          reply = dbus_message_new_method_return (message);
@@ -3586,7 +3758,7 @@ index 8171b4e..9d6a6b9 100644
          dbus_message_unref (reply);
  
          if (! get_session_command_for_name (session_name, NULL)) {
-@@ -1251,58 +1260,61 @@ session_worker_message (DBusConnection *connection,
+@@ -1295,58 +1305,61 @@ session_worker_message (DBusConnection *connection,
                          DBusMessage    *message,
                          void           *user_data)
  {
@@ -3674,7 +3846,7 @@ index 8171b4e..9d6a6b9 100644
          }
  
          return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-@@ -1536,6 +1548,27 @@ session_unregister_handler (DBusConnection  *connection,
+@@ -1580,6 +1593,27 @@ session_unregister_handler (DBusConnection  *connection,
          g_debug ("session_unregister_handler");
  }
  
@@ -3702,17 +3874,19 @@ index 8171b4e..9d6a6b9 100644
  static dbus_bool_t
  allow_user_function (DBusConnection *connection,
                       unsigned long   uid,
-@@ -1550,40 +1583,85 @@ allow_user_function (DBusConnection *connection,
+@@ -1594,44 +1628,110 @@ allow_user_function (DBusConnection *connection,
          return FALSE;
  }
  
--static GdmSessionConversation *
--find_conversation_by_name (GdmSessionDirect *session,
--                           const char       *service_name)
+-static void
+-handle_connection (DBusServer      *server,
+-                   DBusConnection  *new_connection,
+-                   void            *user_data)
 +static gboolean
 +register_worker (GdmSessionDirect *session,
 +                 DBusConnection   *connection)
  {
+-        GdmSessionDirect *session = GDM_SESSION_DIRECT (user_data);
          GdmSessionConversation *conversation;
 +        DBusObjectPathVTable vtable = { &session_unregister_handler,
 +                                        &session_message_handler,
@@ -3720,36 +3894,53 @@ index 8171b4e..9d6a6b9 100644
 +        GList *connection_node;
 +        gulong pid;
  
--        conversation = g_hash_table_lookup (session->priv->conversations, service_name);
+-        g_debug ("GdmSessionDirect: Handing new connection");
 +        g_debug ("GdmSessionDirect: Authenticating new connection");
-+
+ 
+-        conversation = session->priv->conversation;
+-        if (conversation->worker_connection == NULL) {
+-                DBusObjectPathVTable vtable = { &session_unregister_handler,
+-                                                &session_message_handler,
+-                                                NULL, NULL, NULL, NULL
+-                };
 +        connection_node = g_list_find (session->priv->pending_connections, connection);
-+
+ 
+-                conversation->worker_connection = new_connection;
+-                dbus_connection_ref (new_connection);
+-                dbus_connection_setup_with_g_main (new_connection, NULL);
 +        if (connection_node == NULL) {
 +                g_debug ("GdmSessionDirect: Ignoring connection that we aren't tracking");
 +                return FALSE;
 +        }
-+
+ 
+-                g_debug ("GdmSessionDirect: worker connection is %p", new_connection);
+-                dbus_connection_set_exit_on_disconnect (new_connection, FALSE);
 +        session->priv->pending_connections =
 +                g_list_delete_link (session->priv->pending_connections,
 +                                    connection_node);
-+
+ 
+-                dbus_connection_set_unix_user_function (new_connection,
+-                                                        allow_user_function,
+-                                                        session,
+-                                                        NULL);
 +        if (!dbus_connection_get_unix_process_id (connection, &pid)) {
 +                g_warning ("GdmSessionDirect: Unable to read pid on new worker connection");
 +                dbus_connection_unref (connection);
 +                return FALSE;
 +        }
-+
-+        conversation = find_conversation_by_pid (session, (GPid) pid);
  
-         if (conversation == NULL) {
--                g_warning ("Tried to look up non-existant conversation");
+-                dbus_connection_register_object_path (new_connection,
+-                                                      GDM_SESSION_DBUS_PATH,
+-                                                      &vtable,
+-                                                      session);
++        conversation = find_conversation_by_pid (session, (GPid) pid);
++
++        if (conversation == NULL) {
 +                g_warning ("GdmSessionDirect: New worker connection is from unknown source");
 +                dbus_connection_unref (connection);
 +                return FALSE;
-         }
- 
--        return conversation;
++        }
++
 +        conversation->worker_connection = connection;
 +
 +        g_debug ("GdmSessionDirect: worker connection is %p", connection);
@@ -3766,89 +3957,44 @@ index 8171b4e..9d6a6b9 100644
 +        g_debug ("GdmSessionDirect: Conversation started");
 +
 +        return TRUE;
- }
- 
--static GdmSessionConversation *
--find_conversation_by_pid (GdmSessionDirect *session,
--                          GPid              pid)
++}
++
 +static DBusHandlerResult
 +on_message (DBusConnection *connection,
 +            DBusMessage    *message,
 +            void           *user_data)
- {
--        GHashTableIter iter;
--        gpointer key, value;
++{
 +        GdmSessionDirect *session = GDM_SESSION_DIRECT (user_data);
- 
--        g_hash_table_iter_init (&iter, session->priv->conversations);
--        while (g_hash_table_iter_next (&iter, &key, &value)) {
--                GdmSessionConversation *conversation;
++
 +        g_debug ("GdmSessionDirect: got message");
- 
--                conversation = (GdmSessionConversation *) value;
++
 +        if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "Hello")) {
 +                DBusMessage *reply;
- 
--                if (conversation->worker_pid == pid) {
--                        return conversation;
++
 +                if (register_worker (session, connection)) {
 +                        reply = dbus_message_new_method_return (message);
 +                } else {
 +                        reply = dbus_message_new_error (message, DBUS_ERROR_FAILED, "");
-                 }
-+
++                }
+ 
+-                g_debug ("GdmSessionDirect: Emitting conversation-started signal");
+-                _gdm_session_conversation_started (GDM_SESSION (session),
+-                                                   conversation->service_name);
 +                dbus_connection_send (connection, reply, NULL);
 +                return DBUS_HANDLER_RESULT_HANDLED;
          }
- 
--        return NULL;
++
 +        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- }
- 
- static void
-@@ -1592,50 +1670,23 @@ handle_connection (DBusServer      *server,
-                    void            *user_data)
- {
-         GdmSessionDirect *session = GDM_SESSION_DIRECT (user_data);
--        GdmSessionConversation *conversation;
--        gulong pid;
--
-         g_debug ("GdmSessionDirect: Handing new connection");
- 
--        if (!dbus_connection_get_unix_process_id (new_connection, &pid)) {
--                g_warning ("Unable to read pid on new worker connection");
--                return;
--        }
--
--        conversation = find_conversation_by_pid (session, (GPid) pid);
--
--        if (conversation == NULL) {
--                g_warning ("New worker connection is from unknown source");
--                return;
--        }
--
--        if (conversation->worker_connection == NULL) {
--                DBusObjectPathVTable vtable = { &session_unregister_handler,
--                                                &session_message_handler,
--                                                NULL, NULL, NULL, NULL
--                };
--
--                conversation->worker_connection = new_connection;
--                dbus_connection_ref (new_connection);
--                dbus_connection_setup_with_g_main (new_connection, NULL);
--
--                g_debug ("GdmSessionDirect: worker connection is %p", new_connection);
--                dbus_connection_set_exit_on_disconnect (new_connection, FALSE);
--
--                dbus_connection_set_unix_user_function (new_connection,
--                                                        allow_user_function,
--                                                        session,
--                                                        NULL);
--
--                dbus_connection_register_object_path (new_connection,
--                                                      GDM_SESSION_DBUS_PATH,
--                                                      &vtable,
--                                                      session);
++}
++
++static void
++handle_connection (DBusServer      *server,
++                   DBusConnection  *new_connection,
++                   void            *user_data)
++{
++        GdmSessionDirect *session = GDM_SESSION_DIRECT (user_data);
++        g_debug ("GdmSessionDirect: Handing new connection");
++
 +        /* add to the list of pending connections.  We won't be able to
 +         * associate it with a specific worker conversation until we have
 +         * authenticated the connection (from the Hello handler).
@@ -3858,11 +4004,7 @@ index 8171b4e..9d6a6b9 100644
 +                                dbus_connection_ref (new_connection));
 +        dbus_connection_setup_with_g_main (new_connection, NULL);
 +        dbus_connection_set_exit_on_disconnect (new_connection, FALSE);
- 
--                g_debug ("GdmSessionDirect: Emitting conversation-started signal");
--                _gdm_session_conversation_started (GDM_SESSION (session),
--                                                   conversation->service_name);
--        }
++
 +        dbus_connection_set_unix_user_function (new_connection,
 +                                                allow_user_function,
 +                                                session,
@@ -3871,58 +4013,203 @@ index 8171b4e..9d6a6b9 100644
  }
  
  static gboolean
-@@ -1820,6 +1871,8 @@ stop_conversation (GdmSessionConversation *conversation)
+@@ -1677,6 +1777,17 @@ setup_server (GdmSessionDirect *session)
+ }
+ 
+ static void
++free_conversation (GdmSessionConversation *conversation)
++{
++        if (conversation->job != NULL) {
++                g_warning ("Freeing conversation with active job");
++        }
++
++        g_free (conversation->service_name);
++        g_free (conversation);
++}
++
++static void
+ gdm_session_direct_init (GdmSessionDirect *session)
+ {
+         session->priv = G_TYPE_INSTANCE_GET_PRIVATE (session,
+@@ -1700,6 +1811,11 @@ gdm_session_direct_init (GdmSessionDirect *session)
+                           G_CALLBACK (on_session_exited),
+                           NULL);
+ 
++        session->priv->conversations = g_hash_table_new_full (g_str_hash,
++                                                              g_str_equal,
++                                                              (GDestroyNotify) g_free,
++                                                              (GDestroyNotify)
++                                                              free_conversation);
+         session->priv->environment = g_hash_table_new_full (g_str_hash,
+                                                             g_str_equal,
+                                                             (GDestroyNotify) g_free,
+@@ -1723,9 +1839,15 @@ worker_exited (GdmSessionWorkerJob *job,
+ {
+         g_debug ("GdmSessionDirect: Worker job exited: %d", code);
+ 
++        g_object_ref (conversation->job);
+         if (conversation->session->priv->is_running) {
+                 _gdm_session_session_exited (GDM_SESSION (conversation->session), code);
+         }
++
++        g_debug ("GdmSessionDirect: Emitting conversation-stopped signal");
++        _gdm_session_conversation_stopped (GDM_SESSION (conversation->session),
++                                           conversation->service_name);
++        g_object_unref (conversation->job);
+ }
+ 
+ static void
+@@ -1735,9 +1857,15 @@ worker_died (GdmSessionWorkerJob *job,
+ {
+         g_debug ("GdmSessionDirect: Worker job died: %d", signum);
+ 
++        g_object_ref (conversation->job);
+         if (conversation->session->priv->is_running) {
+                 _gdm_session_session_died (GDM_SESSION (conversation->session), signum);
+         }
++
++        g_debug ("GdmSessionDirect: Emitting conversation-stopped signal");
++        _gdm_session_conversation_stopped (GDM_SESSION (conversation->session),
++                                           conversation->service_name);
++        g_object_unref (conversation->job);
+ }
+ 
+ static GdmSessionConversation *
+@@ -1799,17 +1927,21 @@ stop_conversation (GdmSessionConversation *conversation)
+                                               G_CALLBACK (worker_died),
                                                conversation);
  
+-        cancel_pending_query (conversation);
+-
          if (conversation->worker_connection != NULL) {
 +                dbus_connection_remove_filter (conversation->worker_connection, on_message, session);
 +
                  dbus_connection_close (conversation->worker_connection);
                  conversation->worker_connection = NULL;
          }
-@@ -1845,10 +1898,6 @@ gdm_session_direct_start_conversation (GdmSession *session,
  
-         g_hash_table_insert (impl->priv->conversations,
-                              g_strdup (service_name), conversation);
--
--        if (impl->priv->conversation != NULL) {
--                impl->priv->conversation = conversation;
--        }
- }
- 
- static void
-@@ -1999,45 +2048,50 @@ gdm_session_direct_setup_for_user (GdmSession *session,
+         gdm_session_worker_job_stop (conversation->job);
++
+         g_object_unref (conversation->job);
+-        g_free (conversation->service_name);
+-        g_free (conversation);
++        conversation->job = NULL;
++
++        g_debug ("GdmSessionDirect: Emitting conversation-stopped signal");
++        _gdm_session_conversation_stopped (GDM_SESSION (session),
++                                           conversation->service_name);
  }
  
  static void
--gdm_session_direct_authenticate (GdmSession *session)
-+gdm_session_direct_authenticate (GdmSession *session,
-+                                 const char *service_name)
+@@ -1817,12 +1949,35 @@ gdm_session_direct_start_conversation (GdmSession *session,
+                                        const char *service_name)
  {
          GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
-         GdmSessionConversation *conversation;
++        GdmSessionConversation *conversation;
  
          g_return_if_fail (session != NULL);
--        g_return_if_fail (impl->priv->conversation != NULL);
--        g_return_if_fail (dbus_connection_get_is_connected (impl->priv->conversation->worker_connection));
- 
--        conversation = impl->priv->conversation;
--        send_dbus_void_signal (conversation, "Authenticate");
-+        conversation = find_conversation_by_name (impl, service_name);
-+        if (conversation != NULL) {
-+                send_dbus_void_signal (conversation, "Authenticate");
-+        }
- }
  
- static void
--gdm_session_direct_authorize (GdmSession *session)
-+gdm_session_direct_authorize (GdmSession *session,
-+                              const char *service_name)
- {
-         GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
-         GdmSessionConversation *conversation;
+         g_debug ("GdmSessionDirect: starting conversation");
  
-         g_return_if_fail (session != NULL);
+-        impl->priv->conversation = start_conversation (impl, service_name);
++        conversation = start_conversation (impl, service_name);
++
++        g_hash_table_insert (impl->priv->conversations,
++                             g_strdup (service_name), conversation);
++}
++
++static void
++gdm_session_direct_stop_conversation (GdmSession *session,
++                                      const char *service_name)
++{
++        GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
++        GdmSessionConversation *conversation;
++
++        g_return_if_fail (session != NULL);
++
++        g_debug ("GdmSessionDirect: stopping conversation");
++
++        conversation = find_conversation_by_name (impl, service_name);
++
++        if (conversation != NULL) {
++                stop_conversation (conversation);
++                g_hash_table_remove (impl->priv->conversations, service_name);
++        }
+ }
+ 
+ static void
+@@ -1873,8 +2028,8 @@ send_setup (GdmSessionDirect *session,
+         dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &display_hostname);
+         dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &display_x11_authority_file);
+ 
+-        conversation = session->priv->conversation;
+-        if (! send_dbus_message (conversation, message)) {
++        conversation = find_conversation_by_name (session, service_name);
++        if (conversation != NULL && ! send_dbus_message (conversation, message)) {
+                 g_debug ("GdmSessionDirect: Could not send %s signal", "Setup");
+         }
+ 
+@@ -1936,8 +2091,8 @@ send_setup_for_user (GdmSessionDirect *session,
+         dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &display_x11_authority_file);
+         dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &selected_user);
+ 
+-        conversation = session->priv->conversation;
+-        if (! send_dbus_message (conversation, message)) {
++        conversation = find_conversation_by_name (session, service_name);
++        if (conversation != NULL && ! send_dbus_message (conversation, message)) {
+                 g_debug ("GdmSessionDirect: Could not send %s signal", "SetupForUser");
+         }
+ 
+@@ -1951,8 +2106,6 @@ gdm_session_direct_setup (GdmSession *session,
+         GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
+ 
+         g_return_if_fail (session != NULL);
+-        g_return_if_fail (impl->priv->conversation != NULL);
+-        g_return_if_fail (dbus_connection_get_is_connected (impl->priv->conversation->worker_connection));
+ 
+         send_setup (impl, service_name);
+         gdm_session_direct_defaults_changed (impl);
+@@ -1966,8 +2119,6 @@ gdm_session_direct_setup_for_user (GdmSession *session,
+         GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
+ 
+         g_return_if_fail (session != NULL);
+-        g_return_if_fail (impl->priv->conversation != NULL);
+-        g_return_if_fail (dbus_connection_get_is_connected (impl->priv->conversation->worker_connection));
+         g_return_if_fail (username != NULL);
+ 
+         gdm_session_direct_select_user (session, username);
+@@ -1977,45 +2128,50 @@ gdm_session_direct_setup_for_user (GdmSession *session,
+ }
+ 
+ static void
+-gdm_session_direct_authenticate (GdmSession *session)
++gdm_session_direct_authenticate (GdmSession *session,
++                                 const char *service_name)
+ {
+         GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
+         GdmSessionConversation *conversation;
+ 
+         g_return_if_fail (session != NULL);
+-        g_return_if_fail (impl->priv->conversation != NULL);
+-        g_return_if_fail (dbus_connection_get_is_connected (impl->priv->conversation->worker_connection));
+ 
+-        conversation = impl->priv->conversation;
+-        send_dbus_void_signal (conversation, "Authenticate");
++        conversation = find_conversation_by_name (impl, service_name);
++        if (conversation != NULL) {
++                send_dbus_void_signal (conversation, "Authenticate");
++        }
+ }
+ 
+ static void
+-gdm_session_direct_authorize (GdmSession *session)
++gdm_session_direct_authorize (GdmSession *session,
++                              const char *service_name)
+ {
+         GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
+         GdmSessionConversation *conversation;
+ 
+         g_return_if_fail (session != NULL);
 -        g_return_if_fail (impl->priv->conversation != NULL);
 -        g_return_if_fail (dbus_connection_get_is_connected (impl->priv->conversation->worker_connection));
  
@@ -3955,7 +4242,7 @@ index 8171b4e..9d6a6b9 100644
          switch (cred_flag) {
          case GDM_SESSION_CRED_ESTABLISH:
                  send_dbus_void_signal (conversation, "EstablishCredentials");
-@@ -2051,13 +2105,12 @@ gdm_session_direct_accredit (GdmSession *session,
+@@ -2029,13 +2185,12 @@ gdm_session_direct_accredit (GdmSession *session,
  }
  
  static void
@@ -3972,7 +4259,7 @@ index 8171b4e..9d6a6b9 100644
  
          message = dbus_message_new_signal (GDM_SESSION_DBUS_PATH,
                                             GDM_SESSION_DBUS_INTERFACE,
-@@ -2067,7 +2120,6 @@ send_environment_variable (const char       *key,
+@@ -2045,7 +2200,6 @@ send_environment_variable (const char       *key,
          dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &key);
          dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &value);
  
@@ -3980,7 +4267,7 @@ index 8171b4e..9d6a6b9 100644
          if (! send_dbus_message (conversation, message)) {
                  g_debug ("GdmSessionDirect: Could not send %s signal", "SetEnvironmentVariable");
          }
-@@ -2076,12 +2128,13 @@ send_environment_variable (const char       *key,
+@@ -2054,12 +2208,13 @@ send_environment_variable (const char       *key,
  }
  
  static void
@@ -3996,7 +4283,7 @@ index 8171b4e..9d6a6b9 100644
  }
  
  static const char *
-@@ -2203,17 +2256,22 @@ setup_session_environment (GdmSessionDirect *session)
+@@ -2181,17 +2336,22 @@ setup_session_environment (GdmSessionDirect *session)
  }
  
  static void
@@ -4022,7 +4309,7 @@ index 8171b4e..9d6a6b9 100644
  {
          GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
          GdmSessionConversation *conversation;
-@@ -2233,10 +2291,11 @@ gdm_session_direct_start_session (GdmSession *session)
+@@ -2211,15 +2371,38 @@ gdm_session_direct_start_session (GdmSession *session)
  
          g_free (command);
  
@@ -4036,10 +4323,39 @@ index 8171b4e..9d6a6b9 100644
          send_dbus_string_signal (conversation, "StartProgram", program);
          g_free (program);
  }
-@@ -2282,6 +2341,11 @@ gdm_session_direct_close (GdmSession *session)
  
-         stop_all_conversations (impl);
+ static void
++stop_all_conversations (GdmSessionDirect *session)
++{
++        GHashTableIter iter;
++        gpointer key, value;
++
++        if (session->priv->conversations == NULL) {
++                return;
++        }
++
++        g_hash_table_iter_init (&iter, session->priv->conversations);
++        while (g_hash_table_iter_next (&iter, &key, &value)) {
++                GdmSessionConversation *conversation;
++
++                conversation = (GdmSessionConversation *) value;
++
++                stop_conversation (conversation);
++        }
++
++        g_hash_table_remove_all (session->priv->conversations);
++}
++
++static void
+ gdm_session_direct_close (GdmSession *session)
+ {
+         GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
+@@ -2236,6 +2419,13 @@ gdm_session_direct_close (GdmSession *session)
+                                            impl->priv->display_device);
+         }
  
++        stop_all_conversations (impl);
++
 +        g_list_foreach (impl->priv->pending_connections,
 +                        (GFunc) dbus_connection_unref, NULL);
 +        g_list_free (impl->priv->pending_connections);
@@ -4048,7 +4364,7 @@ index 8171b4e..9d6a6b9 100644
          g_free (impl->priv->selected_user);
          impl->priv->selected_user = NULL;
  
-@@ -2314,6 +2378,7 @@ gdm_session_direct_close (GdmSession *session)
+@@ -2268,6 +2458,7 @@ gdm_session_direct_close (GdmSession *session)
  
  static void
  gdm_session_direct_answer_query  (GdmSession *session,
@@ -4056,7 +4372,7 @@ index 8171b4e..9d6a6b9 100644
                                    const char *text)
  {
          GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
-@@ -2321,7 +2386,7 @@ gdm_session_direct_answer_query  (GdmSession *session,
+@@ -2275,7 +2466,7 @@ gdm_session_direct_answer_query  (GdmSession *session,
  
          g_return_if_fail (session != NULL);
  
@@ -4065,7 +4381,20 @@ index 8171b4e..9d6a6b9 100644
  
          answer_pending_query (conversation, text);
  }
-@@ -2396,7 +2461,8 @@ gdm_session_direct_select_session (GdmSession *session,
+@@ -2283,11 +2474,9 @@ gdm_session_direct_answer_query  (GdmSession *session,
+ static void
+ gdm_session_direct_cancel  (GdmSession *session)
+ {
+-        GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
+-
+         g_return_if_fail (session != NULL);
+ 
+-        cancel_pending_query (impl->priv->conversation);
++        stop_all_conversations (GDM_SESSION_DIRECT (session));
+ }
+ 
+ char *
+@@ -2351,7 +2540,8 @@ gdm_session_direct_select_session (GdmSession *session,
                                     const char *text)
  {
          GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
@@ -4075,7 +4404,7 @@ index 8171b4e..9d6a6b9 100644
  
          g_free (impl->priv->selected_session);
  
-@@ -2406,9 +2472,15 @@ gdm_session_direct_select_session (GdmSession *session,
+@@ -2361,9 +2551,15 @@ gdm_session_direct_select_session (GdmSession *session,
                  impl->priv->selected_session = g_strdup (text);
          }
  
@@ -4094,7 +4423,7 @@ index 8171b4e..9d6a6b9 100644
  }
  
  static void
-@@ -2416,7 +2488,8 @@ gdm_session_direct_select_language (GdmSession *session,
+@@ -2371,7 +2567,8 @@ gdm_session_direct_select_language (GdmSession *session,
                                      const char *text)
  {
          GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
@@ -4104,7 +4433,7 @@ index 8171b4e..9d6a6b9 100644
  
          g_free (impl->priv->selected_language);
  
-@@ -2426,9 +2499,15 @@ gdm_session_direct_select_language (GdmSession *session,
+@@ -2381,9 +2578,15 @@ gdm_session_direct_select_language (GdmSession *session,
                  impl->priv->selected_language = g_strdup (text);
          }
  
@@ -4123,7 +4452,7 @@ index 8171b4e..9d6a6b9 100644
  }
  
  static void
-@@ -2436,7 +2515,8 @@ gdm_session_direct_select_layout (GdmSession *session,
+@@ -2391,7 +2594,8 @@ gdm_session_direct_select_layout (GdmSession *session,
                                    const char *text)
  {
          GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
@@ -4133,7 +4462,7 @@ index 8171b4e..9d6a6b9 100644
  
          g_free (impl->priv->selected_layout);
  
-@@ -2446,9 +2526,15 @@ gdm_session_direct_select_layout (GdmSession *session,
+@@ -2401,9 +2605,15 @@ gdm_session_direct_select_layout (GdmSession *session,
                  impl->priv->selected_layout = g_strdup (text);
          }
  
@@ -4152,15 +4481,25 @@ index 8171b4e..9d6a6b9 100644
  }
  
  static void
+@@ -2665,6 +2875,7 @@ static void
+ gdm_session_iface_init (GdmSessionIface *iface)
+ {
+         iface->start_conversation = gdm_session_direct_start_conversation;
++        iface->stop_conversation = gdm_session_direct_stop_conversation;
+         iface->setup = gdm_session_direct_setup;
+         iface->setup_for_user = gdm_session_direct_setup_for_user;
+         iface->authenticate = gdm_session_direct_authenticate;
 diff --git a/daemon/gdm-session-private.h b/daemon/gdm-session-private.h
-index 74b6069..4dc6e44 100644
+index 74b6069..36781dd 100644
 --- a/daemon/gdm-session-private.h
 +++ b/daemon/gdm-session-private.h
-@@ -29,27 +29,39 @@ G_BEGIN_DECLS
+@@ -29,27 +29,41 @@ G_BEGIN_DECLS
  /* state changes */
  void             _gdm_session_conversation_started         (GdmSession   *session,
                                                              const char   *service_name);
 -void             _gdm_session_setup_complete               (GdmSession   *session);
++void             _gdm_session_conversation_stopped         (GdmSession   *session,
++                                                            const char   *service_name);
 +void             _gdm_session_setup_complete               (GdmSession   *session,
 +                                                            const char   *service_name);
  void             _gdm_session_setup_failed                 (GdmSession   *session,
@@ -4201,7 +4540,7 @@ index 74b6069..4dc6e44 100644
                                                              const char   *message);
  void             _gdm_session_session_exited               (GdmSession   *session,
                                                              int           exit_code);
-@@ -70,12 +82,16 @@ void             _gdm_session_selected_user_changed        (GdmSession   *sessio
+@@ -70,12 +84,16 @@ void             _gdm_session_selected_user_changed        (GdmSession   *sessio
  
  /* call and response stuff */
  void             _gdm_session_info_query                   (GdmSession   *session,
@@ -4667,10 +5006,10 @@ index a0b4cbf..98ccc51 100644
  
          return DBUS_HANDLER_RESULT_HANDLED;
 diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c
-index 5e34fb9..2f07e13 100644
+index 775f99b..6abd97d 100644
 --- a/daemon/gdm-session-worker.c
 +++ b/daemon/gdm-session-worker.c
-@@ -2876,6 +2876,28 @@ worker_dbus_filter_function (DBusConnection *connection,
+@@ -2892,6 +2892,28 @@ worker_dbus_filter_function (DBusConnection *connection,
          return DBUS_HANDLER_RESULT_HANDLED;
  }
  
@@ -4699,7 +5038,7 @@ index 5e34fb9..2f07e13 100644
  static GObject *
  gdm_session_worker_constructor (GType                  type,
                                  guint                  n_construct_properties,
-@@ -2902,6 +2924,11 @@ gdm_session_worker_constructor (GType                  type,
+@@ -2918,6 +2940,11 @@ gdm_session_worker_constructor (GType                  type,
                  exit (1);
          }
  
@@ -4712,10 +5051,10 @@ index 5e34fb9..2f07e13 100644
          dbus_connection_set_exit_on_disconnect (worker->priv->connection, TRUE);
  
 diff --git a/daemon/gdm-session.c b/daemon/gdm-session.c
-index 1820e29..a7b4e8b 100644
+index 1820e29..8858071 100644
 --- a/daemon/gdm-session.c
 +++ b/daemon/gdm-session.c
-@@ -24,6 +24,7 @@
+@@ -24,11 +24,13 @@
  #include <glib/gi18n.h>
  #include <glib-object.h>
  
@@ -4723,7 +5062,29 @@ index 1820e29..a7b4e8b 100644
  #include "gdm-session.h"
  #include "gdm-session-private.h"
  
-@@ -116,37 +117,41 @@ gdm_session_setup_for_user (GdmSession *session,
+ enum {
+         CONVERSATION_STARTED = 0,
++        CONVERSATION_STOPPED,
+         SETUP_COMPLETE,
+         SETUP_FAILED,
+         RESET_COMPLETE,
+@@ -89,6 +91,15 @@ gdm_session_start_conversation (GdmSession *session,
+ }
+ 
+ void
++gdm_session_stop_conversation (GdmSession *session,
++                              const char *service_name)
++{
++        g_return_if_fail (GDM_IS_SESSION (session));
++
++        GDM_SESSION_GET_IFACE (session)->stop_conversation (session, service_name);
++}
++
++void
+ gdm_session_close (GdmSession *session)
+ {
+         g_return_if_fail (GDM_IS_SESSION (session));
+@@ -116,37 +127,41 @@ gdm_session_setup_for_user (GdmSession *session,
  }
  
  void
@@ -4771,7 +5132,7 @@ index 1820e29..a7b4e8b 100644
  }
  
  void
-@@ -194,19 +199,21 @@ gdm_session_cancel (GdmSession *session)
+@@ -194,19 +209,21 @@ gdm_session_cancel (GdmSession *session)
  }
  
  void
@@ -4797,16 +5158,26 @@ index 1820e29..a7b4e8b 100644
  }
  
  static void
-@@ -223,7 +230,7 @@ gdm_session_class_init (gpointer g_iface)
+@@ -223,7 +240,17 @@ gdm_session_class_init (gpointer g_iface)
                                NULL,
                                g_cclosure_marshal_VOID__STRING,
                                G_TYPE_NONE,
 -                              0);
 +                              1, G_TYPE_STRING);
++        signals [CONVERSATION_STOPPED] =
++                g_signal_new ("conversation-stopped",
++                              iface_type,
++                              G_SIGNAL_RUN_FIRST,
++                              G_STRUCT_OFFSET (GdmSessionIface, conversation_stopped),
++                              NULL,
++                              NULL,
++                              g_cclosure_marshal_VOID__STRING,
++                              G_TYPE_NONE,
++                              1, G_TYPE_STRING);
          signals [SETUP_COMPLETE] =
                  g_signal_new ("setup-complete",
                                iface_type,
-@@ -231,9 +238,10 @@ gdm_session_class_init (gpointer g_iface)
+@@ -231,9 +258,10 @@ gdm_session_class_init (gpointer g_iface)
                                G_STRUCT_OFFSET (GdmSessionIface, setup_complete),
                                NULL,
                                NULL,
@@ -4819,7 +5190,7 @@ index 1820e29..a7b4e8b 100644
          signals [SETUP_FAILED] =
                  g_signal_new ("setup-failed",
                                iface_type,
-@@ -241,10 +249,10 @@ gdm_session_class_init (gpointer g_iface)
+@@ -241,10 +269,10 @@ gdm_session_class_init (gpointer g_iface)
                                G_STRUCT_OFFSET (GdmSessionIface, setup_failed),
                                NULL,
                                NULL,
@@ -4833,7 +5204,7 @@ index 1820e29..a7b4e8b 100644
          signals [RESET_COMPLETE] =
                  g_signal_new ("reset-complete",
                                iface_type,
-@@ -273,9 +281,9 @@ gdm_session_class_init (gpointer g_iface)
+@@ -273,9 +301,9 @@ gdm_session_class_init (gpointer g_iface)
                                G_STRUCT_OFFSET (GdmSessionIface, authenticated),
                                NULL,
                                NULL,
@@ -4845,7 +5216,7 @@ index 1820e29..a7b4e8b 100644
          signals [AUTHENTICATION_FAILED] =
                  g_signal_new ("authentication-failed",
                                iface_type,
-@@ -283,10 +291,10 @@ gdm_session_class_init (gpointer g_iface)
+@@ -283,10 +311,10 @@ gdm_session_class_init (gpointer g_iface)
                                G_STRUCT_OFFSET (GdmSessionIface, authentication_failed),
                                NULL,
                                NULL,
@@ -4859,7 +5230,7 @@ index 1820e29..a7b4e8b 100644
          signals [AUTHORIZED] =
                  g_signal_new ("authorized",
                                iface_type,
-@@ -294,9 +302,9 @@ gdm_session_class_init (gpointer g_iface)
+@@ -294,9 +322,9 @@ gdm_session_class_init (gpointer g_iface)
                                G_STRUCT_OFFSET (GdmSessionIface, authorized),
                                NULL,
                                NULL,
@@ -4871,7 +5242,7 @@ index 1820e29..a7b4e8b 100644
          signals [AUTHORIZATION_FAILED] =
                  g_signal_new ("authorization-failed",
                                iface_type,
-@@ -304,10 +312,10 @@ gdm_session_class_init (gpointer g_iface)
+@@ -304,10 +332,10 @@ gdm_session_class_init (gpointer g_iface)
                                G_STRUCT_OFFSET (GdmSessionIface, authorization_failed),
                                NULL,
                                NULL,
@@ -4885,7 +5256,7 @@ index 1820e29..a7b4e8b 100644
          signals [ACCREDITED] =
                  g_signal_new ("accredited",
                                iface_type,
-@@ -315,9 +323,9 @@ gdm_session_class_init (gpointer g_iface)
+@@ -315,9 +343,9 @@ gdm_session_class_init (gpointer g_iface)
                                G_STRUCT_OFFSET (GdmSessionIface, accredited),
                                NULL,
                                NULL,
@@ -4897,7 +5268,7 @@ index 1820e29..a7b4e8b 100644
          signals [ACCREDITATION_FAILED] =
                  g_signal_new ("accreditation-failed",
                                iface_type,
-@@ -325,10 +333,10 @@ gdm_session_class_init (gpointer g_iface)
+@@ -325,10 +353,10 @@ gdm_session_class_init (gpointer g_iface)
                                G_STRUCT_OFFSET (GdmSessionIface, accreditation_failed),
                                NULL,
                                NULL,
@@ -4911,7 +5282,7 @@ index 1820e29..a7b4e8b 100644
  
           signals [INFO_QUERY] =
                  g_signal_new ("info-query",
-@@ -337,10 +345,10 @@ gdm_session_class_init (gpointer g_iface)
+@@ -337,10 +365,10 @@ gdm_session_class_init (gpointer g_iface)
                                G_STRUCT_OFFSET (GdmSessionIface, info_query),
                                NULL,
                                NULL,
@@ -4925,7 +5296,7 @@ index 1820e29..a7b4e8b 100644
          signals [SECRET_INFO_QUERY] =
                  g_signal_new ("secret-info-query",
                                iface_type,
-@@ -348,10 +356,10 @@ gdm_session_class_init (gpointer g_iface)
+@@ -348,10 +376,10 @@ gdm_session_class_init (gpointer g_iface)
                                G_STRUCT_OFFSET (GdmSessionIface, secret_info_query),
                                NULL,
                                NULL,
@@ -4939,7 +5310,7 @@ index 1820e29..a7b4e8b 100644
          signals [INFO] =
                  g_signal_new ("info",
                                iface_type,
-@@ -359,10 +367,10 @@ gdm_session_class_init (gpointer g_iface)
+@@ -359,10 +387,10 @@ gdm_session_class_init (gpointer g_iface)
                                G_STRUCT_OFFSET (GdmSessionIface, info),
                                NULL,
                                NULL,
@@ -4953,7 +5324,7 @@ index 1820e29..a7b4e8b 100644
          signals [PROBLEM] =
                  g_signal_new ("problem",
                                iface_type,
-@@ -370,10 +378,10 @@ gdm_session_class_init (gpointer g_iface)
+@@ -370,10 +398,10 @@ gdm_session_class_init (gpointer g_iface)
                                G_STRUCT_OFFSET (GdmSessionIface, problem),
                                NULL,
                                NULL,
@@ -4967,7 +5338,7 @@ index 1820e29..a7b4e8b 100644
          signals [SESSION_OPENED] =
                  g_signal_new ("session-opened",
                                iface_type,
-@@ -381,9 +389,10 @@ gdm_session_class_init (gpointer g_iface)
+@@ -381,9 +409,10 @@ gdm_session_class_init (gpointer g_iface)
                                G_STRUCT_OFFSET (GdmSessionIface, session_opened),
                                NULL,
                                NULL,
@@ -4980,7 +5351,7 @@ index 1820e29..a7b4e8b 100644
          signals [SESSION_OPEN_FAILED] =
                  g_signal_new ("session-open-failed",
                                iface_type,
-@@ -391,10 +400,10 @@ gdm_session_class_init (gpointer g_iface)
+@@ -391,10 +420,10 @@ gdm_session_class_init (gpointer g_iface)
                                G_STRUCT_OFFSET (GdmSessionIface, session_open_failed),
                                NULL,
                                NULL,
@@ -4994,7 +5365,7 @@ index 1820e29..a7b4e8b 100644
          signals [SESSION_STARTED] =
                  g_signal_new ("session-started",
                                iface_type,
-@@ -402,10 +411,10 @@ gdm_session_class_init (gpointer g_iface)
+@@ -402,10 +431,10 @@ gdm_session_class_init (gpointer g_iface)
                                G_STRUCT_OFFSET (GdmSessionIface, session_started),
                                NULL,
                                NULL,
@@ -5008,7 +5379,7 @@ index 1820e29..a7b4e8b 100644
          signals [SESSION_START_FAILED] =
                  g_signal_new ("session-start-failed",
                                iface_type,
-@@ -413,10 +422,10 @@ gdm_session_class_init (gpointer g_iface)
+@@ -413,10 +442,10 @@ gdm_session_class_init (gpointer g_iface)
                                G_STRUCT_OFFSET (GdmSessionIface, session_start_failed),
                                NULL,
                                NULL,
@@ -5022,7 +5393,7 @@ index 1820e29..a7b4e8b 100644
          signals [SESSION_EXITED] =
                  g_signal_new ("session-exited",
                                iface_type,
-@@ -496,19 +505,21 @@ gdm_session_class_init (gpointer g_iface)
+@@ -496,19 +525,21 @@ gdm_session_class_init (gpointer g_iface)
  }
  
  void
@@ -5047,7 +5418,7 @@ index 1820e29..a7b4e8b 100644
  }
  
  void
-@@ -528,114 +539,128 @@ _gdm_session_reset_failed (GdmSession   *session,
+@@ -528,114 +559,128 @@ _gdm_session_reset_failed (GdmSession   *session,
  }
  
  void
@@ -5194,11 +5565,34 @@ index 1820e29..a7b4e8b 100644
  }
  
  void
+@@ -663,6 +708,14 @@ _gdm_session_conversation_started (GdmSession   *session,
+ }
+ 
+ void
++_gdm_session_conversation_stopped (GdmSession   *session,
++                                   const char   *service_name)
++{
++        g_return_if_fail (GDM_IS_SESSION (session));
++        g_signal_emit (session, signals [CONVERSATION_STOPPED], 0, service_name);
++}
++
++void
+ _gdm_session_closed (GdmSession   *session)
+ {
+         g_return_if_fail (GDM_IS_SESSION (session));
 diff --git a/daemon/gdm-session.h b/daemon/gdm-session.h
-index 00c2fa4..20a442b 100644
+index 00c2fa4..22c2ccb 100644
 --- a/daemon/gdm-session.h
 +++ b/daemon/gdm-session.h
-@@ -53,12 +53,17 @@ struct _GdmSessionIface
+@@ -47,18 +47,25 @@ struct _GdmSessionIface
+         /* Methods */
+         void (* start_conversation)          (GdmSession   *session,
+                                               const char   *service_name);
++        void (* stop_conversation)           (GdmSession   *session,
++                                              const char   *service_name);
+         void (* setup)                       (GdmSession   *session,
+                                               const char   *service_name);
+         void (* setup_for_user)              (GdmSession   *session,
                                                const char   *service_name,
                                                const char   *username);
          void (* reset)                       (GdmSession   *session);
@@ -5219,7 +5613,7 @@ index 00c2fa4..20a442b 100644
                                                const char   *text);
          void (* select_language)             (GdmSession   *session,
                                                const char   *text);
-@@ -68,41 +73,58 @@ struct _GdmSessionIface
+@@ -68,41 +75,58 @@ struct _GdmSessionIface
                                                const char   *text);
          void (* select_user)                 (GdmSession   *session,
                                                const char   *text);
@@ -5284,7 +5678,24 @@ index 00c2fa4..20a442b 100644
                                                const char   *message);
          void (* session_exited)              (GdmSession   *session,
                                                int           exit_code);
-@@ -132,15 +154,21 @@ void     gdm_session_setup_for_user              (GdmSession *session,
+@@ -110,6 +134,8 @@ struct _GdmSessionIface
+                                               int           signal_number);
+         void (* conversation_started)        (GdmSession   *session,
+                                               const char   *service_name);
++        void (* conversation_stopped)        (GdmSession   *session,
++                                              const char   *service_name);
+         void (* closed)                      (GdmSession   *session);
+         void (* selected_user_changed)       (GdmSession   *session,
+                                               const char   *text);
+@@ -126,21 +152,29 @@ GType    gdm_session_get_type                    (void) G_GNUC_CONST;
+ 
+ void     gdm_session_start_conversation          (GdmSession *session,
+                                                   const char *service_name);
++void     gdm_session_stop_conversation           (GdmSession *session,
++                                                  const char *service_name);
+ void     gdm_session_setup                       (GdmSession *session,
+                                                   const char *service_name);
+ void     gdm_session_setup_for_user              (GdmSession *session,
                                                    const char *service_name,
                                                    const char *username);
  void     gdm_session_reset                       (GdmSession *session);
@@ -5311,7 +5722,7 @@ index 00c2fa4..20a442b 100644
  void     gdm_session_select_session              (GdmSession *session,
                                                    const char *session_name);
 diff --git a/daemon/gdm-simple-slave.c b/daemon/gdm-simple-slave.c
-index a0b01e2..fed2e8b 100644
+index dc7b437..adcb94a 100644
 --- a/daemon/gdm-simple-slave.c
 +++ b/daemon/gdm-simple-slave.c
 @@ -71,6 +71,8 @@ struct GdmSimpleSlavePrivate
@@ -5323,7 +5734,7 @@ index a0b01e2..fed2e8b 100644
          int                ping_interval;
  
          GPid               server_pid;
-@@ -101,6 +103,7 @@ static void start_greeter      (GdmSimpleSlave *slave);
+@@ -102,6 +104,7 @@ static void start_greeter      (GdmSimpleSlave *slave);
  
  static void
  on_session_started (GdmSession       *session,
@@ -5331,7 +5742,7 @@ index a0b01e2..fed2e8b 100644
                      int               pid,
                      GdmSimpleSlave   *slave)
  {
-@@ -209,19 +212,22 @@ queue_greeter_reset (GdmSimpleSlave *slave)
+@@ -233,23 +236,25 @@ queue_auth_failed_reset (GdmSimpleSlave *slave)
  
  static void
  on_session_setup_complete (GdmSession     *session,
@@ -5355,8 +5766,13 @@ index a0b01e2..fed2e8b 100644
 +                                            message != NULL ? message:  _("Unable to initialize login system"));
          }
  
-         destroy_session (slave);
-@@ -245,18 +251,21 @@ on_session_reset_failed (GdmSession     *session,
+-        destroy_session (slave);
+-        queue_greeter_reset (slave);
++        gdm_session_stop_conversation (session, service_name);
+ }
+ 
+ static void
+@@ -269,29 +274,32 @@ on_session_reset_failed (GdmSession     *session,
  
  static void
  on_session_authenticated (GdmSession     *session,
@@ -5378,8 +5794,12 @@ index a0b01e2..fed2e8b 100644
 +                                            service_name,
                                              message != NULL ? message : _("Unable to authenticate user"));
          }
-         destroy_session (slave);
-@@ -264,7 +273,8 @@ on_session_authentication_failed (GdmSession     *session,
+ 
+-        destroy_session (slave);
+-
+         g_debug ("GdmSimpleSlave: Authentication failed - may retry");
++        gdm_session_stop_conversation (session, service_name);
+         queue_auth_failed_reset (slave);
  }
  
  static void
@@ -5389,7 +5809,7 @@ index a0b01e2..fed2e8b 100644
  {
          if (slave->priv->start_session_when_ready) {
                  char *ssid;
-@@ -285,7 +295,7 @@ gdm_simple_slave_accredit_when_ready (GdmSimpleSlave *slave)
+@@ -312,7 +320,7 @@ gdm_simple_slave_accredit_when_ready (GdmSimpleSlave *slave)
                  g_free (ssid);
                  g_free (username);
  
@@ -5398,7 +5818,7 @@ index a0b01e2..fed2e8b 100644
          } else {
                  slave->priv->waiting_to_start_session = TRUE;
          }
-@@ -293,25 +303,28 @@ gdm_simple_slave_accredit_when_ready (GdmSimpleSlave *slave)
+@@ -320,29 +328,31 @@ gdm_simple_slave_accredit_when_ready (GdmSimpleSlave *slave)
  
  static void
  on_session_authorized (GdmSession     *session,
@@ -5430,8 +5850,13 @@ index a0b01e2..fed2e8b 100644
 +                                            message != NULL ? message :  _("Unable to authorize user"));
          }
  
-         destroy_session (slave);
-@@ -397,31 +410,38 @@ start_session_timeout (GdmSimpleSlave *slave)
+-        destroy_session (slave);
+-        queue_greeter_reset (slave);
++        gdm_session_stop_conversation (session, service_name);
+ }
+ 
+ static gboolean
+@@ -425,31 +435,38 @@ start_session_timeout (GdmSimpleSlave *slave)
  
          g_free (auth_file);
  
@@ -5473,7 +5898,7 @@ index a0b01e2..fed2e8b 100644
                                   const char     *message,
                                   GdmSimpleSlave *slave)
  {
-@@ -442,6 +462,7 @@ on_session_accreditation_failed (GdmSession     *session,
+@@ -470,6 +487,7 @@ on_session_accreditation_failed (GdmSession     *session,
                                  problem = _("Unable to establish credentials");
                          }
                          gdm_greeter_server_problem (slave->priv->greeter_server,
@@ -5481,7 +5906,15 @@ index a0b01e2..fed2e8b 100644
                                                      problem);
                  }
          }
-@@ -457,62 +478,68 @@ on_session_accreditation_failed (GdmSession     *session,
+@@ -478,69 +496,74 @@ on_session_accreditation_failed (GdmSession     *session,
+            when Xorg exits it switches to the VT it was
+            started from.  That interferes with fast
+            user switching. */
+-        destroy_session (slave);
+ 
+-        queue_greeter_reset (slave);
++        gdm_session_stop_conversation (session, service_name);
+ }
  
  static void
  on_session_opened (GdmSession     *session,
@@ -5557,26 +5990,71 @@ index a0b01e2..fed2e8b 100644
  }
  
  static void
-@@ -790,11 +817,12 @@ on_greeter_start_conversation (GdmGreeterServer *greeter_server,
- 
- static void
- on_greeter_begin_verification (GdmGreeterServer *greeter_server,
-+                               const char       *service_name,
-                                GdmSimpleSlave   *slave)
- {
-         g_debug ("GdmSimpleSlave: begin verification");
-         gdm_session_setup (GDM_SESSION (slave->priv->session),
--                           "gdm");
-+                           service_name);
+@@ -583,6 +606,23 @@ on_session_conversation_started (GdmSession     *session,
  }
  
  static void
-@@ -810,21 +838,23 @@ on_greeter_begin_auto_login (GdmGreeterServer *greeter_server,
- 
- static void
- on_greeter_begin_verification_for_user (GdmGreeterServer *greeter_server,
-+                                        const char       *service_name,
-                                         const char       *username,
++on_session_conversation_stopped (GdmSession     *session,
++                                 const char     *service_name,
++                                 GdmSimpleSlave *slave)
++{
++        gboolean res;
++        g_debug ("GdmSimpleSlave: conversation stopped");
++
++        if (slave->priv->greeter_server != NULL) {
++                res = gdm_greeter_server_conversation_stopped (slave->priv->greeter_server,
++                                                               service_name);
++                if (! res) {
++                        g_warning ("Unable to send conversation stopped");
++                }
++        }
++}
++
++static void
+ on_session_selected_user_changed (GdmSession     *session,
+                                   const char     *text,
+                                   GdmSimpleSlave *slave)
+@@ -686,6 +726,10 @@ create_new_session (GdmSimpleSlave *slave)
+                           G_CALLBACK (on_session_conversation_started),
+                           slave);
+         g_signal_connect (slave->priv->session,
++                          "conversation-stopped",
++                          G_CALLBACK (on_session_conversation_stopped),
++                          slave);
++        g_signal_connect (slave->priv->session,
+                           "setup-complete",
+                           G_CALLBACK (on_session_setup_complete),
+                           slave);
+@@ -797,6 +841,9 @@ destroy_session (GdmSimpleSlave *slave)
+                                               G_CALLBACK (on_session_conversation_started),
+                                               slave);
+         g_signal_handlers_disconnect_by_func (slave->priv->session,
++                                              G_CALLBACK (on_session_conversation_stopped),
++                                              slave);
++        g_signal_handlers_disconnect_by_func (slave->priv->session,
+                                               G_CALLBACK (on_session_setup_complete),
+                                               slave);
+         g_signal_handlers_disconnect_by_func (slave->priv->session,
+@@ -926,11 +973,12 @@ on_greeter_start_conversation (GdmGreeterServer *greeter_server,
+ 
+ static void
+ on_greeter_begin_verification (GdmGreeterServer *greeter_server,
++                               const char       *service_name,
+                                GdmSimpleSlave   *slave)
+ {
+         g_debug ("GdmSimpleSlave: begin verification");
+         gdm_session_setup (GDM_SESSION (slave->priv->session),
+-                           "gdm");
++                           service_name);
+ }
+ 
+ static void
+@@ -946,21 +994,23 @@ on_greeter_begin_auto_login (GdmGreeterServer *greeter_server,
+ 
+ static void
+ on_greeter_begin_verification_for_user (GdmGreeterServer *greeter_server,
++                                        const char       *service_name,
+                                         const char       *username,
                                          GdmSimpleSlave   *slave)
  {
          g_debug ("GdmSimpleSlave: begin verification");
@@ -5597,7 +6075,7 @@ index a0b01e2..fed2e8b 100644
  }
  
  static void
-@@ -887,18 +917,20 @@ on_greeter_connected (GdmGreeterServer *greeter_server,
+@@ -1023,18 +1073,20 @@ on_greeter_connected (GdmGreeterServer *greeter_server,
  
  static void
  on_start_session_when_ready (GdmGreeterServer *session,
@@ -5620,7 +6098,7 @@ index a0b01e2..fed2e8b 100644
  {
          g_debug ("GdmSimpleSlave: Will start session when ready and told");
 diff --git a/daemon/test-session.c b/daemon/test-session.c
-index ed13ff7..7f6c5fe 100644
+index 9bfda86..fe78230 100644
 --- a/daemon/test-session.c
 +++ b/daemon/test-session.c
 @@ -44,10 +44,11 @@ on_conversation_started (GdmSession *session,
@@ -5697,8 +6175,8 @@ index ed13ff7..7f6c5fe 100644
 +               const char *service_name,
                 const char *query_text)
  {
-         char answer[1024];
-@@ -178,12 +185,13 @@ on_info_query (GdmSession *session,
+         char  answer[1024];
+@@ -184,12 +191,13 @@ on_info_query (GdmSession *session,
                  gdm_session_close (session);
                  g_main_loop_quit (loop);
          } else {
@@ -5713,7 +6191,7 @@ index ed13ff7..7f6c5fe 100644
           const char *info)
  {
          g_print ("\n** NOTE: %s\n", info);
-@@ -191,6 +199,7 @@ on_info (GdmSession *session,
+@@ -197,6 +205,7 @@ on_info (GdmSession *session,
  
  static void
  on_problem (GdmSession *session,
@@ -5721,7 +6199,7 @@ index ed13ff7..7f6c5fe 100644
              const char *problem)
  {
          g_print ("\n** WARNING: %s\n", problem);
-@@ -198,6 +207,7 @@ on_problem (GdmSession *session,
+@@ -204,6 +213,7 @@ on_problem (GdmSession *session,
  
  static void
  on_secret_info_query (GdmSession *session,
@@ -5729,7 +6207,7 @@ index ed13ff7..7f6c5fe 100644
                        const char *query_text)
  {
          char           answer[1024];
-@@ -222,7 +232,7 @@ on_secret_info_query (GdmSession *session,
+@@ -233,7 +243,7 @@ on_secret_info_query (GdmSession *session,
  
          g_print ("\n");
  
@@ -5739,10 +6217,10 @@ index ed13ff7..7f6c5fe 100644
  
  static void
 diff --git a/gui/simple-greeter/gdm-greeter-client.c b/gui/simple-greeter/gdm-greeter-client.c
-index 8d061a4..0891e8b 100644
+index b175fc9..e42ab1e 100644
 --- a/gui/simple-greeter/gdm-greeter-client.c
 +++ b/gui/simple-greeter/gdm-greeter-client.c
-@@ -134,6 +134,37 @@ emit_string_and_int_signal_for_message (GdmGreeterClient *client,
+@@ -135,6 +135,37 @@ emit_string_and_int_signal_for_message (GdmGreeterClient *client,
  }
  
  static void
@@ -5780,7 +6258,7 @@ index 8d061a4..0891e8b 100644
  emit_string_signal_for_message (GdmGreeterClient *client,
                                  const char       *name,
                                  DBusMessage      *message,
-@@ -200,37 +231,35 @@ static void
+@@ -201,37 +232,35 @@ static void
  on_user_authorized (GdmGreeterClient *client,
                      DBusMessage      *message)
  {
@@ -5823,7 +6301,7 @@ index 8d061a4..0891e8b 100644
  }
  
  static void
-@@ -307,14 +336,22 @@ send_dbus_string_method (DBusConnection *connection,
+@@ -319,14 +348,22 @@ send_dbus_string_method (DBusConnection *connection,
  }
  
  static gboolean
@@ -5849,7 +6327,7 @@ index 8d061a4..0891e8b 100644
  
          g_debug ("GdmGreeterClient: Calling %s", method);
          message = dbus_message_new_method_call (NULL,
-@@ -328,8 +365,77 @@ send_dbus_bool_method (DBusConnection *connection,
+@@ -340,8 +377,77 @@ send_dbus_bool_method (DBusConnection *connection,
  
          dbus_message_iter_init_append (message, &iter);
          dbus_message_iter_append_basic (&iter,
@@ -5928,7 +6406,7 @@ index 8d061a4..0891e8b 100644
  
          dbus_error_init (&error);
          reply = dbus_connection_send_with_reply_and_block (connection,
-@@ -412,37 +518,44 @@ gdm_greeter_client_call_begin_auto_login (GdmGreeterClient *client,
+@@ -424,37 +530,44 @@ gdm_greeter_client_call_begin_auto_login (GdmGreeterClient *client,
  }
  
  void
@@ -5985,7 +6463,7 @@ index 8d061a4..0891e8b 100644
  }
  
  void
-@@ -835,10 +948,10 @@ gdm_greeter_client_class_init (GdmGreeterClientClass *klass)
+@@ -849,10 +962,10 @@ gdm_greeter_client_class_init (GdmGreeterClientClass *klass)
                                G_STRUCT_OFFSET (GdmGreeterClientClass, info_query),
                                NULL,
                                NULL,
@@ -5999,7 +6477,7 @@ index 8d061a4..0891e8b 100644
  
          gdm_greeter_client_signals[SECRET_INFO_QUERY] =
                  g_signal_new ("secret-info-query",
-@@ -847,10 +960,10 @@ gdm_greeter_client_class_init (GdmGreeterClientClass *klass)
+@@ -861,10 +974,10 @@ gdm_greeter_client_class_init (GdmGreeterClientClass *klass)
                                G_STRUCT_OFFSET (GdmGreeterClientClass, secret_info_query),
                                NULL,
                                NULL,
@@ -6013,7 +6491,7 @@ index 8d061a4..0891e8b 100644
  
          gdm_greeter_client_signals[INFO] =
                  g_signal_new ("info",
-@@ -859,10 +972,10 @@ gdm_greeter_client_class_init (GdmGreeterClientClass *klass)
+@@ -873,10 +986,10 @@ gdm_greeter_client_class_init (GdmGreeterClientClass *klass)
                                G_STRUCT_OFFSET (GdmGreeterClientClass, info),
                                NULL,
                                NULL,
@@ -6027,7 +6505,7 @@ index 8d061a4..0891e8b 100644
  
          gdm_greeter_client_signals[PROBLEM] =
                  g_signal_new ("problem",
-@@ -871,10 +984,10 @@ gdm_greeter_client_class_init (GdmGreeterClientClass *klass)
+@@ -885,10 +998,10 @@ gdm_greeter_client_class_init (GdmGreeterClientClass *klass)
                                G_STRUCT_OFFSET (GdmGreeterClientClass, problem),
                                NULL,
                                NULL,
@@ -6041,7 +6519,7 @@ index 8d061a4..0891e8b 100644
  
          gdm_greeter_client_signals[READY] =
                  g_signal_new ("ready",
-@@ -956,8 +1069,9 @@ gdm_greeter_client_class_init (GdmGreeterClientClass *klass)
+@@ -980,8 +1093,9 @@ gdm_greeter_client_class_init (GdmGreeterClientClass *klass)
                                G_STRUCT_OFFSET (GdmGreeterClientClass, user_authorized),
                                NULL,
                                NULL,
@@ -6054,7 +6532,7 @@ index 8d061a4..0891e8b 100644
  
  static void
 diff --git a/gui/simple-greeter/gdm-greeter-client.h b/gui/simple-greeter/gdm-greeter-client.h
-index 88b0281..2f857dc 100644
+index e08aaa5..2f27503 100644
 --- a/gui/simple-greeter/gdm-greeter-client.h
 +++ b/gui/simple-greeter/gdm-greeter-client.h
 @@ -45,17 +45,22 @@ typedef struct
@@ -6079,9 +6557,9 @@ index 88b0281..2f857dc 100644
 +        void (* ready)                   (GdmGreeterClient  *client,
 +                                          const char        *service_name);
          void (* reset)                   (GdmGreeterClient  *client);
+         void (* authentication_failed)   (GdmGreeterClient  *client);
          void (* selected_user_changed)   (GdmGreeterClient  *client,
-                                           const char        *username);
-@@ -69,7 +74,8 @@ typedef struct
+@@ -70,7 +75,8 @@ typedef struct
          void (* timed_login_requested)   (GdmGreeterClient  *client,
                                            const char        *username,
                                            int                delay);
@@ -6091,7 +6569,7 @@ index 88b0281..2f857dc 100644
  } GdmGreeterClientClass;
  
  #define GDM_GREETER_CLIENT_ERROR (gdm_greeter_client_error_quark ())
-@@ -95,8 +101,10 @@ void               gdm_greeter_client_call_start_conversation        (GdmGreeter
+@@ -96,8 +102,10 @@ void               gdm_greeter_client_call_start_conversation        (GdmGreeter
                                                                        const char       *service_name);
  void               gdm_greeter_client_call_begin_auto_login          (GdmGreeterClient *client,
                                                                        const char       *username);
@@ -6103,7 +6581,7 @@ index 88b0281..2f857dc 100644
                                                                          const char       *username);
  void               gdm_greeter_client_call_cancel                    (GdmGreeterClient *client);
  void               gdm_greeter_client_call_disconnect                (GdmGreeterClient *client);
-@@ -111,9 +119,11 @@ void               gdm_greeter_client_call_select_layout             (GdmGreeter
+@@ -112,9 +120,11 @@ void               gdm_greeter_client_call_select_layout             (GdmGreeter
  void               gdm_greeter_client_call_select_session            (GdmGreeterClient *client,
                                                                        const char       *text);
  void               gdm_greeter_client_call_answer_query              (GdmGreeterClient *client,
@@ -6116,10 +6594,10 @@ index 88b0281..2f857dc 100644
  
  
 diff --git a/gui/simple-greeter/gdm-greeter-session.c b/gui/simple-greeter/gdm-greeter-session.c
-index cd0cbdf..e856dd4 100644
+index 63de620..b7e7f1c 100644
 --- a/gui/simple-greeter/gdm-greeter-session.c
 +++ b/gui/simple-greeter/gdm-greeter-session.c
-@@ -65,6 +65,7 @@ static gpointer session_object = NULL;
+@@ -69,6 +69,7 @@ static gpointer session_object = NULL;
  
  static void
  on_info (GdmGreeterClient  *client,
@@ -6127,7 +6605,7 @@ index cd0cbdf..e856dd4 100644
           const char        *text,
           GdmGreeterSession *session)
  {
-@@ -75,6 +76,7 @@ on_info (GdmGreeterClient  *client,
+@@ -79,6 +80,7 @@ on_info (GdmGreeterClient  *client,
  
  static void
  on_problem (GdmGreeterClient  *client,
@@ -6135,7 +6613,7 @@ index cd0cbdf..e856dd4 100644
              const char        *text,
              GdmGreeterSession *session)
  {
-@@ -173,6 +175,7 @@ on_user_authorized (GdmGreeterClient  *client,
+@@ -202,6 +204,7 @@ on_user_authorized (GdmGreeterClient  *client,
  
  static void
  on_info_query (GdmGreeterClient  *client,
@@ -6143,7 +6621,7 @@ index cd0cbdf..e856dd4 100644
                 const char        *text,
                 GdmGreeterSession *session)
  {
-@@ -183,6 +186,7 @@ on_info_query (GdmGreeterClient  *client,
+@@ -212,6 +215,7 @@ on_info_query (GdmGreeterClient  *client,
  
  static void
  on_secret_info_query (GdmGreeterClient  *client,
@@ -6151,7 +6629,7 @@ index cd0cbdf..e856dd4 100644
                        const char        *text,
                        GdmGreeterSession *session)
  {
-@@ -204,7 +208,8 @@ static void
+@@ -233,7 +237,8 @@ static void
  on_begin_verification (GdmGreeterLoginWindow *login_window,
                         GdmGreeterSession     *session)
  {
@@ -6161,7 +6639,7 @@ index cd0cbdf..e856dd4 100644
  }
  
  static void
-@@ -213,6 +218,7 @@ on_begin_verification_for_user (GdmGreeterLoginWindow *login_window,
+@@ -242,6 +247,7 @@ on_begin_verification_for_user (GdmGreeterLoginWindow *login_window,
                                  GdmGreeterSession     *session)
  {
          gdm_greeter_client_call_begin_verification_for_user (session->priv->client,
@@ -6169,7 +6647,7 @@ index cd0cbdf..e856dd4 100644
                                                               username);
  }
  
-@@ -222,6 +228,7 @@ on_query_answer (GdmGreeterLoginWindow *login_window,
+@@ -251,6 +257,7 @@ on_query_answer (GdmGreeterLoginWindow *login_window,
                   GdmGreeterSession     *session)
  {
          gdm_greeter_client_call_answer_query (session->priv->client,
@@ -6177,7 +6655,7 @@ index cd0cbdf..e856dd4 100644
                                                text);
  }
  
-@@ -285,7 +292,7 @@ static void
+@@ -308,7 +315,7 @@ static void
  on_start_session (GdmGreeterLoginWindow *login_window,
                    GdmGreeterSession     *session)
  {
@@ -6187,2316 +6665,2288 @@ index cd0cbdf..e856dd4 100644
  
  static int
 -- 
-1.6.5.2
+1.7.2.1
 
 
-From ef0d8f12990fa0c4b7d88fde8308a1594940eb88 Mon Sep 17 00:00:00 2001
+From 1f97db74673d35527b8003978e6a0f5717de08f4 Mon Sep 17 00:00:00 2001
 From: Ray Strode <rstrode at redhat.com>
-Date: Sat, 7 Feb 2009 11:36:40 -0500
-Subject: [PATCH 07/45] emit "ConversationStopped" signal at end of conv
+Date: Wed, 28 Oct 2009 16:05:14 -0400
+Subject: [PATCH 11/35] Return a different error code for "service won't work" than "auth failed"
 
-This will allow us to track when individual
-PAM conversations fail, instead of doing one
-giant reset.  The reason this is useful is that
-some PAM modules fail immediately for some users
-(for instance the fingerprint PAM module fails if
- a user hasn't enrolled their print).
+If we bubble it up to the greeter then we should be able to have
+a more sensible UI when e.g. fingerprinting isn't enabled.
 ---
- daemon/gdm-greeter-server.c  |   14 ++++++++++++++
- daemon/gdm-greeter-server.h  |    2 ++
- daemon/gdm-session-direct.c  |   36 ++++++++++++++++++++++++++++++++++++
- daemon/gdm-session-private.h |    2 ++
- daemon/gdm-session.c         |   28 ++++++++++++++++++++++++++++
- daemon/gdm-session.h         |    6 ++++++
- daemon/gdm-simple-slave.c    |   34 ++++++++++++++++++++++++++--------
- 7 files changed, 114 insertions(+), 8 deletions(-)
+ daemon/gdm-session-worker.c |   14 +++++++++++---
+ daemon/gdm-session-worker.h |    1 +
+ 2 files changed, 12 insertions(+), 3 deletions(-)
 
-diff --git a/daemon/gdm-greeter-server.c b/daemon/gdm-greeter-server.c
-index dae34c5..ecb2ad6 100644
---- a/daemon/gdm-greeter-server.c
-+++ b/daemon/gdm-greeter-server.c
-@@ -299,6 +299,14 @@ gdm_greeter_server_ready (GdmGreeterServer *greeter_server,
-         return TRUE;
- }
+diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c
+index 6abd97d..ed6cacf 100644
+--- a/daemon/gdm-session-worker.c
++++ b/daemon/gdm-session-worker.c
+@@ -1306,8 +1306,8 @@ gdm_session_worker_initialize_pam (GdmSessionWorker *worker,
+                  */
+                 g_set_error (error,
+                              GDM_SESSION_WORKER_ERROR,
+-                             GDM_SESSION_WORKER_ERROR_AUTHENTICATING,
+-                             _("error initiating conversation with authentication system: %s"),
++                             GDM_SESSION_WORKER_ERROR_SERVICE_UNAVAILABLE,
++                             _("error initiating conversation with authentication system - %s"),
+                              error_code == PAM_ABORT? _("general failure") :
+                              error_code == PAM_BUF_ERR? _("out of memory") :
+                              error_code == PAM_SYSTEM_ERR? _("application programmer error") :
+@@ -1418,7 +1418,15 @@ gdm_session_worker_authenticate_user (GdmSessionWorker *worker,
+         /* blocking call, does the actual conversation */
+         error_code = pam_authenticate (worker->priv->pam_handle, authentication_flags);
  
-+gboolean
-+gdm_greeter_server_conversation_stopped (GdmGreeterServer *greeter_server,
-+                                         const char       *service_name)
-+{
-+        send_dbus_string_signal (greeter_server, "ConversationStopped", service_name);
-+        return TRUE;
-+}
+-        if (error_code != PAM_SUCCESS) {
++        if (error_code == PAM_AUTHINFO_UNAVAIL) {
++                g_debug ("GdmSessionWorker: authentication service unavailable");
 +
- void
- gdm_greeter_server_selected_user_changed (GdmGreeterServer *greeter_server,
-                                           const char       *username)
-@@ -797,6 +805,9 @@ do_introspect (DBusConnection *connection,
-                                "    <method name=\"StartConversation\">\n"
-                                "      <arg name=\"service_name\" direction=\"in\" type=\"s\"/>\n"
-                                "    </method>\n"
-+                               "    <method name=\"StopConversation\">\n"
-+                               "      <arg name=\"service_name\" direction=\"in\" type=\"s\"/>\n"
-+                               "    </method>\n"
-                                "    <method name=\"BeginVerification\">\n"
-                                "      <arg name=\"service_name\" direction=\"in\" type=\"s\"/>\n"
-                                "    </method>\n"
-@@ -868,6 +879,9 @@ do_introspect (DBusConnection *connection,
-                                "    <signal name=\"Ready\">\n"
-                                "      <arg name=\"service-name\" type=\"s\"/>\n"
-                                "    </signal>\n"
-+                               "    <signal name=\"ConversationStopped\">\n"
-+                               "      <arg name=\"service-name\" type=\"s\"/>\n"
-+                               "    </signal>\n"
-                                "    <signal name=\"Reset\">\n"
-                                "    </signal>\n"
-                                "    <signal name=\"UserAuthorized\">\n"
-diff --git a/daemon/gdm-greeter-server.h b/daemon/gdm-greeter-server.h
-index 6d0dd87..976f0b7 100644
---- a/daemon/gdm-greeter-server.h
-+++ b/daemon/gdm-greeter-server.h
-@@ -96,6 +96,8 @@ gboolean            gdm_greeter_server_problem               (GdmGreeterServer *
- gboolean            gdm_greeter_server_reset                 (GdmGreeterServer *greeter_server);
- gboolean            gdm_greeter_server_ready                 (GdmGreeterServer *greeter_server,
-                                                               const char       *service_name);
-+gboolean            gdm_greeter_server_conversation_stopped  (GdmGreeterServer *greeter_server,
-+                                                              const char       *service_name);
- void                gdm_greeter_server_selected_user_changed (GdmGreeterServer *greeter_server,
-                                                               const char       *text);
- void                gdm_greeter_server_default_language_name_changed (GdmGreeterServer *greeter_server,
++                g_set_error (error,
++                             GDM_SESSION_WORKER_ERROR,
++                             GDM_SESSION_WORKER_ERROR_SERVICE_UNAVAILABLE,
++                             "%s", pam_strerror (worker->priv->pam_handle, error_code));
++                goto out;
++        } else if (error_code != PAM_SUCCESS) {
+                 g_debug ("GdmSessionWorker: authentication returned %d: %s", error_code, pam_strerror (worker->priv->pam_handle, error_code));
+ 
+                 /*
+diff --git a/daemon/gdm-session-worker.h b/daemon/gdm-session-worker.h
+index ee5465a..b1c8285 100644
+--- a/daemon/gdm-session-worker.h
++++ b/daemon/gdm-session-worker.h
+@@ -41,6 +41,7 @@ typedef enum _GdmSessionWorkerError {
+         GDM_SESSION_WORKER_ERROR_OPENING_MESSAGE_PIPE,
+         GDM_SESSION_WORKER_ERROR_COMMUNICATING,
+         GDM_SESSION_WORKER_ERROR_WORKER_DIED,
++        GDM_SESSION_WORKER_ERROR_SERVICE_UNAVAILABLE,
+         GDM_SESSION_WORKER_ERROR_AUTHENTICATING,
+         GDM_SESSION_WORKER_ERROR_AUTHORIZING,
+         GDM_SESSION_WORKER_ERROR_OPENING_LOG_FILE,
+-- 
+1.7.2.1
+
+
+From c9f24aa63b98f8a1f0af578720802f406951414d Mon Sep 17 00:00:00 2001
+From: Ray Strode <rstrode at redhat.com>
+Date: Wed, 28 Oct 2009 21:32:00 -0400
+Subject: [PATCH 12/35] Emit "service-unavailable" from session when pam service refuses to work
+
+---
+ daemon/gdm-session-direct.c  |   26 +++++++++++++++++++++++---
+ daemon/gdm-session-private.h |    2 ++
+ daemon/gdm-session-relay.c   |   33 +++++++++++++++++++++++++++++++++
+ daemon/gdm-session-worker.c  |   29 ++++++++++++++++++++++-------
+ daemon/gdm-session.c         |   21 +++++++++++++++++++++
+ daemon/gdm-session.h         |    2 ++
+ 6 files changed, 103 insertions(+), 10 deletions(-)
+
 diff --git a/daemon/gdm-session-direct.c b/daemon/gdm-session-direct.c
-index 9d6a6b9..649dd91 100644
+index 13c8974..5a604bf 100644
 --- a/daemon/gdm-session-direct.c
 +++ b/daemon/gdm-session-direct.c
-@@ -1794,9 +1794,15 @@ worker_exited (GdmSessionWorkerJob *job,
- {
-         g_debug ("GdmSessionDirect: Worker job exited: %d", code);
- 
-+        g_object_ref (conversation->job);
-         if (conversation->session->priv->is_running) {
-                 _gdm_session_session_exited (GDM_SESSION (conversation->session), code);
-         }
-+
-+        g_debug ("GdmSessionDirect: Emitting conversation-stopped signal");
-+        _gdm_session_conversation_stopped (GDM_SESSION (conversation->session),
-+                                           conversation->service_name);
-+        g_object_unref (conversation->job);
+@@ -283,9 +283,27 @@ on_session_exited (GdmSession *session,
  }
  
- static void
-@@ -1806,9 +1812,15 @@ worker_died (GdmSessionWorkerJob *job,
- {
-         g_debug ("GdmSessionDirect: Worker job died: %d", signum);
- 
-+        g_object_ref (conversation->job);
-         if (conversation->session->priv->is_running) {
-                 _gdm_session_session_died (GDM_SESSION (conversation->session), signum);
-         }
-+
-+        g_debug ("GdmSessionDirect: Emitting conversation-stopped signal");
-+        _gdm_session_conversation_stopped (GDM_SESSION (conversation->session),
-+                                           conversation->service_name);
-+        g_object_unref (conversation->job);
- }
- 
- static GdmSessionConversation *
-@@ -1881,6 +1893,10 @@ stop_conversation (GdmSessionConversation *conversation)
- 
-         g_object_unref (conversation->job);
-         conversation->job = NULL;
-+
-+        g_debug ("GdmSessionDirect: Emitting conversation-stopped signal");
-+        _gdm_session_conversation_stopped (GDM_SESSION (session),
-+                                           conversation->service_name);
- }
- 
- static void
-@@ -1901,6 +1917,25 @@ gdm_session_direct_start_conversation (GdmSession *session,
- }
- 
- static void
-+gdm_session_direct_stop_conversation (GdmSession *session,
-+                                      const char *service_name)
+ static DBusHandlerResult
+-gdm_session_direct_handle_setup_complete (GdmSessionDirect *session,
+-                                          GdmSessionConversation *conversation,
+-                                          DBusMessage      *message)
++gdm_session_direct_handle_service_unavailable (GdmSessionDirect *session,
++                                               GdmSessionConversation *conversation,
++                                               DBusMessage      *message)
 +{
-+        GdmSessionDirect *impl = GDM_SESSION_DIRECT (session);
-+        GdmSessionConversation *conversation;
++        DBusMessage *reply;
 +
-+        g_return_if_fail (session != NULL);
++        g_debug ("GdmSessionDirect: Emitting 'service-unavailable' signal");
 +
-+        g_debug ("GdmSessionDirect: stopping conversation");
++        reply = dbus_message_new_method_return (message);
++        dbus_connection_send (conversation->worker_connection, reply, NULL);
++        dbus_message_unref (reply);
 +
-+        conversation = find_conversation_by_name (impl, service_name);
++        _gdm_session_service_unavailable (GDM_SESSION (session), conversation->service_name);
 +
-+        if (conversation != NULL) {
-+                stop_conversation (conversation);
-+                g_hash_table_remove (impl->priv->conversations, service_name);
-+        }
++        return DBUS_HANDLER_RESULT_HANDLED;
 +}
 +
-+static void
- send_setup (GdmSessionDirect *session,
-             const char       *service_name)
- {
-@@ -2794,6 +2829,7 @@ static void
- gdm_session_iface_init (GdmSessionIface *iface)
++static DBusHandlerResult
++gdm_session_direct_handle_setup_complete  (GdmSessionDirect *session,
++                                           GdmSessionConversation *conversation,
++                                           DBusMessage      *message)
  {
-         iface->start_conversation = gdm_session_direct_start_conversation;
-+        iface->stop_conversation = gdm_session_direct_stop_conversation;
-         iface->setup = gdm_session_direct_setup;
-         iface->setup_for_user = gdm_session_direct_setup_for_user;
-         iface->authenticate = gdm_session_direct_authenticate;
+         DBusMessage *reply;
+ 
+@@ -1320,6 +1338,8 @@ session_worker_message (DBusConnection *connection,
+                 return gdm_session_direct_handle_problem (session, conversation, message);
+         } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "CancelPendingQuery")) {
+                 return gdm_session_direct_handle_cancel_pending_query (session, conversation, message);
++        } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "ServiceUnavailable")) {
++                return gdm_session_direct_handle_service_unavailable (session, conversation, message);
+         } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SetupComplete")) {
+                 return gdm_session_direct_handle_setup_complete (session, conversation, message);
+         } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SetupFailed")) {
 diff --git a/daemon/gdm-session-private.h b/daemon/gdm-session-private.h
-index 4dc6e44..36781dd 100644
+index 36781dd..e0a810e 100644
 --- a/daemon/gdm-session-private.h
 +++ b/daemon/gdm-session-private.h
-@@ -29,6 +29,8 @@ G_BEGIN_DECLS
- /* state changes */
- void             _gdm_session_conversation_started         (GdmSession   *session,
+@@ -31,6 +31,8 @@ void             _gdm_session_conversation_started         (GdmSession   *sessio
                                                              const char   *service_name);
-+void             _gdm_session_conversation_stopped         (GdmSession   *session,
+ void             _gdm_session_conversation_stopped         (GdmSession   *session,
+                                                             const char   *service_name);
++void             _gdm_session_service_unavailable          (GdmSession   *session,
 +                                                            const char   *service_name);
  void             _gdm_session_setup_complete               (GdmSession   *session,
                                                              const char   *service_name);
  void             _gdm_session_setup_failed                 (GdmSession   *session,
-diff --git a/daemon/gdm-session.c b/daemon/gdm-session.c
-index a7b4e8b..8858071 100644
---- a/daemon/gdm-session.c
-+++ b/daemon/gdm-session.c
-@@ -30,6 +30,7 @@
+diff --git a/daemon/gdm-session-relay.c b/daemon/gdm-session-relay.c
+index 98ccc51..88aee14 100644
+--- a/daemon/gdm-session-relay.c
++++ b/daemon/gdm-session-relay.c
+@@ -463,6 +463,34 @@ handle_problem (GdmSessionRelay *session_relay,
+ }
  
- enum {
-         CONVERSATION_STARTED = 0,
-+        CONVERSATION_STOPPED,
-         SETUP_COMPLETE,
-         SETUP_FAILED,
-         RESET_COMPLETE,
-@@ -90,6 +91,15 @@ gdm_session_start_conversation (GdmSession *session,
- }
- 
- void
-+gdm_session_stop_conversation (GdmSession *session,
-+                              const char *service_name)
+ static DBusHandlerResult
++handle_service_unavailable (GdmSessionRelay *session_relay,
++                            DBusConnection  *connection,
++                            DBusMessage     *message)
 +{
-+        g_return_if_fail (GDM_IS_SESSION (session));
++        DBusMessage *reply;
++        DBusError    error;
++        char        *service_name;
 +
-+        GDM_SESSION_GET_IFACE (session)->stop_conversation (session, service_name);
++        dbus_error_init (&error);
++        if (! dbus_message_get_args (message, &error,
++                                     DBUS_TYPE_STRING, &service_name,
++                                     DBUS_TYPE_INVALID)) {
++                g_warning ("ERROR: %s", error.message);
++        }
++        dbus_error_free (&error);
++
++        g_debug ("GdmSessionRelay: ServiceUnavailable");
++
++        reply = dbus_message_new_method_return (message);
++        dbus_connection_send (connection, reply, NULL);
++        dbus_message_unref (reply);
++
++        _gdm_session_service_unavailable (GDM_SESSION (session_relay), service_name);
++
++        return DBUS_HANDLER_RESULT_HANDLED;
 +}
 +
-+void
- gdm_session_close (GdmSession *session)
- {
-         g_return_if_fail (GDM_IS_SESSION (session));
-@@ -231,6 +241,16 @@ gdm_session_class_init (gpointer g_iface)
++static DBusHandlerResult
+ handle_setup_complete (GdmSessionRelay *session_relay,
+                        DBusConnection  *connection,
+                        DBusMessage     *message)
+@@ -841,6 +869,8 @@ session_handle_child_message (DBusConnection *connection,
+                 return handle_info (session_relay, connection, message);
+         } else if (dbus_message_is_method_call (message, GDM_SESSION_RELAY_DBUS_INTERFACE, "Problem")) {
+                 return handle_problem (session_relay, connection, message);
++        } else if (dbus_message_is_method_call (message, GDM_SESSION_RELAY_DBUS_INTERFACE, "ServiceUnavailable")) {
++                return handle_service_unavailable (session_relay, connection, message);
+         } else if (dbus_message_is_method_call (message, GDM_SESSION_RELAY_DBUS_INTERFACE, "SetupComplete")) {
+                 return handle_setup_complete (session_relay, connection, message);
+         } else if (dbus_message_is_method_call (message, GDM_SESSION_RELAY_DBUS_INTERFACE, "SetupFailed")) {
+@@ -898,6 +928,9 @@ do_introspect (DBusConnection *connection,
+                                "    <method name=\"ConversationStarted\">\n"
+                                "      <arg name=\"service_name\" direction=\"in\" type=\"s\"/>\n"
+                                "    </method>\n"
++                               "    <method name=\"ServiceUnavailable\">\n"
++                               "      <arg name=\"message\" direction=\"in\" type=\"s\"/>\n"
++                               "    </method>\n"
+                                "    <method name=\"SetupComplete\">\n"
+                                "    </method>\n"
+                                "    <method name=\"SetupFailed\">\n"
+diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c
+index ed6cacf..8e1fa80 100644
+--- a/daemon/gdm-session-worker.c
++++ b/daemon/gdm-session-worker.c
+@@ -2382,9 +2382,16 @@ do_setup (GdmSessionWorker *worker)
+                                                  worker->priv->display_device,
+                                                  &error);
+         if (! res) {
+-                send_dbus_string_method (worker->priv->connection,
+-                                         "SetupFailed",
+-                                         error->message);
++                if (g_error_matches (error,
++                                     GDM_SESSION_WORKER_ERROR,
++                                     GDM_SESSION_WORKER_ERROR_SERVICE_UNAVAILABLE)) {
++                        send_dbus_void_method (worker->priv->connection,
++                                               "ServiceUnavailable");
++                } else {
++                        send_dbus_string_method (worker->priv->connection,
++                                                 "SetupFailed",
++                                                 error->message);
++                }
+                 g_error_free (error);
+                 return;
+         }
+@@ -2405,10 +2412,18 @@ do_authenticate (GdmSessionWorker *worker)
+                                                     worker->priv->password_is_required,
+                                                     &error);
+         if (! res) {
+-                g_debug ("GdmSessionWorker: Unable to verify user");
+-                send_dbus_string_method (worker->priv->connection,
+-                                         "AuthenticationFailed",
+-                                         error->message);
++                if (g_error_matches (error,
++                                     GDM_SESSION_WORKER_ERROR,
++                                     GDM_SESSION_WORKER_ERROR_SERVICE_UNAVAILABLE)) {
++                        g_debug ("GdmSessionWorker: Unable to use authentication service");
++                        send_dbus_void_method (worker->priv->connection,
++                                               "ServiceUnavailable");
++                } else {
++                        g_debug ("GdmSessionWorker: Unable to verify user");
++                        send_dbus_string_method (worker->priv->connection,
++                                                 "AuthenticationFailed",
++                                                 error->message);
++                }
+                 g_error_free (error);
+                 return;
+         }
+diff --git a/daemon/gdm-session.c b/daemon/gdm-session.c
+index 8858071..8c4548a 100644
+--- a/daemon/gdm-session.c
++++ b/daemon/gdm-session.c
+@@ -31,6 +31,7 @@
+ enum {
+         CONVERSATION_STARTED = 0,
+         CONVERSATION_STOPPED,
++        SERVICE_UNAVAILABLE,
+         SETUP_COMPLETE,
+         SETUP_FAILED,
+         RESET_COMPLETE,
+@@ -251,6 +252,17 @@ gdm_session_class_init (gpointer g_iface)
                                g_cclosure_marshal_VOID__STRING,
                                G_TYPE_NONE,
                                1, G_TYPE_STRING);
-+        signals [CONVERSATION_STOPPED] =
-+                g_signal_new ("conversation-stopped",
++        signals [SERVICE_UNAVAILABLE] =
++                g_signal_new ("service-unavailable",
 +                              iface_type,
 +                              G_SIGNAL_RUN_FIRST,
-+                              G_STRUCT_OFFSET (GdmSessionIface, conversation_stopped),
++                              G_STRUCT_OFFSET (GdmSessionIface, service_unavailable),
 +                              NULL,
 +                              NULL,
 +                              g_cclosure_marshal_VOID__STRING,
 +                              G_TYPE_NONE,
-+                              1, G_TYPE_STRING);
++                              1,
++                              G_TYPE_STRING);
          signals [SETUP_COMPLETE] =
                  g_signal_new ("setup-complete",
                                iface_type,
-@@ -688,6 +708,14 @@ _gdm_session_conversation_started (GdmSession   *session,
+@@ -525,6 +537,15 @@ gdm_session_class_init (gpointer g_iface)
  }
  
  void
-+_gdm_session_conversation_stopped (GdmSession   *session,
-+                                   const char   *service_name)
++_gdm_session_service_unavailable (GdmSession   *session,
++                                  const char   *service_name)
 +{
 +        g_return_if_fail (GDM_IS_SESSION (session));
-+        g_signal_emit (session, signals [CONVERSATION_STOPPED], 0, service_name);
++
++        g_signal_emit (session, signals [SERVICE_UNAVAILABLE], 0, service_name);
 +}
 +
 +void
- _gdm_session_closed (GdmSession   *session)
+ _gdm_session_setup_complete (GdmSession   *session,
+                              const char   *service_name)
  {
-         g_return_if_fail (GDM_IS_SESSION (session));
 diff --git a/daemon/gdm-session.h b/daemon/gdm-session.h
-index 20a442b..22c2ccb 100644
+index 22c2ccb..9636b92 100644
 --- a/daemon/gdm-session.h
 +++ b/daemon/gdm-session.h
-@@ -47,6 +47,8 @@ struct _GdmSessionIface
-         /* Methods */
-         void (* start_conversation)          (GdmSession   *session,
+@@ -49,6 +49,8 @@ struct _GdmSessionIface
                                                const char   *service_name);
-+        void (* stop_conversation)           (GdmSession   *session,
+         void (* stop_conversation)           (GdmSession   *session,
+                                               const char   *service_name);
++        void (* service_unavailable)         (GdmSession   *session,
 +                                              const char   *service_name);
          void (* setup)                       (GdmSession   *session,
                                                const char   *service_name);
          void (* setup_for_user)              (GdmSession   *session,
-@@ -132,6 +134,8 @@ struct _GdmSessionIface
-                                               int           signal_number);
-         void (* conversation_started)        (GdmSession   *session,
-                                               const char   *service_name);
-+        void (* conversation_stopped)        (GdmSession   *session,
-+                                              const char   *service_name);
-         void (* closed)                      (GdmSession   *session);
-         void (* selected_user_changed)       (GdmSession   *session,
-                                               const char   *text);
-@@ -148,6 +152,8 @@ GType    gdm_session_get_type                    (void) G_GNUC_CONST;
+-- 
+1.7.2.1
+
+
+From d498108160a5afe7e886016fd0e892f8d06e0fd4 Mon Sep 17 00:00:00 2001
+From: Ray Strode <rstrode at redhat.com>
+Date: Wed, 28 Oct 2009 21:38:52 -0400
+Subject: [PATCH 13/35] Bubble service-unavailable up to greeter
+
+---
+ daemon/gdm-greeter-server.c |   13 +++++++++++--
+ daemon/gdm-greeter-server.h |    5 ++++-
+ daemon/gdm-simple-slave.c   |   36 ++++++++++++++----------------------
+ 3 files changed, 29 insertions(+), 25 deletions(-)
+
+diff --git a/daemon/gdm-greeter-server.c b/daemon/gdm-greeter-server.c
+index 50e4193..4a011da 100644
+--- a/daemon/gdm-greeter-server.c
++++ b/daemon/gdm-greeter-server.c
+@@ -286,9 +286,18 @@ gdm_greeter_server_problem (GdmGreeterServer *greeter_server,
+ }
  
- void     gdm_session_start_conversation          (GdmSession *session,
-                                                   const char *service_name);
-+void     gdm_session_stop_conversation           (GdmSession *session,
-+                                                  const char *service_name);
- void     gdm_session_setup                       (GdmSession *session,
-                                                   const char *service_name);
- void     gdm_session_setup_for_user              (GdmSession *session,
+ gboolean
+-gdm_greeter_server_authentication_failed (GdmGreeterServer *greeter_server)
++gdm_greeter_server_authentication_failed (GdmGreeterServer *greeter_server,
++                                          const char       *service_name)
+ {
+-        send_dbus_void_signal (greeter_server, "AuthenticationFailed");
++        send_dbus_string_signal (greeter_server, "AuthenticationFailed", service_name);
++        return TRUE;
++}
++
++gboolean
++gdm_greeter_server_service_unavailable (GdmGreeterServer *greeter_server,
++                                        const char       *service_name)
++{
++        send_dbus_string_signal (greeter_server, "ServiceUnavailable", service_name);
+         return TRUE;
+ }
+ 
+diff --git a/daemon/gdm-greeter-server.h b/daemon/gdm-greeter-server.h
+index 5af32fd..ff1ff5d 100644
+--- a/daemon/gdm-greeter-server.h
++++ b/daemon/gdm-greeter-server.h
+@@ -93,7 +93,10 @@ gboolean            gdm_greeter_server_info                  (GdmGreeterServer *
+ gboolean            gdm_greeter_server_problem               (GdmGreeterServer *greeter_server,
+                                                               const char       *service_name,
+                                                               const char       *text);
+-gboolean            gdm_greeter_server_authentication_failed (GdmGreeterServer *greeter_server);
++gboolean            gdm_greeter_server_authentication_failed (GdmGreeterServer *greeter_server,
++                                                              const char       *service_name);
++gboolean            gdm_greeter_server_service_unavailable   (GdmGreeterServer *greeter_server,
++                                                              const char       *service_name);
+ gboolean            gdm_greeter_server_reset                 (GdmGreeterServer *greeter_server);
+ gboolean            gdm_greeter_server_ready                 (GdmGreeterServer *greeter_server,
+                                                               const char       *service_name);
 diff --git a/daemon/gdm-simple-slave.c b/daemon/gdm-simple-slave.c
-index fed2e8b..20fe4ab 100644
+index adcb94a..8e15584 100644
 --- a/daemon/gdm-simple-slave.c
 +++ b/daemon/gdm-simple-slave.c
-@@ -230,8 +230,7 @@ on_session_setup_failed (GdmSession     *session,
-                                             message != NULL ? message:  _("Unable to initialize login system"));
-         }
- 
--        destroy_session (slave);
--        queue_greeter_reset (slave);
-+        gdm_session_stop_conversation (session, service_name);
+@@ -197,22 +197,6 @@ greeter_reset_timeout (GdmSimpleSlave *slave)
+         return FALSE;
  }
  
+-static gboolean
+-auth_failed_reset_timeout (GdmSimpleSlave *slave)
+-{
+-        g_debug ("GdmSimpleSlave: auth failed resetting slave");
+-
+-        if (slave->priv->greeter_server != NULL) {
+-                gdm_greeter_server_authentication_failed (slave->priv->greeter_server);
+-                reset_session (slave);
+-        } else {
+-                start_greeter (slave);
+-                create_new_session (slave);
+-        }
+-        slave->priv->greeter_reset_id = 0;
+-        return FALSE;
+-}
+-
  static void
-@@ -268,8 +267,8 @@ on_session_authentication_failed (GdmSession     *session,
-                                             service_name,
-                                             message != NULL ? message : _("Unable to authenticate user"));
-         }
--        destroy_session (slave);
--        queue_greeter_reset (slave);
-+
-+        gdm_session_stop_conversation (session, service_name);
+ queue_greeter_reset (GdmSimpleSlave *slave)
+ {
+@@ -224,14 +208,16 @@ queue_greeter_reset (GdmSimpleSlave *slave)
  }
  
  static void
-@@ -327,8 +326,7 @@ on_session_authorization_failed (GdmSession     *session,
-                                             message != NULL ? message :  _("Unable to authorize user"));
+-queue_auth_failed_reset (GdmSimpleSlave *slave)
++on_session_service_unavailable (GdmSession     *session,
++                                const char     *service_name,
++                                GdmSimpleSlave *slave)
+ {
+-        /* use the greeter reset idle id so we don't do both at once */
+-        if (slave->priv->greeter_reset_id > 0) {
+-                return;
++        if (slave->priv->greeter_server != NULL) {
++                gdm_greeter_server_service_unavailable (slave->priv->greeter_server,
++                                                        service_name);
          }
  
--        destroy_session (slave);
--        queue_greeter_reset (slave);
-+        gdm_session_stop_conversation (session, service_name);
- }
- 
- static gboolean
-@@ -471,9 +469,8 @@ on_session_accreditation_failed (GdmSession     *session,
-            when Xorg exits it switches to the VT it was
-            started from.  That interferes with fast
-            user switching. */
--        destroy_session (slave);
- 
--        queue_greeter_reset (slave);
+-        slave->priv->greeter_reset_id = g_idle_add ((GSourceFunc)auth_failed_reset_timeout, slave);
 +        gdm_session_stop_conversation (session, service_name);
  }
  
  static void
-@@ -582,6 +579,23 @@ on_session_conversation_started (GdmSession     *session,
+@@ -294,7 +280,6 @@ on_session_authentication_failed (GdmSession     *session,
+ 
+         g_debug ("GdmSimpleSlave: Authentication failed - may retry");
+         gdm_session_stop_conversation (session, service_name);
+-        queue_auth_failed_reset (slave);
  }
  
  static void
-+on_session_conversation_stopped (GdmSession     *session,
-+                                 const char     *service_name,
-+                                 GdmSimpleSlave *slave)
-+{
-+        gboolean res;
-+        g_debug ("GdmSimpleSlave: conversation stopped");
-+
-+        if (slave->priv->greeter_server != NULL) {
-+                res = gdm_greeter_server_conversation_stopped (slave->priv->greeter_server,
-+                                                               service_name);
-+                if (! res) {
-+                        g_warning ("Unable to send conversation stopped");
-+                }
-+        }
-+}
-+
-+static void
- on_session_selected_user_changed (GdmSession     *session,
-                                   const char     *text,
-                                   GdmSimpleSlave *slave)
-@@ -670,6 +684,10 @@ create_new_session (GdmSimpleSlave *slave)
-                           G_CALLBACK (on_session_conversation_started),
+@@ -730,6 +715,10 @@ create_new_session (GdmSimpleSlave *slave)
+                           G_CALLBACK (on_session_conversation_stopped),
                            slave);
          g_signal_connect (slave->priv->session,
-+                          "conversation-stopped",
-+                          G_CALLBACK (on_session_conversation_stopped),
++                          "service-unavailable",
++                          G_CALLBACK (on_session_service_unavailable),
 +                          slave);
 +        g_signal_connect (slave->priv->session,
                            "setup-complete",
                            G_CALLBACK (on_session_setup_complete),
                            slave);
+@@ -844,6 +833,9 @@ destroy_session (GdmSimpleSlave *slave)
+                                               G_CALLBACK (on_session_conversation_stopped),
+                                               slave);
+         g_signal_handlers_disconnect_by_func (slave->priv->session,
++                                              G_CALLBACK (on_session_service_unavailable),
++                                              slave);
++        g_signal_handlers_disconnect_by_func (slave->priv->session,
+                                               G_CALLBACK (on_session_setup_complete),
+                                               slave);
+         g_signal_handlers_disconnect_by_func (slave->priv->session,
 -- 
-1.6.5.2
+1.7.2.1
 
 
-From 18811f7154bb5d75feb2bbd90de9f12e34c7dd35 Mon Sep 17 00:00:00 2001
+From f2155acde772064f387e49932bd900962bb22f05 Mon Sep 17 00:00:00 2001
 From: Ray Strode <rstrode at redhat.com>
-Date: Fri, 30 Jan 2009 23:57:31 -0500
-Subject: [PATCH 08/45] Add limited support for multiple pam stacks
+Date: Wed, 28 Oct 2009 21:46:39 -0400
+Subject: [PATCH 14/35] Catch service-unavailable from server in client and propagate it
 
-This hard codes 3 pam stacks and doesn't handle
-switching between them very well yet.
 ---
- gui/simple-greeter/Makefile.am                |    4 +
- gui/simple-greeter/gdm-greeter-login-window.c |   95 +++++++++++--
- gui/simple-greeter/gdm-greeter-login-window.h |   11 ++-
- gui/simple-greeter/gdm-greeter-session.c      |   30 +++-
- gui/simple-greeter/gdm-task-list.c            |  198 +++++++++++++++++++++++++
- gui/simple-greeter/gdm-task-list.h            |   64 ++++++++
- 6 files changed, 382 insertions(+), 20 deletions(-)
- create mode 100644 gui/simple-greeter/gdm-task-list.c
- create mode 100644 gui/simple-greeter/gdm-task-list.h
+ gui/simple-greeter/gdm-greeter-client.c |   20 ++++++++++++++++++++
+ gui/simple-greeter/gdm-greeter-client.h |    2 ++
+ 2 files changed, 22 insertions(+), 0 deletions(-)
 
-diff --git a/gui/simple-greeter/Makefile.am b/gui/simple-greeter/Makefile.am
-index 4628918..f62702b 100644
---- a/gui/simple-greeter/Makefile.am
-+++ b/gui/simple-greeter/Makefile.am
-@@ -85,6 +85,8 @@ test_greeter_login_window_SOURCES = 	\
- 	gdm-user-chooser-widget.c	\
- 	gdm-user-chooser-dialog.h	\
- 	gdm-user-chooser-dialog.c	\
-+	gdm-task-list.h			\
-+	gdm-task-list.c			\
- 	$(NULL)
- 
- test_greeter_login_window_LDADD =	\
-@@ -320,6 +322,8 @@ gdm_simple_greeter_SOURCES =  		\
- 	gdm-session-option-widget.c	\
- 	gdm-user-chooser-widget.h	\
- 	gdm-user-chooser-widget.c	\
-+	gdm-task-list.h			\
-+	gdm-task-list.c			\
- 	$(NULL)
- 
- gdm_simple_greeter_LDADD = 		\
-diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
-index 891f2c7..949494b 100644
---- a/gui/simple-greeter/gdm-greeter-login-window.c
-+++ b/gui/simple-greeter/gdm-greeter-login-window.c
-@@ -50,12 +50,16 @@
- #include <dbus/dbus-glib.h>
- #include <dbus/dbus-glib-lowlevel.h>
+diff --git a/gui/simple-greeter/gdm-greeter-client.c b/gui/simple-greeter/gdm-greeter-client.c
+index e42ab1e..ad3ec7e 100644
+--- a/gui/simple-greeter/gdm-greeter-client.c
++++ b/gui/simple-greeter/gdm-greeter-client.c
+@@ -63,6 +63,7 @@ enum {
+         PROBLEM,
+         INFO_QUERY,
+         SECRET_INFO_QUERY,
++        SERVICE_UNAVAILABLE,
+         READY,
+         RESET,
+         AUTHENTICATION_FAILED,
+@@ -264,6 +265,13 @@ on_problem (GdmGreeterClient *client,
+ }
  
-+#include "gdm-marshal.h"
+ static void
++on_service_unavailable (GdmGreeterClient *client,
++                        DBusMessage      *message)
++{
++        emit_string_signal_for_message (client, "ServiceUnavailable", message, SERVICE_UNAVAILABLE);
++}
 +
- #include "gdm-settings-client.h"
- #include "gdm-settings-keys.h"
- #include "gdm-profile.h"
- 
-+#include "gdm-greeter-client.h"
- #include "gdm-greeter-login-window.h"
- #include "gdm-user-chooser-widget.h"
-+#include "gdm-task-list.h"
- 
- #ifdef HAVE_PAM
- #include <security/pam_appl.h>
-@@ -100,6 +104,7 @@ struct GdmGreeterLoginWindowPrivate
++static void
+ on_ready (GdmGreeterClient *client,
+           DBusMessage      *message)
  {
-         GtkBuilder      *builder;
-         GtkWidget       *user_chooser;
-+        GtkWidget       *conversation_list;
-         GtkWidget       *auth_banner_label;
-         guint            display_is_local : 1;
-         guint            is_interactive : 1;
-@@ -131,6 +136,7 @@ enum {
- };
- 
- enum {
-+        START_CONVERSATION,
-         BEGIN_AUTO_LOGIN,
-         BEGIN_VERIFICATION,
-         BEGIN_VERIFICATION_FOR_USER,
-@@ -360,7 +366,7 @@ on_login_button_clicked_answer_query (GtkButton             *button,
-         text = gtk_entry_get_text (GTK_ENTRY (entry));
+@@ -770,6 +778,8 @@ client_dbus_handle_message (DBusConnection *connection,
+                 on_info (client, message);
+         } else if (dbus_message_is_signal (message, GREETER_SERVER_DBUS_INTERFACE, "Problem")) {
+                 on_problem (client, message);
++        } else if (dbus_message_is_signal (message, GREETER_SERVER_DBUS_INTERFACE, "ServiceUnavailable")) {
++                on_service_unavailable (client, message);
+         } else if (dbus_message_is_signal (message, GREETER_SERVER_DBUS_INTERFACE, "Ready")) {
+                 on_ready (client, message);
+         } else if (dbus_message_is_signal (message, GREETER_SERVER_DBUS_INTERFACE, "Reset")) {
+@@ -1003,6 +1013,16 @@ gdm_greeter_client_class_init (GdmGreeterClientClass *klass)
+                               2,
+                               G_TYPE_STRING, G_TYPE_STRING);
  
-         _gdm_greeter_login_window_set_interactive (login_window, TRUE);
--        g_signal_emit (login_window, signals[QUERY_ANSWER], 0, text);
-+        g_signal_emit (login_window, signals[QUERY_ANSWER], 0, "gdm", text);
++        gdm_greeter_client_signals[SERVICE_UNAVAILABLE] =
++                g_signal_new ("service-unavailable",
++                              G_OBJECT_CLASS_TYPE (object_class),
++                              G_SIGNAL_RUN_FIRST,
++                              G_STRUCT_OFFSET (GdmGreeterClientClass, service_unavailable),
++                              NULL,
++                              NULL,
++                              g_cclosure_marshal_VOID__STRING,
++                              G_TYPE_NONE, 1, G_TYPE_STRING);
++
+         gdm_greeter_client_signals[READY] =
+                 g_signal_new ("ready",
+                               G_OBJECT_CLASS_TYPE (object_class),
+diff --git a/gui/simple-greeter/gdm-greeter-client.h b/gui/simple-greeter/gdm-greeter-client.h
+index 2f27503..917ca9c 100644
+--- a/gui/simple-greeter/gdm-greeter-client.h
++++ b/gui/simple-greeter/gdm-greeter-client.h
+@@ -59,6 +59,8 @@ typedef struct
+         void (* problem)                 (GdmGreeterClient  *client,
+                                           const char        *service_name,
+                                           const char        *problem);
++        void (* service_unavailable)     (GdmGreeterClient  *client,
++                                          const char        *service_name);
+         void (* ready)                   (GdmGreeterClient  *client,
+                                           const char        *service_name);
+         void (* reset)                   (GdmGreeterClient  *client);
+-- 
+1.7.2.1
+
+
+From da4dae9c2483b74e7e949984f5c2fabd4ae683da Mon Sep 17 00:00:00 2001
+From: Ray Strode <rstrode at redhat.com>
+Date: Thu, 5 Feb 2009 15:20:25 -0500
+Subject: [PATCH 15/35] Queue a greeter reset when the user clicks cancel
+
+---
+ daemon/gdm-simple-slave.c |   34 ++++++++++++++++++++++++++++++++++
+ 1 files changed, 34 insertions(+), 0 deletions(-)
+
+diff --git a/daemon/gdm-simple-slave.c b/daemon/gdm-simple-slave.c
+index 8e15584..43eac10 100644
+--- a/daemon/gdm-simple-slave.c
++++ b/daemon/gdm-simple-slave.c
+@@ -959,6 +959,9 @@ on_greeter_start_conversation (GdmGreeterServer *greeter_server,
+                                GdmSimpleSlave   *slave)
+ {
+         g_debug ("GdmSimpleSlave: starting conversation with '%s' pam service'", service_name);
++        if (slave->priv->greeter_reset_id > 0) {
++                return;
++        }
+         gdm_session_start_conversation (GDM_SESSION (slave->priv->session),
+                                         service_name);
  }
- 
- static void
-@@ -625,26 +631,32 @@ gdm_greeter_login_window_reset (GdmGreeterLoginWindow *login_window)
- 
- gboolean
- gdm_greeter_login_window_info (GdmGreeterLoginWindow *login_window,
-+                               const char            *service_name,
-                                const char            *text)
+@@ -969,6 +972,9 @@ on_greeter_begin_verification (GdmGreeterServer *greeter_server,
+                                GdmSimpleSlave   *slave)
  {
-         g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
- 
-         g_debug ("GdmGreeterLoginWindow: info: %s", text);
- 
--        set_message (GDM_GREETER_LOGIN_WINDOW (login_window), text);
-+        if (strcmp (service_name, gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list))) == 0) {
-+                set_message (GDM_GREETER_LOGIN_WINDOW (login_window), text);
+         g_debug ("GdmSimpleSlave: begin verification");
++        if (slave->priv->greeter_reset_id > 0) {
++                return;
 +        }
- 
-         return TRUE;
+         gdm_session_setup (GDM_SESSION (slave->priv->session),
+                            service_name);
  }
- 
- gboolean
- gdm_greeter_login_window_problem (GdmGreeterLoginWindow *login_window,
-+                                  const char            *service_name,
-                                   const char            *text)
+@@ -979,6 +985,9 @@ on_greeter_begin_auto_login (GdmGreeterServer *greeter_server,
+                              GdmSimpleSlave   *slave)
  {
-         g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
+         g_debug ("GdmSimpleSlave: begin auto login for user '%s'", username);
++        if (slave->priv->greeter_reset_id > 0) {
++                return;
++        }
+         gdm_session_setup_for_user (GDM_SESSION (slave->priv->session),
+                                     "gdm-autologin",
+                                     username);
+@@ -991,6 +1000,9 @@ on_greeter_begin_verification_for_user (GdmGreeterServer *greeter_server,
+                                         GdmSimpleSlave   *slave)
+ {
+         g_debug ("GdmSimpleSlave: begin verification");
++        if (slave->priv->greeter_reset_id > 0) {
++                return;
++        }
+         gdm_session_setup_for_user (GDM_SESSION (slave->priv->session),
+                                     service_name,
+                                     username);
+@@ -1002,6 +1014,9 @@ on_greeter_answer (GdmGreeterServer *greeter_server,
+                    const char       *text,
+                    GdmSimpleSlave   *slave)
+ {
++        if (slave->priv->greeter_reset_id > 0) {
++                return;
++        }
+         gdm_session_answer_query (GDM_SESSION (slave->priv->session), service_name, text);
+ }
  
-         g_debug ("GdmGreeterLoginWindow: problem: %s", text);
+@@ -1010,6 +1025,9 @@ on_greeter_session_selected (GdmGreeterServer *greeter_server,
+                              const char       *text,
+                              GdmSimpleSlave   *slave)
+ {
++        if (slave->priv->greeter_reset_id > 0) {
++                return;
++        }
+         gdm_session_select_session (GDM_SESSION (slave->priv->session), text);
+ }
  
--        set_message (GDM_GREETER_LOGIN_WINDOW (login_window), text);
-+        if (strcmp (service_name, gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list))) == 0) {
-+                set_message (GDM_GREETER_LOGIN_WINDOW (login_window), text);
+@@ -1018,6 +1036,9 @@ on_greeter_language_selected (GdmGreeterServer *greeter_server,
+                               const char       *text,
+                               GdmSimpleSlave   *slave)
+ {
++        if (slave->priv->greeter_reset_id > 0) {
++                return;
 +        }
-         gdk_window_beep (GTK_WIDGET (login_window)->window);
+         gdm_session_select_language (GDM_SESSION (slave->priv->session), text);
+ }
  
-         return TRUE;
-@@ -756,6 +768,7 @@ _show_cancel_button (GdmGreeterLoginWindow *login_window)
+@@ -1026,6 +1047,9 @@ on_greeter_layout_selected (GdmGreeterServer *greeter_server,
+                             const char       *text,
+                             GdmSimpleSlave   *slave)
+ {
++        if (slave->priv->greeter_reset_id > 0) {
++                return;
++        }
+         gdm_session_select_layout (GDM_SESSION (slave->priv->session), text);
+ }
  
- gboolean
- gdm_greeter_login_window_info_query (GdmGreeterLoginWindow *login_window,
-+                                     const char            *service_name,
-                                      const char            *text)
+@@ -1042,6 +1066,7 @@ on_greeter_cancel (GdmGreeterServer *greeter_server,
+                    GdmSimpleSlave   *slave)
  {
-         GtkWidget  *entry;
-@@ -765,6 +778,10 @@ gdm_greeter_login_window_info_query (GdmGreeterLoginWindow *login_window,
+         g_debug ("GdmSimpleSlave: Greeter cancelled");
++
+         queue_greeter_reset (slave);
+ }
  
-         _show_cancel_button (login_window);
+@@ -1052,6 +1077,9 @@ on_greeter_connected (GdmGreeterServer *greeter_server,
+         gboolean display_is_local;
  
-+        if (strcmp (service_name, gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list))) != 0) {
-+                return TRUE;
+         g_debug ("GdmSimpleSlave: Greeter connected");
++        if (slave->priv->greeter_reset_id > 0) {
++                return;
 +        }
-+
-         g_debug ("GdmGreeterLoginWindow: info query: %s", text);
- 
-         entry = GTK_WIDGET (gtk_builder_get_object (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->builder, "auth-prompt-entry"));
-@@ -787,6 +804,7 @@ gdm_greeter_login_window_info_query (GdmGreeterLoginWindow *login_window,
  
- gboolean
- gdm_greeter_login_window_secret_info_query (GdmGreeterLoginWindow *login_window,
-+                                            const char            *service_name,
-                                             const char            *text)
+         g_object_get (slave,
+                       "display-is-local", &display_is_local,
+@@ -1069,6 +1097,9 @@ on_start_session_when_ready (GdmGreeterServer *session,
+                              GdmSimpleSlave   *slave)
  {
-         GtkWidget  *entry;
-@@ -796,6 +814,10 @@ gdm_greeter_login_window_secret_info_query (GdmGreeterLoginWindow *login_window,
- 
-         _show_cancel_button (login_window);
- 
-+        if (strcmp (service_name, gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list))) != 0) {
-+                return TRUE;
+         g_debug ("GdmSimpleSlave: Will start session when ready");
++        if (slave->priv->greeter_reset_id > 0) {
++                return;
 +        }
-+
-         entry = GTK_WIDGET (gtk_builder_get_object (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->builder, "auth-prompt-entry"));
-         delete_entry_text (entry);
-         gtk_entry_set_visibility (GTK_ENTRY (entry), FALSE);
-@@ -921,7 +943,10 @@ on_user_chosen (GdmUserChooserWidget  *user_chooser,
-                        0, user_name);
+         slave->priv->start_session_when_ready = TRUE;
  
-         if (strcmp (user_name, GDM_USER_CHOOSER_USER_OTHER) == 0) {
--                g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0);
-+                const char *service_name;
-+
-+                service_name = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
-+                g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0, service_name);
-         } else if (strcmp (user_name, GDM_USER_CHOOSER_USER_GUEST) == 0) {
-                 /* FIXME: handle guest account stuff */
-         } else if (strcmp (user_name, GDM_USER_CHOOSER_USER_AUTO) == 0) {
-@@ -935,7 +960,10 @@ on_user_chosen (GdmUserChooserWidget  *user_chooser,
-                 set_log_in_button_mode (login_window, LOGIN_BUTTON_TIMED_LOGIN);
-                 set_message (login_window, _("Select language and click Log In"));
-         } else {
--                g_signal_emit (login_window, signals[BEGIN_VERIFICATION_FOR_USER], 0, user_name);
-+                const char *service_name;
+         if (slave->priv->waiting_to_start_session) {
+@@ -1082,6 +1113,9 @@ on_start_session_later (GdmGreeterServer *session,
+                         GdmSimpleSlave   *slave)
+ {
+         g_debug ("GdmSimpleSlave: Will start session when ready and told");
++        if (slave->priv->greeter_reset_id > 0) {
++                return;
++        }
+         slave->priv->start_session_when_ready = FALSE;
+ }
+ 
+-- 
+1.7.2.1
+
+
+From f5179490872ab7335a672e7de108150ec4c145da Mon Sep 17 00:00:00 2001
+From: Ray Strode <rstrode at redhat.com>
+Date: Fri, 6 Nov 2009 13:35:26 -0500
+Subject: [PATCH 16/35] Don't delay login for passwd -d users
+
+Before we'd delay login if timed login was enabled, but
+we should have been checking if it was the reason login
+was happening.
+---
+ gui/simple-greeter/gdm-greeter-login-window.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
+index 95371b8..a0caff9 100644
+--- a/gui/simple-greeter/gdm-greeter-login-window.c
++++ b/gui/simple-greeter/gdm-greeter-login-window.c
+@@ -840,7 +840,7 @@ gdm_greeter_login_window_start_session_when_ready (GdmGreeterLoginWindow *login_
+                  * so they can pick language/session.  Will need to refactor things
+                  * a bit so we can share code with timed login.
+                  */
+-                if (!login_window->priv->timed_login_enabled) {
++                if (strcmp (service_name, "gdm-autologin") != 0) {
+ 
+                         g_debug ("GdmGreeterLoginWindow: Okay, we'll start the session anyway,"
+                                  "because the user isn't ever going to get an opportunity to"
+-- 
+1.7.2.1
+
+
+From 41a2faa25a9424f6f4c9cffde9ea996fef4919c9 Mon Sep 17 00:00:00 2001
+From: Ray Strode <rstrode at redhat.com>
+Date: Fri, 30 Jan 2009 23:57:31 -0500
+Subject: [PATCH 17/35] Add a plugin based extension system to greeter
+
+This allows plugins to drive which PAM conversations
+get run.  This commit just adds one plugin "password"
+which does the one PAM conversation we've traditionally
+run.
+---
+ common/gdm-marshal.list                            |    1 +
+ configure.ac                                       |   44 +
+ gui/simple-greeter/Makefile.am                     |   19 +
+ gui/simple-greeter/gdm-greeter-client.c            |   21 +
+ gui/simple-greeter/gdm-greeter-client.h            |    2 +
+ gui/simple-greeter/gdm-greeter-login-window.c      | 1061 +++++++++++++++++---
+ gui/simple-greeter/gdm-greeter-login-window.h      |   36 +-
+ gui/simple-greeter/gdm-greeter-login-window.ui     |   67 +-
+ gui/simple-greeter/gdm-greeter-plugin.c            |  255 +++++
+ gui/simple-greeter/gdm-greeter-plugin.h            |   61 ++
+ gui/simple-greeter/gdm-greeter-session.c           |  161 +++-
+ gui/simple-greeter/gdm-plugin-manager.c            |  478 +++++++++
+ gui/simple-greeter/gdm-plugin-manager.h            |   66 ++
+ gui/simple-greeter/gdm-task-list.c                 |  385 +++++++
+ gui/simple-greeter/gdm-task-list.h                 |   85 ++
+ gui/simple-greeter/gdm-user-chooser-widget.c       |   23 +-
+ gui/simple-greeter/libgdmsimplegreeter/Makefile.am |   48 +
+ .../libgdmsimplegreeter/gdm-conversation.c         |  186 ++++
+ .../libgdmsimplegreeter/gdm-conversation.h         |   93 ++
+ .../libgdmsimplegreeter/gdm-greeter-extension.c    |   93 ++
+ .../libgdmsimplegreeter/gdm-greeter-extension.h    |   55 +
+ gui/simple-greeter/libgdmsimplegreeter/gdm-task.c  |  129 +++
+ gui/simple-greeter/libgdmsimplegreeter/gdm-task.h  |   66 ++
+ .../libgdmsimplegreeter/gdmsimplegreeter.pc.in     |   11 +
+ gui/simple-greeter/plugins/Makefile.am             |    1 +
+ gui/simple-greeter/plugins/password/Makefile.am    |   53 +
+ .../plugins/password/gdm-password-extension.c      |  328 ++++++
+ .../plugins/password/gdm-password-extension.h      |   56 +
+ .../plugins/password/gdm-password.pam              |   19 +
+ gui/simple-greeter/plugins/password/page.ui        |   57 ++
+ gui/simple-greeter/plugins/password/plugin.c       |   40 +
+ po/POTFILES.in                                     |    1 +
+ 32 files changed, 3749 insertions(+), 252 deletions(-)
+ create mode 100644 gui/simple-greeter/gdm-greeter-plugin.c
+ create mode 100644 gui/simple-greeter/gdm-greeter-plugin.h
+ create mode 100644 gui/simple-greeter/gdm-plugin-manager.c
+ create mode 100644 gui/simple-greeter/gdm-plugin-manager.h
+ create mode 100644 gui/simple-greeter/gdm-task-list.c
+ create mode 100644 gui/simple-greeter/gdm-task-list.h
+ create mode 100644 gui/simple-greeter/libgdmsimplegreeter/Makefile.am
+ create mode 100644 gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c
+ create mode 100644 gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h
+ create mode 100644 gui/simple-greeter/libgdmsimplegreeter/gdm-greeter-extension.c
+ create mode 100644 gui/simple-greeter/libgdmsimplegreeter/gdm-greeter-extension.h
+ create mode 100644 gui/simple-greeter/libgdmsimplegreeter/gdm-task.c
+ create mode 100644 gui/simple-greeter/libgdmsimplegreeter/gdm-task.h
+ create mode 100644 gui/simple-greeter/libgdmsimplegreeter/gdmsimplegreeter.pc.in
+ create mode 100644 gui/simple-greeter/plugins/Makefile.am
+ create mode 100644 gui/simple-greeter/plugins/password/Makefile.am
+ create mode 100644 gui/simple-greeter/plugins/password/gdm-password-extension.c
+ create mode 100644 gui/simple-greeter/plugins/password/gdm-password-extension.h
+ create mode 100644 gui/simple-greeter/plugins/password/gdm-password.pam
+ create mode 100644 gui/simple-greeter/plugins/password/page.ui
+ create mode 100644 gui/simple-greeter/plugins/password/plugin.c
+
+diff --git a/common/gdm-marshal.list b/common/gdm-marshal.list
+index d5455e1..d8a9e72 100644
+--- a/common/gdm-marshal.list
++++ b/common/gdm-marshal.list
+@@ -5,3 +5,4 @@ VOID:STRING,STRING
+ VOID:UINT,UINT
+ VOID:STRING,INT
+ VOID:DOUBLE
++BOOLEAN:STRING
+diff --git a/configure.ac b/configure.ac
+index fd920c0..ab35800 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -18,6 +18,22 @@ AC_PROG_CXX
+ AM_PROG_CC_C_O
+ AC_PROG_LIBTOOL()
+ 
++## increment if the plugin interface has additions, changes, removals.
++LT_CURRENT=1
 +
-+                service_name = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
-+                g_signal_emit (login_window, signals[BEGIN_VERIFICATION_FOR_USER], 0, service_name, user_name);
-         }
++## increment any time the source changes; set to
++##  0 if you increment CURRENT
++LT_REVISION=0
++
++## increment if any interfaces have been added; set to 0
++## if any interfaces have been changed or removed. removal has
++## precedence over adding, so set to 0 if both happened.
++LT_AGE=0
++
++AC_SUBST(LT_CURRENT)
++AC_SUBST(LT_REVISION)
++AC_SUBST(LT_AGE)
++
+ AC_HEADER_STDC
  
-         switch_mode (login_window, MODE_AUTHENTICATION);
-@@ -1098,6 +1126,20 @@ create_computer_info (GdmGreeterLoginWindow *login_window)
- #define INVISIBLE_CHAR_BULLET        0x2022
- #define INVISIBLE_CHAR_NONE          0
+ AC_SUBST(VERSION)
+@@ -197,6 +213,15 @@ AC_ARG_WITH(dmconfdir,
+ AC_SUBST(dmconfdir)
  
-+static void
-+on_task_activated (GdmGreeterLoginWindow *login_window,
-+                   const char            *name)
-+{
-+        g_debug ("GdmGreeterLoginWindow: starting conversation with '%s'", name);
-+        g_signal_emit (login_window, signals[START_CONVERSATION], 0, name);
-+}
+ dnl ---------------------------------------------------------------------------
++dnl - Configuration file stuff
++dnl ---------------------------------------------------------------------------
++AC_ARG_WITH(extensionsdatadir,
++            AS_HELP_STRING([--with-extensions-datadir],
++                           [directory where extensions store data, default=DATADIR/gdm/simple-greeter/extensions]),
++            extensionsdatadir=${withval}, extensionsdatadir=${datadir}/gdm/simple-greeter/extensions)
++AC_SUBST(extensionsdatadir)
 +
-+static void
-+on_task_deactivated (GdmGreeterLoginWindow *login_window,
-+                     const char            *name)
-+{
-+        g_debug ("GdmGreeterLoginWindow: conversation '%s' now in background", name);
-+}
++dnl ---------------------------------------------------------------------------
+ dnl - Configure arguments
+ dnl ---------------------------------------------------------------------------
  
- static void
- load_theme (GdmGreeterLoginWindow *login_window)
-@@ -1174,6 +1216,28 @@ load_theme (GdmGreeterLoginWindow *login_window)
-                 gtk_widget_show (login_window->priv->user_chooser);
-         }
+@@ -1273,6 +1298,21 @@ fi
  
-+        /* FIXME: task list should implement GtkBuildable and this should get dropped
-+         */
-+        login_window->priv->conversation_list = gdm_task_list_new ();
-+        gtk_box_pack_start (GTK_BOX (box), login_window->priv->conversation_list, TRUE, TRUE, 0);
+ AC_SUBST(GDM_SCREENSHOT_DIR)
+ 
++dnl ---------------------------------------------------------------------------
++dnl - Directory for simple greeter plugins
++dnl ---------------------------------------------------------------------------
 +
-+        g_signal_connect_swapped (GDM_TASK_LIST (login_window->priv->conversation_list),
-+                                  "activated",
-+                                  G_CALLBACK (on_task_activated),
-+                                  login_window);
-+        g_signal_connect_swapped (GDM_TASK_LIST (login_window->priv->conversation_list),
-+                                  "deactivated",
-+                                  G_CALLBACK (on_task_deactivated),
-+                                  login_window);
-+        gtk_widget_show (login_window->priv->conversation_list);
++AC_ARG_WITH(simple-greeter-plugins-dir,
++            AS_HELP_STRING([--with-simple-greeter-plugins-dir=<dir>],
++                           [simple greeter plugins directory]))
 +
-+        gdm_task_list_add_task (GDM_TASK_LIST (login_window->priv->conversation_list),
-+                                "password-auth", "dialog-password");
-+        gdm_task_list_add_task (GDM_TASK_LIST (login_window->priv->conversation_list),
-+                                "fingerprint-auth", "stock_allow-effects");
-+        gdm_task_list_add_task (GDM_TASK_LIST (login_window->priv->conversation_list),
-+                                "smartcard-auth", "badge-small");
++if ! test -z "$with_simple_greeter_plugins_dir"; then
++   GDM_SIMPLE_GREETER_PLUGINS_DIR=$with_simple_greeter_plugins_dir
++else
++   GDM_SIMPLE_GREETER_PLUGINS_DIR=${libdir}/gdm/simple-greeter/plugins
++fi
 +
-         login_window->priv->auth_banner_label = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "auth-banner-label"));
-         /*make_label_small_italic (login_window->priv->auth_banner_label);*/
++AC_SUBST(GDM_SIMPLE_GREETER_PLUGINS_DIR)
  
-@@ -1348,6 +1412,15 @@ gdm_greeter_login_window_class_init (GdmGreeterLoginWindowClass *klass)
-         widget_class->key_press_event = gdm_greeter_login_window_key_press_event;
-         widget_class->size_request = gdm_greeter_login_window_size_request;
+ dnl ---------------------------------------------------------------------------
+ dnl - Finish
+@@ -1401,6 +1441,10 @@ docs/Makefile
+ gui/Makefile
+ gui/simple-greeter/Makefile
+ gui/simple-greeter/libnotificationarea/Makefile
++gui/simple-greeter/libgdmsimplegreeter/Makefile
++gui/simple-greeter/libgdmsimplegreeter/gdmsimplegreeter.pc
++gui/simple-greeter/plugins/Makefile
++gui/simple-greeter/plugins/password/Makefile
+ gui/simple-chooser/Makefile
+ gui/user-switch-applet/Makefile
+ utils/Makefile
+diff --git a/gui/simple-greeter/Makefile.am b/gui/simple-greeter/Makefile.am
+index 6f7f3ee..b987de4 100644
+--- a/gui/simple-greeter/Makefile.am
++++ b/gui/simple-greeter/Makefile.am
+@@ -2,12 +2,15 @@ NULL =
  
-+        signals [START_CONVERSATION] =
-+                g_signal_new ("start-conversation",
-+                              G_TYPE_FROM_CLASS (object_class),
-+                              G_SIGNAL_RUN_LAST,
-+                              G_STRUCT_OFFSET (GdmGreeterLoginWindowClass, start_conversation),
-+                              NULL,
-+                              NULL,
-+                              g_cclosure_marshal_VOID__STRING,
-+                              G_TYPE_NONE, 1, G_TYPE_STRING);
-         signals [BEGIN_AUTO_LOGIN] =
-                 g_signal_new ("begin-auto-login",
-                               G_TYPE_FROM_CLASS (object_class),
-@@ -1364,9 +1437,9 @@ gdm_greeter_login_window_class_init (GdmGreeterLoginWindowClass *klass)
-                               G_STRUCT_OFFSET (GdmGreeterLoginWindowClass, begin_verification),
-                               NULL,
-                               NULL,
--                              g_cclosure_marshal_VOID__VOID,
-+                              g_cclosure_marshal_VOID__STRING,
-                               G_TYPE_NONE,
--                              0);
-+                              1, G_TYPE_STRING);
-         signals [BEGIN_VERIFICATION_FOR_USER] =
-                 g_signal_new ("begin-verification-for-user",
-                               G_TYPE_FROM_CLASS (object_class),
-@@ -1374,9 +1447,9 @@ gdm_greeter_login_window_class_init (GdmGreeterLoginWindowClass *klass)
-                               G_STRUCT_OFFSET (GdmGreeterLoginWindowClass, begin_verification_for_user),
-                               NULL,
-                               NULL,
--                              g_cclosure_marshal_VOID__STRING,
-+                              gdm_marshal_VOID__STRING_STRING,
-                               G_TYPE_NONE,
--                              1, G_TYPE_STRING);
-+                              2, G_TYPE_STRING, G_TYPE_STRING);
-         signals [QUERY_ANSWER] =
-                 g_signal_new ("query-answer",
-                               G_TYPE_FROM_CLASS (object_class),
-@@ -1384,9 +1457,9 @@ gdm_greeter_login_window_class_init (GdmGreeterLoginWindowClass *klass)
-                               G_STRUCT_OFFSET (GdmGreeterLoginWindowClass, query_answer),
-                               NULL,
-                               NULL,
--                              g_cclosure_marshal_VOID__STRING,
-+                              gdm_marshal_VOID__STRING_STRING,
-                               G_TYPE_NONE,
--                              1, G_TYPE_STRING);
-+                              2, G_TYPE_STRING, G_TYPE_STRING);
-         signals [USER_SELECTED] =
-                 g_signal_new ("user-selected",
-                               G_TYPE_FROM_CLASS (object_class),
-diff --git a/gui/simple-greeter/gdm-greeter-login-window.h b/gui/simple-greeter/gdm-greeter-login-window.h
-index 817d0a2..559b26b 100644
---- a/gui/simple-greeter/gdm-greeter-login-window.h
-+++ b/gui/simple-greeter/gdm-greeter-login-window.h
-@@ -46,12 +46,17 @@ typedef struct
-         GtkWindowClass   parent_class;
+ SUBDIRS = 				\
+ 	libnotificationarea		\
++	libgdmsimplegreeter		\
++	plugins				\
+ 	$(NULL)
  
-         /* signals */
-+        void (* start_conversation)          (GdmGreeterLoginWindow *login_window,
-+                                              const char            *service_name);
-         void (* begin_auto_login)            (GdmGreeterLoginWindow *login_window,
-                                               const char            *username);
--        void (* begin_verification)          (GdmGreeterLoginWindow *login_window);
-+        void (* begin_verification)          (GdmGreeterLoginWindow *login_window,
-+                                              const char            *service_name);
-         void (* begin_verification_for_user) (GdmGreeterLoginWindow *login_window,
-+                                              const char            *service_name,
-                                               const char            *username);
-         void (* query_answer)                (GdmGreeterLoginWindow *login_window,
-+                                              const char            *service_name,
-                                               const char            *text);
-         void (* user_selected)               (GdmGreeterLoginWindow *login_window,
-                                               const char            *text);
-@@ -68,12 +73,16 @@ GtkWidget *         gdm_greeter_login_window_new                (gboolean displa
- gboolean            gdm_greeter_login_window_reset              (GdmGreeterLoginWindow *login_window);
- gboolean            gdm_greeter_login_window_ready              (GdmGreeterLoginWindow *login_window);
- gboolean            gdm_greeter_login_window_info_query         (GdmGreeterLoginWindow *login_window,
-+                                                                 const char *service_name,
-                                                                  const char *text);
- gboolean            gdm_greeter_login_window_secret_info_query  (GdmGreeterLoginWindow *login_window,
-+                                                                 const char *service_name,
-                                                                  const char *text);
- gboolean            gdm_greeter_login_window_info               (GdmGreeterLoginWindow *login_window,
-+                                                                 const char *service_name,
-                                                                  const char *text);
- gboolean            gdm_greeter_login_window_problem            (GdmGreeterLoginWindow *login_window,
-+                                                                 const char *service_name,
-                                                                  const char *text);
+ AM_CPPFLAGS = \
+ 	-I$(top_srcdir)/common				\
+ 	-I$(top_builddir)/common			\
+ 	-I$(top_srcdir)/gui/simple-greeter/libnotificationarea	\
++	-I$(top_srcdir)/gui/simple-greeter/libgdmsimplegreeter	\
+ 	-DDMCONFDIR=\""$(dmconfdir)"\"			\
+ 	-DGDMCONFDIR=\"$(gdmconfdir)\"                  \
+ 	-DDATADIR=\""$(datadir)"\"		 	\
+@@ -20,6 +23,7 @@ AM_CPPFLAGS = \
+ 	-DGDM_CACHE_DIR=\""$(localstatedir)/cache/gdm"\"	\
+ 	-DAT_SPI_REGISTRYD_DIR="\"$(AT_SPI_REGISTRYD_DIR)\""	\
+ 	$(UPOWER_CFLAGS)				\
++	-DGDM_SIMPLE_GREETER_PLUGINS_DIR="\"$(GDM_SIMPLE_GREETER_PLUGINS_DIR)\""\
+ 	$(DISABLE_DEPRECATED_CFLAGS)			\
+ 	$(GTK_CFLAGS)					\
+ 	$(SIMPLE_GREETER_CFLAGS)			\
+@@ -85,10 +89,17 @@ test_greeter_login_window_SOURCES = 	\
+ 	gdm-user-chooser-widget.c	\
+ 	gdm-user-chooser-dialog.h	\
+ 	gdm-user-chooser-dialog.c	\
++	gdm-task-list.h			\
++	gdm-task-list.c			\
++	gdm-plugin-manager.h		\
++	gdm-plugin-manager.c		\
++	gdm-greeter-plugin.h		\
++	gdm-greeter-plugin.c		\
+ 	$(NULL)
  
- void               gdm_greeter_login_window_request_timed_login (GdmGreeterLoginWindow *login_window,
-diff --git a/gui/simple-greeter/gdm-greeter-session.c b/gui/simple-greeter/gdm-greeter-session.c
-index e856dd4..945e210 100644
---- a/gui/simple-greeter/gdm-greeter-session.c
-+++ b/gui/simple-greeter/gdm-greeter-session.c
-@@ -71,7 +71,7 @@ on_info (GdmGreeterClient  *client,
- {
-         g_debug ("GdmGreeterSession: Info: %s", text);
+ test_greeter_login_window_LDADD =	\
+ 	$(top_builddir)/common/libgdmcommon.la	\
++	$(top_builddir)/gui/simple-greeter/libgdmsimplegreeter/libgdmsimplegreeter.la	\
+ 	libgdmuser.la			\
+ 	$(COMMON_LIBS)			\
+ 	$(SIMPLE_GREETER_LIBS)		\
+@@ -139,6 +150,7 @@ test_greeter_panel_SOURCES = 	\
+ test_greeter_panel_LDADD =	\
+ 	$(top_builddir)/common/libgdmcommon.la	\
+ 	$(top_builddir)/gui/simple-greeter/libnotificationarea/libnotificationarea.la	\
++	$(top_builddir)/gui/simple-greeter/libgdmsimplegreeter/libgdmsimplegreeter.la	\
+ 	$(SIMPLE_GREETER_LIBS)		\
+ 	$(GTK_LIBS)			\
+ 	$(GCONF_LIBS)			\
+@@ -314,18 +326,25 @@ gdm_simple_greeter_SOURCES =  		\
+ 	gdm-language-chooser-dialog.c	\
+ 	gdm-language-option-widget.h	\
+ 	gdm-language-option-widget.c	\
++	gdm-plugin-manager.h		\
++	gdm-plugin-manager.c		\
+ 	gdm-sessions.h			\
+ 	gdm-sessions.c			\
+ 	gdm-session-option-widget.h	\
+ 	gdm-session-option-widget.c	\
++	gdm-greeter-plugin.h		\
++	gdm-greeter-plugin.c		\
+ 	gdm-user-chooser-widget.h	\
+ 	gdm-user-chooser-widget.c	\
++	gdm-task-list.h			\
++	gdm-task-list.c			\
+ 	$(NULL)
  
--        gdm_greeter_login_window_info (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), text);
-+        gdm_greeter_login_window_info (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), service_name, text);
+ gdm_simple_greeter_LDADD = 		\
+ 	$(top_builddir)/common/libgdmcommon.la	\
+ 	libgdmuser.la			\
+ 	$(top_builddir)/gui/simple-greeter/libnotificationarea/libnotificationarea.la	\
++	$(top_builddir)/gui/simple-greeter/libgdmsimplegreeter/libgdmsimplegreeter.la	\
+ 	$(COMMON_LIBS)			\
+ 	$(EXTRA_GREETER_LIBS)   	\
+ 	$(SIMPLE_GREETER_LIBS)		\
+diff --git a/gui/simple-greeter/gdm-greeter-client.c b/gui/simple-greeter/gdm-greeter-client.c
+index ad3ec7e..ef6fb43 100644
+--- a/gui/simple-greeter/gdm-greeter-client.c
++++ b/gui/simple-greeter/gdm-greeter-client.c
+@@ -65,6 +65,7 @@ enum {
+         SECRET_INFO_QUERY,
+         SERVICE_UNAVAILABLE,
+         READY,
++        CONVERSATION_STOPPED,
+         RESET,
+         AUTHENTICATION_FAILED,
+         SELECTED_USER_CHANGED,
+@@ -279,6 +280,13 @@ on_ready (GdmGreeterClient *client,
  }
  
  static void
-@@ -82,7 +82,7 @@ on_problem (GdmGreeterClient  *client,
++on_conversation_stopped (GdmGreeterClient *client,
++                         DBusMessage      *message)
++{
++        emit_string_signal_for_message (client, "ConversationStopped", message, CONVERSATION_STOPPED);
++}
++
++static void
+ on_reset (GdmGreeterClient *client,
+           DBusMessage      *message)
  {
-         g_debug ("GdmGreeterSession: Problem: %s", text);
+@@ -782,6 +790,8 @@ client_dbus_handle_message (DBusConnection *connection,
+                 on_service_unavailable (client, message);
+         } else if (dbus_message_is_signal (message, GREETER_SERVER_DBUS_INTERFACE, "Ready")) {
+                 on_ready (client, message);
++        } else if (dbus_message_is_signal (message, GREETER_SERVER_DBUS_INTERFACE, "ConversationStopped")) {
++                on_conversation_stopped (client, message);
+         } else if (dbus_message_is_signal (message, GREETER_SERVER_DBUS_INTERFACE, "Reset")) {
+                 on_reset (client, message);
+         } else if (dbus_message_is_signal (message, GREETER_SERVER_DBUS_INTERFACE, "AuthenticationFailed")) {
+@@ -1034,6 +1044,17 @@ gdm_greeter_client_class_init (GdmGreeterClientClass *klass)
+                               G_TYPE_NONE,
+                               1, G_TYPE_STRING);
  
--        gdm_greeter_login_window_problem (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), text);
-+        gdm_greeter_login_window_problem (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), service_name, text);
- }
++        gdm_greeter_client_signals[CONVERSATION_STOPPED] =
++                g_signal_new ("conversation-stopped",
++                              G_OBJECT_CLASS_TYPE (object_class),
++                              G_SIGNAL_RUN_FIRST,
++                              G_STRUCT_OFFSET (GdmGreeterClientClass, conversation_stopped),
++                              NULL,
++                              NULL,
++                              g_cclosure_marshal_VOID__STRING,
++                              G_TYPE_NONE,
++                              1, G_TYPE_STRING);
++
+         gdm_greeter_client_signals[RESET] =
+                 g_signal_new ("reset",
+                               G_OBJECT_CLASS_TYPE (object_class),
+diff --git a/gui/simple-greeter/gdm-greeter-client.h b/gui/simple-greeter/gdm-greeter-client.h
+index 917ca9c..3fd62d4 100644
+--- a/gui/simple-greeter/gdm-greeter-client.h
++++ b/gui/simple-greeter/gdm-greeter-client.h
+@@ -63,6 +63,8 @@ typedef struct
+                                           const char        *service_name);
+         void (* ready)                   (GdmGreeterClient  *client,
+                                           const char        *service_name);
++        void (* conversation_stopped)    (GdmGreeterClient  *client,
++                                          const char        *service_name);
+         void (* reset)                   (GdmGreeterClient  *client);
+         void (* authentication_failed)   (GdmGreeterClient  *client);
+         void (* selected_user_changed)   (GdmGreeterClient  *client,
+diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
+index a0caff9..36a6d21 100644
+--- a/gui/simple-greeter/gdm-greeter-login-window.c
++++ b/gui/simple-greeter/gdm-greeter-login-window.c
+@@ -1,7 +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) 2008 Red Hat, Inc.
++ * Copyright (C) 2008, 2009 Red Hat, Inc.
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -17,6 +17,9 @@
+  * along with this program; if not, write to the Free Software
+  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+  *
++ * Written by: William Jon McCann <mccann at jhu.edu>
++ *             Ray Strode <rstrode at redhat.com>
++ *
+  */
  
- static void
-@@ -181,7 +181,7 @@ on_info_query (GdmGreeterClient  *client,
- {
-         g_debug ("GdmGreeterSession: Info query: %s", text);
+ #include "config.h"
+@@ -50,12 +53,16 @@
+ #include <dbus/dbus-glib.h>
+ #include <dbus/dbus-glib-lowlevel.h>
  
--        gdm_greeter_login_window_info_query (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), text);
-+        gdm_greeter_login_window_info_query (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), service_name, text);
- }
++#include "gdm-marshal.h"
++
+ #include "gdm-settings-client.h"
+ #include "gdm-settings-keys.h"
+ #include "gdm-profile.h"
  
- static void
-@@ -192,10 +192,18 @@ on_secret_info_query (GdmGreeterClient  *client,
++#include "gdm-greeter-client.h"
+ #include "gdm-greeter-login-window.h"
+ #include "gdm-user-chooser-widget.h"
++#include "gdm-task-list.h"
+ 
+ #ifdef HAVE_PAM
+ #include <security/pam_appl.h>
+@@ -103,13 +110,15 @@ struct GdmGreeterLoginWindowPrivate
  {
-         g_debug ("GdmGreeterSession: Secret info query: %s", text);
+         GtkBuilder      *builder;
+         GtkWidget       *user_chooser;
++        GtkWidget       *conversation_list;
+         GtkWidget       *auth_banner_label;
+         GtkWidget       *current_button;
+-
++        GtkWidget       *auth_page_box;
+         guint            display_is_local : 1;
+         guint            is_interactive : 1;
+         guint            user_chooser_loaded : 1;
+         GConfClient     *client;
++        GList           *tasks_to_enable;
  
--        gdm_greeter_login_window_secret_info_query (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), text);
-+        gdm_greeter_login_window_secret_info_query (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), service_name, text);
- }
+         gboolean         banner_message_enabled;
+         guint            gconf_cnxn;
+@@ -137,6 +146,7 @@ enum {
+ };
  
- static void
-+on_start_conversation (GdmGreeterLoginWindow *login_window,
-+                       const char            *service_name,
-+                       GdmGreeterSession     *session)
-+{
-+        gdm_greeter_client_call_start_conversation (session->priv->client,
-+                                                    service_name);
-+}
-+static void
- on_begin_auto_login (GdmGreeterLoginWindow *login_window,
-                      const char            *username,
-                      GdmGreeterSession     *session)
-@@ -206,29 +214,32 @@ on_begin_auto_login (GdmGreeterLoginWindow *login_window,
+ enum {
++        START_CONVERSATION,
+         BEGIN_AUTO_LOGIN,
+         BEGIN_VERIFICATION,
+         BEGIN_VERIFICATION_FOR_USER,
+@@ -161,6 +171,8 @@ static void     on_user_unchosen            (GdmUserChooserWidget *user_chooser,
+ static void     switch_mode                 (GdmGreeterLoginWindow *login_window,
+                                              int                    number);
+ static void     update_banner_message       (GdmGreeterLoginWindow *login_window);
++static void     gdm_greeter_login_window_start_session_when_ready (GdmGreeterLoginWindow *login_window,
++                                                                   const char            *service_name);
  
- static void
- on_begin_verification (GdmGreeterLoginWindow *login_window,
-+                       const char            *service_name,
-                        GdmGreeterSession     *session)
- {
-         gdm_greeter_client_call_begin_verification (session->priv->client,
--                                                    "gdm");
-+                                                    service_name);
- }
+ G_DEFINE_TYPE (GdmGreeterLoginWindow, gdm_greeter_login_window, GTK_TYPE_WINDOW)
  
- static void
- on_begin_verification_for_user (GdmGreeterLoginWindow *login_window,
-+                                const char            *service_name,
-                                 const char            *username,
-                                 GdmGreeterSession     *session)
+@@ -186,9 +198,6 @@ set_sensitive (GdmGreeterLoginWindow *login_window,
  {
-         gdm_greeter_client_call_begin_verification_for_user (session->priv->client,
--                                                             "gdm",
-+                                                             service_name,
-                                                              username);
- }
+         GtkWidget *box;
+ 
+-        box = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "auth-input-box"));
+-        gtk_widget_set_sensitive (box, sensitive);
+-
+         box = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "buttonbox"));
+         gtk_widget_set_sensitive (box, sensitive);
  
+@@ -198,27 +207,43 @@ set_sensitive (GdmGreeterLoginWindow *login_window,
  static void
- on_query_answer (GdmGreeterLoginWindow *login_window,
-+                 const char            *service_name,
-                  const char            *text,
-                  GdmGreeterSession     *session)
+ set_focus (GdmGreeterLoginWindow *login_window)
  {
-         gdm_greeter_client_call_answer_query (session->priv->client,
--                                              "gdm",
-+                                              service_name,
-                                               text);
- }
- 
-@@ -392,7 +403,10 @@ toggle_login_window (GdmGreeterSession *session,
-                 is_local = gdm_greeter_client_get_display_is_local (session->priv->client);
-                 g_debug ("GdmGreeterSession: Starting a login window local:%d", is_local);
-                 session->priv->login_window = gdm_greeter_login_window_new (is_local);
+-        GtkWidget *entry;
 -
-+                g_signal_connect (session->priv->login_window,
-+                                  "start-conversation",
-+                                  G_CALLBACK (on_start_conversation),
-+                                  session);
-                 g_signal_connect (session->priv->login_window,
-                                   "begin-auto-login",
-                                   G_CALLBACK (on_begin_auto_login),
-diff --git a/gui/simple-greeter/gdm-task-list.c b/gui/simple-greeter/gdm-task-list.c
-new file mode 100644
-index 0000000..e0fd3d4
---- /dev/null
-+++ b/gui/simple-greeter/gdm-task-list.c
-@@ -0,0 +1,198 @@
-+/*
-+ * Copyright (C) 2009 Red Hat, Inc.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+ *
-+ *  Written by: Ray Strode <rstrode at redhat.com>
-+ */
-+
-+#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-task-list.h"
-+
-+#define GDM_TASK_LIST_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_TASK_LIST, GdmTaskListPrivate))
-+
-+typedef struct
-+{
-+        GtkWidget *radio_button;
-+        char      *name;
-+} GdmTask;
-+
-+struct GdmTaskListPrivate
-+{
-+        GtkWidget *box;
-+        GList     *tasks;
-+};
-+
-+enum {
-+        ACTIVATED = 0,
-+        DEACTIVATED,
-+        NUMBER_OF_SIGNALS
-+};
-+
-+static guint    signals[NUMBER_OF_SIGNALS];
-+
-+static void     gdm_task_list_class_init  (GdmTaskListClass *klass);
-+static void     gdm_task_list_init        (GdmTaskList      *task_list);
-+static void     gdm_task_list_finalize    (GObject              *object);
-+
-+G_DEFINE_TYPE (GdmTaskList, gdm_task_list, GTK_TYPE_ALIGNMENT);
-+
-+static void
-+on_task_toggled (GdmTaskList    *widget,
-+                 GtkRadioButton *radio_button)
-+{
+-        entry = GTK_WIDGET (gtk_builder_get_object (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->builder, "auth-prompt-entry"));
 +        GdmTask *task;
+ 
+         gdk_window_focus (gtk_widget_get_window (GTK_WIDGET (login_window)), GDK_CURRENT_TIME);
+ 
+-        if (gtk_widget_get_realized (entry) && ! gtk_widget_has_focus (entry)) {
+-                gtk_widget_grab_focus (entry);
++        task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
 +
-+        task = g_object_get_data (G_OBJECT (radio_button), "gdm-task");
-+
-+        if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (radio_button))) {
-+                g_signal_emit (widget, signals[ACTIVATED], 0, task->name);
-+        } else {
-+                g_signal_emit (widget, signals[DEACTIVATED], 0, task->name);
-+        }
++        if (task != NULL && gdm_conversation_focus (GDM_CONVERSATION (task))) {
++                char *name;
++                name = gdm_task_get_name (task);
++                g_debug ("GdmGreeterLoginWindow: focusing task %s", name);
++                g_free (name);
+         } else if (gtk_widget_get_realized (login_window->priv->user_chooser) && ! gtk_widget_has_focus (login_window->priv->user_chooser)) {
+                 gtk_widget_grab_focus (login_window->priv->user_chooser);
+         }
++        g_object_unref (task);
 +}
 +
-+void
-+gdm_task_list_add_task (GdmTaskList *task_list,
-+                        const char  *name,
-+                        const char  *icon_name)
++static gboolean
++set_task_conversation_message (GdmTaskList *task_list,
++                               GdmTask     *task,
++                               const char  *message)
 +{
-+        GdmTask   *task;
-+        GtkWidget *image;
-+
-+        task = g_new0 (GdmTask, 1);
 +
-+        task->name = g_strdup (name);
-+        if (task_list->priv->tasks == NULL) {
-+                task->radio_button = gtk_radio_button_new (NULL);
-+        } else {
-+                task->radio_button = gtk_radio_button_new_from_widget (GTK_RADIO_BUTTON (((GdmTask *) task_list->priv->tasks->data)->radio_button));
++        gdm_conversation_set_message (GDM_CONVERSATION (task), message);
++        return FALSE;
+ }
+ 
+ static void
+ set_message (GdmGreeterLoginWindow *login_window,
+              const char            *text)
+ {
+-        GtkWidget *label;
++        g_return_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window));
+ 
+-        label = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "auth-message-label"));
+-        gtk_label_set_text (GTK_LABEL (label), text);
++        gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
++                                    (GdmTaskListForeachFunc)
++                                    set_task_conversation_message,
++                                    (gpointer) text);
+ }
+ 
+ static void
+@@ -340,20 +365,66 @@ show_widget (GdmGreeterLoginWindow *login_window,
+ }
+ 
+ static void
+-on_login_button_clicked_answer_query (GtkButton             *button,
+-                                      GdmGreeterLoginWindow *login_window)
++hide_task_actions (GdmTask *task)
+ {
+-        GtkWidget  *entry;
+-        const char *text;
++        GtkActionGroup *actions;
+ 
+-        set_busy (login_window);
+-        set_sensitive (login_window, FALSE);
++        actions = gdm_conversation_get_actions (GDM_CONVERSATION (task));
+ 
+-        entry = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "auth-prompt-entry"));
+-        text = gtk_entry_get_text (GTK_ENTRY (entry));
++        if (actions != NULL) {
++                gtk_action_group_set_visible (actions, FALSE);
++                gtk_action_group_set_sensitive (actions, FALSE);
++                g_object_unref (actions);
 +        }
-+
-+        g_object_set (task->radio_button, "draw-indicator", FALSE, NULL);
-+        g_object_set_data (G_OBJECT (task->radio_button), "gdm-task", task);
-+        g_signal_connect_swapped (task->radio_button,
-+                                  "toggled", G_CALLBACK (on_task_toggled), task_list);
-+        image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_DND);
-+        gtk_widget_show (image);
-+        gtk_container_add (GTK_CONTAINER (task->radio_button), image);
-+        gtk_widget_show (task->radio_button);
-+        gtk_container_add (GTK_CONTAINER (task->radio_button), task_list->priv->box);
-+
-+        gtk_container_add (GTK_CONTAINER (task_list->priv->box), task->radio_button);
-+        task_list->priv->tasks = g_list_append (task_list->priv->tasks, task);
 +}
 +
 +static void
-+gdm_task_list_class_init (GdmTaskListClass *klass)
++grab_default_button_for_task (GdmTask *task)
 +{
-+        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
++        GtkActionGroup *actions;
++        GtkAction *action;
++        GSList    *proxies, *node;
 +
-+        object_class->finalize = gdm_task_list_finalize;
++        actions = gdm_conversation_get_actions (GDM_CONVERSATION (task));
 +
-+        signals [ACTIVATED] = g_signal_new ("activated",
-+                                            G_TYPE_FROM_CLASS (object_class),
-+                                            G_SIGNAL_RUN_FIRST,
-+                                            G_STRUCT_OFFSET (GdmTaskListClass, activated),
-+                                            NULL,
-+                                            NULL,
-+                                            g_cclosure_marshal_VOID__STRING,
-+                                            G_TYPE_NONE,
-+                                            1, G_TYPE_STRING);
++        if (actions == NULL) {
++                return;
++        }
 +
-+        signals [DEACTIVATED] = g_signal_new ("deactivated",
-+                                            G_TYPE_FROM_CLASS (object_class),
-+                                            G_SIGNAL_RUN_FIRST,
-+                                            G_STRUCT_OFFSET (GdmTaskListClass, deactivated),
-+                                            NULL,
-+                                            NULL,
-+                                            g_cclosure_marshal_VOID__STRING,
-+                                            G_TYPE_NONE,
-+                                            1, G_TYPE_STRING);
++        action = gtk_action_group_get_action (actions, GDM_CONVERSATION_DEFAULT_ACTION);
++        g_object_unref (actions);
 +
-+        g_type_class_add_private (klass, sizeof (GdmTaskListPrivate));
-+}
++        if (action == NULL) {
++                return;
++        }
 +
-+static void
-+gdm_task_list_init (GdmTaskList *widget)
-+{
-+        widget->priv = GDM_TASK_LIST_GET_PRIVATE (widget);
++        proxies = gtk_action_get_proxies (action);
++        for (node = proxies; node != NULL; node = node->next) {
++                GtkWidget *widget;
 +
-+        gtk_alignment_set_padding (GTK_ALIGNMENT (widget), 0, 0, 0, 0);
-+        gtk_alignment_set (GTK_ALIGNMENT (widget), 0.0, 0.0, 0, 0);
++                widget = GTK_WIDGET (node->data);
 +
-+        widget->priv->box = gtk_hbox_new (FALSE, 2);
-+        gtk_widget_show (widget->priv->box);
-+        gtk_container_add (GTK_CONTAINER (widget),
-+                           widget->priv->box);
++                if (GTK_WIDGET_CAN_DEFAULT (widget) &&
++                    GTK_WIDGET_VISIBLE (widget)) {
++                        gtk_widget_grab_default (widget);
++                        break;
++                }
++        }
+ 
+-        _gdm_greeter_login_window_set_interactive (login_window, TRUE);
+-        g_signal_emit (login_window, signals[QUERY_ANSWER], 0, text);
 +}
 +
 +static void
-+gdm_task_list_finalize (GObject *object)
++show_task_actions (GdmTask *task)
 +{
-+        GdmTaskList *widget;
-+
-+        g_return_if_fail (object != NULL);
-+        g_return_if_fail (GDM_IS_TASK_LIST (object));
++        GtkActionGroup *actions;
 +
-+        widget = GDM_TASK_LIST (object);
++        actions = gdm_conversation_get_actions (GDM_CONVERSATION (task));
 +
-+        g_list_foreach (widget->priv->tasks, (GFunc) g_free, NULL);
-+        g_list_free (widget->priv->tasks);
++        if (actions != NULL) {
++                gtk_action_group_set_sensitive (actions, TRUE);
++                gtk_action_group_set_visible (actions, TRUE);
++                g_object_unref (actions);
++        }
+ }
+ 
+ static void
+@@ -375,6 +446,7 @@ set_log_in_button_mode (GdmGreeterLoginWindow *login_window,
+         GtkWidget *unlock_button;
+         char      *item;
+         gboolean   in_use;
++        GdmTask   *task;
+ 
+         in_use = FALSE;
+         item = gdm_chooser_widget_get_active_item (GDM_CHOOSER_WIDGET (login_window->priv->user_chooser));
+@@ -416,11 +488,23 @@ set_log_in_button_mode (GdmGreeterLoginWindow *login_window,
+ 
+         switch (mode) {
+         case LOGIN_BUTTON_HIDDEN:
++                task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
++                if (task != NULL) {
++                        hide_task_actions (task);
++                        g_object_unref (task);
++                }
 +
-+        G_OBJECT_CLASS (gdm_task_list_parent_class)->finalize (object);
-+}
+                 gtk_widget_hide (button);
+                 break;
+         case LOGIN_BUTTON_ANSWER_QUERY:
+-                login_window->priv->login_button_handler_id = g_signal_connect (button, "clicked", G_CALLBACK (on_login_button_clicked_answer_query), login_window);
+-                gtk_widget_show (button);
++                task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
++                if (task != NULL) {
++                        show_task_actions (task);
++                        grab_default_button_for_task (task);
++                        g_object_unref (task);
++                }
 +
-+GtkWidget *
-+gdm_task_list_new (void)
++                gtk_widget_hide (button);
+                 break;
+         case LOGIN_BUTTON_TIMED_LOGIN:
+                 login_window->priv->login_button_handler_id = g_signal_connect (button, "clicked", G_CALLBACK (on_login_button_clicked_timed_login), login_window);
+@@ -484,6 +568,24 @@ maybe_show_cancel_button (GdmGreeterLoginWindow *login_window)
+ }
+ 
+ static void
++update_conversation_list_visibility (GdmGreeterLoginWindow *login_window)
 +{
-+        GObject *object;
-+
-+        object = g_object_new (GDM_TYPE_TASK_LIST, NULL);
++        int number_of_tasks;
 +
-+        return GTK_WIDGET (object);
-+}
++        if (login_window->priv->dialog_mode != MODE_AUTHENTICATION) {
++                gtk_widget_hide (login_window->priv->conversation_list);
++                return;
++        }
 +
-+const char *
-+gdm_task_list_get_active_task (GdmTaskList *widget)
-+{
-+        GList *node;
-+
-+        for (node = widget->priv->tasks; node != NULL; node = node->next) {
-+                GdmTask *task;
-+
-+                task = node->data;
-+
-+                if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (task->radio_button)) ) {
-+                        return task->name;
-+                }
++        number_of_tasks = gdm_task_list_get_number_of_visible_tasks (GDM_TASK_LIST (login_window->priv->conversation_list));
++        if (number_of_tasks > 1) {
++                gtk_widget_show (login_window->priv->conversation_list);
++        } else {
++                gtk_widget_hide (login_window->priv->conversation_list);
 +        }
-+
-+        return NULL;
 +}
-diff --git a/gui/simple-greeter/gdm-task-list.h b/gui/simple-greeter/gdm-task-list.h
-new file mode 100644
-index 0000000..ade21b6
---- /dev/null
-+++ b/gui/simple-greeter/gdm-task-list.h
-@@ -0,0 +1,64 @@
-+/*
-+ * Copyright (C) 2009 Red Hat, Inc.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+ *
-+ *  Written by: Ray Strode <rstrode at redhat.com>
-+ */
 +
-+#ifndef __GDM_TASK_LIST_H
-+#define __GDM_TASK_LIST_H
++static void
+ switch_mode (GdmGreeterLoginWindow *login_window,
+              int                    number)
+ {
+@@ -518,6 +620,7 @@ switch_mode (GdmGreeterLoginWindow *login_window,
+         }
+ 
+         show_widget (login_window, "auth-input-box", FALSE);
++        update_conversation_list_visibility (login_window);
+         maybe_show_cancel_button (login_window);
+ 
+         /*
+@@ -548,58 +651,71 @@ switch_mode (GdmGreeterLoginWindow *login_window,
+         }
+ }
+ 
+-static void
+-choose_user (GdmGreeterLoginWindow *login_window,
+-             const char            *user_name)
++static gboolean
++task_has_service_name (GdmTaskList *task_list,
++                       GdmTask     *task,
++                       const char  *service_name)
+ {
+-        guint mode;
++        char *task_service_name;
++        gboolean has_service_name;
+ 
+-        g_assert (user_name != NULL);
++        task_service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (task));
+ 
+-        g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED],
+-                       0, user_name);
++        has_service_name = strcmp (service_name, task_service_name) == 0;
++        g_free (task_service_name);
+ 
+-        mode = MODE_AUTHENTICATION;
+-        if (strcmp (user_name, GDM_USER_CHOOSER_USER_OTHER) == 0) {
+-                g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0);
+-        } else if (strcmp (user_name, GDM_USER_CHOOSER_USER_GUEST) == 0) {
+-                /* FIXME: handle guest account stuff */
+-        } else if (strcmp (user_name, GDM_USER_CHOOSER_USER_AUTO) == 0) {
+-                g_signal_emit (login_window, signals[BEGIN_AUTO_LOGIN], 0,
+-                               login_window->priv->timed_login_username);
++        return has_service_name;
++}
+ 
+-                login_window->priv->timed_login_enabled = TRUE;
+-                restart_timed_login_timeout (login_window);
++static GdmTask *
++find_task_with_service_name (GdmGreeterLoginWindow *login_window,
++                             const char            *service_name)
++{
++        GdmTask *task;
+ 
+-                /* just wait for the user to select language and stuff */
+-                mode = MODE_TIMED_LOGIN;
+-                set_message (login_window, _("Select language and click Log In"));
+-        } else {
+-                g_signal_emit (login_window, signals[BEGIN_VERIFICATION_FOR_USER], 0, user_name);
+-        }
++        task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
++                                           (GdmTaskListForeachFunc)
++                                           task_has_service_name,
++                                           (gpointer) service_name);
+ 
+-        switch_mode (login_window, mode);
++        return task;
+ }
+ 
+-static void
+-retry_login (GdmGreeterLoginWindow *login_window)
++static gboolean
++reset_task (GdmTaskList           *task_list,
++            GdmTask               *task,
++            GdmGreeterLoginWindow *login_window)
+ {
+-        GtkWidget  *entry;
+-        char       *user_name;
++        char *name;
+ 
+-        user_name = gdm_user_chooser_widget_get_chosen_user_name (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser));
+-        if (user_name == NULL) {
+-                return;
+-        }
++        name = gdm_task_get_name (task);
++        g_debug ("Resetting task '%s'", name);
++        g_free (name);
 +
-+#include <glib-object.h>
-+#include <gtk/gtkalignment.h>
++        login_window->priv->tasks_to_enable = g_list_remove (login_window->priv->tasks_to_enable, task);
 +
-+G_BEGIN_DECLS
++        gdm_conversation_reset (GDM_CONVERSATION (task));
++        return FALSE;
++}
+ 
+-        g_debug ("GdmGreeterLoginWindow: Retrying login for %s", user_name);
++static gboolean
++task_is_disabled (GdmTaskList *task_list,
++                  GdmTask     *task)
++{
++        return !gdm_task_is_enabled (task);
++}
+ 
+-        entry = GTK_WIDGET (gtk_builder_get_object (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->builder, "auth-prompt-entry"));
+-        gtk_editable_delete_text (GTK_EDITABLE (entry), 0, -1);
++static gboolean
++tasks_are_enabled (GdmGreeterLoginWindow *login_window)
++{
++        GdmTask *task;
+ 
+-        choose_user (login_window, user_name);
++        task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
++                                           (GdmTaskListForeachFunc)
++                                           task_is_disabled,
++                                           NULL);
+ 
+-        g_free (user_name);
++        return task == NULL;
+ }
+ 
+ static gboolean
+@@ -609,6 +725,10 @@ can_jump_to_authenticate (GdmGreeterLoginWindow *login_window)
+ 
+         if (!login_window->priv->user_chooser_loaded) {
+                 res = FALSE;
++        } else if (!tasks_are_enabled (login_window)) {
++                res = FALSE;
++        } else if (login_window->priv->dialog_mode == MODE_AUTHENTICATION) {
++                res = FALSE;
+         } else if (login_window->priv->user_list_disabled) {
+                 res = (login_window->priv->timed_login_username == NULL);
+         } else {
+@@ -618,11 +738,44 @@ can_jump_to_authenticate (GdmGreeterLoginWindow *login_window)
+         return res;
+ }
+ 
++static gboolean
++begin_task_verification (GdmTaskList           *task_list,
++                         GdmTask               *task,
++                         GdmGreeterLoginWindow *login_window)
++{
++        char *service_name;
 +
-+#define GDM_TYPE_TASK_LIST         (gdm_task_list_get_type ())
-+#define GDM_TASK_LIST(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_TASK_LIST, GdmTaskList))
-+#define GDM_TASK_LIST_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_TASK_LIST, GdmTaskListClass))
-+#define GDM_IS_TASK_LIST(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_TASK_LIST))
-+#define GDM_IS_TASK_LIST_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_TASK_LIST))
-+#define GDM_TASK_LIST_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_TASK_LIST, GdmTaskListClass))
++        if (!gdm_task_is_visible (task)) {
++                return FALSE;
++        }
 +
-+typedef struct GdmTaskListPrivate GdmTaskListPrivate;
++        service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (task));
++        if (service_name != NULL) {
++                g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0, service_name);
++                g_free (service_name);
++        }
 +
-+typedef struct
-+{
-+        GtkAlignment             parent;
-+        GdmTaskListPrivate *priv;
-+} GdmTaskList;
++        return FALSE;
++}
 +
-+typedef struct
++static void
++begin_verification (GdmGreeterLoginWindow *login_window)
 +{
-+        GtkAlignmentClass       parent_class;
-+
-+        void (* deactivated)      (GdmTaskList *widget,
-+                                   const char  *name);
-+        void (* activated)      (GdmTaskList *widget,
-+                                 const char  *name);
-+} GdmTaskListClass;
++        gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
++                                    (GdmTaskListForeachFunc)
++                                    begin_task_verification,
++                                    login_window);
 +
++        switch_mode (login_window, MODE_AUTHENTICATION);
 +
-+GType                  gdm_task_list_get_type               (void);
-+GtkWidget *            gdm_task_list_new                    (void);
++        update_conversation_list_visibility (login_window);
++}
 +
-+const char *           gdm_task_list_get_active_task (GdmTaskList *widget);
-+void                   gdm_task_list_add_task (GdmTaskList *widget,
-+                                               const char  *name,
-+                                               const char  *icon_name);
-+G_END_DECLS
 +
-+#endif /* __GDM_TASK_LIST_H */
--- 
-1.6.5.2
-
-
-From fba64d2a9abead0850ce472959bc8bb4c9072187 Mon Sep 17 00:00:00 2001
-From: Ray Strode <rstrode at redhat.com>
-Date: Fri, 6 Mar 2009 11:19:40 -0500
-Subject: [PATCH 09/45] Create session settings object when first starting worker
-
-This is because one PAM module may complete before setup
-gets called on another, and when one completes *all* PAM
-modules get told about language, session, and layouts
-set by the user.
----
- daemon/gdm-session-worker.c |    3 +--
- 1 files changed, 1 insertions(+), 2 deletions(-)
-
-diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c
-index 2f07e13..8328910 100644
---- a/daemon/gdm-session-worker.c
-+++ b/daemon/gdm-session-worker.c
-@@ -2316,8 +2316,6 @@ do_setup (GdmSessionWorker *worker)
-         GError  *error;
-         gboolean res;
+ static void
+ reset_dialog (GdmGreeterLoginWindow *login_window,
+               guint                  dialog_mode)
+ {
+-        GtkWidget  *entry;
+         GtkWidget  *label;
+         guint       mode;
  
--        worker->priv->user_settings = gdm_session_settings_new ();
+@@ -655,11 +808,10 @@ reset_dialog (GdmGreeterLoginWindow *login_window,
+                 set_message (login_window, "");
+         }
+ 
+-        entry = GTK_WIDGET (gtk_builder_get_object (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->builder, "auth-prompt-entry"));
 -
-         g_signal_connect_swapped (worker->priv->user_settings,
-                                   "notify::language-name",
-                                   G_CALLBACK (on_saved_language_name_read),
-@@ -2970,6 +2968,7 @@ gdm_session_worker_init (GdmSessionWorker *worker)
-                                                            g_str_equal,
-                                                            (GDestroyNotify) g_free,
-                                                            (GDestroyNotify) g_free);
-+        worker->priv->user_settings = gdm_session_settings_new ();
+-        gtk_editable_delete_text (GTK_EDITABLE (entry), 0, -1);
+-
+-        gtk_entry_set_visibility (GTK_ENTRY (entry), TRUE);
++        gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
++                                    (GdmTaskListForeachFunc)
++                                    reset_task,
++                                    login_window);
+ 
+         label = GTK_WIDGET (gtk_builder_get_object (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->builder, "auth-prompt-label"));
+         gtk_label_set_text (GTK_LABEL (label), "");
+@@ -667,7 +819,10 @@ reset_dialog (GdmGreeterLoginWindow *login_window,
+         if (can_jump_to_authenticate (login_window)) {
+                 /* If we don't have a user list jump straight to authenticate */
+                 g_debug ("GdmGreeterLoginWindow: jumping straight to authenticate");
+-                switch_mode (login_window, MODE_AUTHENTICATION);
++
++                g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED],
++                               0, GDM_USER_CHOOSER_USER_OTHER);
++                begin_verification (login_window);
+         } else {
+                 switch_mode (login_window, dialog_mode);
+         }
+@@ -683,88 +838,177 @@ reset_dialog (GdmGreeterLoginWindow *login_window,
  }
  
  static void
--- 
-1.6.5.2
-
-
-From 860e0693230b5d12c34eb055f3d1c9e90a7efe21 Mon Sep 17 00:00:00 2001
-From: Ray Strode <rstrode at redhat.com>
-Date: Thu, 5 Feb 2009 15:20:25 -0500
-Subject: [PATCH 10/45] Queue a greeter reset when the user clicks cancel
-
----
- daemon/gdm-simple-slave.c |   37 +++++++++++++++++++++++++++++++++++++
- 1 files changed, 37 insertions(+), 0 deletions(-)
-
-diff --git a/daemon/gdm-simple-slave.c b/daemon/gdm-simple-slave.c
-index 20fe4ab..bb6097b 100644
---- a/daemon/gdm-simple-slave.c
-+++ b/daemon/gdm-simple-slave.c
-@@ -829,6 +829,9 @@ on_greeter_start_conversation (GdmGreeterServer *greeter_server,
-                                GdmSimpleSlave   *slave)
- {
-         g_debug ("GdmSimpleSlave: starting conversation with '%s' pam service'", service_name);
-+        if (slave->priv->greeter_reset_id > 0) {
-+                return;
-+        }
-         gdm_session_start_conversation (GDM_SESSION (slave->priv->session),
-                                         service_name);
- }
-@@ -839,6 +842,9 @@ on_greeter_begin_verification (GdmGreeterServer *greeter_server,
-                                GdmSimpleSlave   *slave)
+-do_cancel (GdmGreeterLoginWindow *login_window)
++restart_conversations (GdmGreeterLoginWindow *login_window)
  {
-         g_debug ("GdmSimpleSlave: begin verification");
-+        if (slave->priv->greeter_reset_id > 0) {
-+                return;
-+        }
-         gdm_session_setup (GDM_SESSION (slave->priv->session),
-                            service_name);
+-        /* need to wait for response from backend */
+-        set_message (login_window, _("Cancelling…"));
+         set_busy (login_window);
+         set_sensitive (login_window, FALSE);
+         g_signal_emit (login_window, signals[CANCELLED], 0);
  }
-@@ -849,6 +855,9 @@ on_greeter_begin_auto_login (GdmGreeterServer *greeter_server,
-                              GdmSimpleSlave   *slave)
+ 
++static void
++do_cancel (GdmGreeterLoginWindow *login_window)
++{
++        /* need to wait for response from backend */
++        set_message (login_window, _("Cancelling..."));
++        restart_conversations (login_window);
++}
++
+ gboolean
+-gdm_greeter_login_window_ready (GdmGreeterLoginWindow *login_window)
++gdm_greeter_login_window_ready (GdmGreeterLoginWindow *login_window,
++                                const char            *service_name)
  {
-         g_debug ("GdmSimpleSlave: begin auto login for user '%s'", username);
-+        if (slave->priv->greeter_reset_id > 0) {
-+                return;
++        GdmTask *task;
++
+         g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
+ 
++        task = find_task_with_service_name (login_window, service_name);
++
++        if (task != NULL) {
++                if (gdm_chooser_widget_is_loaded (GDM_CHOOSER_WIDGET (login_window->priv->user_chooser))) {
++                        gdm_conversation_set_ready (GDM_CONVERSATION (task));
++                } else {
++                        login_window->priv->tasks_to_enable = g_list_prepend (login_window->priv->tasks_to_enable, task);
++                }
++                g_object_unref (task);
 +        }
-         gdm_session_setup_for_user (GDM_SESSION (slave->priv->session),
-                                     "gdm-autologin",
-                                     username);
-@@ -861,6 +870,9 @@ on_greeter_begin_verification_for_user (GdmGreeterServer *greeter_server,
-                                         GdmSimpleSlave   *slave)
++
+         set_sensitive (GDM_GREETER_LOGIN_WINDOW (login_window), TRUE);
+         set_ready (GDM_GREETER_LOGIN_WINDOW (login_window));
+         set_focus (GDM_GREETER_LOGIN_WINDOW (login_window));
+ 
+-        /* If we are retrying a previously selected user */
+-        if (!login_window->priv->user_list_disabled &&
+-            login_window->priv->dialog_mode == MODE_AUTHENTICATION) {
+-                retry_login (login_window);
+-        } else {
+-                /* If the user list is disabled, then start the PAM conversation */
+-                if (can_jump_to_authenticate (login_window)) {
+-                        g_debug ("Starting PAM conversation since user list disabled");
+-                        g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED],
+-                                       0, GDM_USER_CHOOSER_USER_OTHER);
+-                        g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0);
+-                }
++        /* If the user list is disabled, then start the PAM conversation */
++        if (can_jump_to_authenticate (login_window)) {
++                g_debug ("Starting PAM conversation since user list disabled or no local users");
++                g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED],
++                               0, GDM_USER_CHOOSER_USER_OTHER);
++                begin_verification (login_window);
+         }
+ 
+         return TRUE;
+ }
+ 
+ gboolean
+-gdm_greeter_login_window_authentication_failed (GdmGreeterLoginWindow *login_window)
++gdm_greeter_login_window_conversation_stopped (GdmGreeterLoginWindow *login_window,
++                                               const char            *service_name)
  {
-         g_debug ("GdmSimpleSlave: begin verification");
-+        if (slave->priv->greeter_reset_id > 0) {
-+                return;
++        GdmTask *task;
++
+         g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
+ 
+-        g_debug ("GdmGreeterLoginWindow: got authentication failed");
++        g_debug ("GdmGreeterLoginWindow: conversation '%s' has stopped", service_name);
++
++        /* If the password conversation failed, then start over
++         *
++         * FIXME: we need to get this policy out of the source code
++         */
++        if (strcmp (service_name, "gdm-password") == 0) {
++                g_debug ("GdmGreeterLoginWindow: main conversation failed, starting over");
++                restart_conversations (login_window);
++                return TRUE;
 +        }
-         gdm_session_setup_for_user (GDM_SESSION (slave->priv->session),
-                                     service_name,
-                                     username);
-@@ -872,6 +884,9 @@ on_greeter_answer (GdmGreeterServer *greeter_server,
-                    const char       *text,
-                    GdmSimpleSlave   *slave)
- {
-+        if (slave->priv->greeter_reset_id > 0) {
-+                return;
++
++        task = find_task_with_service_name (login_window, service_name);
++
++        if (task != NULL) {
++                gdm_conversation_reset (GDM_CONVERSATION (task));
++                g_object_unref (task);
 +        }
-         gdm_session_answer_query (GDM_SESSION (slave->priv->session), service_name, text);
++
++        /* If every conversation has failed, then just start over.
++         */
++        task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
++
++        if (!gdm_task_is_enabled (task)) {
++                g_debug ("GdmGreeterLoginWindow: No conversations left, starting over");
++                restart_conversations (login_window);
++        }
++        g_object_unref (task);
+ 
+-        /* FIXME: shake? */
+-        reset_dialog (login_window, MODE_AUTHENTICATION);
++        update_conversation_list_visibility (login_window);
+ 
+         return TRUE;
  }
  
-@@ -880,6 +895,9 @@ on_greeter_session_selected (GdmGreeterServer *greeter_server,
-                              const char       *text,
-                              GdmSimpleSlave   *slave)
- {
-+        if (slave->priv->greeter_reset_id > 0) {
-+                return;
++static gboolean
++restart_task_conversation (GdmTaskList           *task_list,
++                           GdmTask               *task,
++                           GdmGreeterLoginWindow *login_window)
++{
++        char *service_name;
++
++        service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (task));
++        if (service_name != NULL) {
++                char *name;
++
++                name = gdm_task_get_name (task);
++                g_debug ("GdmGreeterLoginWindow: restarting '%s' conversation", name);
++                g_free (name);
++
++                g_signal_emit (login_window, signals[START_CONVERSATION], 0, service_name);
++                g_free (service_name);
 +        }
-         gdm_session_select_session (GDM_SESSION (slave->priv->session), text);
++
++        return FALSE;
++}
++
+ gboolean
+ gdm_greeter_login_window_reset (GdmGreeterLoginWindow *login_window)
+ {
++        g_debug ("GdmGreeterLoginWindow: window reset");
++
+         g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
++        reset_dialog (GDM_GREETER_LOGIN_WINDOW (login_window), MODE_SELECTION);
+ 
+-        g_debug ("GdmGreeterLoginWindow: got reset");
+-        reset_dialog (login_window, MODE_SELECTION);
++        gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
++                                    (GdmTaskListForeachFunc)
++                                    restart_task_conversation,
++                                    login_window);
+ 
+         return TRUE;
  }
  
-@@ -888,6 +906,9 @@ on_greeter_language_selected (GdmGreeterServer *greeter_server,
-                               const char       *text,
-                               GdmSimpleSlave   *slave)
+ gboolean
+ gdm_greeter_login_window_info (GdmGreeterLoginWindow *login_window,
++                               const char            *service_name,
+                                const char            *text)
  {
-+        if (slave->priv->greeter_reset_id > 0) {
-+                return;
+-        g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
++        GdmTask *task;
+ 
++        g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
+         g_debug ("GdmGreeterLoginWindow: info: %s", text);
+ 
+-        set_message (GDM_GREETER_LOGIN_WINDOW (login_window), text);
++        task = find_task_with_service_name (login_window, service_name);
++
++        if (task != NULL) {
++                gdm_conversation_set_message (GDM_CONVERSATION (task),
++                                              text);
++                show_task_actions (task);
++                g_object_unref (task);
 +        }
-         gdm_session_select_language (GDM_SESSION (slave->priv->session), text);
+ 
+         return TRUE;
  }
  
-@@ -896,6 +917,9 @@ on_greeter_layout_selected (GdmGreeterServer *greeter_server,
-                             const char       *text,
-                             GdmSimpleSlave   *slave)
+ gboolean
+ gdm_greeter_login_window_problem (GdmGreeterLoginWindow *login_window,
++                                  const char            *service_name,
+                                   const char            *text)
  {
-+        if (slave->priv->greeter_reset_id > 0) {
-+                return;
+-        g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
++        GdmTask *task;
+ 
++        g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
+         g_debug ("GdmGreeterLoginWindow: problem: %s", text);
+ 
+-        set_message (GDM_GREETER_LOGIN_WINDOW (login_window), text);
+-        gdk_window_beep (gtk_widget_get_window (GTK_WIDGET (login_window)));
++        task = find_task_with_service_name (login_window, service_name);
++
++        if (task != NULL) {
++                gdm_conversation_set_message (GDM_CONVERSATION (task),
++                                              text);
++                show_task_actions (task);
++                g_object_unref (task);
 +        }
-         gdm_session_select_layout (GDM_SESSION (slave->priv->session), text);
++
++        gdk_window_beep (GTK_WIDGET (login_window)->window);
+ 
+         return TRUE;
+ }
+@@ -788,6 +1032,26 @@ request_timed_login (GdmGreeterLoginWindow *login_window)
+         login_window->priv->timed_login_already_enabled = TRUE;
  }
  
-@@ -912,7 +936,11 @@ on_greeter_cancel (GdmGreeterServer *greeter_server,
-                    GdmSimpleSlave   *slave)
- {
-         g_debug ("GdmSimpleSlave: Greeter cancelled");
-+        if (slave->priv->greeter_reset_id > 0) {
-+                return;
++gboolean
++gdm_greeter_login_window_service_unavailable (GdmGreeterLoginWindow *login_window,
++                                              const char            *service_name)
++{
++        GdmTask *task;
++
++        g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
++        g_debug ("GdmGreeterLoginWindow: service unavailable: %s", service_name);
++
++        task = find_task_with_service_name (login_window, service_name);
++
++        if (task != NULL) {
++                gdm_task_list_remove_task (GDM_TASK_LIST (login_window->priv->conversation_list),
++                                           task);
++                g_object_unref (task);
 +        }
-         reset_session (slave);
-+        queue_greeter_reset (slave);
++
++        return TRUE;
++}
++
+ void
+ gdm_greeter_login_window_request_timed_login (GdmGreeterLoginWindow *login_window,
+                                               const char            *username,
+@@ -815,11 +1079,21 @@ gdm_greeter_login_window_request_timed_login (GdmGreeterLoginWindow *login_windo
  }
  
  static void
-@@ -922,6 +950,9 @@ on_greeter_connected (GdmGreeterServer *greeter_server,
-         gboolean display_is_local;
+-gdm_greeter_login_window_start_session_when_ready (GdmGreeterLoginWindow *login_window)
++on_ready_to_start_session (GdmGreeterLoginWindow *login_window,
++                           GParamSpec            *param_spec,
++                           char                  *service_name)
++{
++        gdm_greeter_login_window_start_session_when_ready (login_window, service_name);
++        g_free (service_name);
++}
++
++static void
++gdm_greeter_login_window_start_session_when_ready (GdmGreeterLoginWindow *login_window,
++                                                   const char            *service_name)
+ {
+         if (login_window->priv->is_interactive) {
+                 g_debug ("GdmGreeterLoginWindow: starting session");
+-                g_signal_emit (login_window, signals[START_SESSION], 0);
++                g_signal_emit (login_window, signals[START_SESSION], 0, service_name);
+         } else {
+                 g_debug ("GdmGreeterLoginWindow: not starting session since "
+                          "user hasn't had an opportunity to pick language "
+@@ -829,8 +1103,8 @@ gdm_greeter_login_window_start_session_when_ready (GdmGreeterLoginWindow *login_
+                  */
+                 login_window->priv->start_session_handler_id =
+                     g_signal_connect (login_window, "notify::is-interactive",
+-                                      G_CALLBACK (gdm_greeter_login_window_start_session_when_ready),
+-                                      NULL);
++                                      G_CALLBACK (on_ready_to_start_session),
++                                      g_strdup (service_name));
  
-         g_debug ("GdmSimpleSlave: Greeter connected");
-+        if (slave->priv->greeter_reset_id > 0) {
-+                return;
-+        }
+                 /* FIXME: If the user wasn't asked any questions by pam but
+                  * pam still authorized them (passwd -d, or the questions got
+@@ -853,10 +1127,10 @@ gdm_greeter_login_window_start_session_when_ready (GdmGreeterLoginWindow *login_
  
-         g_object_get (slave,
-                       "display-is-local", &display_is_local,
-@@ -939,6 +970,9 @@ on_start_session_when_ready (GdmGreeterServer *session,
-                              GdmSimpleSlave   *slave)
+ gboolean
+ gdm_greeter_login_window_info_query (GdmGreeterLoginWindow *login_window,
++                                     const char            *service_name,
+                                      const char            *text)
  {
-         g_debug ("GdmSimpleSlave: Will start session when ready");
-+        if (slave->priv->greeter_reset_id > 0) {
-+                return;
-+        }
-         slave->priv->start_session_when_ready = TRUE;
+-        GtkWidget  *entry;
+-        GtkWidget  *label;
++        GdmTask *task;
  
-         if (slave->priv->waiting_to_start_session) {
-@@ -952,6 +986,9 @@ on_start_session_later (GdmGreeterServer *session,
-                         GdmSimpleSlave   *slave)
- {
-         g_debug ("GdmSimpleSlave: Will start session when ready and told");
-+        if (slave->priv->greeter_reset_id > 0) {
-+                return;
-+        }
-         slave->priv->start_session_when_ready = FALSE;
- }
+         g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
  
--- 
-1.6.5.2
-
-
-From a1f313574eff7776a6b8cce3cd4dfb60afdb5c14 Mon Sep 17 00:00:00 2001
-From: Ray Strode <rstrode at redhat.com>
-Date: Fri, 6 Feb 2009 16:23:48 -0500
-Subject: [PATCH 11/45] Add a plugin based extension system to greeter
-
-This allows plugins to drive which PAM conversations
-get run.  This commit just adds one plugin "password"
-which does the one PAM conversation we've traditionally
-run.
----
- configure.ac                                       |   44 ++
- gui/simple-greeter/Makefile.am                     |   15 +
- gui/simple-greeter/gdm-greeter-client.c            |   21 +
- gui/simple-greeter/gdm-greeter-client.h            |    2 +
- gui/simple-greeter/gdm-greeter-login-window.c      |  672 ++++++++++++++++----
- gui/simple-greeter/gdm-greeter-login-window.h      |   21 +-
- gui/simple-greeter/gdm-greeter-login-window.ui     |   49 +--
- gui/simple-greeter/gdm-greeter-plugin.c            |  255 ++++++++
- gui/simple-greeter/gdm-greeter-plugin.h            |   61 ++
- gui/simple-greeter/gdm-greeter-session.c           |   91 +++-
- gui/simple-greeter/gdm-plugin-manager.c            |  478 ++++++++++++++
- gui/simple-greeter/gdm-plugin-manager.h            |   66 ++
- gui/simple-greeter/gdm-task-list.c                 |  223 +++++--
- gui/simple-greeter/gdm-task-list.h                 |   36 +-
- gui/simple-greeter/libgdmsimplegreeter/Makefile.am |   46 ++
- .../libgdmsimplegreeter/gdm-conversation.c         |  147 +++++
- .../libgdmsimplegreeter/gdm-conversation.h         |   87 +++
- .../libgdmsimplegreeter/gdm-greeter-extension.c    |   93 +++
- .../libgdmsimplegreeter/gdm-greeter-extension.h    |   55 ++
- gui/simple-greeter/libgdmsimplegreeter/gdm-task.c  |  117 ++++
- gui/simple-greeter/libgdmsimplegreeter/gdm-task.h  |   62 ++
- .../libgdmsimplegreeter/gdmsimplegreeter.pc.in     |   11 +
- gui/simple-greeter/plugins/Makefile.am             |    1 +
- gui/simple-greeter/plugins/password/Makefile.am    |   53 ++
- .../plugins/password/gdm-password-extension.c      |  314 +++++++++
- .../plugins/password/gdm-password-extension.h      |   56 ++
- .../plugins/password/gdm-password.pam              |   19 +
- gui/simple-greeter/plugins/password/page.ui        |   56 ++
- gui/simple-greeter/plugins/password/plugin.c       |   40 ++
- po/POTFILES.in                                     |    1 +
- 30 files changed, 2955 insertions(+), 237 deletions(-)
- create mode 100644 gui/simple-greeter/gdm-greeter-plugin.c
- create mode 100644 gui/simple-greeter/gdm-greeter-plugin.h
- create mode 100644 gui/simple-greeter/gdm-plugin-manager.c
- create mode 100644 gui/simple-greeter/gdm-plugin-manager.h
- create mode 100644 gui/simple-greeter/libgdmsimplegreeter/Makefile.am
- create mode 100644 gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c
- create mode 100644 gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h
- create mode 100644 gui/simple-greeter/libgdmsimplegreeter/gdm-greeter-extension.c
- create mode 100644 gui/simple-greeter/libgdmsimplegreeter/gdm-greeter-extension.h
- create mode 100644 gui/simple-greeter/libgdmsimplegreeter/gdm-task.c
- create mode 100644 gui/simple-greeter/libgdmsimplegreeter/gdm-task.h
- create mode 100644 gui/simple-greeter/libgdmsimplegreeter/gdmsimplegreeter.pc.in
- create mode 100644 gui/simple-greeter/plugins/Makefile.am
- create mode 100644 gui/simple-greeter/plugins/password/Makefile.am
- create mode 100644 gui/simple-greeter/plugins/password/gdm-password-extension.c
- create mode 100644 gui/simple-greeter/plugins/password/gdm-password-extension.h
- create mode 100644 gui/simple-greeter/plugins/password/gdm-password.pam
- create mode 100644 gui/simple-greeter/plugins/password/page.ui
- create mode 100644 gui/simple-greeter/plugins/password/plugin.c
-
-diff --git a/configure.ac b/configure.ac
-index 5bff081..ae0c399 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -18,6 +18,22 @@ AC_PROG_CXX
- AM_PROG_CC_C_O
- AC_PROG_LIBTOOL()
+@@ -865,15 +1139,15 @@ gdm_greeter_login_window_info_query (GdmGreeterLoginWindow *login_window,
  
-+## increment if the plugin interface has additions, changes, removals.
-+LT_CURRENT=1
-+
-+## increment any time the source changes; set to
-+##  0 if you increment CURRENT
-+LT_REVISION=0
-+
-+## increment if any interfaces have been added; set to 0
-+## if any interfaces have been changed or removed. removal has
-+## precedence over adding, so set to 0 if both happened.
-+LT_AGE=0
-+
-+AC_SUBST(LT_CURRENT)
-+AC_SUBST(LT_REVISION)
-+AC_SUBST(LT_AGE)
-+
- AC_HEADER_STDC
+         g_debug ("GdmGreeterLoginWindow: info query: %s", text);
  
- AC_SUBST(VERSION)
-@@ -193,6 +209,15 @@ AC_ARG_WITH(dmconfdir,
- AC_SUBST(dmconfdir)
+-        entry = GTK_WIDGET (gtk_builder_get_object (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->builder, "auth-prompt-entry"));
+-        gtk_editable_delete_text (GTK_EDITABLE (entry), 0, -1);
+-        gtk_entry_set_visibility (GTK_ENTRY (entry), TRUE);
+-        set_log_in_button_mode (login_window, LOGIN_BUTTON_ANSWER_QUERY);
++        task = find_task_with_service_name (login_window, service_name);
  
- dnl ---------------------------------------------------------------------------
-+dnl - Configuration file stuff
-+dnl ---------------------------------------------------------------------------
-+AC_ARG_WITH(extensionsdatadir,
-+            AS_HELP_STRING([--with-extensions-datadir],
-+                           [directory where extensions store data, default=DATADIR/gdm/simple-greeter/extensions]),
-+            extensionsdatadir=${withval}, extensionsdatadir=${datadir}/gdm/simple-greeter/extensions)
-+AC_SUBST(extensionsdatadir)
+-        label = GTK_WIDGET (gtk_builder_get_object (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->builder, "auth-prompt-label"));
+-        gtk_label_set_text (GTK_LABEL (label), text);
++        if (task != NULL) {
++                gdm_conversation_ask_question (GDM_CONVERSATION (task),
++                                               text);
++                g_object_unref (task);
++        }
+ 
+-        show_widget (login_window, "auth-input-box", TRUE);
++        set_log_in_button_mode (login_window, LOGIN_BUTTON_ANSWER_QUERY);
+         set_sensitive (GDM_GREETER_LOGIN_WINDOW (login_window), TRUE);
+         set_ready (GDM_GREETER_LOGIN_WINDOW (login_window));
+         set_focus (GDM_GREETER_LOGIN_WINDOW (login_window));
+@@ -885,25 +1159,26 @@ gdm_greeter_login_window_info_query (GdmGreeterLoginWindow *login_window,
+ 
+ gboolean
+ gdm_greeter_login_window_secret_info_query (GdmGreeterLoginWindow *login_window,
++                                            const char            *service_name,
+                                             const char            *text)
+ {
+-        GtkWidget  *entry;
+-        GtkWidget  *label;
 +
-+dnl ---------------------------------------------------------------------------
- dnl - Configure arguments
- dnl ---------------------------------------------------------------------------
++        GdmTask *task;
  
-@@ -1263,6 +1288,21 @@ fi
+         g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
  
- AC_SUBST(GDM_SCREENSHOT_DIR)
+         login_window->priv->num_queries++;
+         maybe_show_cancel_button (login_window);
  
-+dnl ---------------------------------------------------------------------------
-+dnl - Directory for simple greeter plugins
-+dnl ---------------------------------------------------------------------------
-+
-+AC_ARG_WITH(simple-greeter-plugins-dir,
-+            AS_HELP_STRING([--with-simple-greeter-plugins-dir=<dir>],
-+                           [simple greeter plugins directory]))
-+
-+if ! test -z "$with_simple_greeter_plugins_dir"; then
-+   GDM_SIMPLE_GREETER_PLUGINS_DIR=$with_simple_greeter_plugins_dir
-+else
-+   GDM_SIMPLE_GREETER_PLUGINS_DIR=${libdir}/gdm/simple-greeter/plugins
-+fi
-+
-+AC_SUBST(GDM_SIMPLE_GREETER_PLUGINS_DIR)
+-        entry = GTK_WIDGET (gtk_builder_get_object (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->builder, "auth-prompt-entry"));
+-        gtk_editable_delete_text (GTK_EDITABLE (entry), 0, -1);
+-        gtk_entry_set_visibility (GTK_ENTRY (entry), FALSE);
+-        set_log_in_button_mode (login_window, LOGIN_BUTTON_ANSWER_QUERY);
++        task = find_task_with_service_name (login_window, service_name);
  
- dnl ---------------------------------------------------------------------------
- dnl - Finish
-@@ -1391,6 +1431,10 @@ docs/Makefile
- gui/Makefile
- gui/simple-greeter/Makefile
- gui/simple-greeter/libnotificationarea/Makefile
-+gui/simple-greeter/libgdmsimplegreeter/Makefile
-+gui/simple-greeter/libgdmsimplegreeter/gdmsimplegreeter.pc
-+gui/simple-greeter/plugins/Makefile
-+gui/simple-greeter/plugins/password/Makefile
- gui/simple-chooser/Makefile
- gui/user-switch-applet/Makefile
- utils/Makefile
-diff --git a/gui/simple-greeter/Makefile.am b/gui/simple-greeter/Makefile.am
-index f62702b..d486535 100644
---- a/gui/simple-greeter/Makefile.am
-+++ b/gui/simple-greeter/Makefile.am
-@@ -2,11 +2,14 @@ NULL =
+-        label = GTK_WIDGET (gtk_builder_get_object (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->builder, "auth-prompt-label"));
+-        gtk_label_set_text (GTK_LABEL (label), text);
++        if (task != NULL) {
++                gdm_conversation_ask_secret (GDM_CONVERSATION (task),
++                                             text);
++                g_object_unref (task);
++        }
  
- SUBDIRS = 				\
- 	libnotificationarea		\
-+	libgdmsimplegreeter		\
-+	plugins				\
- 	$(NULL)
+-        show_widget (login_window, "auth-input-box", TRUE);
++        set_log_in_button_mode (login_window, LOGIN_BUTTON_ANSWER_QUERY);
+         set_sensitive (GDM_GREETER_LOGIN_WINDOW (login_window), TRUE);
+         set_ready (GDM_GREETER_LOGIN_WINDOW (login_window));
+         set_focus (GDM_GREETER_LOGIN_WINDOW (login_window));
+@@ -914,13 +1189,16 @@ gdm_greeter_login_window_secret_info_query (GdmGreeterLoginWindow *login_window,
+ }
  
- AM_CPPFLAGS = \
- 	-I$(top_srcdir)/common				\
- 	-I$(top_srcdir)/gui/simple-greeter/libnotificationarea	\
-+	-I$(top_srcdir)/gui/simple-greeter/libgdmsimplegreeter	\
- 	-DDMCONFDIR=\""$(dmconfdir)"\"			\
- 	-DGDMCONFDIR=\"$(gdmconfdir)\"                  \
- 	-DDATADIR=\""$(datadir)"\"		 	\
-@@ -20,6 +23,7 @@ AM_CPPFLAGS = \
- 	-DAT_SPI_REGISTRYD_DIR="\"$(AT_SPI_REGISTRYD_DIR)\""	\
- 	$(DEVKIT_POWER_CFLAGS)				\
- 	-DI_KNOW_THE_DEVICEKIT_POWER_API_IS_SUBJECT_TO_CHANGE	\
-+	-DGDM_SIMPLE_GREETER_PLUGINS_DIR="\"$(GDM_SIMPLE_GREETER_PLUGINS_DIR)\""\
- 	$(DISABLE_DEPRECATED_CFLAGS)			\
- 	$(GTK_CFLAGS)					\
- 	$(SIMPLE_GREETER_CFLAGS)			\
-@@ -87,10 +91,15 @@ test_greeter_login_window_SOURCES = 	\
- 	gdm-user-chooser-dialog.c	\
- 	gdm-task-list.h			\
- 	gdm-task-list.c			\
-+	gdm-plugin-manager.h		\
-+	gdm-plugin-manager.c		\
-+	gdm-greeter-plugin.h		\
-+	gdm-greeter-plugin.c		\
- 	$(NULL)
+ void
+-gdm_greeter_login_window_user_authorized (GdmGreeterLoginWindow *login_window)
++gdm_greeter_login_window_user_authorized (GdmGreeterLoginWindow *login_window,
++                                          const char            *service_name)
+ {
+         g_return_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window));
  
- test_greeter_login_window_LDADD =	\
- 	$(top_builddir)/common/libgdmcommon.la	\
-+	$(top_builddir)/gui/simple-greeter/libgdmsimplegreeter/libgdmsimplegreeter.la	\
- 	libgdmuser.la			\
- 	$(COMMON_LIBS)			\
- 	$(SIMPLE_GREETER_LIBS)		\
-@@ -141,6 +150,7 @@ test_greeter_panel_SOURCES = 	\
- test_greeter_panel_LDADD =	\
- 	$(top_builddir)/common/libgdmcommon.la	\
- 	$(top_builddir)/gui/simple-greeter/libnotificationarea/libnotificationarea.la	\
-+	$(top_builddir)/gui/simple-greeter/libgdmsimplegreeter/libgdmsimplegreeter.la	\
- 	$(SIMPLE_GREETER_LIBS)		\
- 	$(GTK_LIBS)			\
- 	$(GCONF_LIBS)			\
-@@ -316,10 +326,14 @@ gdm_simple_greeter_SOURCES =  		\
- 	gdm-language-chooser-dialog.c	\
- 	gdm-language-option-widget.h	\
- 	gdm-language-option-widget.c	\
-+	gdm-plugin-manager.h		\
-+	gdm-plugin-manager.c		\
- 	gdm-sessions.h			\
- 	gdm-sessions.c			\
- 	gdm-session-option-widget.h	\
- 	gdm-session-option-widget.c	\
-+	gdm-greeter-plugin.h		\
-+	gdm-greeter-plugin.c		\
- 	gdm-user-chooser-widget.h	\
- 	gdm-user-chooser-widget.c	\
- 	gdm-task-list.h			\
-@@ -330,6 +344,7 @@ gdm_simple_greeter_LDADD = 		\
- 	$(top_builddir)/common/libgdmcommon.la	\
- 	libgdmuser.la			\
- 	$(top_builddir)/gui/simple-greeter/libnotificationarea/libnotificationarea.la	\
-+	$(top_builddir)/gui/simple-greeter/libgdmsimplegreeter/libgdmsimplegreeter.la	\
- 	$(COMMON_LIBS)			\
- 	$(EXTRA_GREETER_LIBS)   	\
- 	$(SIMPLE_GREETER_LIBS)		\
-diff --git a/gui/simple-greeter/gdm-greeter-client.c b/gui/simple-greeter/gdm-greeter-client.c
-index 0891e8b..12572fe 100644
---- a/gui/simple-greeter/gdm-greeter-client.c
-+++ b/gui/simple-greeter/gdm-greeter-client.c
-@@ -64,6 +64,7 @@ enum {
-         INFO_QUERY,
-         SECRET_INFO_QUERY,
-         READY,
-+        CONVERSATION_STOPPED,
-         RESET,
-         SELECTED_USER_CHANGED,
-         DEFAULT_LANGUAGE_NAME_CHANGED,
-@@ -270,6 +271,13 @@ on_ready (GdmGreeterClient *client,
+-        g_debug ("GdmGreeterLoginWindow: user now authorized");
++        g_debug ("GdmGreeterLoginWindow: user now authorized via service %s",
++                  service_name);
+ 
+-        gdm_greeter_login_window_start_session_when_ready (login_window);
++        gdm_greeter_login_window_start_session_when_ready (login_window,
++                                                           service_name);
  }
  
  static void
-+on_conversation_stopped (GdmGreeterClient *client,
-+                         DBusMessage      *message)
+@@ -991,6 +1269,49 @@ on_user_chooser_visibility_changed (GdmGreeterLoginWindow *login_window)
+         update_banner_message (login_window);
+ }
+ 
++static gboolean
++begin_task_verification_for_selected_user (GdmTaskList           *task_list,
++                                           GdmTask               *task,
++                                           GdmGreeterLoginWindow *login_window)
 +{
-+        emit_string_signal_for_message (client, "ConversationStopped", message, CONVERSATION_STOPPED);
-+}
++        char *user_name;
++        char *service_name;
 +
-+static void
- on_reset (GdmGreeterClient *client,
-           DBusMessage      *message)
- {
-@@ -760,6 +768,8 @@ client_dbus_handle_message (DBusConnection *connection,
-                 on_problem (client, message);
-         } else if (dbus_message_is_signal (message, GREETER_SERVER_DBUS_INTERFACE, "Ready")) {
-                 on_ready (client, message);
-+        } else if (dbus_message_is_signal (message, GREETER_SERVER_DBUS_INTERFACE, "ConversationStopped")) {
-+                on_conversation_stopped (client, message);
-         } else if (dbus_message_is_signal (message, GREETER_SERVER_DBUS_INTERFACE, "Reset")) {
-                 on_reset (client, message);
-         } else if (dbus_message_is_signal (message, GREETER_SERVER_DBUS_INTERFACE, "SelectedUserChanged")) {
-@@ -1000,6 +1010,17 @@ gdm_greeter_client_class_init (GdmGreeterClientClass *klass)
-                               G_TYPE_NONE,
-                               1, G_TYPE_STRING);
- 
-+        gdm_greeter_client_signals[CONVERSATION_STOPPED] =
-+                g_signal_new ("conversation-stopped",
-+                              G_OBJECT_CLASS_TYPE (object_class),
-+                              G_SIGNAL_RUN_FIRST,
-+                              G_STRUCT_OFFSET (GdmGreeterClientClass, conversation_stopped),
-+                              NULL,
-+                              NULL,
-+                              g_cclosure_marshal_VOID__STRING,
-+                              G_TYPE_NONE,
-+                              1, G_TYPE_STRING);
++        user_name = gdm_user_chooser_widget_get_chosen_user_name (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser));
 +
-         gdm_greeter_client_signals[RESET] =
-                 g_signal_new ("reset",
-                               G_OBJECT_CLASS_TYPE (object_class),
-diff --git a/gui/simple-greeter/gdm-greeter-client.h b/gui/simple-greeter/gdm-greeter-client.h
-index 2f857dc..f879307 100644
---- a/gui/simple-greeter/gdm-greeter-client.h
-+++ b/gui/simple-greeter/gdm-greeter-client.h
-@@ -61,6 +61,8 @@ typedef struct
-                                           const char        *problem);
-         void (* ready)                   (GdmGreeterClient  *client,
-                                           const char        *service_name);
-+        void (* conversation_stopped)    (GdmGreeterClient  *client,
-+                                          const char        *service_name);
-         void (* reset)                   (GdmGreeterClient  *client);
-         void (* selected_user_changed)   (GdmGreeterClient  *client,
-                                           const char        *username);
-diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
-index 949494b..6becaa0 100644
---- a/gui/simple-greeter/gdm-greeter-login-window.c
-+++ b/gui/simple-greeter/gdm-greeter-login-window.c
-@@ -1,7 +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) 2008 Red Hat, Inc.
-+ * Copyright (C) 2008, 2009 Red Hat, Inc.
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -17,6 +17,9 @@
-  * along with this program; if not, write to the Free Software
-  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-  *
-+ * Written by: William Jon McCann <mccann at jhu.edu>
-+ *             Ray Strode <rstrode at redhat.com>
-+ *
-  */
- 
- #include "config.h"
-@@ -106,6 +109,7 @@ struct GdmGreeterLoginWindowPrivate
-         GtkWidget       *user_chooser;
-         GtkWidget       *conversation_list;
-         GtkWidget       *auth_banner_label;
-+        GtkWidget       *auth_page_box;
-         guint            display_is_local : 1;
-         guint            is_interactive : 1;
-         guint            user_chooser_loaded : 1;
-@@ -161,6 +165,8 @@ static void     on_user_unchosen            (GdmUserChooserWidget *user_chooser,
- static void     switch_mode                 (GdmGreeterLoginWindow *login_window,
-                                              int                    number);
- static void     update_banner_message       (GdmGreeterLoginWindow *login_window);
-+static void     gdm_greeter_login_window_start_session_when_ready (GdmGreeterLoginWindow *login_window,
-+                                                                   const char            *service_name);
- 
- G_DEFINE_TYPE (GdmGreeterLoginWindow, gdm_greeter_login_window, GTK_TYPE_WINDOW)
- 
-@@ -186,9 +192,6 @@ set_sensitive (GdmGreeterLoginWindow *login_window,
- {
-         GtkWidget *box;
- 
--        box = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "auth-input-box"));
--        gtk_widget_set_sensitive (box, sensitive);
--
-         box = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "buttonbox"));
-         gtk_widget_set_sensitive (box, sensitive);
- 
-@@ -198,27 +201,43 @@ set_sensitive (GdmGreeterLoginWindow *login_window,
- static void
- set_focus (GdmGreeterLoginWindow *login_window)
- {
--        GtkWidget *entry;
--
--        entry = GTK_WIDGET (gtk_builder_get_object (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->builder, "auth-prompt-entry"));
-+        GdmTask *task;
- 
-         gdk_window_focus (GTK_WIDGET (login_window)->window, GDK_CURRENT_TIME);
- 
--        if (GTK_WIDGET_REALIZED (entry) && ! GTK_WIDGET_HAS_FOCUS (entry)) {
--                gtk_widget_grab_focus (entry);
-+        task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
++        if (user_name == NULL) {
++                return TRUE;
++        }
 +
-+        if (gdm_conversation_focus (GDM_CONVERSATION (task))) {
-+                char *name;
-+                name = gdm_task_get_name (task);
-+                g_debug ("GdmGreeterLoginWindow: focusing task %s", name);
-+                g_free (name);
-         } else if (GTK_WIDGET_REALIZED (login_window->priv->user_chooser) && ! GTK_WIDGET_HAS_FOCUS (login_window->priv->user_chooser)) {
-                 gtk_widget_grab_focus (login_window->priv->user_chooser);
-         }
-+        g_object_unref (task);
++        service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (task));
++        if (service_name != NULL) {
++                g_signal_emit (login_window, signals[BEGIN_VERIFICATION_FOR_USER], 0, service_name, user_name);
++                g_free (service_name);
++        }
++
++        g_free (user_name);
++        return FALSE;
 +}
 +
-+static gboolean
-+set_task_conversation_message (GdmTaskList *task_list,
-+                               GdmTask     *task,
-+                               const char  *message)
++static void
++enable_waiting_tasks (GdmGreeterLoginWindow *login_window)
 +{
++        GList *node;
++
++        node = login_window->priv->tasks_to_enable;
++        while (node != NULL) {
++                GdmTask *task;
++
++                task = GDM_TASK (node->data);
++
++                gdm_conversation_set_ready (GDM_CONVERSATION (task));
++
++                node = node->next;
++        }
++
++        login_window->priv->tasks_to_enable = NULL;
++}
 +
-+        gdm_conversation_set_message (GDM_CONVERSATION (task), message);
-+        return FALSE;
- }
- 
- static void
- set_message (GdmGreeterLoginWindow *login_window,
-              const char            *text)
- {
--        GtkWidget *label;
-+        g_return_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window));
- 
--        label = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "auth-message-label"));
--        gtk_label_set_text (GTK_LABEL (label), text);
-+        gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
-+                                    (GdmTaskListForeachFunc)
-+                                    set_task_conversation_message,
-+                                    (gpointer) text);
- }
- 
  static void
-@@ -353,30 +372,76 @@ sensitize_widget (GdmGreeterLoginWindow *login_window,
- }
+ on_users_loaded (GdmUserChooserWidget  *user_chooser,
+                  GdmGreeterLoginWindow *login_window)
+@@ -1004,38 +1325,153 @@ on_users_loaded (GdmUserChooserWidget  *user_chooser,
+                 gtk_widget_show (login_window->priv->user_chooser);
+         }
  
- static void
--on_login_button_clicked_answer_query (GtkButton             *button,
--                                      GdmGreeterLoginWindow *login_window)
-+on_login_button_clicked_timed_login (GtkButton             *button,
-+                                     GdmGreeterLoginWindow *login_window)
- {
--        GtkWidget  *entry;
--        const char *text;
++        enable_waiting_tasks (login_window);
++
+         if (login_window->priv->timed_login_username != NULL
+             && !login_window->priv->timed_login_already_enabled) {
+                 request_timed_login (login_window);
+         } else if (can_jump_to_authenticate (login_window)) {
++
+                 /* jump straight to authenticate */
+                 g_debug ("GdmGreeterLoginWindow: jumping straight to authenticate");
 -
-         set_busy (login_window);
-         set_sensitive (login_window, FALSE);
- 
--        entry = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "auth-prompt-entry"));
--        text = gtk_entry_get_text (GTK_ENTRY (entry));
+-                switch_mode (login_window, MODE_AUTHENTICATION);
 -
-         _gdm_greeter_login_window_set_interactive (login_window, TRUE);
--        g_signal_emit (login_window, signals[QUERY_ANSWER], 0, "gdm", text);
- }
- 
- static void
--on_login_button_clicked_timed_login (GtkButton             *button,
--                                     GdmGreeterLoginWindow *login_window)
-+hide_task_actions (GdmTask *task)
- {
--        set_busy (login_window);
--        set_sensitive (login_window, FALSE);
-+        GtkActionGroup *actions;
- 
--        _gdm_greeter_login_window_set_interactive (login_window, TRUE);
-+        actions = gdm_conversation_get_actions (GDM_CONVERSATION (task));
-+
-+        if (actions != NULL) {
-+                gtk_action_group_set_visible (actions, FALSE);
-+                gtk_action_group_set_sensitive (actions, FALSE);
-+                g_object_unref (actions);
+-                g_debug ("Starting PAM conversation since no local users");
+                 g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED],
+                                0, GDM_USER_CHOOSER_USER_OTHER);
+-                g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0);
++                begin_verification (login_window);
 +        }
 +}
 +
 +static void
-+grab_default_button_for_task (GdmTask *task)
++choose_user (GdmGreeterLoginWindow *login_window,
++             const char            *user_name)
 +{
-+        GtkActionGroup *actions;
-+        GtkAction *action;
-+        GSList    *proxies, *node;
++        g_assert (user_name != NULL);
++        g_debug ("GdmGreeterLoginWindow: user chosen '%s'", user_name);
 +
-+        actions = gdm_conversation_get_actions (GDM_CONVERSATION (task));
++        g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED],
++                       0, user_name);
 +
-+        if (actions == NULL) {
-+                return;
-+        }
 +
-+        action = gtk_action_group_get_action (actions, GDM_CONVERSATION_DEFAULT_ACTION);
-+        g_object_unref (actions);
++        gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
++                                    (GdmTaskListForeachFunc)
++                                    begin_task_verification_for_selected_user,
++                                    login_window);
 +
-+        if (action == NULL) {
-+                return;
-+        }
++        switch_mode (login_window, MODE_AUTHENTICATION);
++        update_conversation_list_visibility (login_window);
++}
 +
-+        proxies = gtk_action_get_proxies (action);
-+        for (node = proxies; node != NULL; node = node->next) {
-+                GtkWidget *widget;
++static void
++begin_auto_login (GdmGreeterLoginWindow *login_window)
++{
++        g_signal_emit (login_window, signals[BEGIN_AUTO_LOGIN], 0,
++                       login_window->priv->timed_login_username);
 +
-+                widget = GTK_WIDGET (node->data);
++        login_window->priv->timed_login_enabled = TRUE;
++        restart_timed_login_timeout (login_window);
 +
-+                if (GTK_WIDGET_CAN_DEFAULT (widget) &&
-+                    GTK_WIDGET_VISIBLE (widget)) {
-+                        gtk_widget_grab_default (widget);
-+                        break;
-+                }
-+        }
++        /* just wait for the user to select language and stuff */
++        set_message (login_window, _("Select language and click Log In"));
++
++        switch_mode (login_window, MODE_AUTHENTICATION);
 +
++        show_widget (login_window, "conversation-list", FALSE);
++        gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
++                                    (GdmTaskListForeachFunc) reset_task,
++                                    login_window);
 +}
 +
-+static void
-+show_task_actions (GdmTask *task)
++static gboolean
++reset_task_if_not_given (GdmTaskList *task_list,
++                         GdmTask     *task,
++                         GdmTask     *given_task)
 +{
-+        GtkActionGroup *actions;
++        if (task == given_task) {
++                return FALSE;
+         }
 +
-+        actions = gdm_conversation_get_actions (GDM_CONVERSATION (task));
++        gdm_conversation_reset (GDM_CONVERSATION (task));
++        return FALSE;
++}
 +
-+        if (actions != NULL) {
-+                gtk_action_group_set_sensitive (actions, TRUE);
-+                gtk_action_group_set_visible (actions, TRUE);
-+                g_object_unref (actions);
-+        }
++static void
++reset_every_task_but_given_task (GdmGreeterLoginWindow *login_window,
++                                 GdmTask               *task)
++{
++        gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
++                                    (GdmTaskListForeachFunc)
++                                    reset_task_if_not_given,
++                                    task);
  }
  
  static void
-@@ -384,6 +449,7 @@ set_log_in_button_mode (GdmGreeterLoginWindow *login_window,
-                         int                    mode)
- {
-         GtkWidget *button;
-+        GdmTask   *task;
- 
-         button = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "log-in-button"));
-         gtk_widget_grab_default (button);
-@@ -396,14 +462,27 @@ set_log_in_button_mode (GdmGreeterLoginWindow *login_window,
- 
-         switch (mode) {
-         case LOGIN_BUTTON_HIDDEN:
-+                task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
-+                if (task != NULL) {
-+                        hide_task_actions (task);
-+                        g_object_unref (task);
-+                }
-+
-                 gtk_widget_hide (button);
-                 break;
-         case LOGIN_BUTTON_ANSWER_QUERY:
--                login_window->priv->login_button_handler_id = g_signal_connect (button, "clicked", G_CALLBACK (on_login_button_clicked_answer_query), login_window);
--                gtk_widget_show (button);
-+                task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
-+                if (task != NULL) {
-+                        show_task_actions (task);
-+                        grab_default_button_for_task (task);
-+                        g_object_unref (task);
-+                }
+-on_user_chosen (GdmUserChooserWidget  *user_chooser,
+-                GdmGreeterLoginWindow *login_window)
++begin_single_service_verification (GdmGreeterLoginWindow *login_window,
++                                   const char            *service_name)
++{
++        GdmTask *task;
 +
-+                gtk_widget_hide (button);
-                 break;
-         case LOGIN_BUTTON_TIMED_LOGIN:
-                 login_window->priv->login_button_handler_id = g_signal_connect (button, "clicked", G_CALLBACK (on_login_button_clicked_timed_login), login_window);
++        task = find_task_with_service_name (login_window, service_name);
 +
-                 gtk_widget_show (button);
-                 break;
-         default:
-@@ -452,8 +531,7 @@ switch_mode (GdmGreeterLoginWindow *login_window,
-                 set_log_in_button_mode (login_window, LOGIN_BUTTON_HIDDEN);
- 
-                 show_widget (login_window, "cancel-button", FALSE);
--
--                show_widget (login_window, "auth-input-box", FALSE);
-+                show_widget (login_window, "auth-page-box", FALSE);
- 
-                 sensitize_widget (login_window, "disconnect-button", FALSE);
- 
-@@ -469,6 +547,7 @@ switch_mode (GdmGreeterLoginWindow *login_window,
-                 break;
-         case MODE_AUTHENTICATION:
-                 show_widget (login_window, "disconnect-button", FALSE);
-+                show_widget (login_window, "auth-page-box", TRUE);
-                 default_name = "log-in-button";
-                 break;
-         default:
-@@ -517,25 +596,54 @@ switch_mode (GdmGreeterLoginWindow *login_window,
-         }
- }
- 
--static void
--delete_entry_text (GtkWidget *entry)
-+static gboolean
-+task_has_service_name (GdmTaskList *task_list,
-+                       GdmTask     *task,
-+                       const char  *service_name)
- {
--        const char *typed_text;
--        char       *null_text;
-+        char *task_service_name;
-+        gboolean has_service_name;
++        if (task == NULL) {
++                g_debug ("GdmGreeterLoginWindow: %s has no task associated with it", service_name);
++                return;
++        }
 +
-+        task_service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (task));
++        g_debug ("GdmGreeterLoginWindow: Beginning %s auth conversation", service_name);
 +
-+        has_service_name = strcmp (service_name, task_service_name) == 0;
-+        g_free (task_service_name);
- 
--        /* try to scrub out any secret info */
--        typed_text = gtk_entry_get_text (GTK_ENTRY (entry));
--        null_text = g_strnfill (strlen (typed_text) + 1, '\b');
--        gtk_entry_set_text (GTK_ENTRY (entry), null_text);
--        gtk_entry_set_text (GTK_ENTRY (entry), "");
-+        return has_service_name;
-+}
++        /* FIXME: we should probably give the plugin more say for
++         * what happens here.
++         */
++        g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0, service_name);
 +
-+static GdmTask *
-+find_task_with_service_name (GdmGreeterLoginWindow *login_window,
-+                             const char            *service_name)
-+{
-+        GdmTask *task;
++        switch_mode (login_window, MODE_AUTHENTICATION);
++        gdm_task_list_set_active_task (GDM_TASK_LIST (login_window->priv->conversation_list), task);
 +
-+        task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
-+                                           (GdmTaskListForeachFunc)
-+                                           task_has_service_name,
-+                                           (gpointer) service_name);
++        reset_every_task_but_given_task (login_window, task);
++        g_object_unref (task);
 +
-+        return task;
++        show_widget (login_window, "conversation-list", FALSE);
 +}
 +
-+static gboolean
-+reset_task (GdmTaskList           *task_list,
-+            GdmTask               *task,
-+            GdmGreeterLoginWindow *login_window)
-+{
-+        char *name;
-+
-+        name = gdm_task_get_name (task);
-+        g_debug ("Resetting task '%s'", name);
-+        g_free (name);
-+
-+        gdm_conversation_reset (GDM_CONVERSATION (task));
-+        return FALSE;
- }
- 
- static void
- reset_dialog (GdmGreeterLoginWindow *login_window)
++static void
++on_user_chooser_activated (GdmUserChooserWidget  *user_chooser,
++                           GdmGreeterLoginWindow *login_window)
  {
--        GtkWidget  *entry;
--        GtkWidget  *label;
--
-         g_debug ("GdmGreeterLoginWindow: Resetting dialog");
-         set_busy (login_window);
-         set_sensitive (login_window, FALSE);
-@@ -561,16 +669,13 @@ reset_dialog (GdmGreeterLoginWindow *login_window)
-                 login_window->priv->start_session_handler_id = 0;
-         }
- 
--        entry = GTK_WIDGET (gtk_builder_get_object (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->builder, "auth-prompt-entry"));
-+        gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
-+                                    (GdmTaskListForeachFunc)
-+                                    reset_task,
-+                                    login_window);
+         char *user_name;
+-        guint mode;
++        char *item_id;
  
--        delete_entry_text (entry);
--
--        gtk_entry_set_visibility (GTK_ENTRY (entry), TRUE);
-         set_message (login_window, "");
+         user_name = gdm_user_chooser_widget_get_chosen_user_name (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser));
+-        g_debug ("GdmGreeterLoginWindow: user chosen '%s'", user_name);
  
--        label = GTK_WIDGET (gtk_builder_get_object (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->builder, "auth-prompt-label"));
--        gtk_label_set_text (GTK_LABEL (label), "");
--
-         if (login_window->priv->user_list_disabled) {
-                 switch_mode (login_window, MODE_AUTHENTICATION);
-         } else {
-@@ -598,11 +703,19 @@ do_cancel (GdmGreeterLoginWindow *login_window)
- }
+-        if (user_name == NULL) {
++        if (user_name != NULL) {
++                g_debug ("GdmGreeterLoginWindow: user chosen '%s'", user_name);
++                choose_user (login_window, user_name);
++                g_free (user_name);
+                 return;
+         }
  
- gboolean
--gdm_greeter_login_window_ready (GdmGreeterLoginWindow *login_window)
-+gdm_greeter_login_window_ready (GdmGreeterLoginWindow *login_window,
-+                                const char            *service_name)
- {
-+        GdmTask *task;
+-        choose_user (login_window, user_name);
+-        g_free (user_name);
++        item_id = gdm_chooser_widget_get_active_item (GDM_CHOOSER_WIDGET (user_chooser));
++        g_debug ("GdmGreeterLoginWindow: item chosen '%s'", item_id);
 +
-         g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
- 
--        reset_dialog (login_window);
-+        task = find_task_with_service_name (login_window, service_name);
++        g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED],
++                       0, item_id);
 +
-+        if (task != NULL) {
-+                gdm_conversation_set_ready (GDM_CONVERSATION (task));
-+                g_object_unref (task);
++        if (strcmp (item_id, GDM_USER_CHOOSER_USER_OTHER) == 0) {
++                g_debug ("GdmGreeterLoginWindow: Starting all auth conversations");
++                g_free (item_id);
++
++                begin_verification (login_window);
++        } else if (strcmp (item_id, GDM_USER_CHOOSER_USER_GUEST) == 0) {
++                /* FIXME: handle guest account stuff */
++                g_free (item_id);
++        } else if (strcmp (item_id, GDM_USER_CHOOSER_USER_AUTO) == 0) {
++                g_debug ("GdmGreeterLoginWindow: Starting auto login");
++                g_free (item_id);
++
++                begin_auto_login (login_window);
++        } else {
++                g_debug ("GdmGreeterLoginWindow: Starting single auth conversation");
++                begin_single_service_verification (login_window, item_id);
++                g_free (item_id);
 +        }
- 
-         set_sensitive (GDM_GREETER_LOGIN_WINDOW (login_window), TRUE);
-         set_ready (GDM_GREETER_LOGIN_WINDOW (login_window));
-@@ -620,12 +733,60 @@ gdm_greeter_login_window_ready (GdmGreeterLoginWindow *login_window)
  }
  
- gboolean
--gdm_greeter_login_window_reset (GdmGreeterLoginWindow *login_window)
-+gdm_greeter_login_window_conversation_stopped (GdmGreeterLoginWindow *login_window,
-+                                               const char            *service_name)
- {
-+        GdmTask *task;
-+
-         g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
+ static void
+@@ -1206,11 +1642,74 @@ create_computer_info (GdmGreeterLoginWindow *login_window)
+ #define INVISIBLE_CHAR_BULLET        0x2022
+ #define INVISIBLE_CHAR_NONE          0
  
-+        g_debug ("GdmGreeterLoginWindow: conversation '%s' has stopped", service_name);
++static void
++on_task_activated (GdmGreeterLoginWindow *login_window,
++                   GdmTask               *task)
++{
++        GtkWidget *container;
++        char *name;
 +
-+        task = find_task_with_service_name (login_window, service_name);
++        name = gdm_task_get_name (task);
++        g_debug ("GdmGreeterLoginWindow: task '%s' activated", name);
++        g_free (name);
 +
-+        if (task != NULL) {
-+                gdm_conversation_reset (GDM_CONVERSATION (task));
-+                g_object_unref (task);
++        container = g_object_get_data (G_OBJECT (task),
++                                       "gdm-greeter-login-window-page-container");
++
++        if (container == NULL) {
++                GtkWidget *page;
++
++                container = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
++                gtk_container_add (GTK_CONTAINER (login_window->priv->auth_page_box),
++                                   container);
++
++                page = gdm_conversation_get_page (GDM_CONVERSATION (task));
++                if (page != NULL) {
++                        gtk_container_add (GTK_CONTAINER (container), page);
++                        gtk_widget_show (page);
++                }
++                g_object_set_data (G_OBJECT (task),
++                                   "gdm-greeter-login-window-page-container",
++                                   container);
 +        }
 +
-+        return TRUE;
++        gtk_widget_show (container);
++        switch_mode (login_window, login_window->priv->dialog_mode);
 +}
 +
-+static gboolean
-+restart_task_conversation (GdmTaskList           *task_list,
-+                           GdmTask               *task,
-+                           GdmGreeterLoginWindow *login_window)
++static void
++on_task_deactivated (GdmGreeterLoginWindow *login_window,
++                     GdmTask               *task)
 +{
-+        char *service_name;
++        GtkWidget *container;
++        char *name;
++        GtkActionGroup *actions;
 +
-+        service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (task));
-+        if (service_name != NULL) {
-+                char *name;
++        name = gdm_task_get_name (task);
++        g_debug ("GdmGreeterLoginWindow: task '%s' now in background", name);
++        g_free (name);
 +
-+                name = gdm_task_get_name (task);
-+                g_debug ("GdmGreeterLoginWindow: restarting '%s' conversation", name);
-+                g_free (name);
++        container = g_object_get_data (G_OBJECT (task),
++                                       "gdm-greeter-login-window-page-container");
 +
-+                g_signal_emit (login_window, signals[START_CONVERSATION], 0, service_name);
-+                g_free (service_name);
++        if (container != NULL) {
++                gtk_widget_hide (container);
 +        }
 +
-+        return FALSE;
-+}
-+
-+gboolean
-+gdm_greeter_login_window_reset (GdmGreeterLoginWindow *login_window)
-+{
-+        g_debug ("GdmGreeterLoginWindow: window reset");
++        actions = gdm_conversation_get_actions (GDM_CONVERSATION (task));
 +
-+        g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
-         reset_dialog (GDM_GREETER_LOGIN_WINDOW (login_window));
++        if (actions != NULL) {
++                gtk_action_group_set_sensitive (actions, FALSE);
++                gtk_action_group_set_visible (actions, FALSE);
++                g_object_unref (actions);
++        }
++}
  
-+        gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
-+                                    (GdmTaskListForeachFunc)
-+                                    restart_task_conversation,
-+                                    login_window);
-+
-         return TRUE;
- }
- 
-@@ -634,12 +795,17 @@ gdm_greeter_login_window_info (GdmGreeterLoginWindow *login_window,
-                                const char            *service_name,
-                                const char            *text)
+ static void
+ register_custom_types (GdmGreeterLoginWindow *login_window)
  {
--        g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
-+        GdmTask *task;
- 
-+        g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
-         g_debug ("GdmGreeterLoginWindow: info: %s", text);
- 
--        if (strcmp (service_name, gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list))) == 0) {
--                set_message (GDM_GREETER_LOGIN_WINDOW (login_window), text);
-+        task = find_task_with_service_name (login_window, service_name);
-+
-+        if (task != NULL) {
-+                gdm_conversation_set_message (GDM_CONVERSATION (task),
-+                                              text);
-+                g_object_unref (task);
-         }
+-        GType types[] = { GDM_TYPE_USER_CHOOSER_WIDGET };
++        GType types[] = { GDM_TYPE_USER_CHOOSER_WIDGET,
++                          GDM_TYPE_TASK_LIST };
+         int i;
  
-         return TRUE;
-@@ -650,13 +816,19 @@ gdm_greeter_login_window_problem (GdmGreeterLoginWindow *login_window,
-                                   const char            *service_name,
-                                   const char            *text)
+         for (i = 0; i < G_N_ELEMENTS (types); i++) {
+@@ -1221,7 +1720,6 @@ register_custom_types (GdmGreeterLoginWindow *login_window)
+ static void
+ load_theme (GdmGreeterLoginWindow *login_window)
  {
--        g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
-+        GdmTask *task;
- 
-+        g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
-         g_debug ("GdmGreeterLoginWindow: problem: %s", text);
+-        GtkWidget *entry;
+         GtkWidget *button;
+         GtkWidget *box;
+         GtkWidget *image;
+@@ -1274,7 +1772,7 @@ load_theme (GdmGreeterLoginWindow *login_window)
+                           login_window);
+         g_signal_connect (login_window->priv->user_chooser,
+                           "activated",
+-                          G_CALLBACK (on_user_chosen),
++                          G_CALLBACK (on_user_chooser_activated),
+                           login_window);
+         g_signal_connect (login_window->priv->user_chooser,
+                           "deactivated",
+@@ -1286,30 +1784,30 @@ load_theme (GdmGreeterLoginWindow *login_window)
+                                  G_CALLBACK (on_user_chooser_visibility_changed),
+                                  login_window);
  
--        if (strcmp (service_name, gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list))) == 0) {
--                set_message (GDM_GREETER_LOGIN_WINDOW (login_window), text);
-+        task = find_task_with_service_name (login_window, service_name);
-+
-+        if (task != NULL) {
-+                gdm_conversation_set_message (GDM_CONVERSATION (task),
-+                                              text);
-+                g_object_unref (task);
-         }
++        login_window->priv->conversation_list = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "task-list"));
 +
-         gdk_window_beep (GTK_WIDGET (login_window)->window);
- 
-         return TRUE;
-@@ -715,11 +887,21 @@ gdm_greeter_login_window_request_timed_login (GdmGreeterLoginWindow *login_windo
- }
- 
- static void
--gdm_greeter_login_window_start_session_when_ready (GdmGreeterLoginWindow *login_window)
-+on_ready_to_start_session (GdmGreeterLoginWindow *login_window,
-+                           GParamSpec            *param_spec,
-+                           char                  *service_name)
-+{
-+        gdm_greeter_login_window_start_session_when_ready (login_window, service_name);
-+        g_free (service_name);
-+}
++        g_signal_connect_swapped (GDM_TASK_LIST (login_window->priv->conversation_list),
++                                  "activated",
++                                  G_CALLBACK (on_task_activated),
++                                  login_window);
++        g_signal_connect_swapped (GDM_TASK_LIST (login_window->priv->conversation_list),
++                                  "deactivated",
++                                  G_CALLBACK (on_task_deactivated),
++                                  login_window);
 +
-+static void
-+gdm_greeter_login_window_start_session_when_ready (GdmGreeterLoginWindow *login_window,
-+                                                   const char            *service_name)
- {
-         if (login_window->priv->is_interactive) {
-                 g_debug ("GdmGreeterLoginWindow: starting session");
--                g_signal_emit (login_window, signals[START_SESSION], 0);
-+                g_signal_emit (login_window, signals[START_SESSION], 0, service_name);
-         } else {
-                 g_debug ("GdmGreeterLoginWindow: not starting session since "
-                          "user hasn't had an opportunity to pick language "
-@@ -729,8 +911,8 @@ gdm_greeter_login_window_start_session_when_ready (GdmGreeterLoginWindow *login_
-                  */
-                 login_window->priv->start_session_handler_id =
-                     g_signal_connect (login_window, "notify::is-interactive",
--                                      G_CALLBACK (gdm_greeter_login_window_start_session_when_ready),
--                                      NULL);
-+                                      G_CALLBACK (on_ready_to_start_session),
-+                                      g_strdup (service_name));
- 
-                 /* FIXME: If the user wasn't asked any questions by pam but
-                  * pam still authorized them (passwd -d, or the questions got
-@@ -771,28 +953,23 @@ gdm_greeter_login_window_info_query (GdmGreeterLoginWindow *login_window,
-                                      const char            *service_name,
-                                      const char            *text)
- {
--        GtkWidget  *entry;
--        GtkWidget  *label;
-+        GdmTask *task;
- 
-         g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
+         login_window->priv->auth_banner_label = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "auth-banner-label"));
+         /*make_label_small_italic (login_window->priv->auth_banner_label);*/
++        login_window->priv->auth_page_box = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "auth-page-box"));
  
-         _show_cancel_button (login_window);
+         button = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "cancel-button"));
+         g_signal_connect (button, "clicked", G_CALLBACK (cancel_button_clicked), login_window);
  
--        if (strcmp (service_name, gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list))) != 0) {
--                return TRUE;
+-        entry = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "auth-prompt-entry"));
+-        /* Only change the invisible character if it '*' otherwise assume it is OK */
+-        if ('*' == gtk_entry_get_invisible_char (GTK_ENTRY (entry))) {
+-                gunichar invisible_char;
+-                invisible_char = INVISIBLE_CHAR_BLACK_CIRCLE;
+-                gtk_entry_set_invisible_char (GTK_ENTRY (entry), invisible_char);
 -        }
 -
-         g_debug ("GdmGreeterLoginWindow: info query: %s", text);
- 
--        entry = GTK_WIDGET (gtk_builder_get_object (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->builder, "auth-prompt-entry"));
--        delete_entry_text (entry);
--        gtk_entry_set_visibility (GTK_ENTRY (entry), TRUE);
--        set_log_in_button_mode (login_window, LOGIN_BUTTON_ANSWER_QUERY);
-+        task = find_task_with_service_name (login_window, service_name);
- 
--        label = GTK_WIDGET (gtk_builder_get_object (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->builder, "auth-prompt-label"));
--        gtk_label_set_text (GTK_LABEL (label), text);
-+        if (task != NULL) {
-+                gdm_conversation_ask_question (GDM_CONVERSATION (task),
-+                                               text);
-+                g_object_unref (task);
-+        }
- 
--        show_widget (login_window, "auth-input-box", TRUE);
-+        set_log_in_button_mode (login_window, LOGIN_BUTTON_ANSWER_QUERY);
-         set_sensitive (GDM_GREETER_LOGIN_WINDOW (login_window), TRUE);
-         set_ready (GDM_GREETER_LOGIN_WINDOW (login_window));
-         set_focus (GDM_GREETER_LOGIN_WINDOW (login_window));
-@@ -807,26 +984,22 @@ gdm_greeter_login_window_secret_info_query (GdmGreeterLoginWindow *login_window,
-                                             const char            *service_name,
-                                             const char            *text)
- {
--        GtkWidget  *entry;
--        GtkWidget  *label;
-+
-+        GdmTask *task;
- 
-         g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
+         create_computer_info (login_window);
  
-         _show_cancel_button (login_window);
+         box = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "computer-info-event-box"));
+         g_signal_connect (box, "button-press-event", G_CALLBACK (on_computer_info_label_button_press), login_window);
  
--        if (strcmp (service_name, gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list))) != 0) {
--                return TRUE;
-+        task = find_task_with_service_name (login_window, service_name);
-+
-+        if (task != NULL) {
-+                gdm_conversation_ask_secret (GDM_CONVERSATION (task),
-+                                             text);
-+                g_object_unref (task);
-         }
+-        if (login_window->priv->user_list_disabled) {
+-                switch_mode (login_window, MODE_AUTHENTICATION);
+-        } else {
+-                switch_mode (login_window, MODE_SELECTION);
+-        }
++        switch_mode (login_window, MODE_SELECTION);
  
--        entry = GTK_WIDGET (gtk_builder_get_object (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->builder, "auth-prompt-entry"));
--        delete_entry_text (entry);
--        gtk_entry_set_visibility (GTK_ENTRY (entry), FALSE);
-         set_log_in_button_mode (login_window, LOGIN_BUTTON_ANSWER_QUERY);
--
--        label = GTK_WIDGET (gtk_builder_get_object (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->builder, "auth-prompt-label"));
--        gtk_label_set_text (GTK_LABEL (label), text);
--
--        show_widget (login_window, "auth-input-box", TRUE);
-         set_sensitive (GDM_GREETER_LOGIN_WINDOW (login_window), TRUE);
-         set_ready (GDM_GREETER_LOGIN_WINDOW (login_window));
-         set_focus (GDM_GREETER_LOGIN_WINDOW (login_window));
-@@ -837,13 +1010,16 @@ gdm_greeter_login_window_secret_info_query (GdmGreeterLoginWindow *login_window,
+         gdm_profile_end (NULL);
  }
+@@ -1465,6 +1963,15 @@ gdm_greeter_login_window_class_init (GdmGreeterLoginWindowClass *klass)
+         widget_class->key_press_event = gdm_greeter_login_window_key_press_event;
+         widget_class->size_request = gdm_greeter_login_window_size_request;
  
- void
--gdm_greeter_login_window_user_authorized (GdmGreeterLoginWindow *login_window)
-+gdm_greeter_login_window_user_authorized (GdmGreeterLoginWindow *login_window,
-+                                          const char            *service_name)
- {
-         g_return_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window));
- 
--        g_debug ("GdmGreeterLoginWindow: user now authorized");
-+        g_debug ("GdmGreeterLoginWindow: user now authorized via service %s",
-+                  service_name);
- 
--        gdm_greeter_login_window_start_session_when_ready (login_window);
-+        gdm_greeter_login_window_start_session_when_ready (login_window,
-+                                                           service_name);
- }
++        signals [START_CONVERSATION] =
++                g_signal_new ("start-conversation",
++                              G_TYPE_FROM_CLASS (object_class),
++                              G_SIGNAL_RUN_LAST,
++                              G_STRUCT_OFFSET (GdmGreeterLoginWindowClass, start_conversation),
++                              NULL,
++                              NULL,
++                              g_cclosure_marshal_VOID__STRING,
++                              G_TYPE_NONE, 1, G_TYPE_STRING);
+         signals [BEGIN_AUTO_LOGIN] =
+                 g_signal_new ("begin-auto-login",
+                               G_TYPE_FROM_CLASS (object_class),
+@@ -1481,9 +1988,9 @@ gdm_greeter_login_window_class_init (GdmGreeterLoginWindowClass *klass)
+                               G_STRUCT_OFFSET (GdmGreeterLoginWindowClass, begin_verification),
+                               NULL,
+                               NULL,
+-                              g_cclosure_marshal_VOID__VOID,
++                              g_cclosure_marshal_VOID__STRING,
+                               G_TYPE_NONE,
+-                              0);
++                              1, G_TYPE_STRING);
+         signals [BEGIN_VERIFICATION_FOR_USER] =
+                 g_signal_new ("begin-verification-for-user",
+                               G_TYPE_FROM_CLASS (object_class),
+@@ -1491,9 +1998,9 @@ gdm_greeter_login_window_class_init (GdmGreeterLoginWindowClass *klass)
+                               G_STRUCT_OFFSET (GdmGreeterLoginWindowClass, begin_verification_for_user),
+                               NULL,
+                               NULL,
+-                              g_cclosure_marshal_VOID__STRING,
++                              gdm_marshal_VOID__STRING_STRING,
+                               G_TYPE_NONE,
+-                              1, G_TYPE_STRING);
++                              2, G_TYPE_STRING, G_TYPE_STRING);
+         signals [QUERY_ANSWER] =
+                 g_signal_new ("query-answer",
+                               G_TYPE_FROM_CLASS (object_class),
+@@ -1501,9 +2008,9 @@ gdm_greeter_login_window_class_init (GdmGreeterLoginWindowClass *klass)
+                               G_STRUCT_OFFSET (GdmGreeterLoginWindowClass, query_answer),
+                               NULL,
+                               NULL,
+-                              g_cclosure_marshal_VOID__STRING,
++                              gdm_marshal_VOID__STRING_STRING,
+                               G_TYPE_NONE,
+-                              1, G_TYPE_STRING);
++                              2, G_TYPE_STRING, G_TYPE_STRING);
+         signals [USER_SELECTED] =
+                 g_signal_new ("user-selected",
+                               G_TYPE_FROM_CLASS (object_class),
+@@ -1541,9 +2048,9 @@ gdm_greeter_login_window_class_init (GdmGreeterLoginWindowClass *klass)
+                               G_STRUCT_OFFSET (GdmGreeterLoginWindowClass, start_session),
+                               NULL,
+                               NULL,
+-                              g_cclosure_marshal_VOID__VOID,
++                              g_cclosure_marshal_VOID__STRING,
+                               G_TYPE_NONE,
+-                              0);
++                              1, G_TYPE_STRING);
  
- static void
-@@ -926,6 +1102,46 @@ on_users_loaded (GdmUserChooserWidget  *user_chooser,
-         gdm_chooser_widget_activate_if_one_item (GDM_CHOOSER_WIDGET (login_window->priv->user_chooser));
+         g_object_class_install_property (object_class,
+                                          PROP_DISPLAY_IS_LOCAL,
+@@ -1596,6 +2103,246 @@ on_gconf_key_changed (GConfClient           *client,
+         }
  }
  
-+static gboolean
-+begin_task_verification (GdmTaskList           *task_list,
-+                         GdmTask               *task,
-+                         GdmGreeterLoginWindow *login_window)
++static void
++on_conversation_answer (GdmGreeterLoginWindow *login_window,
++                        const char            *text,
++                        GdmConversation       *conversation)
 +{
-+        char *service_name;
++        if (text != NULL) {
++                char *service_name;
 +
-+        service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (task));
-+        if (service_name != NULL) {
-+                g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0, service_name);
-+                g_free (service_name);
++                service_name = gdm_conversation_get_service_name (conversation);
++                if (service_name != NULL) {
++                        g_signal_emit (login_window, signals[QUERY_ANSWER], 0, service_name, text);
++                        g_free (service_name);
++                }
 +        }
 +
-+        return FALSE;
++        set_sensitive (login_window, TRUE);
++        set_ready (login_window);
 +}
 +
-+static gboolean
-+begin_task_verification_for_selected_user (GdmTaskList           *task_list,
-+                                           GdmTask               *task,
-+                                           GdmGreeterLoginWindow *login_window)
++static void
++on_conversation_cancel (GdmGreeterLoginWindow *login_window,
++                        GdmConversation       *conversation)
 +{
-+        char *user_name;
-+        char *service_name;
-+
-+        user_name = gdm_user_chooser_widget_get_chosen_user_name (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser));
-+
-+        if (user_name == NULL) {
-+                return TRUE;
-+        }
-+
-+        service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (task));
-+        if (service_name != NULL) {
-+                g_signal_emit (login_window, signals[BEGIN_VERIFICATION_FOR_USER], 0, service_name, user_name);
-+                g_free (service_name);
-+        }
-+
-+        g_free (user_name);
-+        return FALSE;
++        do_cancel (login_window);
 +}
 +
- static void
- on_user_chosen (GdmUserChooserWidget  *user_chooser,
-                 GdmGreeterLoginWindow *login_window)
-@@ -943,10 +1159,10 @@ on_user_chosen (GdmUserChooserWidget  *user_chooser,
-                        0, user_name);
- 
-         if (strcmp (user_name, GDM_USER_CHOOSER_USER_OTHER) == 0) {
--                const char *service_name;
--
--                service_name = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
--                g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0, service_name);
-+                gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
-+                                            (GdmTaskListForeachFunc)
-+                                            begin_task_verification,
-+                                            login_window);
-         } else if (strcmp (user_name, GDM_USER_CHOOSER_USER_GUEST) == 0) {
-                 /* FIXME: handle guest account stuff */
-         } else if (strcmp (user_name, GDM_USER_CHOOSER_USER_AUTO) == 0) {
-@@ -960,10 +1176,10 @@ on_user_chosen (GdmUserChooserWidget  *user_chooser,
-                 set_log_in_button_mode (login_window, LOGIN_BUTTON_TIMED_LOGIN);
-                 set_message (login_window, _("Select language and click Log In"));
-         } else {
--                const char *service_name;
--
--                service_name = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
--                g_signal_emit (login_window, signals[BEGIN_VERIFICATION_FOR_USER], 0, service_name, user_name);
-+                gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
-+                                            (GdmTaskListForeachFunc)
-+                                            begin_task_verification_for_selected_user,
-+                                            login_window);
-         }
- 
-         switch_mode (login_window, MODE_AUTHENTICATION);
-@@ -1128,23 +1344,70 @@ create_computer_info (GdmGreeterLoginWindow *login_window)
- 
- static void
- on_task_activated (GdmGreeterLoginWindow *login_window,
--                   const char            *name)
-+                   GdmTask               *task)
- {
--        g_debug ("GdmGreeterLoginWindow: starting conversation with '%s'", name);
--        g_signal_emit (login_window, signals[START_CONVERSATION], 0, name);
-+        GtkWidget *container;
-+        char *name;
-+
-+        name = gdm_task_get_name (task);
-+        g_debug ("GdmGreeterLoginWindow: task '%s' activated", name);
-+        g_free (name);
-+
-+        container = g_object_get_data (G_OBJECT (task),
-+                                       "gdm-greeter-login-window-page-container");
-+
-+        if (container == NULL) {
-+                GtkWidget *page;
-+
-+                container = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
-+                gtk_container_add (GTK_CONTAINER (login_window->priv->auth_page_box),
-+                                   container);
-+
-+                page = gdm_conversation_get_page (GDM_CONVERSATION (task));
-+                if (page != NULL) {
-+                        gtk_container_add (GTK_CONTAINER (container), page);
-+                        gtk_widget_show (page);
-+                }
-+                g_object_set_data (G_OBJECT (task),
-+                                   "gdm-greeter-login-window-page-container",
-+                                   container);
-+        }
-+
-+        gtk_widget_show (container);
-+        set_log_in_button_mode (login_window, login_window->priv->dialog_mode);
- }
- 
- static void
- on_task_deactivated (GdmGreeterLoginWindow *login_window,
--                     const char            *name)
-+                     GdmTask               *task)
- {
--        g_debug ("GdmGreeterLoginWindow: conversation '%s' now in background", name);
-+        GtkWidget *container;
-+        char *name;
-+        GtkActionGroup *actions;
-+
-+        name = gdm_task_get_name (task);
-+        g_debug ("GdmGreeterLoginWindow: task '%s' now in background", name);
-+        g_free (name);
-+
-+        container = g_object_get_data (G_OBJECT (task),
-+                                       "gdm-greeter-login-window-page-container");
++static gboolean
++on_conversation_chose_user (GdmGreeterLoginWindow *login_window,
++                            const char            *username,
++                            GdmConversation       *conversation)
++{
++        if (!gdm_chooser_widget_is_loaded (GDM_CHOOSER_WIDGET (login_window->priv->user_chooser))) {
++                char *name;
 +
-+        if (container != NULL) {
-+                gtk_widget_hide (container);
++                name = gdm_task_get_name (GDM_TASK (conversation));
++                g_warning ("Task %s is trying to choose user before list is loaded", name);
++                g_free (name);
++                return FALSE;
 +        }
 +
-+        actions = gdm_conversation_get_actions (GDM_CONVERSATION (task));
-+
-+        if (actions != NULL) {
-+                gtk_action_group_set_sensitive (actions, FALSE);
-+                gtk_action_group_set_visible (actions, FALSE);
-+                g_object_unref (actions);
++        /* If we're already authenticating then we can't pick a user
++         */
++        if (login_window->priv->dialog_mode == MODE_AUTHENTICATION) {
++                return FALSE;
 +        }
- }
- 
- static void
- load_theme (GdmGreeterLoginWindow *login_window)
- {
--        GtkWidget *entry;
-         GtkWidget *button;
-         GtkWidget *box;
-         GtkWidget *image;
-@@ -1231,27 +1494,13 @@ load_theme (GdmGreeterLoginWindow *login_window)
-                                   login_window);
-         gtk_widget_show (login_window->priv->conversation_list);
- 
--        gdm_task_list_add_task (GDM_TASK_LIST (login_window->priv->conversation_list),
--                                "password-auth", "dialog-password");
--        gdm_task_list_add_task (GDM_TASK_LIST (login_window->priv->conversation_list),
--                                "fingerprint-auth", "stock_allow-effects");
--        gdm_task_list_add_task (GDM_TASK_LIST (login_window->priv->conversation_list),
--                                "smartcard-auth", "badge-small");
--
-         login_window->priv->auth_banner_label = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "auth-banner-label"));
-         /*make_label_small_italic (login_window->priv->auth_banner_label);*/
-+        login_window->priv->auth_page_box = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "auth-page-box"));
- 
-         button = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "cancel-button"));
-         g_signal_connect (button, "clicked", G_CALLBACK (cancel_button_clicked), login_window);
- 
--        entry = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "auth-prompt-entry"));
--        /* Only change the invisible character if it '*' otherwise assume it is OK */
--        if ('*' == gtk_entry_get_invisible_char (GTK_ENTRY (entry))) {
--                gunichar invisible_char;
--                invisible_char = INVISIBLE_CHAR_BLACK_CIRCLE;
--                gtk_entry_set_invisible_char (GTK_ENTRY (entry), invisible_char);
--        }
--
-         create_computer_info (login_window);
- 
-         box = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "computer-info-event-box"));
-@@ -1497,9 +1746,9 @@ gdm_greeter_login_window_class_init (GdmGreeterLoginWindowClass *klass)
-                               G_STRUCT_OFFSET (GdmGreeterLoginWindowClass, start_session),
-                               NULL,
-                               NULL,
--                              g_cclosure_marshal_VOID__VOID,
-+                              g_cclosure_marshal_VOID__STRING,
-                               G_TYPE_NONE,
--                              0);
-+                              1, G_TYPE_STRING);
- 
-         g_object_class_install_property (object_class,
-                                          PROP_DISPLAY_IS_LOCAL,
-@@ -1552,6 +1801,187 @@ on_gconf_key_changed (GConfClient           *client,
-         }
- }
- 
-+static void
-+on_conversation_answer (GdmGreeterLoginWindow *login_window,
-+                        const char            *text,
-+                        GdmConversation       *conversation)
-+{
-+        if (text != NULL) {
-+                char *service_name;
 +
-+                service_name = gdm_conversation_get_service_name (conversation);
-+                if (service_name != NULL) {
-+                        g_signal_emit (login_window, signals[QUERY_ANSWER], 0, service_name, text);
-+                        g_free (service_name);
-+                }
++        if (gdm_task_list_set_active_task (GDM_TASK_LIST (login_window->priv->conversation_list),
++                                           GDM_TASK (conversation))) {
++                gdm_user_chooser_widget_set_chosen_user_name (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser),
++                                                              username);
 +        }
 +
-+        set_sensitive (login_window, TRUE);
-+        set_ready (login_window);
++        return TRUE;
 +}
 +
 +void
@@ -8533,8 +8983,14 @@ index 949494b..6becaa0 100644
 +
 +        action = gtk_widget_get_action (button);
 +
-+        image = gtk_action_create_icon (GTK_ACTION (action), GTK_ICON_SIZE_BUTTON);
++        if (gtk_action_get_is_important (action)) {
++                image = gtk_action_create_icon (GTK_ACTION (action), GTK_ICON_SIZE_BUTTON);
++        } else {
++                image = NULL;
++        }
++
 +        gtk_button_set_image (GTK_BUTTON (button), image);
++
 +}
 +
 +static void
@@ -8625,6 +9081,17 @@ index 949494b..6becaa0 100644
 +                return;
 +        }
 +
++        name = gdm_task_get_name (GDM_TASK (extension));
++        description = gdm_task_get_description (GDM_TASK (extension));
++
++        if (!gdm_task_is_visible (GDM_TASK (extension))) {
++                g_debug ("GdmGreeterLoginWindow: new extension '%s - %s' won't be added",
++                         name, description);
++                g_free (name);
++                g_free (description);
++                return;
++        }
++
 +        actions = gdm_conversation_get_actions (GDM_CONVERSATION (extension));
 +
 +        create_buttons_for_actions (login_window, actions);
@@ -8636,26 +9103,32 @@ index 949494b..6becaa0 100644
 +                                  "answer",
 +                                  G_CALLBACK (on_conversation_answer),
 +                                  login_window);
-+
-+        name = gdm_task_get_name (GDM_TASK (extension));
-+        description = gdm_task_get_description (GDM_TASK (extension));
++        g_signal_connect_swapped (GDM_CONVERSATION (extension),
++                                  "cancel",
++                                  G_CALLBACK (on_conversation_cancel),
++                                  login_window);
++        g_signal_connect_swapped (GDM_CONVERSATION (extension),
++                                  "user-chosen",
++                                  G_CALLBACK (on_conversation_chose_user),
++                                  login_window);
 +
 +        g_debug ("GdmGreeterLoginWindow: new extension '%s - %s' added",
 +                name, description);
 +
-+        g_free (name);
-+        g_free (description);
-+
-+        if (gdm_task_list_get_number_of_tasks (GDM_TASK_LIST (login_window->priv->conversation_list)) == 0) {
-+                gtk_widget_hide (login_window->priv->conversation_list);
-+        } else {
-+                gtk_widget_show (login_window->priv->conversation_list);
-+        }
-+
 +        gdm_task_list_add_task (GDM_TASK_LIST (login_window->priv->conversation_list),
 +                                GDM_TASK (extension));
 +
 +        service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (extension));
++
++        if (gdm_task_is_choosable (GDM_TASK (extension))) {
++                gdm_chooser_widget_add_item (GDM_CHOOSER_WIDGET (login_window->priv->user_chooser),
++                                             service_name, NULL, name, description, ~0,
++                                             FALSE, TRUE, NULL, NULL);
++        }
++
++        g_free (name);
++        g_free (description);
++
 +        g_debug ("GdmGreeterLoginWindow: starting conversation with '%s'", service_name);
 +        g_signal_emit (login_window, signals[START_CONVERSATION], 0, service_name);
 +        g_free (service_name);
@@ -8665,7 +9138,7 @@ index 949494b..6becaa0 100644
  on_window_state_event (GtkWidget           *widget,
                         GdkEventWindowState *event,
 diff --git a/gui/simple-greeter/gdm-greeter-login-window.h b/gui/simple-greeter/gdm-greeter-login-window.h
-index 559b26b..c312a47 100644
+index 504b075..041cbc4 100644
 --- a/gui/simple-greeter/gdm-greeter-login-window.h
 +++ b/gui/simple-greeter/gdm-greeter-login-window.h
 @@ -23,6 +23,9 @@
@@ -8687,7 +9160,24 @@ index 559b26b..c312a47 100644
  typedef struct GdmGreeterLoginWindowPrivate GdmGreeterLoginWindowPrivate;
  
  typedef struct
-@@ -62,7 +67,8 @@ typedef struct
+@@ -46,18 +51,24 @@ typedef struct
+         GtkWindowClass   parent_class;
+ 
+         /* signals */
++        void (* start_conversation)          (GdmGreeterLoginWindow *login_window,
++                                              const char            *service_name);
+         void (* begin_auto_login)            (GdmGreeterLoginWindow *login_window,
+                                               const char            *username);
+-        void (* begin_verification)          (GdmGreeterLoginWindow *login_window);
++        void (* begin_verification)          (GdmGreeterLoginWindow *login_window,
++                                              const char            *service_name);
+         void (* begin_verification_for_user) (GdmGreeterLoginWindow *login_window,
++                                              const char            *service_name,
+                                               const char            *username);
+         void (* query_answer)                (GdmGreeterLoginWindow *login_window,
++                                              const char            *service_name,
+                                               const char            *text);
+         void (* user_selected)               (GdmGreeterLoginWindow *login_window,
                                                const char            *text);
          void (* cancelled)                   (GdmGreeterLoginWindow *login_window);
          void (* disconnected)                (GdmGreeterLoginWindow *login_window);
@@ -8697,19 +9187,32 @@ index 559b26b..c312a47 100644
  
  } GdmGreeterLoginWindowClass;
  
-@@ -71,7 +77,10 @@ GtkWidget *         gdm_greeter_login_window_new                (gboolean displa
+@@ -66,21 +77,36 @@ GtkWidget *         gdm_greeter_login_window_new                (gboolean displa
  
  
  gboolean            gdm_greeter_login_window_reset              (GdmGreeterLoginWindow *login_window);
+-gboolean            gdm_greeter_login_window_authentication_failed (GdmGreeterLoginWindow *login_window);
 -gboolean            gdm_greeter_login_window_ready              (GdmGreeterLoginWindow *login_window);
 +gboolean            gdm_greeter_login_window_ready              (GdmGreeterLoginWindow *login_window,
 +                                                                 const char            *service_name);
 +gboolean            gdm_greeter_login_window_conversation_stopped (GdmGreeterLoginWindow *login_window,
 +                                                                   const char            *service_name);
  gboolean            gdm_greeter_login_window_info_query         (GdmGreeterLoginWindow *login_window,
-                                                                  const char *service_name,
++                                                                 const char *service_name,
+                                                                  const char *text);
+ gboolean            gdm_greeter_login_window_secret_info_query  (GdmGreeterLoginWindow *login_window,
++                                                                 const char *service_name,
+                                                                  const char *text);
+ gboolean            gdm_greeter_login_window_info               (GdmGreeterLoginWindow *login_window,
++                                                                 const char *service_name,
+                                                                  const char *text);
+ gboolean            gdm_greeter_login_window_problem            (GdmGreeterLoginWindow *login_window,
++                                                                 const char *service_name,
                                                                   const char *text);
-@@ -88,7 +97,13 @@ gboolean            gdm_greeter_login_window_problem            (GdmGreeterLogin
+ 
++gboolean            gdm_greeter_login_window_service_unavailable (GdmGreeterLoginWindow *login_window,
++                                                                  const char *service_name);
++
  void               gdm_greeter_login_window_request_timed_login (GdmGreeterLoginWindow *login_window,
                                                                   const char            *username,
                                                                   int                    delay);
@@ -8725,25 +9228,42 @@ index 559b26b..c312a47 100644
  G_END_DECLS
  
 diff --git a/gui/simple-greeter/gdm-greeter-login-window.ui b/gui/simple-greeter/gdm-greeter-login-window.ui
-index 0bf02a9..4dbd825 100644
+index 83375ed..35195d8 100644
 --- a/gui/simple-greeter/gdm-greeter-login-window.ui
 +++ b/gui/simple-greeter/gdm-greeter-login-window.ui
-@@ -163,37 +163,8 @@
-                           <placeholder/>
-                         </child>
+@@ -158,69 +158,40 @@
+                     <child>
+                       <object class="GtkVBox" id="selection-box">
+                         <property name="visible">True</property>
+-                        <property name="spacing">10</property>
++                        <property name="spacing">2</property>
                          <child>
--                          <object class="GtkHBox" id="auth-input-box">
-+                          <object class="GtkHBox" id="auth-page-box">
+-                          <object class="GdmUserChooserWidget" id="user-chooser">
+-                            <property name="visible">False</property>
+-                          </object>
+-                          <packing>
+-                            <property name="expand">True</property>
+-                            <property name="fill">True</property>
+-                            <property name="position">0</property>
+-                          </packing>
+-                        </child>
+-                        <child>
+-                          <object class="GtkHBox" id="auth-input-box">
++                          <object class="GtkAlignment" id="task-list-alignment">
                              <property name="visible">True</property>
 -                            <property name="spacing">6</property>
--                            <child>
++                            <property name="xalign">1.0</property>
++                            <property name="xscale">0.0</property>
+                             <child>
 -                              <object class="GtkLabel" id="auth-prompt-label">
 -                                <property name="visible">True</property>
 -
 -                                <accessibility>
 -                                  <relation type="label-for" target="auth-prompt-entry"/>
 -                                </accessibility>
--                              </object>
++                              <object class="GdmTaskList" id="task-list">
++                                <property name="visible">False</property>
+                               </object>
 -                              <packing>
 -                                <property name="expand">False</property>
 -                                <property name="fill">False</property>
@@ -8764,34 +9284,42 @@ index 0bf02a9..4dbd825 100644
 -                                <property name="position">1</property>
 -                              </packing>
 -                            </child>
-                             <child>
-                               <placeholder/>
+-                            <child>
+-                              <placeholder/>
                              </child>
-@@ -201,24 +172,6 @@
+                           </object>
                            <packing>
                              <property name="expand">False</property>
                              <property name="fill">False</property>
--                            <property name="position">1</property>
--                          </packing>
--                        </child>
--                        <child>
++                            <property name="position">0</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GdmUserChooserWidget" id="user-chooser">
++                            <property name="visible">False</property>
++                          </object>
++                          <packing>
++                            <property name="expand">True</property>
++                            <property name="fill">True</property>
+                             <property name="position">1</property>
+                           </packing>
+                         </child>
+                         <child>
 -                          <object class="GtkHBox" id="auth-message-box">
--                            <property name="visible">True</property>
--                            <child>
++                          <object class="GtkHBox" id="auth-page-box">
+                             <property name="visible">True</property>
++                            <property name="border_width">10</property>
+                             <child>
 -                              <object class="GtkLabel" id="auth-message-label">
 -                                <property name="visible">True</property>
 -                              </object>
 -                              <packing>
 -                                <property name="position">0</property>
 -                              </packing>
--                            </child>
--                          </object>
--                          <packing>
--                            <property name="expand">False</property>
--                            <property name="fill">False</property>
-                             <property name="position">2</property>
-                           </packing>
-                         </child>
++                              <placeholder/>
+                             </child>
+                           </object>
+                           <packing>
 diff --git a/gui/simple-greeter/gdm-greeter-plugin.c b/gui/simple-greeter/gdm-greeter-plugin.c
 new file mode 100644
 index 0000000..02814a2
@@ -9121,7 +9649,7 @@ index 0000000..904c231
 +
 +#endif
 diff --git a/gui/simple-greeter/gdm-greeter-session.c b/gui/simple-greeter/gdm-greeter-session.c
-index 945e210..848ea1e 100644
+index b7e7f1c..051a5cc 100644
 --- a/gui/simple-greeter/gdm-greeter-session.c
 +++ b/gui/simple-greeter/gdm-greeter-session.c
 @@ -39,6 +39,8 @@
@@ -9133,7 +9661,7 @@ index 945e210..848ea1e 100644
  #include "gdm-profile.h"
  
  #define GDM_GREETER_SESSION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_GREETER_SESSION, GdmGreeterSessionPrivate))
-@@ -46,9 +48,11 @@
+@@ -48,6 +50,7 @@
  struct GdmGreeterSessionPrivate
  {
          GdmGreeterClient      *client;
@@ -9141,11 +9669,35 @@ index 945e210..848ea1e 100644
  
          GtkWidget             *login_window;
          GtkWidget             *panel;
+@@ -75,7 +78,7 @@ on_info (GdmGreeterClient  *client,
+ {
+         g_debug ("GdmGreeterSession: Info: %s", text);
+ 
+-        gdm_greeter_login_window_info (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), text);
++        gdm_greeter_login_window_info (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), service_name, text);
+ }
+ 
+ static void
+@@ -86,7 +89,17 @@ on_problem (GdmGreeterClient  *client,
+ {
+         g_debug ("GdmGreeterSession: Problem: %s", text);
+ 
+-        gdm_greeter_login_window_problem (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), text);
++        gdm_greeter_login_window_problem (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), service_name, text);
++}
 +
- };
++static void
++on_service_unavailable (GdmGreeterClient  *client,
++                        const char        *service_name,
++                        GdmGreeterSession *session)
++{
++        g_debug ("GdmGreeterSession: Service Unavailable: %s", service_name);
++
++        gdm_greeter_login_window_service_unavailable (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), service_name);
+ }
  
- enum {
-@@ -92,7 +96,19 @@ on_ready (GdmGreeterClient  *client,
+ static void
+@@ -96,7 +109,19 @@ on_ready (GdmGreeterClient  *client,
  {
          g_debug ("GdmGreeterSession: Ready");
  
@@ -9166,7 +9718,37 @@ index 945e210..848ea1e 100644
  }
  
  static void
-@@ -167,10 +183,11 @@ on_timed_login_requested (GdmGreeterClient  *client,
+@@ -112,29 +137,6 @@ on_reset (GdmGreeterClient  *client,
+ }
+ 
+ static void
+-on_authentication_failed (GdmGreeterClient  *client,
+-                          GdmGreeterSession *session)
+-{
+-        g_debug ("GdmGreeterSession: Authentication failed");
+-
+-        session->priv->num_tries++;
+-
+-        if (session->priv->num_tries < MAX_LOGIN_TRIES) {
+-                g_debug ("GdmGreeterSession: Retrying login (%d)",
+-                         session->priv->num_tries);
+-
+-                gdm_greeter_login_window_authentication_failed (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window));
+-        } else {
+-                g_debug ("GdmGreeterSession: Maximum number of login tries exceeded (%d) - resetting",
+-                         session->priv->num_tries - 1);
+-                session->priv->num_tries = 0;
+-
+-                gdm_greeter_panel_reset (GDM_GREETER_PANEL (session->priv->panel));
+-                gdm_greeter_login_window_reset (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window));
+-        }
+-}
+-
+-static void
+ show_or_hide_user_options (GdmGreeterSession *session,
+                            const char        *username)
+ {
+@@ -196,10 +198,11 @@ on_timed_login_requested (GdmGreeterClient  *client,
  
  static void
  on_user_authorized (GdmGreeterClient  *client,
@@ -9179,7 +9761,72 @@ index 945e210..848ea1e 100644
  }
  
  static void
-@@ -289,7 +306,6 @@ on_cancelled (GdmGreeterLoginWindow *login_window,
+@@ -210,7 +213,7 @@ on_info_query (GdmGreeterClient  *client,
+ {
+         g_debug ("GdmGreeterSession: Info query: %s", text);
+ 
+-        gdm_greeter_login_window_info_query (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), text);
++        gdm_greeter_login_window_info_query (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), service_name, text);
+ }
+ 
+ static void
+@@ -221,10 +224,18 @@ on_secret_info_query (GdmGreeterClient  *client,
+ {
+         g_debug ("GdmGreeterSession: Secret info query: %s", text);
+ 
+-        gdm_greeter_login_window_secret_info_query (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), text);
++        gdm_greeter_login_window_secret_info_query (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), service_name, text);
+ }
+ 
+ static void
++on_start_conversation (GdmGreeterLoginWindow *login_window,
++                       const char            *service_name,
++                       GdmGreeterSession     *session)
++{
++        gdm_greeter_client_call_start_conversation (session->priv->client,
++                                                    service_name);
++}
++static void
+ on_begin_auto_login (GdmGreeterLoginWindow *login_window,
+                      const char            *username,
+                      GdmGreeterSession     *session)
+@@ -235,29 +246,32 @@ on_begin_auto_login (GdmGreeterLoginWindow *login_window,
+ 
+ static void
+ on_begin_verification (GdmGreeterLoginWindow *login_window,
++                       const char            *service_name,
+                        GdmGreeterSession     *session)
+ {
+         gdm_greeter_client_call_begin_verification (session->priv->client,
+-                                                    "gdm");
++                                                    service_name);
+ }
+ 
+ static void
+ on_begin_verification_for_user (GdmGreeterLoginWindow *login_window,
++                                const char            *service_name,
+                                 const char            *username,
+                                 GdmGreeterSession     *session)
+ {
+         gdm_greeter_client_call_begin_verification_for_user (session->priv->client,
+-                                                             "gdm",
++                                                             service_name,
+                                                              username);
+ }
+ 
+ static void
+ on_query_answer (GdmGreeterLoginWindow *login_window,
++                 const char            *service_name,
+                  const char            *text,
+                  GdmGreeterSession     *session)
+ {
+         gdm_greeter_client_call_answer_query (session->priv->client,
+-                                              "gdm",
++                                              service_name,
+                                               text);
+ }
+ 
+@@ -301,7 +315,6 @@ on_cancelled (GdmGreeterLoginWindow *login_window,
  {
          gdm_greeter_panel_hide_user_options (GDM_GREETER_PANEL (session->priv->panel));
          gdm_greeter_client_call_cancel (session->priv->client);
@@ -9187,7 +9834,7 @@ index 945e210..848ea1e 100644
  }
  
  static void
-@@ -301,9 +317,10 @@ on_disconnected (GdmGreeterLoginWindow *login_window,
+@@ -313,9 +326,10 @@ on_disconnected (GdmGreeterLoginWindow *login_window,
  
  static void
  on_start_session (GdmGreeterLoginWindow *login_window,
@@ -9199,7 +9846,19 @@ index 945e210..848ea1e 100644
  }
  
  static int
-@@ -462,8 +479,6 @@ gdm_greeter_session_start (GdmGreeterSession *session,
+@@ -410,7 +424,10 @@ toggle_login_window (GdmGreeterSession *session,
+                 is_local = gdm_greeter_client_get_display_is_local (session->priv->client);
+                 g_debug ("GdmGreeterSession: Starting a login window local:%d", is_local);
+                 session->priv->login_window = gdm_greeter_login_window_new (is_local);
+-
++                g_signal_connect (session->priv->login_window,
++                                  "start-conversation",
++                                  G_CALLBACK (on_start_conversation),
++                                  session);
+                 g_signal_connect (session->priv->login_window,
+                                   "begin-auto-login",
+                                   G_CALLBACK (on_begin_auto_login),
+@@ -466,8 +483,6 @@ gdm_greeter_session_start (GdmGreeterSession *session,
          toggle_panel (session, TRUE);
          toggle_login_window (session, TRUE);
  
@@ -9208,7 +9867,7 @@ index 945e210..848ea1e 100644
          gdm_profile_end (NULL);
  
          return res;
-@@ -573,6 +588,64 @@ gdm_greeter_session_event_handler (GdkEvent          *event,
+@@ -577,6 +592,64 @@ gdm_greeter_session_event_handler (GdkEvent          *event,
  }
  
  static void
@@ -9273,18 +9932,32 @@ index 945e210..848ea1e 100644
  gdm_greeter_session_init (GdmGreeterSession *session)
  {
          gdm_profile_start (NULL);
-@@ -601,6 +674,10 @@ gdm_greeter_session_init (GdmGreeterSession *session)
+@@ -601,16 +674,20 @@ gdm_greeter_session_init (GdmGreeterSession *session)
+                           G_CALLBACK (on_problem),
+                           session);
+         g_signal_connect (session->priv->client,
++                          "service-unavailable",
++                          G_CALLBACK (on_service_unavailable),
++                          session);
++        g_signal_connect (session->priv->client,
+                           "ready",
                            G_CALLBACK (on_ready),
                            session);
          g_signal_connect (session->priv->client,
+-                          "reset",
+-                          G_CALLBACK (on_reset),
 +                          "conversation-stopped",
 +                          G_CALLBACK (on_conversation_stopped),
-+                          session);
-+        g_signal_connect (session->priv->client,
-                           "reset",
-                           G_CALLBACK (on_reset),
                            session);
-@@ -635,6 +712,8 @@ gdm_greeter_session_init (GdmGreeterSession *session)
+         g_signal_connect (session->priv->client,
+-                          "authentication-failed",
+-                          G_CALLBACK (on_authentication_failed),
++                          "reset",
++                          G_CALLBACK (on_reset),
+                           session);
+         g_signal_connect (session->priv->client,
+                           "selected-user-changed",
+@@ -643,6 +720,8 @@ gdm_greeter_session_init (GdmGreeterSession *session)
          gdk_event_handler_set ((GdkEventFunc) gdm_greeter_session_event_handler,
                                 session, NULL);
  
@@ -9850,47 +10523,96 @@ index 0000000..f181140
 +
 +#endif /* __GDM_PLUGIN_MANAGER_H */
 diff --git a/gui/simple-greeter/gdm-task-list.c b/gui/simple-greeter/gdm-task-list.c
-index e0fd3d4..3dff10e 100644
---- a/gui/simple-greeter/gdm-task-list.c
+new file mode 100644
+index 0000000..a7f8c74
+--- /dev/null
 +++ b/gui/simple-greeter/gdm-task-list.c
-@@ -37,12 +37,6 @@
- 
- #define GDM_TASK_LIST_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_TASK_LIST, GdmTaskListPrivate))
- 
--typedef struct
--{
--        GtkWidget *radio_button;
--        char      *name;
--} GdmTask;
--
- struct GdmTaskListPrivate
- {
-         GtkWidget *box;
-@@ -59,54 +53,162 @@ static guint    signals[NUMBER_OF_SIGNALS];
- 
- static void     gdm_task_list_class_init  (GdmTaskListClass *klass);
- static void     gdm_task_list_init        (GdmTaskList      *task_list);
--static void     gdm_task_list_finalize    (GObject              *object);
+@@ -0,0 +1,385 @@
++/*
++ * Copyright (C) 2009 Red Hat, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ *  Written by: Ray Strode <rstrode at redhat.com>
++ */
++
++#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-task-list.h"
++
++#define GDM_TASK_LIST_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_TASK_LIST, GdmTaskListPrivate))
++
++struct GdmTaskListPrivate
++{
++        GtkWidget *box;
++        GList     *tasks;
++};
++
++enum {
++        ACTIVATED = 0,
++        DEACTIVATED,
++        NUMBER_OF_SIGNALS
++};
++
++static guint    signals[NUMBER_OF_SIGNALS];
++
++static void     gdm_task_list_class_init  (GdmTaskListClass *klass);
++static void     gdm_task_list_init        (GdmTaskList      *task_list);
 +static void     gdm_task_list_finalize    (GObject          *object);
- 
- G_DEFINE_TYPE (GdmTaskList, gdm_task_list, GTK_TYPE_ALIGNMENT);
- 
- static void
- on_task_toggled (GdmTaskList    *widget,
--                 GtkRadioButton *radio_button)
++
++G_DEFINE_TYPE (GdmTaskList, gdm_task_list, GTK_TYPE_ALIGNMENT);
++
++static void
++on_task_toggled (GdmTaskList    *widget,
 +                 GtkRadioButton *button)
- {
-         GdmTask *task;
- 
--        task = g_object_get_data (G_OBJECT (radio_button), "gdm-task");
++{
++        GdmTask *task;
++
 +        task = g_object_get_data (G_OBJECT (button), "gdm-task");
- 
--        if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (radio_button))) {
--                g_signal_emit (widget, signals[ACTIVATED], 0, task->name);
++
 +        if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) {
++
++                GList     *task_node;
++
++                /* Sort the list such that the tasks the user clicks last end
++                 * up first.  This doesn't change the order in which the tasks
++                 * appear in the UI, but will affect which tasks we implicitly
++                 * activate if the currently active task gets disabled.
++                 */
++                task_node = g_list_find (widget->priv->tasks, task);
++                if (task_node != NULL) {
++                        widget->priv->tasks = g_list_delete_link (widget->priv->tasks, task_node);
++                        widget->priv->tasks = g_list_prepend (widget->priv->tasks,
++                                                              task);
++                }
++
 +                g_signal_emit (widget, signals[ACTIVATED], 0, task);
-         } else {
--                g_signal_emit (widget, signals[DEACTIVATED], 0, task->name);
++        } else {
 +                g_signal_emit (widget, signals[DEACTIVATED], 0, task);
 +        }
 +}
@@ -9920,23 +10642,10 @@ index e0fd3d4..3dff10e 100644
 +                 GdmTask     *task)
 +{
 +        GtkWidget *button;
-+        GList     *task_node;
 +
 +        button = g_object_get_data (G_OBJECT (task), "gdm-task-list-button");
 +
 +        gtk_widget_set_sensitive (button, TRUE);
-+
-+        /* Sort the list such that the tasks the user clicks last end
-+         * up first.  This doesn't change the order in which the tasks
-+         * appear in the UI, but will affect which tasks we implicitly
-+         * activate if the currently active task gets disabled.
-+         */
-+        task_node = g_list_find (task_list->priv->tasks, task);
-+        if (task_node != NULL) {
-+                task_list->priv->tasks = g_list_delete_link (task_list->priv->tasks, task_node);
-+                task_list->priv->tasks = g_list_prepend (task_list->priv->tasks,
-+                                                         task);
-+        }
 +}
 +
 +static void
@@ -9973,47 +10682,30 @@ index e0fd3d4..3dff10e 100644
 +
 +        if (was_active) {
 +                activate_first_available_task (task_list);
-         }
- }
- 
- void
- gdm_task_list_add_task (GdmTaskList *task_list,
--                        const char  *name,
--                        const char  *icon_name)
++        }
++}
++
++void
++gdm_task_list_add_task (GdmTaskList *task_list,
 +                        GdmTask     *task)
- {
--        GdmTask   *task;
-         GtkWidget *image;
++{
++        GtkWidget *image;
 +        GtkWidget *button;
 +        GIcon     *icon;
 +        char      *description;
- 
--        task = g_new0 (GdmTask, 1);
--
--        task->name = g_strdup (name);
-         if (task_list->priv->tasks == NULL) {
--                task->radio_button = gtk_radio_button_new (NULL);
++
++        if (task_list->priv->tasks == NULL) {
 +                button = gtk_radio_button_new (NULL);
-         } else {
--                task->radio_button = gtk_radio_button_new_from_widget (GTK_RADIO_BUTTON (((GdmTask *) task_list->priv->tasks->data)->radio_button));
++        } else {
 +                GdmTask *previous_task;
 +                GtkRadioButton *previous_button;
 +
 +                previous_task = GDM_TASK (task_list->priv->tasks->data);
 +                previous_button = GTK_RADIO_BUTTON (g_object_get_data (G_OBJECT (previous_task), "gdm-task-list-button"));
 +                button = gtk_radio_button_new_from_widget (previous_button);
-         }
++        }
 +        g_object_set_data (G_OBJECT (task), "gdm-task-list-button", button);
- 
--        g_object_set (task->radio_button, "draw-indicator", FALSE, NULL);
--        g_object_set_data (G_OBJECT (task->radio_button), "gdm-task", task);
--        g_signal_connect_swapped (task->radio_button,
--                                  "toggled", G_CALLBACK (on_task_toggled), task_list);
--        image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_DND);
--        gtk_widget_show (image);
--        gtk_container_add (GTK_CONTAINER (task->radio_button), image);
--        gtk_widget_show (task->radio_button);
--        gtk_container_add (GTK_CONTAINER (task->radio_button), task_list->priv->box);
++
 +        g_object_set (G_OBJECT (button), "draw-indicator", FALSE, NULL);
 +        g_object_set_data (G_OBJECT (button), "gdm-task", task);
 +        g_signal_connect_swapped (button, "toggled",
@@ -10030,9 +10722,7 @@ index e0fd3d4..3dff10e 100644
 +        g_signal_connect_swapped (G_OBJECT (task), "disabled",
 +                                  G_CALLBACK (on_task_disabled),
 +                                  task_list);
- 
--        gtk_container_add (GTK_CONTAINER (task_list->priv->box), task->radio_button);
--        task_list->priv->tasks = g_list_append (task_list->priv->tasks, task);
++
 +        icon = gdm_task_get_icon (task);
 +        image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_SMALL_TOOLBAR);
 +        g_object_unref (icon);
@@ -10051,62 +10741,104 @@ index e0fd3d4..3dff10e 100644
 +        if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) {
 +                g_signal_emit (task_list, signals[ACTIVATED], 0, task);
 +        }
- }
- 
- static void
-@@ -122,9 +224,9 @@ gdm_task_list_class_init (GdmTaskListClass *klass)
-                                             G_STRUCT_OFFSET (GdmTaskListClass, activated),
-                                             NULL,
-                                             NULL,
--                                            g_cclosure_marshal_VOID__STRING,
++}
++
++void
++gdm_task_list_remove_task (GdmTaskList *task_list,
++                           GdmTask     *task)
++{
++        GtkWidget *button;
++
++        task_list->priv->tasks = g_list_remove (task_list->priv->tasks, task);
++
++        button = g_object_get_data (G_OBJECT (task), "gdm-task-list-button");
++
++        if (button != NULL) {
++            g_signal_handlers_disconnect_by_func (G_OBJECT (task),
++                                                  G_CALLBACK (on_task_enabled),
++                                                  task_list);
++            g_signal_handlers_disconnect_by_func (G_OBJECT (task),
++                                                  G_CALLBACK (on_task_disabled),
++                                                  task_list);
++            gtk_widget_destroy (button);
++            g_object_set_data (G_OBJECT (task), "gdm-task-list-button", NULL);
++        }
++
++        g_object_unref (task);
++
++        activate_first_available_task (task_list);
++}
++
++static void
++gdm_task_list_class_init (GdmTaskListClass *klass)
++{
++        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
++
++        object_class->finalize = gdm_task_list_finalize;
++
++        signals [ACTIVATED] = g_signal_new ("activated",
++                                            G_TYPE_FROM_CLASS (object_class),
++                                            G_SIGNAL_RUN_FIRST,
++                                            G_STRUCT_OFFSET (GdmTaskListClass, activated),
++                                            NULL,
++                                            NULL,
 +                                            g_cclosure_marshal_VOID__OBJECT,
-                                             G_TYPE_NONE,
--                                            1, G_TYPE_STRING);
++                                            G_TYPE_NONE,
 +                                            1, G_TYPE_OBJECT);
- 
-         signals [DEACTIVATED] = g_signal_new ("deactivated",
-                                             G_TYPE_FROM_CLASS (object_class),
-@@ -132,22 +234,19 @@ gdm_task_list_class_init (GdmTaskListClass *klass)
-                                             G_STRUCT_OFFSET (GdmTaskListClass, deactivated),
-                                             NULL,
-                                             NULL,
--                                            g_cclosure_marshal_VOID__STRING,
++
++        signals [DEACTIVATED] = g_signal_new ("deactivated",
++                                            G_TYPE_FROM_CLASS (object_class),
++                                            G_SIGNAL_RUN_FIRST,
++                                            G_STRUCT_OFFSET (GdmTaskListClass, deactivated),
++                                            NULL,
++                                            NULL,
 +                                            g_cclosure_marshal_VOID__OBJECT,
-                                             G_TYPE_NONE,
--                                            1, G_TYPE_STRING);
++                                            G_TYPE_NONE,
 +                                            1, G_TYPE_OBJECT);
- 
-         g_type_class_add_private (klass, sizeof (GdmTaskListPrivate));
--}
--
--static void
--gdm_task_list_init (GdmTaskList *widget)
-+} static void gdm_task_list_init (GdmTaskList *widget)
- {
-         widget->priv = GDM_TASK_LIST_GET_PRIVATE (widget);
- 
-         gtk_alignment_set_padding (GTK_ALIGNMENT (widget), 0, 0, 0, 0);
-         gtk_alignment_set (GTK_ALIGNMENT (widget), 0.0, 0.0, 0, 0);
- 
--        widget->priv->box = gtk_hbox_new (FALSE, 2);
++
++        g_type_class_add_private (klass, sizeof (GdmTaskListPrivate));
++}
++
++static void
++gdm_task_list_init (GdmTaskList *widget)
++{
++        widget->priv = GDM_TASK_LIST_GET_PRIVATE (widget);
++
++        gtk_alignment_set_padding (GTK_ALIGNMENT (widget), 0, 0, 0, 0);
++        gtk_alignment_set (GTK_ALIGNMENT (widget), 0.0, 0.0, 0, 0);
++
 +        widget->priv->box = gtk_hbox_new (TRUE, 2);
-         gtk_widget_show (widget->priv->box);
-         gtk_container_add (GTK_CONTAINER (widget),
-                            widget->priv->box);
-@@ -163,7 +262,7 @@ gdm_task_list_finalize (GObject *object)
- 
-         widget = GDM_TASK_LIST (object);
- 
--        g_list_foreach (widget->priv->tasks, (GFunc) g_free, NULL);
++        gtk_widget_show (widget->priv->box);
++        gtk_container_add (GTK_CONTAINER (widget),
++                           widget->priv->box);
++}
++
++static void
++gdm_task_list_finalize (GObject *object)
++{
++        GdmTaskList *widget;
++
++        g_return_if_fail (object != NULL);
++        g_return_if_fail (GDM_IS_TASK_LIST (object));
++
++        widget = GDM_TASK_LIST (object);
++
 +        g_list_foreach (widget->priv->tasks, (GFunc) g_object_unref, NULL);
-         g_list_free (widget->priv->tasks);
- 
-         G_OBJECT_CLASS (gdm_task_list_parent_class)->finalize (object);
-@@ -179,20 +278,46 @@ gdm_task_list_new (void)
-         return GTK_WIDGET (object);
- }
- 
--const char *
++        g_list_free (widget->priv->tasks);
++
++        G_OBJECT_CLASS (gdm_task_list_parent_class)->finalize (object);
++}
++
++GtkWidget *
++gdm_task_list_new (void)
++{
++        GObject *object;
++
++        object = g_object_new (GDM_TYPE_TASK_LIST, NULL);
++
++        return GTK_WIDGET (object);
++}
++
 +gboolean
 +gdm_task_list_task_is_active (GdmTaskList *task_list,
 +                              GdmTask     *task)
@@ -10119,96 +10851,139 @@ index e0fd3d4..3dff10e 100644
 +}
 +
 +GdmTask *
- gdm_task_list_get_active_task (GdmTaskList *widget)
- {
--        GList *node;
++gdm_task_list_get_active_task (GdmTaskList *widget)
++{
 +        return gdm_task_list_foreach_task (widget,
 +                                        (GdmTaskListForeachFunc)
 +                                        gdm_task_list_task_is_active,
 +                                        NULL);
 +}
- 
--        for (node = widget->priv->tasks; node != NULL; node = node->next) {
--                GdmTask *task;
++
 +gboolean
 +gdm_task_list_set_active_task (GdmTaskList *widget,
 +                               GdmTask     *task)
 +{
 +        GtkWidget *button;
- 
--                task = node->data;
++        gboolean   was_sensitive;
++        gboolean   was_activated;
++
++        if (!gdm_task_is_visible (task)) {
++                return FALSE;
++        }
++
++        was_sensitive = GTK_WIDGET_SENSITIVE (widget);
++        gtk_widget_set_sensitive (GTK_WIDGET (widget), TRUE);
++
 +        button = GTK_WIDGET (g_object_get_data (G_OBJECT (task),
 +                             "gdm-task-list-button"));
- 
--                if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (task->radio_button)) ) {
--                        return task->name;
++
++        was_activated = FALSE;
 +        if (GTK_WIDGET_IS_SENSITIVE (button)) {
 +                if (gtk_widget_activate (button)) {
-+                        return TRUE;
-                 }
-         }
- 
--        return NULL;
-+        return FALSE;
++                        was_activated = TRUE;
++                }
++        }
++
++        gtk_widget_set_sensitive (GTK_WIDGET (widget), was_sensitive);
++        return was_activated;
 +}
 +
 +int
 +gdm_task_list_get_number_of_tasks (GdmTaskList *widget)
 +{
 +        return g_list_length (widget->priv->tasks);
- }
++}
++
++int
++gdm_task_list_get_number_of_visible_tasks (GdmTaskList *widget)
++{
++        GList *node;
++        int number_of_visible_tasks;
++
++        number_of_visible_tasks = 0;
++        for (node = widget->priv->tasks; node != NULL; node = node->next) {
++                GdmTask *task;
++
++                task = node->data;
++
++                if (gdm_task_is_enabled (task) && gdm_task_is_visible (task)) {
++                        number_of_visible_tasks++;
++                }
++        }
++
++        return number_of_visible_tasks;
++}
 diff --git a/gui/simple-greeter/gdm-task-list.h b/gui/simple-greeter/gdm-task-list.h
-index ade21b6..8bc0c0e 100644
---- a/gui/simple-greeter/gdm-task-list.h
+new file mode 100644
+index 0000000..1c15168
+--- /dev/null
 +++ b/gui/simple-greeter/gdm-task-list.h
-@@ -22,8 +22,11 @@
- #define __GDM_TASK_LIST_H
- 
- #include <glib-object.h>
+@@ -0,0 +1,85 @@
++/*
++ * Copyright (C) 2009 Red Hat, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ *  Written by: Ray Strode <rstrode at redhat.com>
++ */
++
++#ifndef __GDM_TASK_LIST_H
++#define __GDM_TASK_LIST_H
++
++#include <glib-object.h>
 +#include <gio/gio.h>
- #include <gtk/gtkalignment.h>
- 
++#include <gtk/gtkalignment.h>
++
 +#include "gdm-task.h"
 +
- G_BEGIN_DECLS
- 
- #define GDM_TYPE_TASK_LIST         (gdm_task_list_get_type ())
-@@ -34,31 +37,44 @@ G_BEGIN_DECLS
- #define GDM_TASK_LIST_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_TASK_LIST, GdmTaskListClass))
- 
- typedef struct GdmTaskListPrivate GdmTaskListPrivate;
++G_BEGIN_DECLS
++
++#define GDM_TYPE_TASK_LIST         (gdm_task_list_get_type ())
++#define GDM_TASK_LIST(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_TASK_LIST, GdmTaskList))
++#define GDM_TASK_LIST_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_TASK_LIST, GdmTaskListClass))
++#define GDM_IS_TASK_LIST(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_TASK_LIST))
++#define GDM_IS_TASK_LIST_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_TASK_LIST))
++#define GDM_TASK_LIST_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_TASK_LIST, GdmTaskListClass))
++
++typedef struct GdmTaskListPrivate GdmTaskListPrivate;
 +typedef struct _GdmTaskList GdmTaskList;
- 
--typedef struct
++
 +typedef gboolean (* GdmTaskListForeachFunc) (GdmTaskList *task_list,
 +                                            GdmTask     *task,
 +                                            gpointer     data);
 +
 +struct _GdmTaskList
- {
-         GtkAlignment             parent;
-         GdmTaskListPrivate *priv;
--} GdmTaskList;
++{
++        GtkAlignment             parent;
++        GdmTaskListPrivate *priv;
 +};
- 
- typedef struct
- {
-         GtkAlignmentClass       parent_class;
- 
-         void (* deactivated)      (GdmTaskList *widget,
--                                   const char  *name);
++
++typedef struct
++{
++        GtkAlignmentClass       parent_class;
++
++        void (* deactivated)      (GdmTaskList *widget,
 +                                   GdmTask     *task);
-         void (* activated)      (GdmTaskList *widget,
--                                 const char  *name);
++        void (* activated)      (GdmTaskList *widget,
 +                                 GdmTask     *task);
- } GdmTaskListClass;
- 
++} GdmTaskListClass;
++
 +GType       gdm_task_list_get_type               (void);
 +GtkWidget * gdm_task_list_new                    (void);
 +
- 
--GType                  gdm_task_list_get_type               (void);
--GtkWidget *            gdm_task_list_new                    (void);
++
 +gboolean    gdm_task_list_task_is_active (GdmTaskList *task_list,
 +                                          GdmTask     *task);
 +GdmTask *   gdm_task_list_get_active_task (GdmTaskList *widget);
@@ -10219,30 +10994,68 @@ index ade21b6..8bc0c0e 100644
 +                                     gpointer               data);
 +void        gdm_task_list_add_task        (GdmTaskList *widget,
 +                                           GdmTask     *task);
- 
--const char *           gdm_task_list_get_active_task (GdmTaskList *widget);
--void                   gdm_task_list_add_task (GdmTaskList *widget,
--                                               const char  *name,
--                                               const char  *icon_name);
++
++void        gdm_task_list_remove_task        (GdmTaskList *widget,
++                                              GdmTask     *task);
++
 +int         gdm_task_list_get_number_of_tasks (GdmTaskList *widget);
- G_END_DECLS
- 
- #endif /* __GDM_TASK_LIST_H */
-diff --git a/gui/simple-greeter/libgdmsimplegreeter/Makefile.am b/gui/simple-greeter/libgdmsimplegreeter/Makefile.am
-new file mode 100644
-index 0000000..1ef5725
---- /dev/null
-+++ b/gui/simple-greeter/libgdmsimplegreeter/Makefile.am
-@@ -0,0 +1,46 @@
-+NULL =
 +
-+AM_CPPFLAGS = \
-+	-I.					\
-+	-I..					\
-+	-DBINDIR=\"$(bindir)\"			\
-+	-DDATADIR=\"$(datadir)\"		\
-+	-DLIBDIR=\"$(libdir)\"			\
-+	-DLIBEXECDIR=\"$(libexecdir)\"		\
++int         gdm_task_list_get_number_of_visible_tasks (GdmTaskList *widget);
++G_END_DECLS
++
++#endif /* __GDM_TASK_LIST_H */
+diff --git a/gui/simple-greeter/gdm-user-chooser-widget.c b/gui/simple-greeter/gdm-user-chooser-widget.c
+index 211b033..33708b9 100644
+--- a/gui/simple-greeter/gdm-user-chooser-widget.c
++++ b/gui/simple-greeter/gdm-user-chooser-widget.c
+@@ -365,9 +365,30 @@ gdm_user_chooser_widget_set_show_user_auto (GdmUserChooserWidget *widget,
+ char *
+ gdm_user_chooser_widget_get_chosen_user_name (GdmUserChooserWidget *widget)
+ {
++        char *active_item_id;
++        gboolean isnt_user;
++
+         g_return_val_if_fail (GDM_IS_USER_CHOOSER_WIDGET (widget), NULL);
+ 
+-        return gdm_chooser_widget_get_active_item (GDM_CHOOSER_WIDGET (widget));
++        active_item_id = gdm_chooser_widget_get_active_item (GDM_CHOOSER_WIDGET (widget));
++        if (active_item_id == NULL) {
++                g_debug ("GdmUserChooserWidget: no active item in list");
++                return NULL;
++        }
++
++        gdm_chooser_widget_lookup_item (GDM_CHOOSER_WIDGET (widget), active_item_id,
++                                        NULL, NULL, NULL, NULL, NULL,
++                                        &isnt_user);
++
++        if (isnt_user) {
++                g_debug ("GdmUserChooserWidget: active item '%s' isn't a user", active_item_id);
++                g_free (active_item_id);
++                return NULL;
++        }
++
++        g_debug ("GdmUserChooserWidget: active item '%s' is a user", active_item_id);
++
++        return active_item_id;
+ }
+ 
+ void
+diff --git a/gui/simple-greeter/libgdmsimplegreeter/Makefile.am b/gui/simple-greeter/libgdmsimplegreeter/Makefile.am
+new file mode 100644
+index 0000000..0d7a0bd
+--- /dev/null
++++ b/gui/simple-greeter/libgdmsimplegreeter/Makefile.am
+@@ -0,0 +1,48 @@
++NULL =
++
++AM_CPPFLAGS = \
++	-I.					\
++	-I..					\
++	-I$(top_srcdir)/common			\
++	-DBINDIR=\"$(bindir)\"			\
++	-DDATADIR=\"$(datadir)\"		\
++	-DLIBDIR=\"$(libdir)\"			\
++	-DLIBEXECDIR=\"$(libexecdir)\"		\
 +	-DLOGDIR=\"$(logdir)\"			\
 +	-DPIXMAPDIR=\"$(pixmapdir)\"		\
 +	-DSBINDIR=\"$(sbindir)\"		\
@@ -10264,6 +11077,7 @@ index 0000000..1ef5725
 +
 +libgdmsimplegreeter_la_LIBADD =			\
 +	$(GTK_LIBS)				\
++	$(top_builddir)/common/libgdmcommon.la	\
 +	$(NULL)
 +
 +libgdmsimplegreeter_la_LDFLAGS = 		\
@@ -10282,10 +11096,10 @@ index 0000000..1ef5725
 +MAINTAINERCLEANFILES = Makefile.in
 diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c
 new file mode 100644
-index 0000000..e21c56b
+index 0000000..ee763ef
 --- /dev/null
 +++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c
-@@ -0,0 +1,147 @@
+@@ -0,0 +1,186 @@
 +/*
 + * Copyright (C) 2009 Red Hat, Inc.
 + *
@@ -10313,11 +11127,13 @@ index 0000000..e21c56b
 +#include <gtk/gtk.h>
 +
 +#include "gdm-conversation.h"
++#include "gdm-marshal.h"
 +#include "gdm-task.h"
 +
-+
 +enum {
 +        ANSWER,
++        USER_CHOSEN,
++        CANCEL,
 +        LAST_SIGNAL
 +};
 +
@@ -10359,6 +11175,25 @@ index 0000000..e21c56b
 +                              g_cclosure_marshal_VOID__STRING,
 +                              G_TYPE_NONE,
 +                              1, G_TYPE_STRING);
++        signals [USER_CHOSEN] =
++                g_signal_new ("user-chosen",
++                              iface_type,
++                              G_SIGNAL_RUN_LAST,
++                              G_STRUCT_OFFSET (GdmConversationIface, user_chosen),
++                              NULL,
++                              NULL,
++                              gdm_marshal_BOOLEAN__STRING,
++                              G_TYPE_BOOLEAN,
++                              1, G_TYPE_STRING);
++        signals [CANCEL] =
++                g_signal_new ("cancel",
++                              iface_type,
++                              G_SIGNAL_RUN_FIRST,
++                              G_STRUCT_OFFSET (GdmConversationIface, cancel),
++                              NULL,
++                              NULL,
++                              g_cclosure_marshal_VOID__VOID,
++                              G_TYPE_NONE, 0);
 +}
 +
 +void
@@ -10433,12 +11268,30 @@ index 0000000..e21c56b
 +        g_signal_emit (conversation, signals [ANSWER], 0, answer);
 +}
 +
++void
++gdm_conversation_cancel (GdmConversation   *conversation)
++{
++        g_signal_emit (conversation, signals [CANCEL], 0);
++}
++
++gboolean
++gdm_conversation_choose_user (GdmConversation *conversation,
++                              const char      *username)
++{
++        gboolean was_chosen;
++
++        was_chosen = FALSE;
++
++        g_signal_emit (conversation, signals [USER_CHOSEN], 0, username, &was_chosen);
++
++        return was_chosen;
++}
 diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h
 new file mode 100644
-index 0000000..f1910cf
+index 0000000..b37b21e
 --- /dev/null
 +++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h
-@@ -0,0 +1,87 @@
+@@ -0,0 +1,93 @@
 +/*
 + * Copyright (C) Red Hat, Inc.
 + *
@@ -10475,6 +11328,7 @@ index 0000000..f1910cf
 +#define GDM_CONVERSATION_GET_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), GDM_TYPE_CONVERSATION, GdmConversationIface))
 +
 +#define GDM_CONVERSATION_DEFAULT_ACTION "default-action"
++#define GDM_CONVERSATION_OTHER_USER "__other"
 +
 +typedef struct _GdmConversation      GdmConversation;
 +typedef struct _GdmConversationIface GdmConversationIface;
@@ -10500,6 +11354,8 @@ index 0000000..f1910cf
 +
 +        /* signals */
 +        char * (* answer)       (GdmConversation *conversation);
++        void   (* cancel)       (GdmConversation *conversation);
++        gboolean  (* user_chosen)  (GdmConversation *conversation);
 +};
 +
 +GType  gdm_conversation_get_type     (void) G_GNUC_CONST;
@@ -10522,6 +11378,9 @@ index 0000000..f1910cf
 + */
 +void   gdm_conversation_answer (GdmConversation   *conversation,
 +                                const char        *answer);
++void   gdm_conversation_cancel (GdmConversation   *conversation);
++gboolean  gdm_conversation_choose_user (GdmConversation   *conversation,
++                                        const char        *username);
 +
 +G_END_DECLS
 +
@@ -10688,10 +11547,10 @@ index 0000000..283ba0e
 +#endif /* __GDM_GREETER_EXTENSION_H */
 diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-task.c b/gui/simple-greeter/libgdmsimplegreeter/gdm-task.c
 new file mode 100644
-index 0000000..f72fa78
+index 0000000..858b1ef
 --- /dev/null
 +++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-task.c
-@@ -0,0 +1,117 @@
+@@ -0,0 +1,129 @@
 +/*
 + * Copyright (C) 2009 Red Hat, Inc.
 + *
@@ -10782,6 +11641,18 @@ index 0000000..f72fa78
 +        return !g_object_get_data (G_OBJECT (task), "gdm-task-is-disabled");
 +}
 +
++gboolean
++gdm_task_is_choosable (GdmTask *task)
++{
++        return GDM_TASK_GET_IFACE (task)->is_choosable (task);
++}
++
++gboolean
++gdm_task_is_visible (GdmTask *task)
++{
++        return GDM_TASK_GET_IFACE (task)->is_visible (task);
++}
++
 +static void
 +gdm_task_class_init (gpointer g_iface)
 +{
@@ -10811,10 +11682,10 @@ index 0000000..f72fa78
 +}
 diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-task.h b/gui/simple-greeter/libgdmsimplegreeter/gdm-task.h
 new file mode 100644
-index 0000000..9894e65
+index 0000000..51e2b0a
 --- /dev/null
 +++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-task.h
-@@ -0,0 +1,62 @@
+@@ -0,0 +1,66 @@
 +/*
 + * Copyright (C) Red Hat, Inc.
 + *
@@ -10861,6 +11732,8 @@ index 0000000..9894e65
 +        GIcon * (* get_icon)        (GdmTask   *task);
 +        char *  (* get_description) (GdmTask   *task);
 +        char *  (* get_name)        (GdmTask   *task);
++        gboolean  (* is_choosable)    (GdmTask   *task);
++        gboolean  (* is_visible)    (GdmTask   *task);
 +        /* signals */
 +        void (* enabled) (GdmTask *task);
 +        void (* disabled) (GdmTask *task);
@@ -10874,6 +11747,8 @@ index 0000000..9894e65
 +void   gdm_task_set_enabled     (GdmTask   *task,
 +                                 gboolean   should_enable);
 +gboolean   gdm_task_is_enabled     (GdmTask   *task);
++gboolean   gdm_task_is_choosable   (GdmTask   *task);
++gboolean   gdm_task_is_visible   (GdmTask   *task);
 +G_END_DECLS
 +
 +#endif /* __GDM_TASK_H */
@@ -10962,10 +11837,10 @@ index 0000000..764904d
 +        Makefile.in
 diff --git a/gui/simple-greeter/plugins/password/gdm-password-extension.c b/gui/simple-greeter/plugins/password/gdm-password-extension.c
 new file mode 100644
-index 0000000..3acab3f
+index 0000000..255283e
 --- /dev/null
 +++ b/gui/simple-greeter/plugins/password/gdm-password-extension.c
-@@ -0,0 +1,314 @@
+@@ -0,0 +1,328 @@
 +/*
 + * Copyright (C) 2009 Red Hat, Inc.
 + *
@@ -11156,12 +12031,26 @@ index 0000000..3acab3f
 +        return g_strdup (_("Log into session with username and password"));
 +}
 +
++gboolean
++gdm_password_extension_is_choosable (GdmTask *task)
++{
++        return FALSE;
++}
++
++gboolean
++gdm_password_extension_is_visible (GdmTask *task)
++{
++        return TRUE;
++}
++
 +static void
 +gdm_task_iface_init (GdmTaskIface *iface)
 +{
 +        iface->get_icon = gdm_password_extension_get_icon;
 +        iface->get_description = gdm_password_extension_get_description;
 +        iface->get_name = gdm_password_extension_get_name;
++        iface->is_choosable = gdm_password_extension_is_choosable;
++        iface->is_visible = gdm_password_extension_is_visible;
 +}
 +
 +static void
@@ -11369,10 +12258,10 @@ index 0000000..bac431d
 +session     required      pam_unix.so
 diff --git a/gui/simple-greeter/plugins/password/page.ui b/gui/simple-greeter/plugins/password/page.ui
 new file mode 100644
-index 0000000..fe6da78
+index 0000000..8fa5c7b
 --- /dev/null
 +++ b/gui/simple-greeter/plugins/password/page.ui
-@@ -0,0 +1,56 @@
+@@ -0,0 +1,57 @@
 +<?xml version="1.0"?>
 +<interface>
 +  <requires lib="gtk+" version="2.14"/>
@@ -11382,6 +12271,7 @@ index 0000000..fe6da78
 +      <child>
 +        <object class="GtkHBox" id="auth-input-box">
 +          <property name="visible">True</property>
++          <property name="spacing">6</property>
 +          <child>
 +            <object class="GtkLabel" id="auth-prompt-label">
 +              <property name="visible">True</property>
@@ -11488,345 +12378,208 @@ index 1fccb90..7c344c9 100644
  gui/user-switch-applet/gdm-entry-menu-item.c
  gui/user-switch-applet/GNOME_FastUserSwitchApplet.server.in.in
 -- 
-1.6.5.2
+1.7.2.1
 
 
-From 8094d63efe5aacf78b00709baa7ec645919ed09d Mon Sep 17 00:00:00 2001
+From b5ea9d8c7671dbdcabdf76fa523d5bd339826628 Mon Sep 17 00:00:00 2001
 From: Ray Strode <rstrode at redhat.com>
-Date: Sat, 7 Feb 2009 21:17:49 -0500
-Subject: [PATCH 12/45] Force session reset if all PAM conversations fail
+Date: Wed, 4 Aug 2010 18:25:50 -0400
+Subject: [PATCH 18/35] squash with password
 
 ---
- gui/simple-greeter/gdm-greeter-login-window.c |   22 +++++++++++++++++++---
- 1 files changed, 19 insertions(+), 3 deletions(-)
+ .../plugins/password/gdm-password-extension.c      |   11 ++++++++++-
+ 1 files changed, 10 insertions(+), 1 deletions(-)
 
-diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
-index 6becaa0..c411c76 100644
---- a/gui/simple-greeter/gdm-greeter-login-window.c
-+++ b/gui/simple-greeter/gdm-greeter-login-window.c
-@@ -693,15 +693,21 @@ reset_dialog (GdmGreeterLoginWindow *login_window)
+diff --git a/gui/simple-greeter/plugins/password/gdm-password-extension.c b/gui/simple-greeter/plugins/password/gdm-password-extension.c
+index 255283e..11a171c 100644
+--- a/gui/simple-greeter/plugins/password/gdm-password-extension.c
++++ b/gui/simple-greeter/plugins/password/gdm-password-extension.c
+@@ -33,6 +33,7 @@ struct _GdmPasswordExtensionPrivate
+         GIcon     *icon;
+         GtkWidget *page;
+         GtkActionGroup *actions;
++        GtkAction *login_action;
+ 
+         GtkWidget *message_label;
+         GtkWidget *prompt_label;
+@@ -78,6 +79,8 @@ gdm_password_extension_ask_question (GdmConversation *conversation,
+         gtk_widget_show (extension->priv->prompt_entry);
+         gtk_widget_grab_focus (extension->priv->prompt_entry);
+         extension->priv->answer_pending = TRUE;
++
++        gtk_action_set_sensitive (extension->priv->login_action, TRUE);
  }
  
  static void
--do_cancel (GdmGreeterLoginWindow *login_window)
-+restart_conversations (GdmGreeterLoginWindow *login_window)
+@@ -92,6 +95,8 @@ gdm_password_extension_ask_secret (GdmConversation *conversation,
+         gtk_widget_show (extension->priv->prompt_entry);
+         gtk_widget_grab_focus (extension->priv->prompt_entry);
+         extension->priv->answer_pending = TRUE;
++
++        gtk_action_set_sensitive (extension->priv->login_action, TRUE);
+ }
+ 
+ static void
+@@ -249,9 +254,11 @@ gdm_password_extension_finalize (GObject *object)
+ }
+ 
+ static void
+-on_activate_log_in (GdmPasswordExtension *extension)
++on_activate_log_in (GdmPasswordExtension *extension,
++                    GtkAction            *action)
  {
--        /* need to wait for response from backend */
--        set_message (login_window, _("Cancelling..."));
-         set_busy (login_window);
-         set_sensitive (login_window, FALSE);
-         g_signal_emit (login_window, signals[CANCELLED], 0);
+         gdm_password_extension_request_answer (GDM_CONVERSATION (extension));
++        gtk_action_set_sensitive (action, FALSE);
  }
  
-+static void
-+do_cancel (GdmGreeterLoginWindow *login_window)
-+{
-+        /* need to wait for response from backend */
-+        set_message (login_window, _("Cancelling..."));
-+        restart_conversations (login_window);
-+}
+ static void
+@@ -311,6 +318,8 @@ create_actions (GdmPasswordExtension *extension)
+         g_object_set (G_OBJECT (action), "icon-name", "go-home", NULL);
+         gtk_action_group_add_action (extension->priv->actions,
+                                      action);
 +
- gboolean
- gdm_greeter_login_window_ready (GdmGreeterLoginWindow *login_window,
-                                 const char            *service_name)
-@@ -749,6 +755,16 @@ gdm_greeter_login_window_conversation_stopped (GdmGreeterLoginWindow *login_wind
-                 g_object_unref (task);
++        extension->priv->login_action = action;
+ }
+ 
+ static void
+-- 
+1.7.2.1
+
+
+From 36baeff2c9b1b625301a342d183102f686444b90 Mon Sep 17 00:00:00 2001
+From: Ray Strode <rstrode at redhat.com>
+Date: Fri, 6 Aug 2010 11:13:10 -0400
+Subject: [PATCH 19/35] task list fix
+
+---
+ gui/simple-greeter/gdm-task-list.c |   11 ++++++++---
+ 1 files changed, 8 insertions(+), 3 deletions(-)
+
+diff --git a/gui/simple-greeter/gdm-task-list.c b/gui/simple-greeter/gdm-task-list.c
+index a7f8c74..906938d 100644
+--- a/gui/simple-greeter/gdm-task-list.c
++++ b/gui/simple-greeter/gdm-task-list.c
+@@ -68,7 +68,6 @@ on_task_toggled (GdmTaskList    *widget,
+         if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) {
+ 
+                 GList     *task_node;
+-
+                 /* Sort the list such that the tasks the user clicks last end
+                  * up first.  This doesn't change the order in which the tasks
+                  * appear in the UI, but will affect which tasks we implicitly
+@@ -135,7 +134,6 @@ activate_first_available_task (GdmTaskList *task_list)
+ 
+                 node = node->next;
          }
+-
+ }
  
-+        /* If every conversation has failed, then just start over.
-+         */
-+        task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
+ static void
+@@ -218,8 +216,15 @@ gdm_task_list_remove_task (GdmTaskList *task_list,
+                            GdmTask     *task)
+ {
+         GtkWidget *button;
++        GList     *node;
 +
-+        if (!gdm_task_is_enabled (task)) {
-+                g_debug ("GdmGreeterLoginWindow: No conversations left, starting over");
-+                restart_conversations (login_window);
-+        }
-+        g_object_unref (task);
++        node = g_list_find (task_list->priv->tasks, task);
 +
-         return TRUE;
- }
++        if (node == NULL) {
++                return;
++        }
+ 
+-        task_list->priv->tasks = g_list_remove (task_list->priv->tasks, task);
++        task_list->priv->tasks = g_list_delete_link (task_list->priv->tasks, node);
+ 
+         button = g_object_get_data (G_OBJECT (task), "gdm-task-list-button");
  
 -- 
-1.6.5.2
+1.7.2.1
 
 
-From a05f9c20b28fc210d973d51f0b663852ab2415eb Mon Sep 17 00:00:00 2001
+From 9b7b6cb2950c1ed71d0091d96027c4d2eb40e966 Mon Sep 17 00:00:00 2001
 From: Ray Strode <rstrode at redhat.com>
-Date: Wed, 18 Feb 2009 12:32:39 -0500
-Subject: [PATCH 13/45] Add a way for plugins to pick users from list
+Date: Tue, 29 Jun 2010 14:13:35 -0400
+Subject: [PATCH 20/35] Show cancel button after first message
 
-The smartcard plugin is going to want to
-start its conversation as soon as the card
-gets plugged in.
+Not all PAM modules ask for input at the keyboard. We need
+to show the cancel button after the first message even if
+that message isn't asking for input.
 ---
- gui/simple-greeter/gdm-greeter-login-window.c      |   36 ++++++++++++++++++++
- .../libgdmsimplegreeter/gdm-conversation.c         |   32 +++++++++++++++++
- .../libgdmsimplegreeter/gdm-conversation.h         |    6 +++
- 3 files changed, 74 insertions(+), 0 deletions(-)
+ gui/simple-greeter/gdm-greeter-login-window.c |    3 +++
+ 1 files changed, 3 insertions(+), 0 deletions(-)
 
 diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
-index c411c76..c84ba1c 100644
+index 36a6d21..5845c7b 100644
 --- a/gui/simple-greeter/gdm-greeter-login-window.c
 +++ b/gui/simple-greeter/gdm-greeter-login-window.c
-@@ -1836,6 +1836,34 @@ on_conversation_answer (GdmGreeterLoginWindow *login_window,
+@@ -827,6 +827,7 @@ reset_dialog (GdmGreeterLoginWindow *login_window,
+                 switch_mode (login_window, dialog_mode);
+         }
+ 
++        gtk_widget_set_sensitive (login_window->priv->conversation_list, TRUE);
+         set_sensitive (login_window, TRUE);
          set_ready (login_window);
- }
+         set_focus (GDM_GREETER_LOGIN_WINDOW (login_window));
+@@ -977,6 +978,7 @@ gdm_greeter_login_window_info (GdmGreeterLoginWindow *login_window,
+         g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
+         g_debug ("GdmGreeterLoginWindow: info: %s", text);
  
-+static void
-+on_conversation_cancel (GdmGreeterLoginWindow *login_window,
-+                        GdmConversation       *conversation)
-+{
-+        do_cancel (login_window);
-+}
-+
-+static void
-+on_conversation_chose_user (GdmGreeterLoginWindow *login_window,
-+                            const char            *username,
-+                            GdmConversation       *conversation)
-+{
-+        if (!gdm_chooser_widget_is_loaded (GDM_CHOOSER_WIDGET (login_window->priv->user_chooser))) {
-+                char *name;
-+
-+                name = gdm_task_get_name (GDM_TASK (conversation));
-+                g_warning ("Task %s is trying to choose user before list is loaded", name);
-+                g_free (name);
++        maybe_show_cancel_button (login_window);
+         task = find_task_with_service_name (login_window, service_name);
+ 
+         if (task != NULL) {
+@@ -999,6 +1001,7 @@ gdm_greeter_login_window_problem (GdmGreeterLoginWindow *login_window,
+         g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
+         g_debug ("GdmGreeterLoginWindow: problem: %s", text);
+ 
++        maybe_show_cancel_button (login_window);
+         task = find_task_with_service_name (login_window, service_name);
+ 
+         if (task != NULL) {
+-- 
+1.7.2.1
+
+
+From ceece80bd67dd943d1888b8b6cd0a14d0afe188b Mon Sep 17 00:00:00 2001
+From: Ray Strode <rstrode at redhat.com>
+Date: Wed, 28 Oct 2009 11:13:10 -0400
+Subject: [PATCH 21/35] Prevent start session signal handler from getting called multiple times
+
+It was causing a double free.
+---
+ gui/simple-greeter/gdm-greeter-login-window.c |    9 +++++++++
+ 1 files changed, 9 insertions(+), 0 deletions(-)
+
+diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
+index 5845c7b..d0c0781 100644
+--- a/gui/simple-greeter/gdm-greeter-login-window.c
++++ b/gui/simple-greeter/gdm-greeter-login-window.c
+@@ -1086,8 +1086,17 @@ on_ready_to_start_session (GdmGreeterLoginWindow *login_window,
+                            GParamSpec            *param_spec,
+                            char                  *service_name)
+ {
++        if (!login_window->priv->is_interactive) {
 +                return;
 +        }
 +
-+        if (gdm_task_list_set_active_task (GDM_TASK_LIST (login_window->priv->conversation_list),
-+                                           GDM_TASK (conversation))) {
-+                gdm_user_chooser_widget_set_chosen_user_name (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser),
-+                                                              username);
-+        }
-+}
-+
- void
- gdm_greeter_login_window_remove_extension (GdmGreeterLoginWindow *login_window,
-  GdmGreeterExtension *extension)
-@@ -1973,6 +2001,14 @@ gdm_greeter_login_window_add_extension (GdmGreeterLoginWindow *login_window,
-                                   "answer",
-                                   G_CALLBACK (on_conversation_answer),
-                                   login_window);
-+        g_signal_connect_swapped (GDM_CONVERSATION (extension),
-+                                  "cancel",
-+                                  G_CALLBACK (on_conversation_cancel),
-+                                  login_window);
-+        g_signal_connect_swapped (GDM_CONVERSATION (extension),
-+                                  "user-chosen",
-+                                  G_CALLBACK (on_conversation_chose_user),
-+                                  login_window);
- 
-         name = gdm_task_get_name (GDM_TASK (extension));
-         description = gdm_task_get_description (GDM_TASK (extension));
-diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c
-index e21c56b..cef435c 100644
---- a/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c
-+++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c
-@@ -30,6 +30,8 @@
- 
- enum {
-         ANSWER,
-+        USER_CHOSEN,
-+        CANCEL,
-         LAST_SIGNAL
- };
- 
-@@ -71,6 +73,25 @@ gdm_conversation_class_init (gpointer g_iface)
-                               g_cclosure_marshal_VOID__STRING,
-                               G_TYPE_NONE,
-                               1, G_TYPE_STRING);
-+        signals [USER_CHOSEN] =
-+                g_signal_new ("user-chosen",
-+                              iface_type,
-+                              G_SIGNAL_RUN_FIRST,
-+                              G_STRUCT_OFFSET (GdmConversationIface, user_chosen),
-+                              NULL,
-+                              NULL,
-+                              g_cclosure_marshal_VOID__STRING,
-+                              G_TYPE_NONE,
-+                              1, G_TYPE_STRING);
-+        signals [CANCEL] =
-+                g_signal_new ("cancel",
-+                              iface_type,
-+                              G_SIGNAL_RUN_FIRST,
-+                              G_STRUCT_OFFSET (GdmConversationIface, cancel),
-+                              NULL,
-+                              NULL,
-+                              g_cclosure_marshal_VOID__VOID,
-+                              G_TYPE_NONE, 0);
- }
- 
- void
-@@ -145,3 +166,14 @@ gdm_conversation_answer (GdmConversation   *conversation,
-         g_signal_emit (conversation, signals [ANSWER], 0, answer);
- }
- 
-+void
-+gdm_conversation_cancel (GdmConversation   *conversation)
-+{
-+        g_signal_emit (conversation, signals [CANCEL], 0);
-+}
-+void
-+gdm_conversation_choose_user (GdmConversation *conversation,
-+                              const char      *username)
-+{
-+        g_signal_emit (conversation, signals [USER_CHOSEN], 0, username);
-+}
-diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h
-index f1910cf..fb4bf49 100644
---- a/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h
-+++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h
-@@ -34,6 +34,7 @@ G_BEGIN_DECLS
- #define GDM_CONVERSATION_GET_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), GDM_TYPE_CONVERSATION, GdmConversationIface))
- 
- #define GDM_CONVERSATION_DEFAULT_ACTION "default-action"
-+#define GDM_CONVERSATION_OTHER_USER "__other"
- 
- typedef struct _GdmConversation      GdmConversation;
- typedef struct _GdmConversationIface GdmConversationIface;
-@@ -59,6 +60,8 @@ struct _GdmConversationIface
- 
-         /* signals */
-         char * (* answer)       (GdmConversation *conversation);
-+        void   (* cancel)       (GdmConversation *conversation);
-+        void   (* user_chosen)     (GdmConversation *conversation);
- };
- 
- GType  gdm_conversation_get_type     (void) G_GNUC_CONST;
-@@ -81,6 +84,9 @@ gboolean   gdm_conversation_focus    (GdmConversation *conversation);
-  */
- void   gdm_conversation_answer (GdmConversation   *conversation,
-                                 const char        *answer);
-+void   gdm_conversation_cancel (GdmConversation   *conversation);
-+void   gdm_conversation_choose_user (GdmConversation   *conversation,
-+                                     const char        *username);
- 
- G_END_DECLS
- 
--- 
-1.6.5.2
-
-
-From 06025871fec0c2b9bd2f92f9d91e4bc400ef66f0 Mon Sep 17 00:00:00 2001
-From: Ray Strode <rstrode at redhat.com>
-Date: Fri, 20 Feb 2009 14:05:20 -0500
-Subject: [PATCH 14/45] Add new api to ask when chooser widget is done loading items
-
----
- gui/simple-greeter/gdm-chooser-widget.c |    8 ++++++++
- gui/simple-greeter/gdm-chooser-widget.h |    2 ++
- 2 files changed, 10 insertions(+), 0 deletions(-)
-
-diff --git a/gui/simple-greeter/gdm-chooser-widget.c b/gui/simple-greeter/gdm-chooser-widget.c
-index 0f6859a..2282179 100644
---- a/gui/simple-greeter/gdm-chooser-widget.c
-+++ b/gui/simple-greeter/gdm-chooser-widget.c
-@@ -92,6 +92,7 @@ struct GdmChooserWidgetPrivate
- 
-         guint32                  should_hide_inactive_items : 1;
-         guint32                  emit_activated_after_resize_animation : 1;
-+        guint32                  is_loaded : 1;
- 
-         GdmChooserWidgetPosition separator_position;
-         GdmChooserWidgetState    state;
-@@ -2518,9 +2519,16 @@ gdm_chooser_widget_propagate_pending_key_events (GdmChooserWidget *widget)
-         gdm_scrollable_widget_replay_queued_key_events (GDM_SCROLLABLE_WIDGET (widget->priv->scrollable_widget));
- }
- 
-+gboolean
-+gdm_chooser_widget_is_loaded (GdmChooserWidget *widget)
-+{
-+        return widget->priv->is_loaded;
-+}
-+
- void
- gdm_chooser_widget_loaded (GdmChooserWidget *widget)
- {
-         gdm_chooser_widget_grow (widget);
-+        widget->priv->is_loaded = TRUE;
-         g_signal_emit (widget, signals[LOADED], 0);
- }
-diff --git a/gui/simple-greeter/gdm-chooser-widget.h b/gui/simple-greeter/gdm-chooser-widget.h
-index 7e3e59c..6a07843 100644
---- a/gui/simple-greeter/gdm-chooser-widget.h
-+++ b/gui/simple-greeter/gdm-chooser-widget.h
-@@ -136,6 +136,8 @@ int            gdm_chooser_widget_get_number_of_items          (GdmChooserWidget
- void           gdm_chooser_widget_activate_if_one_item         (GdmChooserWidget          *widget);
- void           gdm_chooser_widget_propagate_pending_key_events (GdmChooserWidget          *widget);
- 
-+gboolean       gdm_chooser_widget_is_loaded                    (GdmChooserWidget          *widget);
+         gdm_greeter_login_window_start_session_when_ready (login_window, service_name);
+         g_free (service_name);
 +
- /* Protected
-  */
- void           gdm_chooser_widget_loaded                       (GdmChooserWidget          *widget);
--- 
-1.6.5.2
-
-
-From a175227f789f92990543c5beb81b0ea4363e83de Mon Sep 17 00:00:00 2001
-From: Ray Strode <rstrode at redhat.com>
-Date: Fri, 20 Feb 2009 14:31:27 -0500
-Subject: [PATCH 15/45] Tell tasks they're ready only after user list loads
-
-This way they won't try to access the list prematurely.
----
- gui/simple-greeter/gdm-greeter-login-window.c |   28 ++++++++++++++++++++++++-
- 1 files changed, 27 insertions(+), 1 deletions(-)
-
-diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
-index c84ba1c..7c34c4a 100644
---- a/gui/simple-greeter/gdm-greeter-login-window.c
-+++ b/gui/simple-greeter/gdm-greeter-login-window.c
-@@ -708,6 +708,27 @@ do_cancel (GdmGreeterLoginWindow *login_window)
-         restart_conversations (login_window);
++        if (login_window->priv->start_session_handler_id > 0) {
++                g_signal_handler_disconnect (login_window, login_window->priv->start_session_handler_id);
++                login_window->priv->start_session_handler_id = 0;
++        }
  }
  
-+static void
-+on_can_set_task_ready (GtkWidget *user_chooser,
-+                       GdmTask   *task)
-+{
-+        g_signal_handlers_disconnect_by_func (user_chooser,
-+                                              on_can_set_task_ready,
-+                                              task);
-+        gdm_conversation_set_ready (GDM_CONVERSATION (task));
-+        g_object_unref (task);
-+}
-+
-+static void
-+set_task_ready_when_loaded (GdmGreeterLoginWindow *login_window,
-+                            GdmTask               *task)
-+{
-+        g_signal_connect (login_window->priv->user_chooser,
-+                          "loaded",
-+                          G_CALLBACK (on_can_set_task_ready),
-+                          g_object_ref (task));
-+}
-+
- gboolean
- gdm_greeter_login_window_ready (GdmGreeterLoginWindow *login_window,
-                                 const char            *service_name)
-@@ -719,7 +740,12 @@ gdm_greeter_login_window_ready (GdmGreeterLoginWindow *login_window,
-         task = find_task_with_service_name (login_window, service_name);
- 
-         if (task != NULL) {
--                gdm_conversation_set_ready (GDM_CONVERSATION (task));
-+                if (gdm_chooser_widget_is_loaded (GDM_CHOOSER_WIDGET (login_window->priv->user_chooser))) {
-+                        gdm_conversation_set_ready (GDM_CONVERSATION (task));
-+                } else {
-+
-+                        set_task_ready_when_loaded (login_window, task);
-+                }
-                 g_object_unref (task);
-         }
- 
+ static void
 -- 
-1.6.5.2
+1.7.2.1
 
 
-From cbaef7f79019d648a7bb96d2f660dc23b0bd1a3f Mon Sep 17 00:00:00 2001
+From ff1cf4ba57e24b40ef74eaffb14bf842b1cd96a4 Mon Sep 17 00:00:00 2001
 From: Ray Strode <rstrode at redhat.com>
 Date: Fri, 6 Feb 2009 16:25:47 -0500
-Subject: [PATCH 16/45] Add fingerprint plugin
+Subject: [PATCH 22/35] Add fingerprint plugin
 
 This commit adds a plugin to initiate a conversation for
 fingerprint scans.
@@ -11834,18 +12587,18 @@ fingerprint scans.
  configure.ac                                       |    4 +
  gui/simple-greeter/plugins/Makefile.am             |    2 +-
  gui/simple-greeter/plugins/fingerprint/Makefile.am |   56 ++++
- .../fingerprint/gdm-fingerprint-extension.c        |  299 ++++++++++++++++++++
+ .../fingerprint/gdm-fingerprint-extension.c        |  347 ++++++++++++++++++++
  .../fingerprint/gdm-fingerprint-extension.h        |   56 ++++
- .../plugins/fingerprint/gdm-fingerprint.pam        |   17 ++
+ .../plugins/fingerprint/gdm-fingerprint.pam        |   17 +
  .../plugins/fingerprint/icons/16x16/Makefile.am    |    5 +
  .../fingerprint/icons/16x16/gdm-fingerprint.png    |  Bin 0 -> 461 bytes
  .../plugins/fingerprint/icons/48x48/Makefile.am    |    5 +
  .../fingerprint/icons/48x48/gdm-fingerprint.png    |  Bin 0 -> 1638 bytes
  .../plugins/fingerprint/icons/Makefile.am          |    1 +
- gui/simple-greeter/plugins/fingerprint/page.ui     |   56 ++++
+ gui/simple-greeter/plugins/fingerprint/page.ui     |   57 ++++
  gui/simple-greeter/plugins/fingerprint/plugin.c    |   40 +++
  po/POTFILES.in                                     |    1 +
- 14 files changed, 541 insertions(+), 1 deletions(-)
+ 14 files changed, 590 insertions(+), 1 deletions(-)
  create mode 100644 gui/simple-greeter/plugins/fingerprint/Makefile.am
  create mode 100644 gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c
  create mode 100644 gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.h
@@ -11859,10 +12612,10 @@ fingerprint scans.
  create mode 100644 gui/simple-greeter/plugins/fingerprint/plugin.c
 
 diff --git a/configure.ac b/configure.ac
-index ae0c399..24b4c5a 100644
+index ab35800..af7c2f3 100644
 --- a/configure.ac
 +++ b/configure.ac
-@@ -1435,6 +1435,10 @@ gui/simple-greeter/libgdmsimplegreeter/Makefile
+@@ -1445,6 +1445,10 @@ gui/simple-greeter/libgdmsimplegreeter/Makefile
  gui/simple-greeter/libgdmsimplegreeter/gdmsimplegreeter.pc
  gui/simple-greeter/plugins/Makefile
  gui/simple-greeter/plugins/password/Makefile
@@ -11944,10 +12697,10 @@ index 0000000..25fb6e8
 +        Makefile.in
 diff --git a/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c b/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c
 new file mode 100644
-index 0000000..b20dd65
+index 0000000..55f5d32
 --- /dev/null
 +++ b/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c
-@@ -0,0 +1,299 @@
+@@ -0,0 +1,347 @@
 +/*
 + * Copyright (C) 2009 Red Hat, Inc.
 + *
@@ -11970,6 +12723,8 @@ index 0000000..b20dd65
 + */
 +
 +#include <config.h>
++#include <stdlib.h>
++
 +#include "gdm-fingerprint-extension.h"
 +#include "gdm-conversation.h"
 +#include "gdm-task.h"
@@ -12138,12 +12893,60 @@ index 0000000..b20dd65
 +        return g_strdup (_("Log into session with fingerprint"));
 +}
 +
++gboolean
++gdm_fingerprint_extension_is_choosable (GdmTask *task)
++{
++        return FALSE;
++}
++
++gboolean
++gdm_fingerprint_extension_is_visible (GdmTask *task)
++{
++        char *contents, **lines;
++        gboolean ret;
++        guint i;
++
++        /* Stolen from gnome-about-me.
++         *
++         * FIXME: We should fix pam_fprintd to return authinfo_unavail instead of
++         * doing this distro specific hack.
++         */
++
++        if (g_file_get_contents ("/etc/sysconfig/authconfig",
++                                 &contents, NULL, NULL) == FALSE) {
++                return FALSE;
++        }
++
++        lines = g_strsplit (contents, "\n", -1);
++        g_free (contents);
++
++        ret = FALSE;
++
++        for (i = 0; lines[i] ; i++) {
++                if (g_str_has_prefix (lines[i], "USEFPRINTD=") != FALSE) {
++                        char *value;
++
++                        value = lines[i] + strlen ("USEFPRINTD=");
++                        if (rpmatch (value)) {
++                                ret = TRUE;
++                                break;
++                        }
++                }
++        }
++
++        g_strfreev (lines);
++
++        return ret;
++}
++
 +static void
 +gdm_task_iface_init (GdmTaskIface *iface)
 +{
 +        iface->get_icon = gdm_fingerprint_extension_get_icon;
 +        iface->get_description = gdm_fingerprint_extension_get_description;
 +        iface->get_name = gdm_fingerprint_extension_get_name;
++        iface->is_choosable = gdm_fingerprint_extension_is_choosable;
++        iface->is_visible = gdm_fingerprint_extension_is_visible;
 +}
 +
 +static void
@@ -12230,8 +13033,6 @@ index 0000000..b20dd65
 +static void
 +create_actions (GdmFingerprintExtension *extension)
 +{
-+        GtkAction *action;
-+
 +        extension->priv->actions = gtk_action_group_new ("gdm-fingerprint-extension");
 +}
 +
@@ -12423,10 +13224,10 @@ index 0000000..c20f10d
 +SUBDIRS = 16x16 48x48
 diff --git a/gui/simple-greeter/plugins/fingerprint/page.ui b/gui/simple-greeter/plugins/fingerprint/page.ui
 new file mode 100644
-index 0000000..fe6da78
+index 0000000..8fa5c7b
 --- /dev/null
 +++ b/gui/simple-greeter/plugins/fingerprint/page.ui
-@@ -0,0 +1,56 @@
+@@ -0,0 +1,57 @@
 +<?xml version="1.0"?>
 +<interface>
 +  <requires lib="gtk+" version="2.14"/>
@@ -12436,6 +13237,7 @@ index 0000000..fe6da78
 +      <child>
 +        <object class="GtkHBox" id="auth-input-box">
 +          <property name="visible">True</property>
++          <property name="spacing">6</property>
 +          <child>
 +            <object class="GtkLabel" id="auth-prompt-label">
 +              <property name="visible">True</property>
@@ -12542,26 +13344,26 @@ index 7c344c9..dd08b21 100644
  gui/user-switch-applet/gdm-entry-menu-item.c
  gui/user-switch-applet/GNOME_FastUserSwitchApplet.server.in.in
 -- 
-1.6.5.2
+1.7.2.1
 
 
-From 1e159ae72507ea1c411eb82af7abfbe8c8b1862c Mon Sep 17 00:00:00 2001
+From b186d5b4703e6c193e404925e2257d78261b6ba3 Mon Sep 17 00:00:00 2001
 From: Ray Strode <rstrode at redhat.com>
 Date: Fri, 6 Feb 2009 16:25:47 -0500
-Subject: [PATCH 17/45] Add smartcard plugin
+Subject: [PATCH 23/35] Add smartcard plugin
 
 This commit adds a plugin to initiate a conversation when
 smartcards are inserted.
 ---
  configure.ac                                       |   11 +
  gui/simple-greeter/plugins/Makefile.am             |    2 +-
- gui/simple-greeter/plugins/smartcard/Makefile.am   |   77 ++
- .../plugins/smartcard/gdm-smartcard-extension.c    |  418 ++++++
+ gui/simple-greeter/plugins/smartcard/Makefile.am   |   77 +
+ .../plugins/smartcard/gdm-smartcard-extension.c    |  510 +++++++
  .../plugins/smartcard/gdm-smartcard-extension.h    |   56 +
- .../plugins/smartcard/gdm-smartcard-manager.c      | 1394 ++++++++++++++++++++
+ .../plugins/smartcard/gdm-smartcard-manager.c      | 1521 ++++++++++++++++++++
  .../plugins/smartcard/gdm-smartcard-manager.h      |   86 ++
- .../plugins/smartcard/gdm-smartcard-worker.c       |  167 +++
- .../plugins/smartcard/gdm-smartcard.c              |  558 ++++++++
+ .../plugins/smartcard/gdm-smartcard-worker.c       |  186 +++
+ .../plugins/smartcard/gdm-smartcard.c              |  554 +++++++
  .../plugins/smartcard/gdm-smartcard.h              |   94 ++
  .../plugins/smartcard/gdm-smartcard.pam            |   18 +
  .../plugins/smartcard/icons/16x16/Makefile.am      |    5 +
@@ -12569,10 +13371,10 @@ smartcards are inserted.
  .../plugins/smartcard/icons/48x48/Makefile.am      |    5 +
  .../smartcard/icons/48x48/gdm-smartcard.png        |  Bin 0 -> 4202 bytes
  .../plugins/smartcard/icons/Makefile.am            |    1 +
- gui/simple-greeter/plugins/smartcard/page.ui       |   56 +
+ gui/simple-greeter/plugins/smartcard/page.ui       |   57 +
  gui/simple-greeter/plugins/smartcard/plugin.c      |   40 +
  po/POTFILES.in                                     |    3 +
- 19 files changed, 2990 insertions(+), 1 deletions(-)
+ 19 files changed, 3225 insertions(+), 1 deletions(-)
  create mode 100644 gui/simple-greeter/plugins/smartcard/Makefile.am
  create mode 100644 gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c
  create mode 100644 gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.h
@@ -12591,13 +13393,13 @@ smartcards are inserted.
  create mode 100644 gui/simple-greeter/plugins/smartcard/plugin.c
 
 diff --git a/configure.ac b/configure.ac
-index 24b4c5a..edf1c5c 100644
+index af7c2f3..abec739 100644
 --- a/configure.ac
 +++ b/configure.ac
 @@ -67,6 +67,7 @@ LIBCANBERRA_GTK_REQUIRED_VERSION=0.4
  #FONTCONFIG_REQUIRED_VERSION=2.6.0
  FONTCONFIG_REQUIRED_VERSION=2.5.0
- DEVKIT_POWER_REQUIRED_VERSION=008
+ UPOWER_REQUIRED_VERSION=0.9.0
 +NSS_REQUIRED_VERSION=3.11.1
  
  EXTRA_COMPILE_WARNINGS(yes)
@@ -12615,7 +13417,7 @@ index 24b4c5a..edf1c5c 100644
  PKG_CHECK_MODULES(XLIB, x11 xau, ,
    [AC_PATH_XTRA
      if test "x$no_x" = xyes; then
-@@ -1439,6 +1446,10 @@ gui/simple-greeter/plugins/fingerprint/Makefile
+@@ -1449,6 +1456,10 @@ gui/simple-greeter/plugins/fingerprint/Makefile
  gui/simple-greeter/plugins/fingerprint/icons/Makefile
  gui/simple-greeter/plugins/fingerprint/icons/16x16/Makefile
  gui/simple-greeter/plugins/fingerprint/icons/48x48/Makefile
@@ -12718,10 +13520,10 @@ index 0000000..1ccebda
 +        Makefile.in
 diff --git a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c
 new file mode 100644
-index 0000000..6fa01fb
+index 0000000..b925f5e
 --- /dev/null
 +++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c
-@@ -0,0 +1,418 @@
+@@ -0,0 +1,510 @@
 +/*
 + * Copyright (C) 2009 Red Hat, Inc.
 + *
@@ -12750,7 +13552,9 @@ index 0000000..6fa01fb
 +
 +#include <errno.h>
 +#include <fcntl.h>
++#include <signal.h>
 +#include <stdio.h>
++#include <stdlib.h>
 +#include <sys/types.h>
 +#include <unistd.h>
 +
@@ -12777,6 +13581,7 @@ index 0000000..6fa01fb
 +        int        number_of_tokens;
 +
 +        guint      answer_pending : 1;
++        guint      select_when_ready : 1;
 +};
 +
 +static void gdm_smartcard_extension_finalize (GObject *object);
@@ -12826,8 +13631,14 @@ index 0000000..6fa01fb
 +                }
 +
 +                if (extension->priv->number_of_tokens == 1) {
-+                        gdm_conversation_choose_user (GDM_CONVERSATION (extension),
-+                                                      GDM_CONVERSATION_OTHER_USER);
++                        if (!gdm_conversation_choose_user (GDM_CONVERSATION (extension),
++                                                          PAMSERVICENAME)) {
++                                g_debug ("could not choose smart card user, cancelling...");
++                                gdm_conversation_cancel (GDM_CONVERSATION (extension));
++                                extension->priv->select_when_ready = TRUE;
++                        } else {
++                                g_debug ("chose smart card user!");
++                        }
 +                } else if (extension->priv->number_of_tokens == 0) {
 +                        gdm_conversation_cancel (GDM_CONVERSATION (extension));
 +                }
@@ -12874,8 +13685,14 @@ index 0000000..6fa01fb
 +}
 +
 +static void
++stop_watching_for_smartcards (GdmSmartcardExtension *extension)
++{
++        kill (extension->priv->worker_pid, SIGTERM);
++}
++
++static void
 +gdm_smartcard_extension_set_message (GdmConversation *conversation,
-+                                       const char *message)
++                                     const char      *message)
 +{
 +        GdmSmartcardExtension *extension = GDM_SMARTCARD_EXTENSION (conversation);
 +        gtk_widget_show (extension->priv->message_label);
@@ -12884,7 +13701,7 @@ index 0000000..6fa01fb
 +
 +static void
 +gdm_smartcard_extension_ask_question (GdmConversation *conversation,
-+                                        const char      *message)
++                                      const char      *message)
 +{
 +        GdmSmartcardExtension *extension = GDM_SMARTCARD_EXTENSION (conversation);
 +        gtk_widget_show (extension->priv->prompt_label);
@@ -12899,7 +13716,7 @@ index 0000000..6fa01fb
 +
 +static void
 +gdm_smartcard_extension_ask_secret (GdmConversation *conversation,
-+                                      const char      *message)
++                                    const char      *message)
 +{
 +        GdmSmartcardExtension *extension = GDM_SMARTCARD_EXTENSION (conversation);
 +        gtk_widget_show (extension->priv->prompt_label);
@@ -12934,10 +13751,16 @@ index 0000000..6fa01fb
 +        GdmSmartcardExtension *extension = GDM_SMARTCARD_EXTENSION (conversation);
 +        gdm_task_set_enabled (GDM_TASK (conversation), TRUE);
 +
-+        if (extension->priv->worker_pid <= 0)
-+          {
++        if (extension->priv->worker_pid <= 0) {
 +                watch_for_smartcards (extension);
-+          }
++        }
++
++        if (extension->priv->select_when_ready) {
++                if (gdm_conversation_choose_user (GDM_CONVERSATION (extension),
++                                                  PAMSERVICENAME)) {
++                        extension->priv->select_when_ready = FALSE;
++                }
++        }
 +}
 +
 +char *
@@ -13014,12 +13837,78 @@ index 0000000..6fa01fb
 +        return g_strdup (_("Log into session with smartcard"));
 +}
 +
-+static void
-+gdm_task_iface_init (GdmTaskIface *iface)
++gboolean
++gdm_smartcard_extension_is_choosable (GdmTask *task)
 +{
-+        iface->get_icon = gdm_smartcard_extension_get_icon;
-+        iface->get_description = gdm_smartcard_extension_get_description;
-+        iface->get_name = gdm_smartcard_extension_get_name;
++        return TRUE;
++}
++
++gboolean
++gdm_smartcard_extension_is_visible (GdmTask *task)
++{
++        char *contents, **lines, *pid_dir;
++        gboolean ret;
++        guint i;
++        pid_t pid;
++
++        /*
++         * FIXME: We shouldn't use a distro specific hack here
++         */
++
++        if (g_file_get_contents ("/var/run/pcscd.pid",
++                                 &contents, NULL, NULL) == FALSE) {
++                return FALSE;
++        }
++
++        pid = (pid_t) atoi (contents);
++        g_free (contents);
++
++        if (pid == 0) {
++                return FALSE;
++        }
++
++        pid_dir = g_strdup_printf ("/proc/%d", (int) pid);
++        if (!g_file_test (pid_dir, G_FILE_TEST_EXISTS)) {
++                g_free (pid_dir);
++                return FALSE;
++        }
++        g_free (pid_dir);
++
++        if (g_file_get_contents ("/etc/sysconfig/authconfig",
++                                 &contents, NULL, NULL) == FALSE) {
++                return FALSE;
++        }
++
++        lines = g_strsplit (contents, "\n", -1);
++        g_free (contents);
++
++        ret = FALSE;
++
++        for (i = 0; lines[i] ; i++) {
++                if (g_str_has_prefix (lines[i], "USESMARTCARD=") != FALSE) {
++                        char *value;
++
++                        value = lines[i] + strlen ("USESMARTCARD=");
++                        if (rpmatch (value)) {
++                                ret = TRUE;
++                                break;
++                        }
++                }
++        }
++
++        g_strfreev (lines);
++
++        return TRUE;
++}
++
++static void
++gdm_task_iface_init (GdmTaskIface *iface)
++{
++        iface->get_icon = gdm_smartcard_extension_get_icon;
++        iface->get_description = gdm_smartcard_extension_get_description;
++        iface->get_name = gdm_smartcard_extension_get_name;
++        iface->is_choosable = gdm_smartcard_extension_is_choosable;
++        iface->is_visible = gdm_smartcard_extension_is_visible;
 +}
 +
 +static void
@@ -13058,6 +13947,11 @@ index 0000000..6fa01fb
 +static void
 +gdm_smartcard_extension_finalize (GObject *object)
 +{
++        GdmSmartcardExtension *extension = GDM_SMARTCARD_EXTENSION (object);
++
++        if (extension->priv->worker_pid > 0) {
++                stop_watching_for_smartcards (extension);
++        }
 +}
 +
 +static void
@@ -13204,10 +14098,10 @@ index 0000000..285b51a
 +#endif /* GDM_SMARTCARD_EXTENSION_H */
 diff --git a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-manager.c b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-manager.c
 new file mode 100644
-index 0000000..e346a9c
+index 0000000..5af0da9
 --- /dev/null
 +++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-manager.c
-@@ -0,0 +1,1394 @@
+@@ -0,0 +1,1521 @@
 +/* gdm-smartcard-manager.c - object for monitoring smartcard insertion and
 + *                           removal events
 + *
@@ -13253,6 +14147,7 @@ index 0000000..e346a9c
 +#include <glib/gi18n.h>
 +
 +#include <prerror.h>
++#include <prinit.h>
 +#include <nss.h>
 +#include <pk11func.h>
 +#include <secmod.h>
@@ -13286,15 +14181,14 @@ index 0000000..e346a9c
 +
 +struct _GdmSmartcardManagerPrivate {
 +        GdmSmartcardManagerState state;
-+        SECMODModule *module;
++        GList        *modules;
 +        char        *module_path;
 +
-+        GSource *smartcard_event_source;
++        GList        *workers;
++
 +        GPid smartcard_event_watcher_pid;
 +        GHashTable *smartcards;
 +
-+        GThread    *worker_thread;
-+
 +        guint poll_timeout_id;
 +
 +        guint32 is_unstoppable : 1;
@@ -13302,9 +14196,14 @@ index 0000000..e346a9c
 +};
 +
 +struct _GdmSmartcardManagerWorker {
++        GdmSmartcardManager *manager;
++        gint manager_fd;
++
++        GThread      *thread;
 +        SECMODModule *module;
 +        GHashTable *smartcards;
-+        gint write_fd;
++        gint fd;
++        GSource *event_source;
 +
 +        guint32 nss_is_loaded : 1;
 +};
@@ -13329,10 +14228,13 @@ index 0000000..e346a9c
 +static gboolean gdm_smartcard_manager_stop_now (GdmSmartcardManager *manager);
 +static void gdm_smartcard_manager_queue_stop (GdmSmartcardManager *manager);
 +
-+static gboolean gdm_smartcard_manager_create_worker (GdmSmartcardManager *manager,
-+                                                     int *worker_fd, GThread **worker_thread);
++static GdmSmartcardManagerWorker *gdm_smartcard_manager_create_worker (GdmSmartcardManager  *manager,
++                                                                       SECMODModule         *module);
 +
-+static GdmSmartcardManagerWorker * gdm_smartcard_manager_worker_new (gint write_fd);
++static GdmSmartcardManagerWorker * gdm_smartcard_manager_worker_new (GdmSmartcardManager *manager,
++                                                                     int                  worker_fd,
++                                                                     int                  manager_fd,
++                                                                     SECMODModule        *module);
 +static void gdm_smartcard_manager_worker_free (GdmSmartcardManagerWorker *worker);
 +static gboolean gdm_open_pipe (gint *write_fd, gint *read_fd);
 +static gboolean sc_read_bytes (gint fd, gpointer bytes, gsize num_bytes);
@@ -13554,7 +14456,6 @@ index 0000000..e346a9c
 +                                                     GdmSmartcardManagerPrivate);
 +        manager->priv->poll_timeout_id = 0;
 +        manager->priv->is_unstoppable = FALSE;
-+        manager->priv->module = NULL;
 +
 +        manager->priv->smartcards =
 +                g_hash_table_new_full (g_str_hash,
@@ -13563,7 +14464,7 @@ index 0000000..e346a9c
 +                                       (GDestroyNotify) g_object_unref);
 +
 +        if (!g_thread_supported()) {
-+        g_thread_init (NULL);
++                g_thread_init (NULL);
 +        }
 +
 +}
@@ -13646,14 +14547,18 @@ index 0000000..e346a9c
 +static gboolean
 +gdm_smartcard_manager_check_for_and_process_events (GIOChannel          *io_channel,
 +                                                    GIOCondition         condition,
-+                                                    GdmSmartcardManager *manager)
++                                                    GdmSmartcardManagerWorker *worker)
 +{
 +        GdmSmartcard *card;
++        GdmSmartcardManager *manager;
 +        gboolean should_stop;
 +        guchar event_type;
 +        char *card_name;
 +        gint fd;
 +
++        manager = worker->manager;
++
++        g_debug ("event!");
 +        card = NULL;
 +        should_stop = (condition & G_IO_HUP) || (condition & G_IO_ERR);
 +
@@ -13667,6 +14572,7 @@ index 0000000..e346a9c
 +        }
 +
 +        if (!(condition & G_IO_IN)) {
++                g_debug ("nevermind outta here!");
 +                goto out;
 +        }
 +
@@ -13674,18 +14580,21 @@ index 0000000..e346a9c
 +
 +        event_type = '\0';
 +        if (!sc_read_bytes (fd, &event_type, 1)) {
++                g_debug ("could not read event type, stopping");
 +                should_stop = TRUE;
 +                goto out;
 +        }
 +
-+        card = sc_read_smartcard (fd, manager->priv->module);
++        card = sc_read_smartcard (fd, worker->module);
 +
 +        if (card == NULL) {
++                g_debug ("could not read card, stopping");
 +                should_stop = TRUE;
 +                goto out;
 +        }
 +
 +        card_name = gdm_smartcard_get_name (card);
++        g_debug ("card '%s' had event %c", card_name, event_type);
 +
 +        switch (event_type) {
 +                case 'I':
@@ -13734,10 +14643,48 @@ index 0000000..e346a9c
 +}
 +
 +static void
-+gdm_smartcard_manager_event_processing_stopped_handler (GdmSmartcardManager *manager)
++stop_manager (GdmSmartcardManager *manager)
 +{
-+        manager->priv->smartcard_event_source = NULL;
-+        gdm_smartcard_manager_stop_now (manager);
++        manager->priv->state = GDM_SMARTCARD_MANAGER_STATE_STOPPED;
++
++        if (manager->priv->nss_is_loaded) {
++                NSS_Shutdown ();
++                manager->priv->nss_is_loaded = FALSE;
++        }
++        g_debug ("smartcard manager stopped");
++}
++
++static void
++stop_worker (GdmSmartcardManagerWorker *worker)
++{
++        GdmSmartcardManager *manager;
++
++        manager = worker->manager;
++
++        if (worker->event_source != NULL) {
++                g_source_destroy (worker->event_source);
++                worker->event_source = NULL;
++        }
++
++        if (worker->thread != NULL) {
++                SECMOD_CancelWait (worker->module);
++                worker->thread = NULL;
++        }
++
++        SECMOD_DestroyModule (worker->module);
++        manager->priv->workers = g_list_remove (manager->priv->workers, worker);
++
++        if (manager->priv->workers == NULL && manager->priv->state != GDM_SMARTCARD_MANAGER_STATE_STOPPED) {
++                stop_manager (manager);
++        }
++}
++
++static void
++gdm_smartcard_manager_event_processing_stopped_handler (GdmSmartcardManagerWorker *worker)
++{
++        worker->event_source = NULL;
++
++        stop_worker (worker);
 +}
 +
 +static gboolean
@@ -13774,19 +14721,19 @@ index 0000000..e346a9c
 +static void
 +gdm_smartcard_manager_stop_watching_for_events (GdmSmartcardManager  *manager)
 +{
-+        if (manager->priv->smartcard_event_source != NULL) {
-+                g_source_destroy (manager->priv->smartcard_event_source);
-+                manager->priv->smartcard_event_source = NULL;
-+        }
++        GList *node;
 +
-+        if (manager->priv->worker_thread != NULL) {
-+                SECMOD_CancelWait (manager->priv->module);
-+                /* FIXME: The function above doesn't seem to
-+                 * always wake up WaitForAnyTokenEvent
-+                 */
-+                exit (0);
-+                g_thread_join (manager->priv->worker_thread);
-+                manager->priv->worker_thread = NULL;
++        node = manager->priv->workers;
++        while (node != NULL) {
++                GdmSmartcardManagerWorker *worker;
++                GList *next_node;
++
++                worker = (GdmSmartcardManagerWorker *) node->data;
++                next_node = node->next;
++
++                stop_worker (worker);
++
++                node = next_node;
 +        }
 +}
 +
@@ -13795,12 +14742,14 @@ index 0000000..e346a9c
 +{
 +        SECStatus status = SECSuccess;
 +        static const guint32 flags =
-+        NSS_INIT_READONLY | NSS_INIT_NOCERTDB | NSS_INIT_NOMODDB |
++        NSS_INIT_READONLY |
 +        NSS_INIT_FORCEOPEN | NSS_INIT_NOROOTINIT |
 +        NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD;
 +
 +        g_debug ("attempting to load NSS database '%s'",
-+                  GDM_SMARTCARD_MANAGER_NSS_DB);
++                 GDM_SMARTCARD_MANAGER_NSS_DB);
++
++        PR_Init (PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
 +
 +        status = NSS_Initialize (GDM_SMARTCARD_MANAGER_NSS_DB,
 +                                 "", "", SECMOD_DB, flags);
@@ -13843,19 +14792,46 @@ index 0000000..e346a9c
 +        return FALSE;
 +}
 +
-+static SECMODModule *
-+load_driver (char   *module_path,
-+                    GError **error)
++static GList *
++get_available_modules (GdmSmartcardManager  *manager)
 +{
-+        SECMODModule *module;
++        SECMODModuleList *module_list, *tmp;
++        GList *modules;
++
++        g_debug ("Getting list of suitable modules");
++
++        module_list = SECMOD_GetDefaultModuleList ();
++        modules = NULL;
++        for (tmp = module_list; tmp != NULL; tmp = tmp->next) {
++                if (!SECMOD_HasRemovableSlots (tmp->module) ||
++                    !tmp->module->loaded)
++                        continue;
++
++                g_debug ("Using module '%s'", tmp->module->commonName);
++
++                modules = g_list_prepend (modules,
++                                          SECMOD_ReferenceModule (tmp->module));
++        }
++
++        return modules;
++}
++
++static gboolean
++load_driver (GdmSmartcardManager  *manager,
++             char                 *module_path,
++             GError              **error)
++{
++        GList *modules;
 +        char *module_spec;
 +        gboolean module_explicitly_specified;
 +
 +        g_debug ("attempting to load driver...");
 +
-+        module = NULL;
++        modules = NULL;
 +        module_explicitly_specified = module_path != NULL;
 +        if (module_explicitly_specified) {
++                SECMODModule *module;
++
 +                module_spec = g_strdup_printf ("library=\"%s\"", module_path);
 +                g_debug ("loading smartcard driver using spec '%s'",
 +                          module_spec);
@@ -13866,23 +14842,31 @@ index 0000000..e346a9c
 +                g_free (module_spec);
 +                module_spec = NULL;
 +
-+        } else {
-+                SECMODModuleList *modules, *tmp;
++                if (!SECMOD_HasRemovableSlots (module) ||
++                    !module->loaded) {
++                        modules = g_list_prepend (modules, module);
++                } else {
++                        g_debug ("fallback module found but not %s",
++                                 SECMOD_HasRemovableSlots (module)?
++                                 "removable" : "loaded");
++                        SECMOD_DestroyModule (module);
++                }
 +
-+                modules = SECMOD_GetDefaultModuleList ();
++        } else {
++                SECMODListLock *lock;
 +
-+                for (tmp = modules; tmp != NULL; tmp = tmp->next) {
-+                        if (!SECMOD_HasRemovableSlots (tmp->module) ||
-+                            !tmp->module->loaded)
-+                                continue;
++                lock = SECMOD_GetDefaultModuleListLock ();
 +
-+                        module = SECMOD_ReferenceModule (tmp->module);
-+                        break;
++                if (lock != NULL) {
++                        SECMOD_GetReadLock (lock);
++                        modules = get_available_modules (manager);
++                        SECMOD_ReleaseReadLock (lock);
 +                }
 +
 +                /* fallback to compiled in driver path
 +                 */
-+                if (module == NULL) {
++                if (modules == NULL) {
++                        SECMODModule *module;
 +                        module_path = GDM_SMARTCARD_MANAGER_DRIVER;
 +                        module_spec = g_strdup_printf ("library=\"%s\"", module_path);
 +                        g_debug ("loading smartcard driver using spec '%s'",
@@ -13893,26 +14877,28 @@ index 0000000..e346a9c
 +                                FALSE /* recurse */);
 +                        g_free (module_spec);
 +                        module_spec = NULL;
++
++                        if (!SECMOD_HasRemovableSlots (module) ||
++                            !module->loaded) {
++                                modules = g_list_prepend (modules, module);
++                        } else {
++                                g_debug ("fallback module found but not loaded");
++                                SECMOD_DestroyModule (module);
++                        }
 +                }
 +
 +        }
 +
-+        if (!module_explicitly_specified && module == NULL) {
++        if (!module_explicitly_specified && modules == NULL) {
 +                g_set_error (error,
 +                             GDM_SMARTCARD_MANAGER_ERROR,
 +                             GDM_SMARTCARD_MANAGER_ERROR_LOADING_DRIVER,
 +                             _("no suitable smartcard driver could be found"));
-+        } else if (module == NULL || !module->loaded) {
++        } else if (modules == NULL) {
 +
 +                gsize error_message_size;
 +                char *error_message;
 +
-+                if (module != NULL && !module->loaded) {
-+                        g_debug ("module found but not loaded?!");
-+                        SECMOD_DestroyModule (module);
-+                        module = NULL;
-+                }
-+
 +                error_message_size = PR_GetErrorTextLength ();
 +
 +                if (error_message_size == 0) {
@@ -13939,74 +14925,58 @@ index 0000000..e346a9c
 +                g_slice_free1 (error_message_size, error_message);
 +        }
 +
++        manager->priv->modules = modules;
 +out:
-+        return module;
++        return manager->priv->modules != NULL;
 +}
 +
 +static void
 +gdm_smartcard_manager_get_all_cards (GdmSmartcardManager *manager)
 +{
++        GList *node;
 +        int i;
 +
-+        for (i = 0; i < manager->priv->module->slotCount; i++) {
-+                GdmSmartcard *card;
-+                CK_SLOT_ID    slot_id;
-+                gint          slot_series;
-+                char *card_name;
++        node = manager->priv->workers;
++        while (node != NULL) {
++
++                GdmSmartcardManagerWorker *worker;
++
++                worker = (GdmSmartcardManagerWorker *) node->data;
++
++                for (i = 0; i < worker->module->slotCount; i++) {
++                        GdmSmartcard *card;
++                        CK_SLOT_ID    slot_id;
++                        gint          slot_series;
++                        char         *card_name;
 +
-+                slot_id = PK11_GetSlotID (manager->priv->module->slots[i]);
-+                slot_series = PK11_GetSlotSeries (manager->priv->module->slots[i]);
++                        slot_id = PK11_GetSlotID (worker->module->slots[i]);
++                        slot_series = PK11_GetSlotSeries (worker->module->slots[i]);
 +
-+                card = _gdm_smartcard_new (manager->priv->module,
-+                                                slot_id, slot_series);
++                        card = _gdm_smartcard_new (worker->module,
++                                                   slot_id, slot_series);
 +
-+                card_name = gdm_smartcard_get_name (card);
++                        card_name = gdm_smartcard_get_name (card);
 +
-+                g_hash_table_replace (manager->priv->smartcards,
-+                                      card_name, card);
++                        g_hash_table_replace (manager->priv->smartcards,
++                                              card_name, card);
++                }
++                node = node->next;
 +        }
 +}
 +
-+gboolean
-+gdm_smartcard_manager_start (GdmSmartcardManager  *manager,
-+                             GError              **error)
++static GdmSmartcardManagerWorker *
++start_worker (GdmSmartcardManager  *manager,
++              SECMODModule         *module,
++              GError              **error)
 +{
-+        GError *watching_error;
-+        gint worker_fd;
-+        GPid worker_pid;
 +        GIOChannel *io_channel;
 +        GSource *source;
 +        GIOFlags channel_flags;
-+        GError *nss_error;
-+
-+        if (manager->priv->state == GDM_SMARTCARD_MANAGER_STATE_STARTED) {
-+                g_debug ("smartcard manager already started");
-+                return TRUE;
-+        }
-+
-+        manager->priv->state = GDM_SMARTCARD_MANAGER_STATE_STARTING;
-+
-+        worker_fd = -1;
-+        worker_pid = 0;
-+
-+        nss_error = NULL;
-+        if (!manager->priv->nss_is_loaded && !sc_load_nss (&nss_error)) {
-+                g_propagate_error (error, nss_error);
-+                goto out;
-+        }
-+        manager->priv->nss_is_loaded = TRUE;
-+
-+        if (manager->priv->module == NULL) {
-+                manager->priv->module = load_driver (manager->priv->module_path, &nss_error);
-+        }
-+
-+        if (manager->priv->module == NULL) {
-+                g_propagate_error (error, nss_error);
-+                goto out;
-+        }
++        GdmSmartcardManagerWorker *worker;
 +
-+        if (!gdm_smartcard_manager_create_worker (manager, &worker_fd, &manager->priv->worker_thread)) {
++        worker = gdm_smartcard_manager_create_worker (manager, module);
 +
++        if (worker == NULL) {
 +                g_set_error (error,
 +                             GDM_SMARTCARD_MANAGER_ERROR,
 +                             GDM_SMARTCARD_MANAGER_ERROR_WATCHING_FOR_EVENTS,
@@ -14016,25 +14986,82 @@ index 0000000..e346a9c
 +                goto out;
 +        }
 +
-+        io_channel = g_io_channel_unix_new (worker_fd);
++        io_channel = g_io_channel_unix_new (worker->manager_fd);
 +
 +        channel_flags = g_io_channel_get_flags (io_channel);
-+        watching_error = NULL;
 +
 +        source = g_io_create_watch (io_channel, G_IO_IN | G_IO_HUP);
 +        g_io_channel_unref (io_channel);
 +        io_channel = NULL;
 +
-+        manager->priv->smartcard_event_source = source;
++        worker->event_source = source;
 +
-+        g_source_set_callback (manager->priv->smartcard_event_source,
++        g_source_set_callback (worker->event_source,
 +                               (GSourceFunc) (GIOFunc)
 +                               gdm_smartcard_manager_check_for_and_process_events,
-+                               manager,
++                               worker,
 +                               (GDestroyNotify)
 +                               gdm_smartcard_manager_event_processing_stopped_handler);
-+        g_source_attach (manager->priv->smartcard_event_source, NULL);
-+        g_source_unref (manager->priv->smartcard_event_source);
++        g_source_attach (worker->event_source, NULL);
++        g_source_unref (worker->event_source);
++out:
++        return worker;
++}
++
++static void
++start_workers (GdmSmartcardManager *manager)
++{
++        GList        *node;
++
++        node = manager->priv->modules;
++        while (node != NULL) {
++                SECMODModule *module;
++                GdmSmartcardManagerWorker *worker;
++                GError *error;
++
++                module = (SECMODModule *) node->data;
++
++                error = NULL;
++                worker = start_worker (manager, module, &error);
++                if (worker == NULL) {
++                        g_warning ("%s", error->message);
++                        g_error_free (error);
++                } else {
++                        manager->priv->workers = g_list_prepend (manager->priv->workers,
++                                                                 worker);
++                }
++                node = node->next;
++        }
++}
++
++gboolean
++gdm_smartcard_manager_start (GdmSmartcardManager  *manager,
++                             GError              **error)
++{
++        GError *nss_error;
++
++        if (manager->priv->state == GDM_SMARTCARD_MANAGER_STATE_STARTED) {
++                g_debug ("smartcard manager already started");
++                return TRUE;
++        }
++
++        manager->priv->state = GDM_SMARTCARD_MANAGER_STATE_STARTING;
++
++        nss_error = NULL;
++        if (!manager->priv->nss_is_loaded && !sc_load_nss (&nss_error)) {
++                g_propagate_error (error, nss_error);
++                goto out;
++        }
++        manager->priv->nss_is_loaded = TRUE;
++
++        if (manager->priv->modules == NULL) {
++                if (!load_driver (manager, manager->priv->module_path, &nss_error)) {
++                        g_propagate_error (error, nss_error);
++                        goto out;
++                }
++        }
++
++        start_workers (manager);
 +
 +        /* populate the hash with cards that are already inserted
 +         */
@@ -14062,21 +15089,8 @@ index 0000000..e346a9c
 +                return FALSE;
 +        }
 +
-+        manager->priv->state = GDM_SMARTCARD_MANAGER_STATE_STOPPED;
 +        gdm_smartcard_manager_stop_watching_for_events (manager);
 +
-+        if (manager->priv->module != NULL) {
-+                SECMOD_DestroyModule (manager->priv->module);
-+                manager->priv->module = NULL;
-+        }
-+
-+        if (manager->priv->nss_is_loaded) {
-+                NSS_Shutdown ();
-+                manager->priv->nss_is_loaded = FALSE;
-+        }
-+
-+        g_debug ("smartcard manager stopped");
-+
 +        return FALSE;
 +}
 +
@@ -14132,13 +15146,18 @@ index 0000000..e346a9c
 +}
 +
 +static GdmSmartcardManagerWorker *
-+gdm_smartcard_manager_worker_new (gint write_fd)
++gdm_smartcard_manager_worker_new (GdmSmartcardManager *manager,
++                                  gint                 worker_fd,
++                                  gint                 manager_fd,
++                                  SECMODModule        *module)
 +{
 +        GdmSmartcardManagerWorker *worker;
 +
 +        worker = g_slice_new0 (GdmSmartcardManagerWorker);
-+        worker->write_fd = write_fd;
-+        worker->module = NULL;
++        worker->manager = manager;
++        worker->fd = worker_fd;
++        worker->manager_fd = manager_fd;
++        worker->module = module;
 +
 +        worker->smartcards =
 +                g_hash_table_new_full ((GHashFunc) sc_slot_id_hash,
@@ -14171,7 +15190,7 @@ index 0000000..e346a9c
 +        total_bytes_read = 0;
 +
 +        do {
-+                bytes_read = read (fd, bytes + total_bytes_read, bytes_left);
++                bytes_read = read (fd, (gchar *) bytes + total_bytes_read, bytes_left);
 +                g_assert (bytes_read <= (ssize_t) bytes_left);
 +
 +                if (bytes_read <= 0) {
@@ -14204,7 +15223,7 @@ index 0000000..e346a9c
 +        total_bytes_written = 0;
 +
 +        do {
-+                bytes_written = write (fd, bytes + total_bytes_written, bytes_left);
++                bytes_written = write (fd, (gchar *) bytes + total_bytes_written, bytes_left);
 +                g_assert (bytes_written <= (ssize_t) bytes_left);
 +
 +                if (bytes_written <= 0) {
@@ -14281,11 +15300,11 @@ index 0000000..e346a9c
 +{
 +        g_debug ("card '%s' removed!", gdm_smartcard_get_name (card));
 +
-+        if (!sc_write_bytes (worker->write_fd, "R", 1)) {
++        if (!sc_write_bytes (worker->fd, "R", 1)) {
 +                goto error_out;
 +        }
 +
-+        if (!sc_write_smartcard (worker->write_fd, card)) {
++        if (!sc_write_smartcard (worker->fd, card)) {
 +                goto error_out;
 +        }
 +
@@ -14307,11 +15326,11 @@ index 0000000..e346a9c
 +
 +        write_error = NULL;
 +        g_debug ("card '%s' inserted!", gdm_smartcard_get_name (card));
-+        if (!sc_write_bytes (worker->write_fd, "I", 1)) {
++        if (!sc_write_bytes (worker->fd, "I", 1)) {
 +                goto error_out;
 +        }
 +
-+        if (!sc_write_smartcard (worker->write_fd, card)) {
++        if (!sc_write_smartcard (worker->fd, card)) {
 +                goto error_out;
 +        }
 +
@@ -14342,6 +15361,7 @@ index 0000000..e346a9c
 +         */
 +
 +        slot = SECMOD_WaitForAnyTokenEvent (worker->module, 0, PR_SecondsToInterval (1));
++
 +        processing_error = NULL;
 +
 +        if (slot == NULL) {
@@ -14462,24 +15482,27 @@ index 0000000..e346a9c
 +gdm_smartcard_manager_worker_run (GdmSmartcardManagerWorker *worker)
 +{
 +        GError *error;
++        gboolean should_continue;
 +
-+
-+        error = NULL;
-+
-+        while (gdm_smartcard_manager_worker_watch_for_and_process_event (worker, &error));
++        do
++        {
++                error = NULL;
++                should_continue = gdm_smartcard_manager_worker_watch_for_and_process_event (worker, &error);
++        }
++        while (should_continue);
 +
 +        if (error != NULL)  {
 +                g_debug ("could not process card event - %s", error->message);
 +                g_error_free (error);
 +        }
 +
++out:
 +        gdm_smartcard_manager_worker_free (worker);
 +}
 +
-+static gboolean
++static GdmSmartcardManagerWorker *
 +gdm_smartcard_manager_create_worker (GdmSmartcardManager  *manager,
-+                                     gint                 *worker_fd,
-+                                     GThread             **worker_thread)
++                                     SECMODModule         *module)
 +{
 +        GdmSmartcardManagerWorker *worker;
 +        gint write_fd, read_fd;
@@ -14490,23 +15513,21 @@ index 0000000..e346a9c
 +                return FALSE;
 +        }
 +
-+        worker = gdm_smartcard_manager_worker_new (write_fd);
-+        worker->module = manager->priv->module;
++        worker = gdm_smartcard_manager_worker_new (manager,
++                                                   write_fd,
++                                                   read_fd,
++                                                   module);
 +
-+        *worker_thread = g_thread_create ((GThreadFunc)
++        worker->thread = g_thread_create ((GThreadFunc)
 +                                          gdm_smartcard_manager_worker_run,
-+                                          worker, TRUE, NULL);
++                                          worker, FALSE, NULL);
 +
-+        if (*worker_thread == NULL) {
++        if (worker->thread == NULL) {
 +                gdm_smartcard_manager_worker_free (worker);
-+                return FALSE;
-+        }
-+
-+        if (worker_fd) {
-+                *worker_fd = read_fd;
++                return NULL;
 +        }
 +
-+        return TRUE;
++        return worker;
 +}
 +
 +#ifdef GDM_SMARTCARD_MANAGER_ENABLE_TEST
@@ -14696,14 +15717,15 @@ index 0000000..932a703
 +#endif                                /* GDM_SMARTCARD_MANAGER_H */
 diff --git a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-worker.c b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-worker.c
 new file mode 100644
-index 0000000..75e4f33
+index 0000000..9af1346
 --- /dev/null
 +++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-worker.c
-@@ -0,0 +1,167 @@
+@@ -0,0 +1,186 @@
 +#include "config.h"
 +
 +#include <fcntl.h>
 +#include <locale.h>
++#include <sys/prctl.h>
 +#include <stdlib.h>
 +#include <unistd.h>
 +
@@ -14805,10 +15827,23 @@ index 0000000..75e4f33
 +}
 +
 +static void
++on_alrm_signal (int signal_number)
++{
++        raise (SIGKILL);
++}
++
++static void
 +on_term_signal (int signal_number)
 +{
 +        close (signal_pipe_fds[1]);
 +        signal_pipe_fds[1] = -1;
++
++        /* Give us 10 seconds to clean up orderly.
++         * If that fails, then the smartcard stack
++         * is hung up and we need to die hard
++         */
++        alarm (10);
++        signal (SIGALRM, on_alrm_signal);
 +}
 +
 +static gboolean
@@ -14845,8 +15880,6 @@ index 0000000..75e4f33
 +
 +        watch_for_smartcards ();
 +
-+        signal (SIGTERM, on_term_signal);
-+        signal (SIGPIPE, on_term_signal);
 +        if (pipe (signal_pipe_fds) != 0) {
 +                return 1;
 +        }
@@ -14861,6 +15894,13 @@ index 0000000..75e4f33
 +        g_io_channel_set_close_on_unref (io_channel, TRUE);
 +        g_io_channel_unref (io_channel);
 +
++        signal (SIGTERM, on_term_signal);
++        signal (SIGPIPE, on_term_signal);
++
++#ifdef HAVE_SYS_PRCTL_H
++        prctl (PR_SET_PDEATHSIG, SIGTERM);
++#endif
++
 +        g_main_loop_run (event_loop);
 +
 +        stop_watching_for_smartcards ();
@@ -14869,10 +15909,10 @@ index 0000000..75e4f33
 +}
 diff --git a/gui/simple-greeter/plugins/smartcard/gdm-smartcard.c b/gui/simple-greeter/plugins/smartcard/gdm-smartcard.c
 new file mode 100644
-index 0000000..c0e2739
+index 0000000..1af3638
 --- /dev/null
 +++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard.c
-@@ -0,0 +1,558 @@
+@@ -0,0 +1,554 @@
 +/* gdm-smartcard.c - smartcard object
 + *
 + * Copyright (C) 2006 Ray Strode <rstrode at redhat.com>
@@ -15273,10 +16313,6 @@ index 0000000..c0e2739
 +        card->priv = G_TYPE_INSTANCE_GET_PRIVATE (card,
 +                                                  GDM_TYPE_SMARTCARD,
 +                                                  GdmSmartcardPrivate);
-+
-+        if (card->priv->slot != NULL) {
-+                card->priv->name = g_strdup (PK11_GetTokenName (card->priv->slot));
-+        }
 +}
 +
 +static void gdm_smartcard_finalize (GObject *object)
@@ -15533,14 +16569,14 @@ index 0000000..20303bd
 +#endif                                /* GDM_SMARTCARD_H */
 diff --git a/gui/simple-greeter/plugins/smartcard/gdm-smartcard.pam b/gui/simple-greeter/plugins/smartcard/gdm-smartcard.pam
 new file mode 100644
-index 0000000..3c803f7
+index 0000000..d5ac1fa
 --- /dev/null
 +++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard.pam
 @@ -0,0 +1,18 @@
 +# Sample PAM file for doing smartcard authentication.
 +# Distros should replace this with what makes sense for them.
 +auth        required      pam_env.so
-+auth        [success=done ignore=ignore default=die] pam_pkcs11.so wait_for_card
++auth        [success=done ignore=ignore default=die] pam_pkcs11.so wait_for_card card_only
 +auth        requisite     pam_succeed_if.so uid >= 500 quiet
 +auth        required      pam_deny.so
 +
@@ -15703,10 +16739,10 @@ index 0000000..c20f10d
 +SUBDIRS = 16x16 48x48
 diff --git a/gui/simple-greeter/plugins/smartcard/page.ui b/gui/simple-greeter/plugins/smartcard/page.ui
 new file mode 100644
-index 0000000..fe6da78
+index 0000000..8fa5c7b
 --- /dev/null
 +++ b/gui/simple-greeter/plugins/smartcard/page.ui
-@@ -0,0 +1,56 @@
+@@ -0,0 +1,57 @@
 +<?xml version="1.0"?>
 +<interface>
 +  <requires lib="gtk+" version="2.14"/>
@@ -15716,6 +16752,7 @@ index 0000000..fe6da78
 +      <child>
 +        <object class="GtkHBox" id="auth-input-box">
 +          <property name="visible">True</property>
++          <property name="spacing">6</property>
 +          <child>
 +            <object class="GtkLabel" id="auth-prompt-label">
 +              <property name="visible">True</property>
@@ -15744,1082 +16781,134 @@ index 0000000..fe6da78
 +        </packing>
 +      </child>
 +      <child>
-+        <object class="GtkHBox" id="auth-message-box">
-+          <property name="visible">True</property>
-+          <child>
-+            <object class="GtkLabel" id="auth-message-label">
-+              <property name="visible">True</property>
-+            </object>
-+            <packing>
-+              <property name="position">0</property>
-+            </packing>
-+          </child>
-+        </object>
-+        <packing>
-+          <property name="expand">True</property>
-+          <property name="fill">True</property>
-+          <property name="position">1</property>
-+        </packing>
-+      </child>
-+    </object>
-+</interface>
-diff --git a/gui/simple-greeter/plugins/smartcard/plugin.c b/gui/simple-greeter/plugins/smartcard/plugin.c
-new file mode 100644
-index 0000000..fffbd50
---- /dev/null
-+++ b/gui/simple-greeter/plugins/smartcard/plugin.c
-@@ -0,0 +1,40 @@
-+/*
-+ * Copyright (C) 2009 Red Hat, Inc.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+ *
-+ * Written By: Ray Strode <rstrode at redhat.com>
-+ *
-+ */
-+
-+#include "gdm-smartcard-extension.h"
-+
-+#include <gio/gio.h>
-+#include <gtk/gtk.h>
-+
-+GdmGreeterExtension *
-+gdm_greeter_plugin_get_extension (void)
-+{
-+        static GObject *extension;
-+
-+        if (extension != NULL) {
-+                g_object_ref (extension);
-+        } else {
-+                extension = g_object_new (GDM_TYPE_SMARTCARD_EXTENSION, NULL);
-+                g_object_add_weak_pointer (extension, (gpointer *) &extension);
-+        }
-+
-+        return GDM_GREETER_EXTENSION (extension);
-+}
-diff --git a/po/POTFILES.in b/po/POTFILES.in
-index dd08b21..ed922a5 100644
---- a/po/POTFILES.in
-+++ b/po/POTFILES.in
-@@ -86,6 +86,9 @@ gui/simple-greeter/gdm-user-chooser-widget.c
- gui/simple-greeter/greeter-main.c
- gui/simple-greeter/plugins/password/gdm-password-extension.c
- gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c
-+gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c
-+gui/simple-greeter/plugins/smartcard/gdm-smartcard-manager.c
-+gui/simple-greeter/plugins/smartcard/gdm-smartcard.c
- gui/user-switch-applet/applet.c
- gui/user-switch-applet/gdm-entry-menu-item.c
- gui/user-switch-applet/GNOME_FastUserSwitchApplet.server.in.in
--- 
-1.6.5.2
-
-
-From 5ba7fbd8fab03b01e4818f3c7b262be73582988f Mon Sep 17 00:00:00 2001
-From: Ray Strode <rstrode at redhat.com>
-Date: Mon, 23 Feb 2009 17:57:06 -0500
-Subject: [PATCH 18/45] Add a new "choosable" property to show tasks in user list
-
-Useful for Smartcard and some future "Guest" account plugin
----
- gui/simple-greeter/gdm-greeter-login-window.c      |   13 ++++++++++---
- gui/simple-greeter/libgdmsimplegreeter/gdm-task.c  |    6 ++++++
- gui/simple-greeter/libgdmsimplegreeter/gdm-task.h  |    2 ++
- .../fingerprint/gdm-fingerprint-extension.c        |    7 +++++++
- .../plugins/password/gdm-password-extension.c      |    7 +++++++
- .../plugins/smartcard/gdm-smartcard-extension.c    |    7 +++++++
- 6 files changed, 39 insertions(+), 3 deletions(-)
-
-diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
-index 7c34c4a..19b3e5e 100644
---- a/gui/simple-greeter/gdm-greeter-login-window.c
-+++ b/gui/simple-greeter/gdm-greeter-login-window.c
-@@ -2042,9 +2042,6 @@ gdm_greeter_login_window_add_extension (GdmGreeterLoginWindow *login_window,
-         g_debug ("GdmGreeterLoginWindow: new extension '%s - %s' added",
-                 name, description);
- 
--        g_free (name);
--        g_free (description);
--
-         if (gdm_task_list_get_number_of_tasks (GDM_TASK_LIST (login_window->priv->conversation_list)) == 0) {
-                 gtk_widget_hide (login_window->priv->conversation_list);
-         } else {
-@@ -2055,6 +2052,16 @@ gdm_greeter_login_window_add_extension (GdmGreeterLoginWindow *login_window,
-                                 GDM_TASK (extension));
- 
-         service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (extension));
-+
-+        if (gdm_task_is_choosable (GDM_TASK (extension))) {
-+                gdm_chooser_widget_add_item (GDM_CHOOSER_WIDGET (login_window->priv->user_chooser),
-+                                             service_name, NULL, name, description, ~0,
-+                                             FALSE, TRUE);
-+        }
-+
-+        g_free (name);
-+        g_free (description);
-+
-         g_debug ("GdmGreeterLoginWindow: starting conversation with '%s'", service_name);
-         g_signal_emit (login_window, signals[START_CONVERSATION], 0, service_name);
-         g_free (service_name);
-diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-task.c b/gui/simple-greeter/libgdmsimplegreeter/gdm-task.c
-index f72fa78..05fd75c 100644
---- a/gui/simple-greeter/libgdmsimplegreeter/gdm-task.c
-+++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-task.c
-@@ -88,6 +88,12 @@ gdm_task_is_enabled (GdmTask   *task)
-         return !g_object_get_data (G_OBJECT (task), "gdm-task-is-disabled");
- }
- 
-+gboolean
-+gdm_task_is_choosable (GdmTask *task)
-+{
-+        return GDM_TASK_GET_IFACE (task)->is_choosable (task);
-+}
-+
- static void
- gdm_task_class_init (gpointer g_iface)
- {
-diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-task.h b/gui/simple-greeter/libgdmsimplegreeter/gdm-task.h
-index 9894e65..c75bf29 100644
---- a/gui/simple-greeter/libgdmsimplegreeter/gdm-task.h
-+++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-task.h
-@@ -44,6 +44,7 @@ struct _GdmTaskIface
-         GIcon * (* get_icon)        (GdmTask   *task);
-         char *  (* get_description) (GdmTask   *task);
-         char *  (* get_name)        (GdmTask   *task);
-+        gboolean  (* is_choosable)    (GdmTask   *task);
-         /* signals */
-         void (* enabled) (GdmTask *task);
-         void (* disabled) (GdmTask *task);
-@@ -57,6 +58,7 @@ char  *gdm_task_get_name        (GdmTask   *task);
- void   gdm_task_set_enabled     (GdmTask   *task,
-                                  gboolean   should_enable);
- gboolean   gdm_task_is_enabled     (GdmTask   *task);
-+gboolean   gdm_task_is_choosable   (GdmTask   *task);
- G_END_DECLS
- 
- #endif /* __GDM_TASK_H */
-diff --git a/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c b/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c
-index b20dd65..7aa99e7 100644
---- a/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c
-+++ b/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c
-@@ -188,12 +188,19 @@ gdm_fingerprint_extension_get_description (GdmTask *task)
-         return g_strdup (_("Log into session with fingerprint"));
- }
- 
-+gboolean
-+gdm_fingerprint_extension_is_choosable (GdmTask *task)
-+{
-+        return FALSE;
-+}
-+
- static void
- gdm_task_iface_init (GdmTaskIface *iface)
- {
-         iface->get_icon = gdm_fingerprint_extension_get_icon;
-         iface->get_description = gdm_fingerprint_extension_get_description;
-         iface->get_name = gdm_fingerprint_extension_get_name;
-+        iface->is_choosable = gdm_fingerprint_extension_is_choosable;
- }
- 
- static void
-diff --git a/gui/simple-greeter/plugins/password/gdm-password-extension.c b/gui/simple-greeter/plugins/password/gdm-password-extension.c
-index 3acab3f..4922c65 100644
---- a/gui/simple-greeter/plugins/password/gdm-password-extension.c
-+++ b/gui/simple-greeter/plugins/password/gdm-password-extension.c
-@@ -188,12 +188,19 @@ gdm_password_extension_get_description (GdmTask *task)
-         return g_strdup (_("Log into session with username and password"));
- }
- 
-+gboolean
-+gdm_password_extension_is_choosable (GdmTask *task)
-+{
-+        return FALSE;
-+}
-+
- static void
- gdm_task_iface_init (GdmTaskIface *iface)
- {
-         iface->get_icon = gdm_password_extension_get_icon;
-         iface->get_description = gdm_password_extension_get_description;
-         iface->get_name = gdm_password_extension_get_name;
-+        iface->is_choosable = gdm_password_extension_is_choosable;
- }
- 
- static void
-diff --git a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c
-index 6fa01fb..25d5de4 100644
---- a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c
-+++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c
-@@ -290,12 +290,19 @@ gdm_smartcard_extension_get_description (GdmTask *task)
-         return g_strdup (_("Log into session with smartcard"));
- }
- 
-+gboolean
-+gdm_smartcard_extension_is_choosable (GdmTask *task)
-+{
-+        return TRUE;
-+}
-+
- static void
- gdm_task_iface_init (GdmTaskIface *iface)
- {
-         iface->get_icon = gdm_smartcard_extension_get_icon;
-         iface->get_description = gdm_smartcard_extension_get_description;
-         iface->get_name = gdm_smartcard_extension_get_name;
-+        iface->is_choosable = gdm_smartcard_extension_is_choosable;
- }
- 
- static void
--- 
-1.6.5.2
-
-
-From 9cd27be6c651595ecae069504a8017aa677cc560 Mon Sep 17 00:00:00 2001
-From: Ray Strode <rstrode at redhat.com>
-Date: Tue, 24 Feb 2009 15:12:35 -0500
-Subject: [PATCH 19/45] Separate handling of non-users in user list from users
-
-Now get_chosen_user returns NULL if the activated item
-wasn't a user.  We also separate the handling of on item
-activation in two functions depending on the item type.
-
-This will be useful for adding custom handling for plugin
-added items.
----
- gui/simple-greeter/gdm-greeter-login-window.c      |   53 +++++++++++++-------
- gui/simple-greeter/gdm-user-chooser-widget.c       |   23 ++++++++-
- .../fingerprint/gdm-fingerprint-extension.c        |    2 -
- 3 files changed, 56 insertions(+), 22 deletions(-)
-
-diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
-index 19b3e5e..35ebe65 100644
---- a/gui/simple-greeter/gdm-greeter-login-window.c
-+++ b/gui/simple-greeter/gdm-greeter-login-window.c
-@@ -1185,29 +1185,49 @@ begin_task_verification_for_selected_user (GdmTaskList           *task_list,
- }
- 
- static void
--on_user_chosen (GdmUserChooserWidget  *user_chooser,
--                GdmGreeterLoginWindow *login_window)
-+on_user_chosen (GdmGreeterLoginWindow *login_window,
-+                const char            *user_name)
- {
--        char *user_name;
-+        g_debug ("GdmGreeterLoginWindow: user chosen '%s'", user_name);
-+
-+        g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED],
-+                       0, user_name);
-+
-+        gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
-+                                    (GdmTaskListForeachFunc)
-+                                    begin_task_verification_for_selected_user,
-+                                    login_window);
-+
-+        switch_mode (login_window, MODE_AUTHENTICATION);
-+}
-+
-+static void
-+on_user_chooser_activated (GdmUserChooserWidget  *user_chooser,
-+                           GdmGreeterLoginWindow *login_window)
-+{
-+        char *item_id;
- 
-         user_name = gdm_user_chooser_widget_get_chosen_user_name (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser));
--        g_debug ("GdmGreeterLoginWindow: user chosen '%s'", user_name);
- 
--        if (user_name == NULL) {
-+        if (user_name != NULL) {
-+                g_debug ("GdmGreeterLoginWindow: user chosen '%s'", user_name);
-+                on_user_chosen (login_window, user_name);
-+                g_free (user_name);
-                 return;
-         }
- 
--        g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED],
--                       0, user_name);
-+        item_id = gdm_chooser_widget_get_active_item (GDM_CHOOSER_WIDGET (user_chooser));
-+        g_debug ("GdmGreeterLoginWindow: item chosen '%s'", item_id);
- 
--        if (strcmp (user_name, GDM_USER_CHOOSER_USER_OTHER) == 0) {
-+        if (strcmp (item_id, GDM_USER_CHOOSER_USER_OTHER) == 0) {
-+                g_debug ("GdmGreeterLoginWindow: Starting all auth conversations");
-                 gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
-                                             (GdmTaskListForeachFunc)
-                                             begin_task_verification,
-                                             login_window);
--        } else if (strcmp (user_name, GDM_USER_CHOOSER_USER_GUEST) == 0) {
--                /* FIXME: handle guest account stuff */
--        } else if (strcmp (user_name, GDM_USER_CHOOSER_USER_AUTO) == 0) {
-+                g_free (item_id);
-+        } else if (strcmp (item_id, GDM_USER_CHOOSER_USER_AUTO) == 0) {
-+                g_debug ("GdmGreeterLoginWindow: Starting auto login");
-                 g_signal_emit (login_window, signals[BEGIN_AUTO_LOGIN], 0,
-                                login_window->priv->timed_login_username);
- 
-@@ -1217,16 +1237,11 @@ on_user_chosen (GdmUserChooserWidget  *user_chooser,
-                 /* just wait for the user to select language and stuff */
-                 set_log_in_button_mode (login_window, LOGIN_BUTTON_TIMED_LOGIN);
-                 set_message (login_window, _("Select language and click Log In"));
--        } else {
--                gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
--                                            (GdmTaskListForeachFunc)
--                                            begin_task_verification_for_selected_user,
--                                            login_window);
-+                g_free (item_id);
-         }
- 
-+        g_debug ("GdmGreeterLoginWindow: Switching to shrunken authentication mode");
-         switch_mode (login_window, MODE_AUTHENTICATION);
--
--        g_free (user_name);
- }
- 
- static void
-@@ -1505,7 +1520,7 @@ load_theme (GdmGreeterLoginWindow *login_window)
-                           login_window);
-         g_signal_connect (login_window->priv->user_chooser,
-                           "activated",
--                          G_CALLBACK (on_user_chosen),
-+                          G_CALLBACK (on_user_chooser_activated),
-                           login_window);
-         g_signal_connect (login_window->priv->user_chooser,
-                           "deactivated",
-diff --git a/gui/simple-greeter/gdm-user-chooser-widget.c b/gui/simple-greeter/gdm-user-chooser-widget.c
-index 77e06a7..bff71e5 100644
---- a/gui/simple-greeter/gdm-user-chooser-widget.c
-+++ b/gui/simple-greeter/gdm-user-chooser-widget.c
-@@ -269,9 +269,30 @@ gdm_user_chooser_widget_set_show_user_auto (GdmUserChooserWidget *widget,
- char *
- gdm_user_chooser_widget_get_chosen_user_name (GdmUserChooserWidget *widget)
- {
-+        char *active_item_id;
-+        gboolean isnt_user;
-+
-         g_return_val_if_fail (GDM_IS_USER_CHOOSER_WIDGET (widget), NULL);
- 
--        return gdm_chooser_widget_get_active_item (GDM_CHOOSER_WIDGET (widget));
-+        active_item_id = gdm_chooser_widget_get_active_item (GDM_CHOOSER_WIDGET (widget));
-+        if (active_item_id == NULL) {
-+                g_debug ("GdmUserChooserWidget: no active item in list");
-+                return NULL;
-+        }
-+
-+        gdm_chooser_widget_lookup_item (GDM_CHOOSER_WIDGET (widget), active_item_id,
-+                                        NULL, NULL, NULL, NULL, NULL,
-+                                        &isnt_user);
-+
-+        if (isnt_user) {
-+                g_debug ("GdmUserChooserWidget: active item '%s' isn't a user", active_item_id);
-+                g_free (active_item_id);
-+                return NULL;
-+        }
-+
-+        g_debug ("GdmUserChooserWidget: active item '%s' is a user", active_item_id);
-+
-+        return active_item_id;
- }
- 
- void
-diff --git a/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c b/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c
-index 7aa99e7..316ef46 100644
---- a/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c
-+++ b/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c
-@@ -287,8 +287,6 @@ create_page (GdmFingerprintExtension *extension)
- static void
- create_actions (GdmFingerprintExtension *extension)
- {
--        GtkAction *action;
--
-         extension->priv->actions = gtk_action_group_new ("gdm-fingerprint-extension");
- }
- 
--- 
-1.6.5.2
-
-
-From cae064823f5bc4811e4f7ba03a660c7f578eddfd Mon Sep 17 00:00:00 2001
-From: Ray Strode <rstrode at redhat.com>
-Date: Fri, 27 Feb 2009 15:44:13 -0500
-Subject: [PATCH 20/45] Initiate smart card auth when clicking on it in list
-
----
- gui/simple-greeter/gdm-greeter-login-window.c      |   24 ++++++++++++++++++++
- .../plugins/smartcard/gdm-smartcard-extension.c    |    2 +-
- 2 files changed, 25 insertions(+), 1 deletions(-)
-
-diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
-index 35ebe65..8b8b0ee 100644
---- a/gui/simple-greeter/gdm-greeter-login-window.c
-+++ b/gui/simple-greeter/gdm-greeter-login-window.c
-@@ -682,6 +682,7 @@ reset_dialog (GdmGreeterLoginWindow *login_window)
-                 switch_mode (login_window, MODE_SELECTION);
-         }
- 
-+        gtk_widget_set_sensitive (login_window->priv->conversation_list, TRUE);
-         set_sensitive (login_window, TRUE);
-         set_ready (login_window);
-         set_focus (GDM_GREETER_LOGIN_WINDOW (login_window));
-@@ -1205,6 +1206,7 @@ static void
- on_user_chooser_activated (GdmUserChooserWidget  *user_chooser,
-                            GdmGreeterLoginWindow *login_window)
- {
-+        char *user_name;
-         char *item_id;
- 
-         user_name = gdm_user_chooser_widget_get_chosen_user_name (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser));
-@@ -1238,6 +1240,28 @@ on_user_chooser_activated (GdmUserChooserWidget  *user_chooser,
-                 set_log_in_button_mode (login_window, LOGIN_BUTTON_TIMED_LOGIN);
-                 set_message (login_window, _("Select language and click Log In"));
-                 g_free (item_id);
-+        } else {
-+                GdmTask *task;
-+
-+                task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
-+                                                   (GdmTaskListForeachFunc)
-+                                                   task_has_service_name,
-+                                                   (gpointer) item_id);
-+
-+                if (task == NULL) {
-+                        g_debug ("GdmGreeterLoginWindow: %s has no task associated with it", item_id);
-+                        g_free (item_id);
-+                        return;
-+                }
-+                g_debug ("GdmGreeterLoginWindow: Beginning auth conversation for item %s", item_id);
-+
-+                /* FIXME: we should probably give the plugin more say for
-+                 * what happens here.
-+                 */
-+                g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0, item_id);
-+                g_free (item_id);
-+
-+                gtk_widget_set_sensitive (login_window->priv->conversation_list, FALSE);
-         }
- 
-         g_debug ("GdmGreeterLoginWindow: Switching to shrunken authentication mode");
-diff --git a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c
-index 25d5de4..a9e41f4 100644
---- a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c
-+++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c
-@@ -103,7 +103,7 @@ on_smartcard_event (GIOChannel   *io_channel,
- 
-                 if (extension->priv->number_of_tokens == 1) {
-                         gdm_conversation_choose_user (GDM_CONVERSATION (extension),
--                                                      GDM_CONVERSATION_OTHER_USER);
-+                                                      PAMSERVICENAME);
-                 } else if (extension->priv->number_of_tokens == 0) {
-                         gdm_conversation_cancel (GDM_CONVERSATION (extension));
-                 }
--- 
-1.6.5.2
-
-
-From 89f9325e15e876bbab865263d2c3b8d4587620a0 Mon Sep 17 00:00:00 2001
-From: Ray Strode <rstrode at redhat.com>
-Date: Mon, 2 Mar 2009 11:10:28 -0500
-Subject: [PATCH 21/45] Only show task list if user is selected
-
----
- gui/simple-greeter/gdm-greeter-login-window.c |   32 ++++++++++++++----------
- gui/simple-greeter/gdm-task-list.c            |   11 +++++++-
- 2 files changed, 28 insertions(+), 15 deletions(-)
-
-diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
-index 8b8b0ee..ffcd950 100644
---- a/gui/simple-greeter/gdm-greeter-login-window.c
-+++ b/gui/simple-greeter/gdm-greeter-login-window.c
-@@ -515,6 +515,7 @@ switch_mode (GdmGreeterLoginWindow *login_window,
- {
-         const char *default_name;
-         GtkWidget  *box;
-+        int         number_of_tasks;
- 
-         /* Should never switch to MODE_UNDEFINED */
-         g_assert (number != MODE_UNDEFINED);
-@@ -532,6 +533,7 @@ switch_mode (GdmGreeterLoginWindow *login_window,
- 
-                 show_widget (login_window, "cancel-button", FALSE);
-                 show_widget (login_window, "auth-page-box", FALSE);
-+                show_widget (login_window, "conversation-list", FALSE);
- 
-                 sensitize_widget (login_window, "disconnect-button", FALSE);
- 
-@@ -546,8 +548,15 @@ switch_mode (GdmGreeterLoginWindow *login_window,
-                 login_window->priv->show_cancel_button = TRUE;
-                 break;
-         case MODE_AUTHENTICATION:
-+                gtk_widget_set_size_request (GTK_WIDGET (login_window),
-+                                             GTK_WIDGET (login_window)->allocation.width,
-+                                             -1);
-                 show_widget (login_window, "disconnect-button", FALSE);
-                 show_widget (login_window, "auth-page-box", TRUE);
-+
-+                number_of_tasks = gdm_task_list_get_number_of_tasks (GDM_TASK_LIST (login_window->priv->conversation_list));
-+                show_widget (login_window, "conversation-list", number_of_tasks > 1);
-+
-                 default_name = "log-in-button";
-                 break;
-         default:
-@@ -1223,11 +1232,14 @@ on_user_chooser_activated (GdmUserChooserWidget  *user_chooser,
- 
-         if (strcmp (item_id, GDM_USER_CHOOSER_USER_OTHER) == 0) {
-                 g_debug ("GdmGreeterLoginWindow: Starting all auth conversations");
-+                g_free (item_id);
-+
-                 gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
-                                             (GdmTaskListForeachFunc)
-                                             begin_task_verification,
-                                             login_window);
--                g_free (item_id);
-+
-+                switch_mode (login_window, MODE_AUTHENTICATION);
-         } else if (strcmp (item_id, GDM_USER_CHOOSER_USER_AUTO) == 0) {
-                 g_debug ("GdmGreeterLoginWindow: Starting auto login");
-                 g_signal_emit (login_window, signals[BEGIN_AUTO_LOGIN], 0,
-@@ -1240,6 +1252,8 @@ on_user_chooser_activated (GdmUserChooserWidget  *user_chooser,
-                 set_log_in_button_mode (login_window, LOGIN_BUTTON_TIMED_LOGIN);
-                 set_message (login_window, _("Select language and click Log In"));
-                 g_free (item_id);
-+
-+                switch_mode (login_window, MODE_AUTHENTICATION);
-         } else {
-                 GdmTask *task;
- 
-@@ -1254,18 +1268,17 @@ on_user_chooser_activated (GdmUserChooserWidget  *user_chooser,
-                         return;
-                 }
-                 g_debug ("GdmGreeterLoginWindow: Beginning auth conversation for item %s", item_id);
--
-                 /* FIXME: we should probably give the plugin more say for
-                  * what happens here.
-                  */
-                 g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0, item_id);
-                 g_free (item_id);
- 
--                gtk_widget_set_sensitive (login_window->priv->conversation_list, FALSE);
--        }
-+                switch_mode (login_window, MODE_AUTHENTICATION);
-+                gdm_task_list_set_active_task (GDM_TASK_LIST (login_window->priv->conversation_list), task);
- 
--        g_debug ("GdmGreeterLoginWindow: Switching to shrunken authentication mode");
--        switch_mode (login_window, MODE_AUTHENTICATION);
-+                g_object_unref (task);
-+        }
- }
- 
- static void
-@@ -1573,7 +1586,6 @@ load_theme (GdmGreeterLoginWindow *login_window)
-                                   "deactivated",
-                                   G_CALLBACK (on_task_deactivated),
-                                   login_window);
--        gtk_widget_show (login_window->priv->conversation_list);
- 
-         login_window->priv->auth_banner_label = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "auth-banner-label"));
-         /*make_label_small_italic (login_window->priv->auth_banner_label);*/
-@@ -2081,12 +2093,6 @@ gdm_greeter_login_window_add_extension (GdmGreeterLoginWindow *login_window,
-         g_debug ("GdmGreeterLoginWindow: new extension '%s - %s' added",
-                 name, description);
- 
--        if (gdm_task_list_get_number_of_tasks (GDM_TASK_LIST (login_window->priv->conversation_list)) == 0) {
--                gtk_widget_hide (login_window->priv->conversation_list);
--        } else {
--                gtk_widget_show (login_window->priv->conversation_list);
--        }
--
-         gdm_task_list_add_task (GDM_TASK_LIST (login_window->priv->conversation_list),
-                                 GDM_TASK (extension));
- 
-diff --git a/gui/simple-greeter/gdm-task-list.c b/gui/simple-greeter/gdm-task-list.c
-index 3dff10e..be50832 100644
---- a/gui/simple-greeter/gdm-task-list.c
-+++ b/gui/simple-greeter/gdm-task-list.c
-@@ -303,17 +303,24 @@ gdm_task_list_set_active_task (GdmTaskList *widget,
-                                GdmTask     *task)
- {
-         GtkWidget *button;
-+        gboolean   was_sensitive;
-+        gboolean   was_activated;
-+
-+        was_sensitive = GTK_WIDGET_SENSITIVE (widget);
-+        gtk_widget_set_sensitive (GTK_WIDGET (widget), TRUE);
- 
-         button = GTK_WIDGET (g_object_get_data (G_OBJECT (task),
-                              "gdm-task-list-button"));
- 
-+        was_activated = FALSE;
-         if (GTK_WIDGET_IS_SENSITIVE (button)) {
-                 if (gtk_widget_activate (button)) {
--                        return TRUE;
-+                        was_activated = TRUE;
-                 }
-         }
- 
--        return FALSE;
-+        gtk_widget_set_sensitive (GTK_WIDGET (widget), was_sensitive);
-+        return was_activated;
- }
- 
- int
--- 
-1.6.5.2
-
-
-From 919c58b2816701ef7ed0b8be4aefb7d162f81003 Mon Sep 17 00:00:00 2001
-From: Ray Strode <rstrode at redhat.com>
-Date: Mon, 2 Mar 2009 13:53:34 -0500
-Subject: [PATCH 22/45] Pull verification functions out into their own subroutines
-
-This makes the function smaller and easier to read
----
- gui/simple-greeter/gdm-greeter-login-window.c |  132 +++++++++++++++++--------
- 1 files changed, 92 insertions(+), 40 deletions(-)
-
-diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
-index ffcd950..0c06607 100644
---- a/gui/simple-greeter/gdm-greeter-login-window.c
-+++ b/gui/simple-greeter/gdm-greeter-login-window.c
-@@ -1170,6 +1170,17 @@ begin_task_verification (GdmTaskList           *task_list,
-         return FALSE;
- }
- 
-+static void
-+begin_verification (GdmGreeterLoginWindow *login_window)
-+{
-+        gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
-+                                    (GdmTaskListForeachFunc)
-+                                    begin_task_verification,
-+                                    login_window);
-+
-+        switch_mode (login_window, MODE_AUTHENTICATION);
-+}
-+
- static gboolean
- begin_task_verification_for_selected_user (GdmTaskList           *task_list,
-                                            GdmTask               *task,
-@@ -1195,6 +1206,15 @@ begin_task_verification_for_selected_user (GdmTaskList           *task_list,
- }
- 
- static void
-+begin_verification_for_selected_user (GdmGreeterLoginWindow *login_window)
-+{
-+        gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
-+                                    (GdmTaskListForeachFunc)
-+                                    begin_task_verification_for_selected_user,
-+                                    login_window);
-+}
-+
-+static void
- on_user_chosen (GdmGreeterLoginWindow *login_window,
-                 const char            *user_name)
- {
-@@ -1203,12 +1223,75 @@ on_user_chosen (GdmGreeterLoginWindow *login_window,
-         g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED],
-                        0, user_name);
- 
-+        begin_verification_for_selected_user (login_window);
-+
-+        switch_mode (login_window, MODE_AUTHENTICATION);
-+}
-+
-+static void
-+begin_auto_login (GdmGreeterLoginWindow *login_window)
-+{
-+        g_signal_emit (login_window, signals[BEGIN_AUTO_LOGIN], 0,
-+                       login_window->priv->timed_login_username);
-+
-+        login_window->priv->timed_login_enabled = TRUE;
-+        restart_timed_login_timeout (login_window);
-+
-+        /* just wait for the user to select language and stuff */
-+        set_log_in_button_mode (login_window, LOGIN_BUTTON_TIMED_LOGIN);
-+        set_message (login_window, _("Select language and click Log In"));
-+
-+        switch_mode (login_window, MODE_AUTHENTICATION);
-+}
-+
-+static gboolean
-+reset_task_if_not_given (GdmTaskList *task_list,
-+                         GdmTask     *task,
-+                         GdmTask     *given_task)
-+{
-+        if (task == given_task) {
-+                return FALSE;
-+        }
-+
-+        gdm_conversation_reset (GDM_CONVERSATION (task));
-+        return FALSE;
-+}
-+
-+static void
-+reset_every_task_but_given_task (GdmGreeterLoginWindow *login_window,
-+                                 GdmTask               *task)
-+{
-         gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
-                                     (GdmTaskListForeachFunc)
--                                    begin_task_verification_for_selected_user,
--                                    login_window);
-+                                    reset_task_if_not_given,
-+                                    task);
-+}
-+
-+static void
-+begin_single_service_verification (GdmGreeterLoginWindow *login_window,
-+                                   const char            *service_name)
-+{
-+        GdmTask *task;
-+
-+        task = find_task_with_service_name (login_window, service_name);
-+
-+        if (task == NULL) {
-+                g_debug ("GdmGreeterLoginWindow: %s has no task associated with it", service_name);
-+                return;
-+        }
-+
-+        g_debug ("GdmGreeterLoginWindow: Beginning %s auth conversation", service_name);
-+
-+        /* FIXME: we should probably give the plugin more say for
-+         * what happens here.
-+         */
-+        g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0, service_name);
- 
-         switch_mode (login_window, MODE_AUTHENTICATION);
-+        gdm_task_list_set_active_task (GDM_TASK_LIST (login_window->priv->conversation_list), task);
-+
-+        reset_every_task_but_given_task (login_window, task);
-+        g_object_unref (task);
- }
- 
- static void
-@@ -1230,54 +1313,23 @@ on_user_chooser_activated (GdmUserChooserWidget  *user_chooser,
-         item_id = gdm_chooser_widget_get_active_item (GDM_CHOOSER_WIDGET (user_chooser));
-         g_debug ("GdmGreeterLoginWindow: item chosen '%s'", item_id);
- 
-+        g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED],
-+                       0, item_id);
-+
-         if (strcmp (item_id, GDM_USER_CHOOSER_USER_OTHER) == 0) {
-                 g_debug ("GdmGreeterLoginWindow: Starting all auth conversations");
-                 g_free (item_id);
- 
--                gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
--                                            (GdmTaskListForeachFunc)
--                                            begin_task_verification,
--                                            login_window);
--
--                switch_mode (login_window, MODE_AUTHENTICATION);
-+                begin_verification (login_window);
-         } else if (strcmp (item_id, GDM_USER_CHOOSER_USER_AUTO) == 0) {
-                 g_debug ("GdmGreeterLoginWindow: Starting auto login");
--                g_signal_emit (login_window, signals[BEGIN_AUTO_LOGIN], 0,
--                               login_window->priv->timed_login_username);
--
--                login_window->priv->timed_login_enabled = TRUE;
--                restart_timed_login_timeout (login_window);
--
--                /* just wait for the user to select language and stuff */
--                set_log_in_button_mode (login_window, LOGIN_BUTTON_TIMED_LOGIN);
--                set_message (login_window, _("Select language and click Log In"));
-                 g_free (item_id);
- 
--                switch_mode (login_window, MODE_AUTHENTICATION);
-+                begin_auto_login (login_window);
-         } else {
--                GdmTask *task;
--
--                task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
--                                                   (GdmTaskListForeachFunc)
--                                                   task_has_service_name,
--                                                   (gpointer) item_id);
--
--                if (task == NULL) {
--                        g_debug ("GdmGreeterLoginWindow: %s has no task associated with it", item_id);
--                        g_free (item_id);
--                        return;
--                }
--                g_debug ("GdmGreeterLoginWindow: Beginning auth conversation for item %s", item_id);
--                /* FIXME: we should probably give the plugin more say for
--                 * what happens here.
--                 */
--                g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0, item_id);
-+                g_debug ("GdmGreeterLoginWindow: Starting single auth conversation");
-+                begin_single_service_verification (login_window, item_id);
-                 g_free (item_id);
--
--                switch_mode (login_window, MODE_AUTHENTICATION);
--                gdm_task_list_set_active_task (GDM_TASK_LIST (login_window->priv->conversation_list), task);
--
--                g_object_unref (task);
-         }
- }
- 
--- 
-1.6.5.2
-
-
-From 114b9be6024ef4b6c73fb7c1ad909346b6379d91 Mon Sep 17 00:00:00 2001
-From: Ray Strode <rstrode at redhat.com>
-Date: Mon, 2 Mar 2009 17:09:16 -0500
-Subject: [PATCH 23/45] Notify plugins if their user choose requests fail
-
-This allows the smart card plugin to cancel pending
-conversations when a card gets inserted.
-
-This isn't perfect.  We really want to only cancel
-the conversations if they're for a user other
-than the user the smartcard is for.
----
- common/gdm-marshal.list                            |    1 +
- gui/simple-greeter/gdm-greeter-login-window.c      |   12 ++++++++-
- gui/simple-greeter/libgdmsimplegreeter/Makefile.am |    2 +
- .../libgdmsimplegreeter/gdm-conversation.c         |   19 +++++++++++-----
- .../libgdmsimplegreeter/gdm-conversation.h         |    6 ++--
- .../plugins/smartcard/gdm-smartcard-extension.c    |   23 +++++++++++++++----
- 6 files changed, 47 insertions(+), 16 deletions(-)
-
-diff --git a/common/gdm-marshal.list b/common/gdm-marshal.list
-index d5455e1..d8a9e72 100644
---- a/common/gdm-marshal.list
-+++ b/common/gdm-marshal.list
-@@ -5,3 +5,4 @@ VOID:STRING,STRING
- VOID:UINT,UINT
- VOID:STRING,INT
- VOID:DOUBLE
-+BOOLEAN:STRING
-diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
-index 0c06607..8bbd07e 100644
---- a/gui/simple-greeter/gdm-greeter-login-window.c
-+++ b/gui/simple-greeter/gdm-greeter-login-window.c
-@@ -1972,7 +1972,7 @@ on_conversation_cancel (GdmGreeterLoginWindow *login_window,
-         do_cancel (login_window);
- }
- 
--static void
-+static gboolean
- on_conversation_chose_user (GdmGreeterLoginWindow *login_window,
-                             const char            *username,
-                             GdmConversation       *conversation)
-@@ -1983,7 +1983,13 @@ on_conversation_chose_user (GdmGreeterLoginWindow *login_window,
-                 name = gdm_task_get_name (GDM_TASK (conversation));
-                 g_warning ("Task %s is trying to choose user before list is loaded", name);
-                 g_free (name);
--                return;
-+                return FALSE;
-+        }
-+
-+        /* If we're already authenticating then we can't pick a user
-+         */
-+        if (login_window->priv->dialog_mode == MODE_AUTHENTICATION) {
-+                return FALSE;
-         }
- 
-         if (gdm_task_list_set_active_task (GDM_TASK_LIST (login_window->priv->conversation_list),
-@@ -1991,6 +1997,8 @@ on_conversation_chose_user (GdmGreeterLoginWindow *login_window,
-                 gdm_user_chooser_widget_set_chosen_user_name (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser),
-                                                               username);
-         }
-+
-+        return TRUE;
- }
- 
- void
-diff --git a/gui/simple-greeter/libgdmsimplegreeter/Makefile.am b/gui/simple-greeter/libgdmsimplegreeter/Makefile.am
-index 1ef5725..0d7a0bd 100644
---- a/gui/simple-greeter/libgdmsimplegreeter/Makefile.am
-+++ b/gui/simple-greeter/libgdmsimplegreeter/Makefile.am
-@@ -3,6 +3,7 @@ NULL =
- AM_CPPFLAGS = \
- 	-I.					\
- 	-I..					\
-+	-I$(top_srcdir)/common			\
- 	-DBINDIR=\"$(bindir)\"			\
- 	-DDATADIR=\"$(datadir)\"		\
- 	-DLIBDIR=\"$(libdir)\"			\
-@@ -28,6 +29,7 @@ libgdmsimplegreeter_la_SOURCES =		\
- 
- libgdmsimplegreeter_la_LIBADD =			\
- 	$(GTK_LIBS)				\
-+	$(top_builddir)/common/libgdmcommon.la	\
- 	$(NULL)
- 
- libgdmsimplegreeter_la_LDFLAGS = 		\
-diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c
-index cef435c..ee763ef 100644
---- a/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c
-+++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c
-@@ -25,9 +25,9 @@
- #include <gtk/gtk.h>
- 
- #include "gdm-conversation.h"
-+#include "gdm-marshal.h"
- #include "gdm-task.h"
- 
--
- enum {
-         ANSWER,
-         USER_CHOSEN,
-@@ -76,12 +76,12 @@ gdm_conversation_class_init (gpointer g_iface)
-         signals [USER_CHOSEN] =
-                 g_signal_new ("user-chosen",
-                               iface_type,
--                              G_SIGNAL_RUN_FIRST,
-+                              G_SIGNAL_RUN_LAST,
-                               G_STRUCT_OFFSET (GdmConversationIface, user_chosen),
-                               NULL,
-                               NULL,
--                              g_cclosure_marshal_VOID__STRING,
--                              G_TYPE_NONE,
-+                              gdm_marshal_BOOLEAN__STRING,
-+                              G_TYPE_BOOLEAN,
-                               1, G_TYPE_STRING);
-         signals [CANCEL] =
-                 g_signal_new ("cancel",
-@@ -171,9 +171,16 @@ gdm_conversation_cancel (GdmConversation   *conversation)
- {
-         g_signal_emit (conversation, signals [CANCEL], 0);
- }
--void
++        <object class="GtkHBox" id="auth-message-box">
++          <property name="visible">True</property>
++          <child>
++            <object class="GtkLabel" id="auth-message-label">
++              <property name="visible">True</property>
++            </object>
++            <packing>
++              <property name="position">0</property>
++            </packing>
++          </child>
++        </object>
++        <packing>
++          <property name="expand">True</property>
++          <property name="fill">True</property>
++          <property name="position">1</property>
++        </packing>
++      </child>
++    </object>
++</interface>
+diff --git a/gui/simple-greeter/plugins/smartcard/plugin.c b/gui/simple-greeter/plugins/smartcard/plugin.c
+new file mode 100644
+index 0000000..fffbd50
+--- /dev/null
++++ b/gui/simple-greeter/plugins/smartcard/plugin.c
+@@ -0,0 +1,40 @@
++/*
++ * Copyright (C) 2009 Red Hat, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * Written By: Ray Strode <rstrode at redhat.com>
++ *
++ */
 +
-+gboolean
- gdm_conversation_choose_user (GdmConversation *conversation,
-                               const char      *username)
- {
--        g_signal_emit (conversation, signals [USER_CHOSEN], 0, username);
-+        gboolean was_chosen;
++#include "gdm-smartcard-extension.h"
 +
-+        was_chosen = FALSE;
++#include <gio/gio.h>
++#include <gtk/gtk.h>
 +
-+        g_signal_emit (conversation, signals [USER_CHOSEN], 0, username, &was_chosen);
++GdmGreeterExtension *
++gdm_greeter_plugin_get_extension (void)
++{
++        static GObject *extension;
 +
-+        return was_chosen;
- }
-diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h
-index fb4bf49..b37b21e 100644
---- a/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h
-+++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h
-@@ -61,7 +61,7 @@ struct _GdmConversationIface
-         /* signals */
-         char * (* answer)       (GdmConversation *conversation);
-         void   (* cancel)       (GdmConversation *conversation);
--        void   (* user_chosen)     (GdmConversation *conversation);
-+        gboolean  (* user_chosen)  (GdmConversation *conversation);
- };
- 
- GType  gdm_conversation_get_type     (void) G_GNUC_CONST;
-@@ -85,8 +85,8 @@ gboolean   gdm_conversation_focus    (GdmConversation *conversation);
- void   gdm_conversation_answer (GdmConversation   *conversation,
-                                 const char        *answer);
- void   gdm_conversation_cancel (GdmConversation   *conversation);
--void   gdm_conversation_choose_user (GdmConversation   *conversation,
--                                     const char        *username);
-+gboolean  gdm_conversation_choose_user (GdmConversation   *conversation,
-+                                        const char        *username);
- 
- G_END_DECLS
- 
-diff --git a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c
-index a9e41f4..274132e 100644
---- a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c
-+++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c
-@@ -53,6 +53,7 @@ struct _GdmSmartcardExtensionPrivate
-         int        number_of_tokens;
- 
-         guint      answer_pending : 1;
-+        guint      select_when_ready : 1;
- };
- 
- static void gdm_smartcard_extension_finalize (GObject *object);
-@@ -102,8 +103,14 @@ on_smartcard_event (GIOChannel   *io_channel,
-                 }
- 
-                 if (extension->priv->number_of_tokens == 1) {
--                        gdm_conversation_choose_user (GDM_CONVERSATION (extension),
--                                                      PAMSERVICENAME);
-+                        if (!gdm_conversation_choose_user (GDM_CONVERSATION (extension),
-+                                                          PAMSERVICENAME)) {
-+                                g_debug ("could not choose smart card user, cancelling...");
-+                                gdm_conversation_cancel (GDM_CONVERSATION (extension));
-+                                extension->priv->select_when_ready = TRUE;
-+                        } else {
-+                                g_debug ("chose smart card user!");
-+                        }
-                 } else if (extension->priv->number_of_tokens == 0) {
-                         gdm_conversation_cancel (GDM_CONVERSATION (extension));
-                 }
-@@ -210,10 +217,16 @@ gdm_smartcard_extension_set_ready (GdmConversation *conversation)
-         GdmSmartcardExtension *extension = GDM_SMARTCARD_EXTENSION (conversation);
-         gdm_task_set_enabled (GDM_TASK (conversation), TRUE);
- 
--        if (extension->priv->worker_pid <= 0)
--          {
-+        if (extension->priv->worker_pid <= 0) {
-                 watch_for_smartcards (extension);
--          }
++        if (extension != NULL) {
++                g_object_ref (extension);
++        } else {
++                extension = g_object_new (GDM_TYPE_SMARTCARD_EXTENSION, NULL);
++                g_object_add_weak_pointer (extension, (gpointer *) &extension);
 +        }
 +
-+        if (extension->priv->select_when_ready) {
-+                if (gdm_conversation_choose_user (GDM_CONVERSATION (extension),
-+                                                  PAMSERVICENAME)) {
-+                        extension->priv->select_when_ready = FALSE;
-+                }
-+        }
- }
- 
- char *
++        return GDM_GREETER_EXTENSION (extension);
++}
+diff --git a/po/POTFILES.in b/po/POTFILES.in
+index dd08b21..ed922a5 100644
+--- a/po/POTFILES.in
++++ b/po/POTFILES.in
+@@ -86,6 +86,9 @@ gui/simple-greeter/gdm-user-chooser-widget.c
+ gui/simple-greeter/greeter-main.c
+ gui/simple-greeter/plugins/password/gdm-password-extension.c
+ gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c
++gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c
++gui/simple-greeter/plugins/smartcard/gdm-smartcard-manager.c
++gui/simple-greeter/plugins/smartcard/gdm-smartcard.c
+ gui/user-switch-applet/applet.c
+ gui/user-switch-applet/gdm-entry-menu-item.c
+ gui/user-switch-applet/GNOME_FastUserSwitchApplet.server.in.in
 -- 
-1.6.5.2
+1.7.2.1
 
 
-From aaa059c8141fae5ed428ab67232dc901153f963b Mon Sep 17 00:00:00 2001
+From 1b0996ab22621ae16faa847a940d3df36a837efe Mon Sep 17 00:00:00 2001
 From: Ray Strode <rstrode at redhat.com>
-Date: Mon, 13 Apr 2009 14:19:50 -0400
-Subject: [PATCH 24/45] reset all conversations if password conversation fails
+Date: Wed, 4 Aug 2010 18:26:01 -0400
+Subject: [PATCH 24/35] squash with smartcard
 
-This is a temporary hack until we store plugin policy in
-gconf.
 ---
- gui/simple-greeter/gdm-greeter-login-window.c |   10 ++++++++++
- 1 files changed, 10 insertions(+), 0 deletions(-)
+ .../plugins/smartcard/gdm-smartcard-extension.c    |    3 +++
+ 1 files changed, 3 insertions(+), 0 deletions(-)
 
-diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
-index 8bbd07e..64d8fdc 100644
---- a/gui/simple-greeter/gdm-greeter-login-window.c
-+++ b/gui/simple-greeter/gdm-greeter-login-window.c
-@@ -784,6 +784,16 @@ gdm_greeter_login_window_conversation_stopped (GdmGreeterLoginWindow *login_wind
- 
-         g_debug ("GdmGreeterLoginWindow: conversation '%s' has stopped", service_name);
+diff --git a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c
+index b925f5e..b40a21c 100644
+--- a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c
++++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c
+@@ -184,6 +184,7 @@ gdm_smartcard_extension_ask_question (GdmConversation *conversation,
+         gtk_entry_set_visibility (GTK_ENTRY (extension->priv->prompt_entry), TRUE);
+         gtk_widget_show (extension->priv->prompt_entry);
+         gtk_action_set_visible (extension->priv->login_action, TRUE);
++        gtk_action_set_sensitive (extension->priv->login_action, TRUE);
+         gtk_widget_grab_focus (extension->priv->prompt_entry);
+         extension->priv->answer_pending = TRUE;
+ }
+@@ -200,6 +201,7 @@ gdm_smartcard_extension_ask_secret (GdmConversation *conversation,
+         gtk_widget_show (extension->priv->prompt_entry);
+         gtk_widget_grab_focus (extension->priv->prompt_entry);
+         gtk_action_set_visible (extension->priv->login_action, TRUE);
++        gtk_action_set_sensitive (extension->priv->login_action, TRUE);
+         extension->priv->answer_pending = TRUE;
+ }
  
-+        /* If the password conversation failed, then start over
-+         *
-+         * FIXME: we need to get this policy out of the source code
-+         */
-+        if (strcmp (service_name, "gdm-password") == 0) {
-+                g_debug ("GdmGreeterLoginWindow: main conversation failed, starting over");
-+                restart_conversations (login_window);
-+                return TRUE;
-+        }
-+
-         task = find_task_with_service_name (login_window, service_name);
+@@ -475,6 +477,7 @@ static void
+ on_activate_log_in (GdmSmartcardExtension *extension)
+ {
+         gdm_smartcard_extension_request_answer (GDM_CONVERSATION (extension));
++        gtk_action_set_sensitive (extension->priv->login_action, FALSE);
+ }
  
-         if (task != NULL) {
+ static void
 -- 
-1.6.5.2
+1.7.2.1
 
 
-From b5b16b965a8ecfbcd5c43abe20f77c460f7030fb Mon Sep 17 00:00:00 2001
+From 74292dc8bf5f84a83b4ff339b53f1430479fa2d9 Mon Sep 17 00:00:00 2001
 From: Ray Strode <rstrode at redhat.com>
 Date: Tue, 21 Apr 2009 10:25:18 -0400
-Subject: [PATCH 25/45] When one PAM conversation wins, stop the others
+Subject: [PATCH 25/35] When one PAM conversation wins, stop the others
 
 At some point we'll want to have policy here, to allow
 e.g. two factor authentication.
@@ -16829,10 +16918,10 @@ e.g. two factor authentication.
  2 files changed, 53 insertions(+), 20 deletions(-)
 
 diff --git a/daemon/gdm-session-direct.c b/daemon/gdm-session-direct.c
-index 649dd91..5d7dabc 100644
+index 5a604bf..41c7dc2 100644
 --- a/daemon/gdm-session-direct.c
 +++ b/daemon/gdm-session-direct.c
-@@ -2305,6 +2305,47 @@ gdm_session_direct_open_session (GdmSession *session,
+@@ -2370,6 +2370,47 @@ gdm_session_direct_open_session (GdmSession *session,
  }
  
  static void
@@ -16880,7 +16969,7 @@ index 649dd91..5d7dabc 100644
  gdm_session_direct_start_session (GdmSession *session,
                                    const char *service_name)
  {
-@@ -2316,6 +2357,16 @@ gdm_session_direct_start_session (GdmSession *session,
+@@ -2381,6 +2422,16 @@ gdm_session_direct_start_session (GdmSession *session,
          g_return_if_fail (session != NULL);
          g_return_if_fail (impl->priv->is_running == FALSE);
  
@@ -16897,7 +16986,7 @@ index 649dd91..5d7dabc 100644
          command = get_session_command (impl);
  
          if (gdm_session_direct_bypasses_xsession (impl)) {
-@@ -2326,8 +2377,6 @@ gdm_session_direct_start_session (GdmSession *session,
+@@ -2391,8 +2442,6 @@ gdm_session_direct_start_session (GdmSession *session,
  
          g_free (command);
  
@@ -16906,7 +16995,7 @@ index 649dd91..5d7dabc 100644
          setup_session_environment (impl);
          send_environment (impl, conversation);
  
-@@ -2338,23 +2387,7 @@ gdm_session_direct_start_session (GdmSession *session,
+@@ -2403,23 +2452,7 @@ gdm_session_direct_start_session (GdmSession *session,
  static void
  stop_all_conversations (GdmSessionDirect *session)
  {
@@ -16932,10 +17021,10 @@ index 649dd91..5d7dabc 100644
  
  static void
 diff --git a/daemon/gdm-simple-slave.c b/daemon/gdm-simple-slave.c
-index bb6097b..6454d7d 100644
+index 43eac10..7725205 100644
 --- a/daemon/gdm-simple-slave.c
 +++ b/daemon/gdm-simple-slave.c
-@@ -586,7 +586,7 @@ on_session_conversation_stopped (GdmSession     *session,
+@@ -598,7 +598,7 @@ on_session_conversation_stopped (GdmSession     *session,
          gboolean res;
          g_debug ("GdmSimpleSlave: conversation stopped");
  
@@ -16945,13 +17034,13 @@ index bb6097b..6454d7d 100644
                                                                 service_name);
                  if (! res) {
 -- 
-1.6.5.2
+1.7.2.1
 
 
-From 7843a6507d736deb7859a550dfeaaeff1e18f05f Mon Sep 17 00:00:00 2001
+From 67a3f9ac9abc64c35c0d2b5b91a1ccc823f5b20d Mon Sep 17 00:00:00 2001
 From: Ray Strode <rstrode at redhat.com>
 Date: Fri, 24 Jul 2009 14:41:48 -0400
-Subject: [PATCH 26/45] KILL pam stack instead of TERM pam stack
+Subject: [PATCH 26/35] KILL stuck processes if they don't die on TERM
 
 Some PAM modules are really slow to shut down.
 We need to handle them being slow to shut down better,
@@ -16960,1150 +17049,1623 @@ in the mean time force them to die immediately.
 
 This is a temporary hack.
 ---
+ common/gdm-common.c             |   48 ++++++++++++++++++++++++++++++++++++--
+ common/gdm-common.h             |    2 +
  daemon/gdm-session-worker-job.c |    2 +-
- 1 files changed, 1 insertions(+), 1 deletions(-)
-
-diff --git a/daemon/gdm-session-worker-job.c b/daemon/gdm-session-worker-job.c
-index 0327d77..d99b8a5 100644
---- a/daemon/gdm-session-worker-job.c
-+++ b/daemon/gdm-session-worker-job.c
-@@ -320,7 +320,7 @@ gdm_session_worker_job_stop (GdmSessionWorkerJob *session_worker_job)
- 
-         g_debug ("GdmSessionWorkerJob: Stopping job pid:%d", session_worker_job->priv->pid);
- 
--        res = gdm_signal_pid (session_worker_job->priv->pid, SIGTERM);
-+        res = gdm_signal_pid (session_worker_job->priv->pid, SIGKILL);
- 
-         if (res < 0) {
-                 g_warning ("Unable to kill session worker process");
--- 
-1.6.5.2
-
-
-From 7dd5a90558faf19a1541cddcd1b343975872cf10 Mon Sep 17 00:00:00 2001
-From: Ray Strode <rstrode at redhat.com>
-Date: Wed, 21 Oct 2009 16:08:52 -0400
-Subject: [PATCH 27/45] Don't show tasklist for autologin
+ 3 files changed, 48 insertions(+), 4 deletions(-)
 
----
- gui/simple-greeter/gdm-greeter-login-window.c |    5 +++++
- 1 files changed, 5 insertions(+), 0 deletions(-)
-
-diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
-index 64d8fdc..3f756c4 100644
---- a/gui/simple-greeter/gdm-greeter-login-window.c
-+++ b/gui/simple-greeter/gdm-greeter-login-window.c
-@@ -1252,6 +1252,11 @@ begin_auto_login (GdmGreeterLoginWindow *login_window)
-         set_message (login_window, _("Select language and click Log In"));
- 
-         switch_mode (login_window, MODE_AUTHENTICATION);
-+
-+        show_widget (login_window, "conversation-list", FALSE);
-+        gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
-+                                    (GdmTaskListForeachFunc) reset_task,
-+                                    login_window);
+diff --git a/common/gdm-common.c b/common/gdm-common.c
+index de80700..7a4e26d 100644
+--- a/common/gdm-common.c
++++ b/common/gdm-common.c
+@@ -93,13 +93,25 @@ gdm_get_pwent_for_name (const char     *name,
  }
  
- static gboolean
--- 
-1.6.5.2
-
-
-From 5562e59bab560b9184a4af60f21e05583d51560a Mon Sep 17 00:00:00 2001
-From: Ray Strode <rstrode at redhat.com>
-Date: Fri, 23 Oct 2009 17:39:19 -0400
-Subject: [PATCH 28/45] Drop the other hiding stuff for now.
-
-It depends on buttons being available that we don't have
-in the multi-stack branch.
----
- gui/simple-greeter/gdm-user-chooser-widget.c |    8 +-------
- 1 files changed, 1 insertions(+), 7 deletions(-)
-
-diff --git a/gui/simple-greeter/gdm-user-chooser-widget.c b/gui/simple-greeter/gdm-user-chooser-widget.c
-index bff71e5..4d3c445 100644
---- a/gui/simple-greeter/gdm-user-chooser-widget.c
-+++ b/gui/simple-greeter/gdm-user-chooser-widget.c
-@@ -140,13 +140,7 @@ update_other_user_visibility (GdmUserChooserWidget *widget)
-                 return;
-         }
- 
--        number_of_users = gdm_chooser_widget_get_number_of_items (GDM_CHOOSER_WIDGET (widget));
--
--        /* we hide the Other user if it's the last one, and we show it
--         * if there's another user */
--        if (number_of_users == 1 && widget->priv->has_user_other) {
--                remove_user_other (widget);
--        } if (number_of_users >= 1 && !widget->priv->has_user_other) {
-+        if (!widget->priv->has_user_other) {
-                 add_user_other (widget);
-         }
- }
--- 
-1.6.5.2
-
-
-From 4069e5bfa6976b2f1df8053d9260adcbad6617be Mon Sep 17 00:00:00 2001
-From: Ray Strode <rstrode at redhat.com>
-Date: Wed, 28 Oct 2009 11:13:10 -0400
-Subject: [PATCH 29/45] Prevent start session signal handler from getting called multiple times
-
-It was causing a double free.
----
- gui/simple-greeter/gdm-greeter-login-window.c |    9 +++++++++
- 1 files changed, 9 insertions(+), 0 deletions(-)
-
-diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
-index 3f756c4..64ba6e8 100644
---- a/gui/simple-greeter/gdm-greeter-login-window.c
-+++ b/gui/simple-greeter/gdm-greeter-login-window.c
-@@ -953,8 +953,17 @@ on_ready_to_start_session (GdmGreeterLoginWindow *login_window,
-                            GParamSpec            *param_spec,
-                            char                  *service_name)
+ int
+-gdm_wait_on_pid (int pid)
++gdm_wait_on_and_kill_pid (int pid,
++                          int timeout)
  {
-+        if (!login_window->priv->is_interactive) {
-+                return;
+         int status;
+-
++        int ret;
++        int num_tries;
++        int flags;
++
++        if (timeout > 0) {
++                flags = WNOHANG;
++                num_tries = 10 * timeout;
++        } else {
++                flags = 0;
++                num_tries = 0;
 +        }
+  wait_again:
+         errno = 0;
+-        if (waitpid (pid, &status, 0) < 0) {
++        ret = waitpid (pid, &status, flags);
++        if (ret < 0) {
+                 if (errno == EINTR) {
+                         goto wait_again;
+                 } else if (errno == ECHILD) {
+@@ -107,6 +119,30 @@ gdm_wait_on_pid (int pid)
+                 } else {
+                         g_debug ("GdmCommon: waitpid () should not fail");
+                 }
++        } else if (ret == 0) {
++                num_tries--;
 +
-         gdm_greeter_login_window_start_session_when_ready (login_window, service_name);
-         g_free (service_name);
++                if (num_tries > 0) {
++                        g_usleep (G_USEC_PER_SEC / 10);
++                } else {
++                        char *path;
++                        char *command;
++
++                        path = g_strdup_printf ("/proc/%ld/cmdline", (long) pid);
++                        if (g_file_get_contents (path, &command, NULL, NULL)) {;
++                                g_debug ("GdmCommon: process (pid:%d, command '%s') isn't dying, now killing it.",
++                                         (int) pid, command);
++                                g_free (command);
++                        } else {
++                                g_debug ("GdmCommon: process (pid:%d) isn't dying, now killing it.",
++                                         (int) pid);
++                        }
++                        g_free (path);
 +
-+        if (login_window->priv->start_session_handler_id > 0) {
-+                g_signal_handler_disconnect (login_window, login_window->priv->start_session_handler_id);
-+                login_window->priv->start_session_handler_id = 0;
-+        }
++                        kill (pid, SIGKILL);
++                        flags = 0;
++                }
++                goto wait_again;
+         }
+ 
+         g_debug ("GdmCommon: process (pid:%d) done (%s:%d)",
+@@ -122,6 +158,12 @@ gdm_wait_on_pid (int pid)
  }
  
- static void
+ int
++gdm_wait_on_pid (int pid)
++{
++    return gdm_wait_on_and_kill_pid (pid, 0);
++}
++
++int
+ gdm_signal_pid (int pid,
+                 int signal)
+ {
+diff --git a/common/gdm-common.h b/common/gdm-common.h
+index 8faeda5..06300c8 100644
+--- a/common/gdm-common.h
++++ b/common/gdm-common.h
+@@ -34,6 +34,8 @@ gboolean       gdm_is_version_unstable            (void);
+ void           gdm_set_fatal_warnings_if_unstable (void);
+ 
+ int            gdm_wait_on_pid           (int pid);
++int            gdm_wait_on_and_kill_pid  (int pid,
++                                          int timeout);
+ int            gdm_signal_pid            (int pid,
+                                           int signal);
+ gboolean       gdm_get_pwent_for_name    (const char     *name,
+diff --git a/daemon/gdm-session-worker-job.c b/daemon/gdm-session-worker-job.c
+index be85f30..8b93663 100644
+--- a/daemon/gdm-session-worker-job.c
++++ b/daemon/gdm-session-worker-job.c
+@@ -296,7 +296,7 @@ session_worker_job_died (GdmSessionWorkerJob *session_worker_job)
+         int exit_status;
+ 
+         g_debug ("GdmSessionWorkerJob: Waiting on process %d", session_worker_job->priv->pid);
+-        exit_status = gdm_wait_on_pid (session_worker_job->priv->pid);
++        exit_status = gdm_wait_on_and_kill_pid (session_worker_job->priv->pid, 3);
+ 
+         if (WIFEXITED (exit_status) && (WEXITSTATUS (exit_status) != 0)) {
+                 g_debug ("GdmSessionWorkerJob: Wait on child process failed");
 -- 
-1.6.5.2
+1.7.2.1
 
 
-From eaede120f202f33631bfa65245fb181baf63947b Mon Sep 17 00:00:00 2001
+From ec1151e4c20d0cc61e7b0a0ccbcf82d589d93795 Mon Sep 17 00:00:00 2001
 From: Ray Strode <rstrode at redhat.com>
-Date: Wed, 28 Oct 2009 13:57:53 -0400
-Subject: [PATCH 30/45] Don't show unimportant images on plugin buttons
+Date: Fri, 23 Oct 2009 17:39:19 -0400
+Subject: [PATCH 27/35] Drop the other hiding stuff for now.
 
+It depends on buttons being available that we don't have
+in the multi-stack branch.
 ---
- gui/simple-greeter/gdm-greeter-login-window.c |    8 +++++++-
- 1 files changed, 7 insertions(+), 1 deletions(-)
+ gui/simple-greeter/gdm-user-chooser-widget.c |    8 +-------
+ 1 files changed, 1 insertions(+), 7 deletions(-)
 
-diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
-index 64ba6e8..4dc4aee 100644
---- a/gui/simple-greeter/gdm-greeter-login-window.c
-+++ b/gui/simple-greeter/gdm-greeter-login-window.c
-@@ -2059,8 +2059,14 @@ on_button_action_icon_name_changed (GtkWidget *button)
- 
-         action = gtk_widget_get_action (button);
+diff --git a/gui/simple-greeter/gdm-user-chooser-widget.c b/gui/simple-greeter/gdm-user-chooser-widget.c
+index 33708b9..f8cf845 100644
+--- a/gui/simple-greeter/gdm-user-chooser-widget.c
++++ b/gui/simple-greeter/gdm-user-chooser-widget.c
+@@ -150,13 +150,7 @@ update_other_user_visibility (GdmUserChooserWidget *widget)
+                 goto out;
+         }
  
--        image = gtk_action_create_icon (GTK_ACTION (action), GTK_ICON_SIZE_BUTTON);
-+        if (gtk_action_get_is_important (action)) {
-+                image = gtk_action_create_icon (GTK_ACTION (action), GTK_ICON_SIZE_BUTTON);
-+        } else {
-+                image = NULL;
-+        }
-+
-         gtk_button_set_image (GTK_BUTTON (button), image);
-+
- }
+-        number_of_users = gdm_chooser_widget_get_number_of_items (GDM_CHOOSER_WIDGET (widget));
+-
+-        /* we hide the Other user if it's the last one, and we show it
+-         * if there's another user */
+-        if (number_of_users == 1 && widget->priv->has_user_other) {
+-                remove_user_other (widget);
+-        } if (number_of_users >= 1 && !widget->priv->has_user_other) {
++        if (!widget->priv->has_user_other) {
+                 add_user_other (widget);
+         }
  
- static void
 -- 
-1.6.5.2
+1.7.2.1
 
 
-From e3ad31f7d7904108c4daf74f753e06ac72d8d2f4 Mon Sep 17 00:00:00 2001
+From 871f015fb50b7192ebf3497b3b2b4741275e2d90 Mon Sep 17 00:00:00 2001
 From: Ray Strode <rstrode at redhat.com>
-Date: Wed, 28 Oct 2009 14:10:35 -0400
-Subject: [PATCH 31/45] Add visibility concept to task iface
+Date: Tue, 13 Jul 2010 22:36:19 -0400
+Subject: [PATCH 28/35] add better debug spew (needs squash)
 
 ---
- gui/simple-greeter/libgdmsimplegreeter/gdm-task.c |    6 ++++++
- gui/simple-greeter/libgdmsimplegreeter/gdm-task.h |    2 ++
- 2 files changed, 8 insertions(+), 0 deletions(-)
+ daemon/gdm-session-direct.c |    8 ++++----
+ 1 files changed, 4 insertions(+), 4 deletions(-)
 
-diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-task.c b/gui/simple-greeter/libgdmsimplegreeter/gdm-task.c
-index 05fd75c..858b1ef 100644
---- a/gui/simple-greeter/libgdmsimplegreeter/gdm-task.c
-+++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-task.c
-@@ -94,6 +94,12 @@ gdm_task_is_choosable (GdmTask *task)
-         return GDM_TASK_GET_IFACE (task)->is_choosable (task);
- }
+diff --git a/daemon/gdm-session-direct.c b/daemon/gdm-session-direct.c
+index 41c7dc2..e4e4166 100644
+--- a/daemon/gdm-session-direct.c
++++ b/daemon/gdm-session-direct.c
+@@ -210,7 +210,7 @@ find_conversation_by_name (GdmSessionDirect *session,
+         conversation = g_hash_table_lookup (session->priv->conversations, service_name);
  
-+gboolean
-+gdm_task_is_visible (GdmTask *task)
-+{
-+        return GDM_TASK_GET_IFACE (task)->is_visible (task);
-+}
-+
- static void
- gdm_task_class_init (gpointer g_iface)
+         if (conversation == NULL) {
+-                g_warning ("Tried to look up non-existant conversation");
++                g_warning ("Tried to look up non-existent conversation %s", service_name);
+         }
+ 
+         return conversation;
+@@ -1800,7 +1800,7 @@ static void
+ free_conversation (GdmSessionConversation *conversation)
  {
-diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-task.h b/gui/simple-greeter/libgdmsimplegreeter/gdm-task.h
-index c75bf29..51e2b0a 100644
---- a/gui/simple-greeter/libgdmsimplegreeter/gdm-task.h
-+++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-task.h
-@@ -45,6 +45,7 @@ struct _GdmTaskIface
-         char *  (* get_description) (GdmTask   *task);
-         char *  (* get_name)        (GdmTask   *task);
-         gboolean  (* is_choosable)    (GdmTask   *task);
-+        gboolean  (* is_visible)    (GdmTask   *task);
-         /* signals */
-         void (* enabled) (GdmTask *task);
-         void (* disabled) (GdmTask *task);
-@@ -59,6 +60,7 @@ void   gdm_task_set_enabled     (GdmTask   *task,
-                                  gboolean   should_enable);
- gboolean   gdm_task_is_enabled     (GdmTask   *task);
- gboolean   gdm_task_is_choosable   (GdmTask   *task);
-+gboolean   gdm_task_is_visible   (GdmTask   *task);
- G_END_DECLS
+         if (conversation->job != NULL) {
+-                g_warning ("Freeing conversation with active job");
++                g_warning ("Freeing conversation '%s' with active job", conversation->service_name);
+         }
+ 
+         g_free (conversation->service_name);
+@@ -1973,7 +1973,7 @@ gdm_session_direct_start_conversation (GdmSession *session,
+ 
+         g_return_if_fail (session != NULL);
+ 
+-        g_debug ("GdmSessionDirect: starting conversation");
++        g_debug ("GdmSessionDirect: starting conversation %s", service_name);
+ 
+         conversation = start_conversation (impl, service_name);
+ 
+@@ -1990,7 +1990,7 @@ gdm_session_direct_stop_conversation (GdmSession *session,
+ 
+         g_return_if_fail (session != NULL);
+ 
+-        g_debug ("GdmSessionDirect: stopping conversation");
++        g_debug ("GdmSessionDirect: stopping conversation %s", service_name);
+ 
+         conversation = find_conversation_by_name (impl, service_name);
  
- #endif /* __GDM_TASK_H */
 -- 
-1.6.5.2
+1.7.2.1
 
 
-From 0d607bd26ca93ae72f86c743e92b72f0a3b2d20f Mon Sep 17 00:00:00 2001
+From f59d1a42aa6d874d9342915c0f1632dbcf905c11 Mon Sep 17 00:00:00 2001
 From: Ray Strode <rstrode at redhat.com>
-Date: Wed, 28 Oct 2009 14:10:50 -0400
-Subject: [PATCH 32/45] adapt fingerprint to task iface
+Date: Tue, 13 Jul 2010 22:37:35 -0400
+Subject: [PATCH 29/35] switch to proper mode when going to timed login
 
 ---
- .../fingerprint/gdm-fingerprint-extension.c        |    7 +++++++
- 1 files changed, 7 insertions(+), 0 deletions(-)
+ gui/simple-greeter/gdm-greeter-login-window.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
 
-diff --git a/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c b/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c
-index 316ef46..e1fc0ed 100644
---- a/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c
-+++ b/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c
-@@ -194,6 +194,12 @@ gdm_fingerprint_extension_is_choosable (GdmTask *task)
-         return FALSE;
- }
+diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
+index d0c0781..217aac8 100644
+--- a/gui/simple-greeter/gdm-greeter-login-window.c
++++ b/gui/simple-greeter/gdm-greeter-login-window.c
+@@ -1384,7 +1384,7 @@ begin_auto_login (GdmGreeterLoginWindow *login_window)
+         /* just wait for the user to select language and stuff */
+         set_message (login_window, _("Select language and click Log In"));
  
-+gboolean
-+gdm_fingerprint_extension_is_visible (GdmTask *task)
-+{
-+        return TRUE;
-+}
-+
- static void
- gdm_task_iface_init (GdmTaskIface *iface)
- {
-@@ -201,6 +207,7 @@ gdm_task_iface_init (GdmTaskIface *iface)
-         iface->get_description = gdm_fingerprint_extension_get_description;
-         iface->get_name = gdm_fingerprint_extension_get_name;
-         iface->is_choosable = gdm_fingerprint_extension_is_choosable;
-+        iface->is_visible = gdm_fingerprint_extension_is_visible;
- }
+-        switch_mode (login_window, MODE_AUTHENTICATION);
++        switch_mode (login_window, MODE_TIMED_LOGIN);
  
- static void
+         show_widget (login_window, "conversation-list", FALSE);
+         gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
 -- 
-1.6.5.2
+1.7.2.1
 
 
-From 8e609a783bf231736d76ee07c7f31a253efeb030 Mon Sep 17 00:00:00 2001
+From 62d2a6eb5ff91892ad3b57b861fd4bcd274027b7 Mon Sep 17 00:00:00 2001
 From: Ray Strode <rstrode at redhat.com>
-Date: Wed, 28 Oct 2009 14:11:05 -0400
-Subject: [PATCH 33/45] adapt smartcard plugin to task iface
+Date: Tue, 3 Aug 2010 15:21:26 -0400
+Subject: [PATCH 30/35] Drop "Cancelling" message for plugin initiated cancels
 
+The plugin may be cancelling the mesage for a number of
+reasons.  We could potentially let it specify the message,
+but for now just drop the message.
 ---
- .../plugins/smartcard/gdm-smartcard-extension.c    |    7 +++++++
- 1 files changed, 7 insertions(+), 0 deletions(-)
+ gui/simple-greeter/gdm-greeter-login-window.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
 
-diff --git a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c
-index 274132e..9967d5f 100644
---- a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c
-+++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c
-@@ -309,6 +309,12 @@ gdm_smartcard_extension_is_choosable (GdmTask *task)
-         return TRUE;
- }
- 
-+gboolean
-+gdm_smartcard_extension_is_visible (GdmTask *task)
-+{
-+        return TRUE;
-+}
-+
- static void
- gdm_task_iface_init (GdmTaskIface *iface)
+diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
+index 217aac8..13798ff 100644
+--- a/gui/simple-greeter/gdm-greeter-login-window.c
++++ b/gui/simple-greeter/gdm-greeter-login-window.c
+@@ -2138,7 +2138,7 @@ static void
+ on_conversation_cancel (GdmGreeterLoginWindow *login_window,
+                         GdmConversation       *conversation)
  {
-@@ -316,6 +322,7 @@ gdm_task_iface_init (GdmTaskIface *iface)
-         iface->get_description = gdm_smartcard_extension_get_description;
-         iface->get_name = gdm_smartcard_extension_get_name;
-         iface->is_choosable = gdm_smartcard_extension_is_choosable;
-+        iface->is_visible = gdm_smartcard_extension_is_visible;
+-        do_cancel (login_window);
++        restart_conversations (login_window);
  }
  
- static void
+ static gboolean
 -- 
-1.6.5.2
+1.7.2.1
 
 
-From 122d3d05610a17e076788ffa865c131422b02d92 Mon Sep 17 00:00:00 2001
+From aedf0cf1393a47694691432b4c328ff242afd3a1 Mon Sep 17 00:00:00 2001
 From: Ray Strode <rstrode at redhat.com>
-Date: Wed, 28 Oct 2009 14:10:50 -0400
-Subject: [PATCH 34/45] adapt password to task iface
+Date: Wed, 4 Aug 2010 18:11:27 -0400
+Subject: [PATCH 31/35] drop code for label that doesn't exist anymore
 
 ---
- .../plugins/password/gdm-password-extension.c      |    7 +++++++
- 1 files changed, 7 insertions(+), 0 deletions(-)
+ gui/simple-greeter/gdm-greeter-login-window.c |    6 ------
+ 1 files changed, 0 insertions(+), 6 deletions(-)
 
-diff --git a/gui/simple-greeter/plugins/password/gdm-password-extension.c b/gui/simple-greeter/plugins/password/gdm-password-extension.c
-index 4922c65..255283e 100644
---- a/gui/simple-greeter/plugins/password/gdm-password-extension.c
-+++ b/gui/simple-greeter/plugins/password/gdm-password-extension.c
-@@ -194,6 +194,12 @@ gdm_password_extension_is_choosable (GdmTask *task)
-         return FALSE;
- }
- 
-+gboolean
-+gdm_password_extension_is_visible (GdmTask *task)
-+{
-+        return TRUE;
-+}
-+
- static void
- gdm_task_iface_init (GdmTaskIface *iface)
+diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
+index 13798ff..536d4bb 100644
+--- a/gui/simple-greeter/gdm-greeter-login-window.c
++++ b/gui/simple-greeter/gdm-greeter-login-window.c
+@@ -776,9 +776,6 @@ static void
+ reset_dialog (GdmGreeterLoginWindow *login_window,
+               guint                  dialog_mode)
  {
-@@ -201,6 +207,7 @@ gdm_task_iface_init (GdmTaskIface *iface)
-         iface->get_description = gdm_password_extension_get_description;
-         iface->get_name = gdm_password_extension_get_name;
-         iface->is_choosable = gdm_password_extension_is_choosable;
-+        iface->is_visible = gdm_password_extension_is_visible;
- }
+-        GtkWidget  *label;
+-        guint       mode;
+-
+         g_debug ("GdmGreeterLoginWindow: Resetting dialog to mode %u", dialog_mode);
+         set_busy (login_window);
+         set_sensitive (login_window, FALSE);
+@@ -813,9 +810,6 @@ reset_dialog (GdmGreeterLoginWindow *login_window,
+                                     reset_task,
+                                     login_window);
  
- static void
+-        label = GTK_WIDGET (gtk_builder_get_object (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->builder, "auth-prompt-label"));
+-        gtk_label_set_text (GTK_LABEL (label), "");
+-
+         if (can_jump_to_authenticate (login_window)) {
+                 /* If we don't have a user list jump straight to authenticate */
+                 g_debug ("GdmGreeterLoginWindow: jumping straight to authenticate");
 -- 
-1.6.5.2
+1.7.2.1
 
 
-From 32c4cb5a2eb033a179e5c2970edac0ac20e5de6a Mon Sep 17 00:00:00 2001
+From 388e0d6b74765907c9bc348269dfb9ee4b7a2105 Mon Sep 17 00:00:00 2001
 From: Ray Strode <rstrode at redhat.com>
-Date: Wed, 28 Oct 2009 16:05:14 -0400
-Subject: [PATCH 35/45] Return a different error code for "service won't work" than "auth failed"
+Date: Wed, 4 Aug 2010 18:03:52 -0400
+Subject: [PATCH 32/35] Add delay when showing messages (needs split)
 
-If we bubble it up to the greeter then we should be able to have
-a more sensible UI when e.g. fingerprinting isn't enabled.
+Previously, there were times when the user would be unable
+to read messages, because they would blink by so fast.
+
+This jumble of assorted changes (which needs to be split up)
+adds some queueing and timeouts to make sure the messages stay on
+screen for a sufficient amount of time.
 ---
- daemon/gdm-session-worker.c |   12 ++++++++++--
- daemon/gdm-session-worker.h |    1 +
- 2 files changed, 11 insertions(+), 2 deletions(-)
+ gui/simple-greeter/gdm-greeter-login-window.c      |  119 ++++++++++++++++++--
+ .../libgdmsimplegreeter/gdm-conversation.c         |   18 +++
+ .../libgdmsimplegreeter/gdm-conversation.h         |    2 +
+ .../fingerprint/gdm-fingerprint-extension.c        |   20 ++++
+ .../plugins/password/gdm-password-extension.c      |   20 ++++
+ .../plugins/smartcard/gdm-smartcard-extension.c    |   19 +++
+ 6 files changed, 188 insertions(+), 10 deletions(-)
 
-diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c
-index 8328910..adc8dcf 100644
---- a/daemon/gdm-session-worker.c
-+++ b/daemon/gdm-session-worker.c
-@@ -1294,7 +1294,7 @@ gdm_session_worker_initialize_pam (GdmSessionWorker *worker,
-                  */
-                 g_set_error (error,
-                              GDM_SESSION_WORKER_ERROR,
--                             GDM_SESSION_WORKER_ERROR_AUTHENTICATING,
-+                             GDM_SESSION_WORKER_ERROR_SERVICE_UNAVAILABLE,
-                              _("error initiating conversation with authentication system - %s"),
-                              error_code == PAM_ABORT? _("general failure") :
-                              error_code == PAM_BUF_ERR? _("out of memory") :
-@@ -1406,7 +1406,15 @@ gdm_session_worker_authenticate_user (GdmSessionWorker *worker,
-         /* blocking call, does the actual conversation */
-         error_code = pam_authenticate (worker->priv->pam_handle, authentication_flags);
+diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
+index 536d4bb..2d7c400 100644
+--- a/gui/simple-greeter/gdm-greeter-login-window.c
++++ b/gui/simple-greeter/gdm-greeter-login-window.c
+@@ -137,6 +137,9 @@ struct GdmGreeterLoginWindowPrivate
  
--        if (error_code != PAM_SUCCESS) {
-+        if (error_code == PAM_AUTHINFO_UNAVAIL) {
-+                g_debug ("GdmSessionWorker: authentication service unavailable");
+         guint            login_button_handler_id;
+         guint            start_session_handler_id;
 +
-+                g_set_error (error,
-+                             GDM_SESSION_WORKER_ERROR,
-+                             GDM_SESSION_WORKER_ERROR_SERVICE_UNAVAILABLE,
-+                             "%s", pam_strerror (worker->priv->pam_handle, error_code));
-+                goto out;
-+        } else if (error_code != PAM_SUCCESS) {
-                 g_debug ("GdmSessionWorker: authentication returned %d: %s", error_code, pam_strerror (worker->priv->pam_handle, error_code));
++        char            *service_name_of_session_ready_to_start;
++
+ };
  
-                 /*
-diff --git a/daemon/gdm-session-worker.h b/daemon/gdm-session-worker.h
-index ee5465a..b1c8285 100644
---- a/daemon/gdm-session-worker.h
-+++ b/daemon/gdm-session-worker.h
-@@ -41,6 +41,7 @@ typedef enum _GdmSessionWorkerError {
-         GDM_SESSION_WORKER_ERROR_OPENING_MESSAGE_PIPE,
-         GDM_SESSION_WORKER_ERROR_COMMUNICATING,
-         GDM_SESSION_WORKER_ERROR_WORKER_DIED,
-+        GDM_SESSION_WORKER_ERROR_SERVICE_UNAVAILABLE,
-         GDM_SESSION_WORKER_ERROR_AUTHENTICATING,
-         GDM_SESSION_WORKER_ERROR_AUTHORIZING,
-         GDM_SESSION_WORKER_ERROR_OPENING_LOG_FILE,
--- 
-1.6.5.2
-
-
-From 0ca589b40a9e0671471d5207558849f6572a5e63 Mon Sep 17 00:00:00 2001
-From: Ray Strode <rstrode at redhat.com>
-Date: Wed, 28 Oct 2009 21:32:00 -0400
-Subject: [PATCH 36/45] Emit "service-unavailable" from session when pam service refuses to work
-
----
- daemon/gdm-session-direct.c  |   26 +++++++++++++++++++++++---
- daemon/gdm-session-private.h |    2 ++
- daemon/gdm-session-relay.c   |   33 +++++++++++++++++++++++++++++++++
- daemon/gdm-session-worker.c  |   29 ++++++++++++++++++++++-------
- daemon/gdm-session.c         |   21 +++++++++++++++++++++
- daemon/gdm-session.h         |    2 ++
- 6 files changed, 103 insertions(+), 10 deletions(-)
-
-diff --git a/daemon/gdm-session-direct.c b/daemon/gdm-session-direct.c
-index 5d7dabc..0d283cd 100644
---- a/daemon/gdm-session-direct.c
-+++ b/daemon/gdm-session-direct.c
-@@ -280,9 +280,27 @@ on_session_exited (GdmSession *session,
+ enum {
+@@ -173,6 +176,8 @@ static void     switch_mode                 (GdmGreeterLoginWindow *login_window
+ static void     update_banner_message       (GdmGreeterLoginWindow *login_window);
+ static void     gdm_greeter_login_window_start_session_when_ready (GdmGreeterLoginWindow *login_window,
+                                                                    const char            *service_name);
++static void handle_stopped_conversation (GdmGreeterLoginWindow *login_window,
++                                         const char            *service_name);
+ 
+ G_DEFINE_TYPE (GdmGreeterLoginWindow, gdm_greeter_login_window, GTK_TYPE_WINDOW)
+ 
+@@ -231,6 +236,7 @@ set_task_conversation_message (GdmTaskList *task_list,
+ {
+ 
+         gdm_conversation_set_message (GDM_CONVERSATION (task), message);
++        g_object_set_data (G_OBJECT (task), "message-pending", GINT_TO_POINTER (TRUE));
+         return FALSE;
+ }
+ 
+@@ -882,16 +888,12 @@ gdm_greeter_login_window_ready (GdmGreeterLoginWindow *login_window,
+         return TRUE;
+ }
+ 
+-gboolean
+-gdm_greeter_login_window_conversation_stopped (GdmGreeterLoginWindow *login_window,
+-                                               const char            *service_name)
++static void
++handle_stopped_conversation (GdmGreeterLoginWindow *login_window,
++                             const char            *service_name)
+ {
+         GdmTask *task;
+ 
+-        g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
+-
+-        g_debug ("GdmGreeterLoginWindow: conversation '%s' has stopped", service_name);
+-
+         /* If the password conversation failed, then start over
+          *
+          * FIXME: we need to get this policy out of the source code
+@@ -899,13 +901,15 @@ gdm_greeter_login_window_conversation_stopped (GdmGreeterLoginWindow *login_wind
+         if (strcmp (service_name, "gdm-password") == 0) {
+                 g_debug ("GdmGreeterLoginWindow: main conversation failed, starting over");
+                 restart_conversations (login_window);
+-                return TRUE;
++                return;
+         }
+ 
+         task = find_task_with_service_name (login_window, service_name);
+ 
+         if (task != NULL) {
+                 gdm_conversation_reset (GDM_CONVERSATION (task));
++
++                g_object_set_data (G_OBJECT (task), "needs-to-be-stopped", GINT_TO_POINTER (FALSE));
+                 g_object_unref (task);
+         }
+ 
+@@ -920,6 +924,34 @@ gdm_greeter_login_window_conversation_stopped (GdmGreeterLoginWindow *login_wind
+         g_object_unref (task);
+ 
+         update_conversation_list_visibility (login_window);
++}
++
++gboolean
++gdm_greeter_login_window_conversation_stopped (GdmGreeterLoginWindow *login_window,
++                                               const char            *service_name)
++{
++        GdmTask *task;
++        gboolean messages_pending;
++
++        g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
++
++        g_debug ("GdmGreeterLoginWindow: conversation '%s' has stopped", service_name);
++
++        task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
++        if (task != NULL && task_has_service_name (GDM_TASK_LIST (login_window->priv->conversation_list), task, service_name)) {
++
++                messages_pending = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (task), "message-pending"));
++        } else {
++                messages_pending = FALSE;
++        }
++
++        if (!messages_pending) {
++                handle_stopped_conversation (login_window, service_name);
++        } else {
++                g_assert (task != NULL);
++
++                g_object_set_data (G_OBJECT (task), "needs-to-be-stopped", GINT_TO_POINTER (TRUE));
++        }
+ 
+         return TRUE;
  }
+@@ -931,6 +963,7 @@ restart_task_conversation (GdmTaskList           *task_list,
+ {
+         char *service_name;
  
- static DBusHandlerResult
--gdm_session_direct_handle_setup_complete (GdmSessionDirect *session,
--                                          GdmSessionConversation *conversation,
--                                          DBusMessage      *message)
-+gdm_session_direct_handle_service_unavailable (GdmSessionDirect *session,
-+                                               GdmSessionConversation *conversation,
-+                                               DBusMessage      *message)
++        g_object_set_data (G_OBJECT (task), "needs-to-be-stopped", GINT_TO_POINTER (FALSE));
+         service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (task));
+         if (service_name != NULL) {
+                 char *name;
+@@ -959,6 +992,9 @@ gdm_greeter_login_window_reset (GdmGreeterLoginWindow *login_window)
+                                     restart_task_conversation,
+                                     login_window);
+ 
++        g_free (login_window->priv->service_name_of_session_ready_to_start);
++        login_window->priv->service_name_of_session_ready_to_start = NULL;
++
+         return TRUE;
+ }
+ 
+@@ -976,6 +1012,7 @@ gdm_greeter_login_window_info (GdmGreeterLoginWindow *login_window,
+         task = find_task_with_service_name (login_window, service_name);
+ 
+         if (task != NULL) {
++                g_object_set_data (G_OBJECT (task), "message-pending", GINT_TO_POINTER (TRUE));
+                 gdm_conversation_set_message (GDM_CONVERSATION (task),
+                                               text);
+                 show_task_actions (task);
+@@ -999,6 +1036,7 @@ gdm_greeter_login_window_problem (GdmGreeterLoginWindow *login_window,
+         task = find_task_with_service_name (login_window, service_name);
+ 
+         if (task != NULL) {
++                g_object_set_data (G_OBJECT (task), "message-pending", GINT_TO_POINTER (TRUE));
+                 gdm_conversation_set_message (GDM_CONVERSATION (task),
+                                               text);
+                 show_task_actions (task);
+@@ -1094,12 +1132,40 @@ on_ready_to_start_session (GdmGreeterLoginWindow *login_window,
+ }
+ 
+ static void
++gdm_greeter_login_window_start_session (GdmGreeterLoginWindow *login_window)
 +{
-+        DBusMessage *reply;
++        g_debug ("GdmGreeterLoginWindow: starting session");
++        g_signal_emit (login_window,
++                       signals[START_SESSION],
++                       0,
++                       login_window->priv->service_name_of_session_ready_to_start);
++        g_free (login_window->priv->service_name_of_session_ready_to_start);
++        login_window->priv->service_name_of_session_ready_to_start = NULL;
++}
 +
-+        g_debug ("GdmSessionDirect: Emitting 'service-unavailable' signal");
++static void
+ gdm_greeter_login_window_start_session_when_ready (GdmGreeterLoginWindow *login_window,
+                                                    const char            *service_name)
+ {
+         if (login_window->priv->is_interactive) {
+-                g_debug ("GdmGreeterLoginWindow: starting session");
+-                g_signal_emit (login_window, signals[START_SESSION], 0, service_name);
++                gboolean messages_pending;
++                GdmTask *task;
 +
-+        reply = dbus_message_new_method_return (message);
-+        dbus_connection_send (conversation->worker_connection, reply, NULL);
-+        dbus_message_unref (reply);
++                set_sensitive (GDM_GREETER_LOGIN_WINDOW (login_window), FALSE);
 +
-+        _gdm_session_service_unavailable (GDM_SESSION (session), conversation->service_name);
++                task = find_task_with_service_name (login_window, service_name);
 +
-+        return DBUS_HANDLER_RESULT_HANDLED;
-+}
++                if (task != NULL) {
++                        messages_pending = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (task), "message-pending"));
 +
-+static DBusHandlerResult
-+gdm_session_direct_handle_setup_complete  (GdmSessionDirect *session,
-+                                           GdmSessionConversation *conversation,
-+                                           DBusMessage      *message)
- {
-         DBusMessage *reply;
- 
-@@ -1275,6 +1293,8 @@ session_worker_message (DBusConnection *connection,
-                 return gdm_session_direct_handle_problem (session, conversation, message);
-         } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "CancelPendingQuery")) {
-                 return gdm_session_direct_handle_cancel_pending_query (session, conversation, message);
-+        } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "ServiceUnavailable")) {
-+                return gdm_session_direct_handle_service_unavailable (session, conversation, message);
-         } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SetupComplete")) {
-                 return gdm_session_direct_handle_setup_complete (session, conversation, message);
-         } else if (dbus_message_is_method_call (message, GDM_SESSION_DBUS_INTERFACE, "SetupFailed")) {
-diff --git a/daemon/gdm-session-private.h b/daemon/gdm-session-private.h
-index 36781dd..e0a810e 100644
---- a/daemon/gdm-session-private.h
-+++ b/daemon/gdm-session-private.h
-@@ -31,6 +31,8 @@ void             _gdm_session_conversation_started         (GdmSession   *sessio
-                                                             const char   *service_name);
- void             _gdm_session_conversation_stopped         (GdmSession   *session,
-                                                             const char   *service_name);
-+void             _gdm_session_service_unavailable          (GdmSession   *session,
-+                                                            const char   *service_name);
- void             _gdm_session_setup_complete               (GdmSession   *session,
-                                                             const char   *service_name);
- void             _gdm_session_setup_failed                 (GdmSession   *session,
-diff --git a/daemon/gdm-session-relay.c b/daemon/gdm-session-relay.c
-index 98ccc51..88aee14 100644
---- a/daemon/gdm-session-relay.c
-+++ b/daemon/gdm-session-relay.c
-@@ -463,6 +463,34 @@ handle_problem (GdmSessionRelay *session_relay,
++                } else {
++                        messages_pending = FALSE;
++                }
++
++                login_window->priv->service_name_of_session_ready_to_start = g_strdup (service_name);
++                if (!messages_pending) {
++                        gdm_greeter_login_window_start_session (login_window);
++                }
+         } else {
+                 g_debug ("GdmGreeterLoginWindow: not starting session since "
+                          "user hasn't had an opportunity to pick language "
+@@ -2164,6 +2230,35 @@ on_conversation_chose_user (GdmGreeterLoginWindow *login_window,
+         return TRUE;
  }
  
- static DBusHandlerResult
-+handle_service_unavailable (GdmSessionRelay *session_relay,
-+                            DBusConnection  *connection,
-+                            DBusMessage     *message)
++static void
++on_conversation_message_set (GdmGreeterLoginWindow *login_window,
++                             GdmConversation       *conversation)
 +{
-+        DBusMessage *reply;
-+        DBusError    error;
-+        char        *service_name;
++        gboolean needs_to_be_stopped;
 +
-+        dbus_error_init (&error);
-+        if (! dbus_message_get_args (message, &error,
-+                                     DBUS_TYPE_STRING, &service_name,
-+                                     DBUS_TYPE_INVALID)) {
-+                g_warning ("ERROR: %s", error.message);
-+        }
-+        dbus_error_free (&error);
++        g_object_set_data (G_OBJECT (conversation), "message-pending", GINT_TO_POINTER (FALSE));
 +
-+        g_debug ("GdmSessionRelay: ServiceUnavailable");
++        needs_to_be_stopped = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (conversation), "needs-to-be-stopped"));
 +
-+        reply = dbus_message_new_method_return (message);
-+        dbus_connection_send (connection, reply, NULL);
-+        dbus_message_unref (reply);
++        if (needs_to_be_stopped) {
++                char *service_name;
 +
-+        _gdm_session_service_unavailable (GDM_SESSION (session_relay), service_name);
++                service_name = gdm_conversation_get_service_name (conversation);
++                handle_stopped_conversation (login_window, service_name);
++                g_free (service_name);
++        }
 +
-+        return DBUS_HANDLER_RESULT_HANDLED;
-+}
++        if (login_window->priv->service_name_of_session_ready_to_start != NULL ) {
++                GdmTask *task;
 +
-+static DBusHandlerResult
- handle_setup_complete (GdmSessionRelay *session_relay,
-                        DBusConnection  *connection,
-                        DBusMessage     *message)
-@@ -841,6 +869,8 @@ session_handle_child_message (DBusConnection *connection,
-                 return handle_info (session_relay, connection, message);
-         } else if (dbus_message_is_method_call (message, GDM_SESSION_RELAY_DBUS_INTERFACE, "Problem")) {
-                 return handle_problem (session_relay, connection, message);
-+        } else if (dbus_message_is_method_call (message, GDM_SESSION_RELAY_DBUS_INTERFACE, "ServiceUnavailable")) {
-+                return handle_service_unavailable (session_relay, connection, message);
-         } else if (dbus_message_is_method_call (message, GDM_SESSION_RELAY_DBUS_INTERFACE, "SetupComplete")) {
-                 return handle_setup_complete (session_relay, connection, message);
-         } else if (dbus_message_is_method_call (message, GDM_SESSION_RELAY_DBUS_INTERFACE, "SetupFailed")) {
-@@ -898,6 +928,9 @@ do_introspect (DBusConnection *connection,
-                                "    <method name=\"ConversationStarted\">\n"
-                                "      <arg name=\"service_name\" direction=\"in\" type=\"s\"/>\n"
-                                "    </method>\n"
-+                               "    <method name=\"ServiceUnavailable\">\n"
-+                               "      <arg name=\"message\" direction=\"in\" type=\"s\"/>\n"
-+                               "    </method>\n"
-                                "    <method name=\"SetupComplete\">\n"
-                                "    </method>\n"
-                                "    <method name=\"SetupFailed\">\n"
-diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c
-index adc8dcf..4b77249 100644
---- a/daemon/gdm-session-worker.c
-+++ b/daemon/gdm-session-worker.c
-@@ -2364,9 +2364,16 @@ do_setup (GdmSessionWorker *worker)
-                                                  worker->priv->display_device,
-                                                  &error);
-         if (! res) {
--                send_dbus_string_method (worker->priv->connection,
--                                         "SetupFailed",
--                                         error->message);
-+                if (g_error_matches (error,
-+                                     GDM_SESSION_WORKER_ERROR,
-+                                     GDM_SESSION_WORKER_ERROR_SERVICE_UNAVAILABLE)) {
-+                        send_dbus_void_method (worker->priv->connection,
-+                                               "ServiceUnavailable");
-+                } else {
-+                        send_dbus_string_method (worker->priv->connection,
-+                                                 "SetupFailed",
-+                                                 error->message);
-+                }
-                 g_error_free (error);
-                 return;
-         }
-@@ -2387,10 +2394,18 @@ do_authenticate (GdmSessionWorker *worker)
-                                                     worker->priv->password_is_required,
-                                                     &error);
-         if (! res) {
--                g_debug ("GdmSessionWorker: Unable to verify user");
--                send_dbus_string_method (worker->priv->connection,
--                                         "AuthenticationFailed",
--                                         error->message);
-+                if (g_error_matches (error,
-+                                     GDM_SESSION_WORKER_ERROR,
-+                                     GDM_SESSION_WORKER_ERROR_SERVICE_UNAVAILABLE)) {
-+                        g_debug ("GdmSessionWorker: Unable to use authentication service");
-+                        send_dbus_void_method (worker->priv->connection,
-+                                               "ServiceUnavailable");
-+                } else {
-+                        g_debug ("GdmSessionWorker: Unable to verify user");
-+                        send_dbus_string_method (worker->priv->connection,
-+                                                 "AuthenticationFailed",
-+                                                 error->message);
++                task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
++
++                if (task == GDM_TASK (conversation)) {
++                        gdm_greeter_login_window_start_session (login_window);
 +                }
-                 g_error_free (error);
-                 return;
-         }
-diff --git a/daemon/gdm-session.c b/daemon/gdm-session.c
-index 8858071..8c4548a 100644
---- a/daemon/gdm-session.c
-+++ b/daemon/gdm-session.c
-@@ -31,6 +31,7 @@
- enum {
-         CONVERSATION_STARTED = 0,
-         CONVERSATION_STOPPED,
-+        SERVICE_UNAVAILABLE,
-         SETUP_COMPLETE,
-         SETUP_FAILED,
-         RESET_COMPLETE,
-@@ -251,6 +252,17 @@ gdm_session_class_init (gpointer g_iface)
-                               g_cclosure_marshal_VOID__STRING,
-                               G_TYPE_NONE,
-                               1, G_TYPE_STRING);
-+        signals [SERVICE_UNAVAILABLE] =
-+                g_signal_new ("service-unavailable",
++        }
++}
++
+ void
+ gdm_greeter_login_window_remove_extension (GdmGreeterLoginWindow *login_window,
+  GdmGreeterExtension *extension)
+@@ -2326,6 +2421,10 @@ gdm_greeter_login_window_add_extension (GdmGreeterLoginWindow *login_window,
+                                   "user-chosen",
+                                   G_CALLBACK (on_conversation_chose_user),
+                                   login_window);
++        g_signal_connect_swapped (GDM_CONVERSATION (extension),
++                                  "message-set",
++                                  G_CALLBACK (on_conversation_message_set),
++                                  login_window);
+ 
+         g_debug ("GdmGreeterLoginWindow: new extension '%s - %s' added",
+                 name, description);
+diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c
+index ee763ef..1320d9c 100644
+--- a/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c
++++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c
+@@ -32,6 +32,7 @@ enum {
+         ANSWER,
+         USER_CHOSEN,
+         CANCEL,
++        MESSAGE_SET,
+         LAST_SIGNAL
+ };
+ 
+@@ -92,6 +93,16 @@ gdm_conversation_class_init (gpointer g_iface)
+                               NULL,
+                               g_cclosure_marshal_VOID__VOID,
+                               G_TYPE_NONE, 0);
++
++        signals [MESSAGE_SET] =
++                g_signal_new ("message-set",
 +                              iface_type,
 +                              G_SIGNAL_RUN_FIRST,
-+                              G_STRUCT_OFFSET (GdmSessionIface, service_unavailable),
++                              G_STRUCT_OFFSET (GdmConversationIface, message_set),
 +                              NULL,
 +                              NULL,
-+                              g_cclosure_marshal_VOID__STRING,
-+                              G_TYPE_NONE,
-+                              1,
-+                              G_TYPE_STRING);
-         signals [SETUP_COMPLETE] =
-                 g_signal_new ("setup-complete",
-                               iface_type,
-@@ -525,6 +537,15 @@ gdm_session_class_init (gpointer g_iface)
++                              g_cclosure_marshal_VOID__VOID,
++                              G_TYPE_NONE, 0);
+ }
+ 
+ void
+@@ -184,3 +195,10 @@ gdm_conversation_choose_user (GdmConversation *conversation,
+ 
+         return was_chosen;
  }
++
++void
++gdm_conversation_message_set (GdmConversation *conversation)
++{
++        g_signal_emit (conversation, signals [MESSAGE_SET], 0);
++}
++
+diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h
+index b37b21e..f76b18c 100644
+--- a/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h
++++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h
+@@ -62,6 +62,7 @@ struct _GdmConversationIface
+         char * (* answer)       (GdmConversation *conversation);
+         void   (* cancel)       (GdmConversation *conversation);
+         gboolean  (* user_chosen)  (GdmConversation *conversation);
++        void   (* message_set)  (GdmConversation *conversation);
+ };
+ 
+ GType  gdm_conversation_get_type     (void) G_GNUC_CONST;
+@@ -87,6 +88,7 @@ void   gdm_conversation_answer (GdmConversation   *conversation,
+ void   gdm_conversation_cancel (GdmConversation   *conversation);
+ gboolean  gdm_conversation_choose_user (GdmConversation   *conversation,
+                                         const char        *username);
++void gdm_conversation_message_set (GdmConversation *conversation);
+ 
+ G_END_DECLS
+ 
+diff --git a/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c b/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c
+index 55f5d32..2f7e968 100644
+--- a/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c
++++ b/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c
+@@ -41,6 +41,8 @@ struct _GdmFingerprintExtensionPrivate
+         GtkWidget *prompt_entry;
+ 
+         guint      answer_pending : 1;
++
++        guint      message_timeout_id;
+ };
+ 
+ static void gdm_fingerprint_extension_finalize (GObject *object);
+@@ -59,6 +61,17 @@ G_DEFINE_TYPE_WITH_CODE (GdmFingerprintExtension,
+                          G_IMPLEMENT_INTERFACE (GDM_TYPE_CONVERSATION,
+                                                 gdm_conversation_iface_init));
  
- void
-+_gdm_session_service_unavailable (GdmSession   *session,
-+                                  const char   *service_name)
++static gboolean
++on_message_expired (GdmConversation *conversation)
 +{
-+        g_return_if_fail (GDM_IS_SESSION (session));
++        GdmFingerprintExtension *extension = GDM_FINGERPRINT_EXTENSION (conversation);
++        extension->priv->message_timeout_id = 0;
 +
-+        g_signal_emit (session, signals [SERVICE_UNAVAILABLE], 0, service_name);
++        gdm_conversation_message_set (conversation);
++
++        return FALSE;
 +}
 +
-+void
- _gdm_session_setup_complete (GdmSession   *session,
-                              const char   *service_name)
+ static void
+ gdm_fingerprint_extension_set_message (GdmConversation *conversation,
+                                        const char *message)
+@@ -66,6 +79,11 @@ gdm_fingerprint_extension_set_message (GdmConversation *conversation,
+         GdmFingerprintExtension *extension = GDM_FINGERPRINT_EXTENSION (conversation);
+         gtk_widget_show (extension->priv->message_label);
+         gtk_label_set_text (GTK_LABEL (extension->priv->message_label), message);
++
++        if (extension->priv->message_timeout_id  != 0) {
++                g_source_remove (extension->priv->message_timeout_id);
++        }
++        extension->priv->message_timeout_id = g_timeout_add_seconds (2, (GSourceFunc) on_message_expired, conversation);
+ }
+ 
+ static void
+@@ -282,6 +300,8 @@ gdm_fingerprint_extension_class_init (GdmFingerprintExtensionClass *extension_cl
+ static void
+ gdm_fingerprint_extension_finalize (GObject *object)
  {
-diff --git a/daemon/gdm-session.h b/daemon/gdm-session.h
-index 22c2ccb..9636b92 100644
---- a/daemon/gdm-session.h
-+++ b/daemon/gdm-session.h
-@@ -49,6 +49,8 @@ struct _GdmSessionIface
-                                               const char   *service_name);
-         void (* stop_conversation)           (GdmSession   *session,
-                                               const char   *service_name);
-+        void (* service_unavailable)         (GdmSession   *session,
-+                                              const char   *service_name);
-         void (* setup)                       (GdmSession   *session,
-                                               const char   *service_name);
-         void (* setup_for_user)              (GdmSession   *session,
--- 
-1.6.5.2
-
-
-From 3ce57b17d7b4306825ae0a8aa9f0c0ea2601f33e Mon Sep 17 00:00:00 2001
-From: Ray Strode <rstrode at redhat.com>
-Date: Wed, 28 Oct 2009 21:38:52 -0400
-Subject: [PATCH 37/45] Bubble service-unavailable up to greeter
-
----
- daemon/gdm-greeter-server.c |    8 ++++++++
- daemon/gdm-greeter-server.h |    2 ++
- daemon/gdm-simple-slave.c   |   17 +++++++++++++++++
- 3 files changed, 27 insertions(+), 0 deletions(-)
-
-diff --git a/daemon/gdm-greeter-server.c b/daemon/gdm-greeter-server.c
-index ecb2ad6..1ae64a7 100644
---- a/daemon/gdm-greeter-server.c
-+++ b/daemon/gdm-greeter-server.c
-@@ -285,6 +285,14 @@ gdm_greeter_server_problem (GdmGreeterServer *greeter_server,
++        GdmFingerprintExtension *extension = GDM_FINGERPRINT_EXTENSION (object);
++        g_source_remove (extension->priv->message_timeout_id);
  }
  
- gboolean
-+gdm_greeter_server_service_unavailable (GdmGreeterServer *greeter_server,
-+                                        const char       *service_name)
+ static void
+diff --git a/gui/simple-greeter/plugins/password/gdm-password-extension.c b/gui/simple-greeter/plugins/password/gdm-password-extension.c
+index 11a171c..5157ea2 100644
+--- a/gui/simple-greeter/plugins/password/gdm-password-extension.c
++++ b/gui/simple-greeter/plugins/password/gdm-password-extension.c
+@@ -40,6 +40,8 @@ struct _GdmPasswordExtensionPrivate
+         GtkWidget *prompt_entry;
+ 
+         guint      answer_pending : 1;
++
++        guint      message_timeout_id;
+ };
+ 
+ static void gdm_password_extension_finalize (GObject *object);
+@@ -58,6 +60,16 @@ G_DEFINE_TYPE_WITH_CODE (GdmPasswordExtension,
+                          G_IMPLEMENT_INTERFACE (GDM_TYPE_CONVERSATION,
+                                                 gdm_conversation_iface_init));
+ 
++static gboolean
++on_message_expired (GdmConversation *conversation)
 +{
-+        send_dbus_string_signal (greeter_server, "ServiceUnavailable", service_name);
-+        return TRUE;
++        GdmPasswordExtension *extension = GDM_PASSWORD_EXTENSION (conversation);
++        extension->priv->message_timeout_id = 0;
++
++        gdm_conversation_message_set (conversation);
++        return FALSE;
 +}
 +
-+gboolean
- gdm_greeter_server_reset (GdmGreeterServer *greeter_server)
+ static void
+ gdm_password_extension_set_message (GdmConversation *conversation,
+                                     const char *message)
+@@ -65,6 +77,11 @@ gdm_password_extension_set_message (GdmConversation *conversation,
+         GdmPasswordExtension *extension = GDM_PASSWORD_EXTENSION (conversation);
+         gtk_widget_show (extension->priv->message_label);
+         gtk_label_set_text (GTK_LABEL (extension->priv->message_label), message);
++
++        if (extension->priv->message_timeout_id  != 0) {
++                g_source_remove (extension->priv->message_timeout_id);
++        }
++        extension->priv->message_timeout_id = g_timeout_add_seconds (2, (GSourceFunc) on_message_expired, conversation);
+ }
+ 
+ static void
+@@ -251,6 +268,9 @@ gdm_password_extension_class_init (GdmPasswordExtensionClass *extension_class)
+ static void
+ gdm_password_extension_finalize (GObject *object)
  {
-         send_dbus_void_signal (greeter_server, "Reset");
-diff --git a/daemon/gdm-greeter-server.h b/daemon/gdm-greeter-server.h
-index 976f0b7..c1da2f4 100644
---- a/daemon/gdm-greeter-server.h
-+++ b/daemon/gdm-greeter-server.h
-@@ -93,6 +93,8 @@ gboolean            gdm_greeter_server_info                  (GdmGreeterServer *
- gboolean            gdm_greeter_server_problem               (GdmGreeterServer *greeter_server,
-                                                               const char       *service_name,
-                                                               const char       *text);
-+gboolean            gdm_greeter_server_service_unavailable   (GdmGreeterServer *greeter_server,
-+                                                              const char       *service_name);
- gboolean            gdm_greeter_server_reset                 (GdmGreeterServer *greeter_server);
- gboolean            gdm_greeter_server_ready                 (GdmGreeterServer *greeter_server,
-                                                               const char       *service_name);
-diff --git a/daemon/gdm-simple-slave.c b/daemon/gdm-simple-slave.c
-index 6454d7d..5c3a7fd 100644
---- a/daemon/gdm-simple-slave.c
-+++ b/daemon/gdm-simple-slave.c
-@@ -211,6 +211,19 @@ queue_greeter_reset (GdmSimpleSlave *slave)
++
++        GdmPasswordExtension *extension = GDM_PASSWORD_EXTENSION (object);
++        g_source_remove (extension->priv->message_timeout_id);
  }
  
  static void
-+on_session_service_unavailable (GdmSession     *session,
-+                                const char     *service_name,
-+                                GdmSimpleSlave *slave)
+diff --git a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c
+index b40a21c..5e234b9 100644
+--- a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c
++++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c
+@@ -56,6 +56,8 @@ struct _GdmSmartcardExtensionPrivate
+ 
+         guint      answer_pending : 1;
+         guint      select_when_ready : 1;
++
++        guint      message_timeout_id;
+ };
+ 
+ static void gdm_smartcard_extension_finalize (GObject *object);
+@@ -164,6 +166,16 @@ stop_watching_for_smartcards (GdmSmartcardExtension *extension)
+         kill (extension->priv->worker_pid, SIGTERM);
+ }
+ 
++static gboolean
++on_message_expired (GdmConversation *conversation)
 +{
-+        if (slave->priv->greeter_server != NULL) {
-+                gdm_greeter_server_service_unavailable (slave->priv->greeter_server,
-+                                                        service_name);
-+        }
++        GdmSmartcardExtension *extension = GDM_SMARTCARD_EXTENSION (conversation);
++        extension->priv->message_timeout_id = 0;
 +
-+        gdm_session_stop_conversation (session, service_name);
++        gdm_conversation_message_set (conversation);
++        return FALSE;
 +}
 +
-+static void
- on_session_setup_complete (GdmSession     *session,
-                            const char     *service_name,
-                            GdmSimpleSlave *slave)
-@@ -688,6 +701,10 @@ create_new_session (GdmSimpleSlave *slave)
-                           G_CALLBACK (on_session_conversation_stopped),
-                           slave);
-         g_signal_connect (slave->priv->session,
-+                          "service-unavailable",
-+                          G_CALLBACK (on_session_service_unavailable),
-+                          slave);
-+        g_signal_connect (slave->priv->session,
-                           "setup-complete",
-                           G_CALLBACK (on_session_setup_complete),
-                           slave);
+ static void
+ gdm_smartcard_extension_set_message (GdmConversation *conversation,
+                                      const char      *message)
+@@ -171,6 +183,11 @@ gdm_smartcard_extension_set_message (GdmConversation *conversation,
+         GdmSmartcardExtension *extension = GDM_SMARTCARD_EXTENSION (conversation);
+         gtk_widget_show (extension->priv->message_label);
+         gtk_label_set_text (GTK_LABEL (extension->priv->message_label), message);
++
++        if (extension->priv->message_timeout_id  != 0) {
++                g_source_remove (extension->priv->message_timeout_id);
++        }
++        extension->priv->message_timeout_id = g_timeout_add_seconds (2, (GSourceFunc) on_message_expired, conversation);
+ }
+ 
+ static void
+@@ -428,6 +445,8 @@ gdm_smartcard_extension_finalize (GObject *object)
+         if (extension->priv->worker_pid > 0) {
+                 stop_watching_for_smartcards (extension);
+         }
++
++        g_source_remove (extension->priv->message_timeout_id);
+ }
+ 
+ static void
 -- 
-1.6.5.2
+1.7.2.1
 
 
-From 7514ee20b05aeadea6f7593c44cb69d530a8338c Mon Sep 17 00:00:00 2001
+From 5e112d485929ce2c66c36677c7905530baf1fc92 Mon Sep 17 00:00:00 2001
 From: Ray Strode <rstrode at redhat.com>
-Date: Wed, 28 Oct 2009 21:46:39 -0400
-Subject: [PATCH 38/45] Catch service-unavailable from server in client and propagate it
+Date: Wed, 4 Aug 2010 19:27:14 -0400
+Subject: [PATCH 33/35] Drop cancelling message
 
+We cancel very quickly in most cases now, so the message isn't useful
 ---
- gui/simple-greeter/gdm-greeter-client.c |   20 ++++++++++++++++++++
- gui/simple-greeter/gdm-greeter-client.h |    2 ++
- 2 files changed, 22 insertions(+), 0 deletions(-)
+ gui/simple-greeter/gdm-greeter-login-window.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
 
-diff --git a/gui/simple-greeter/gdm-greeter-client.c b/gui/simple-greeter/gdm-greeter-client.c
-index 12572fe..6a26f16 100644
---- a/gui/simple-greeter/gdm-greeter-client.c
-+++ b/gui/simple-greeter/gdm-greeter-client.c
-@@ -63,6 +63,7 @@ enum {
-         PROBLEM,
-         INFO_QUERY,
-         SECRET_INFO_QUERY,
-+        SERVICE_UNAVAILABLE,
-         READY,
-         CONVERSATION_STOPPED,
-         RESET,
-@@ -264,6 +265,13 @@ on_problem (GdmGreeterClient *client,
+diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
+index 2d7c400..904269c 100644
+--- a/gui/simple-greeter/gdm-greeter-login-window.c
++++ b/gui/simple-greeter/gdm-greeter-login-window.c
+@@ -850,7 +850,7 @@ static void
+ do_cancel (GdmGreeterLoginWindow *login_window)
+ {
+         /* need to wait for response from backend */
+-        set_message (login_window, _("Cancelling..."));
++        //set_message (login_window, _("Cancelling..."));
+         restart_conversations (login_window);
  }
  
+-- 
+1.7.2.1
+
+
+From ade29eb7766e364273d4202f5a5339aeed11eb7f Mon Sep 17 00:00:00 2001
+From: Ray Strode <rstrode at redhat.com>
+Date: Fri, 6 Aug 2010 11:14:23 -0400
+Subject: [PATCH 34/35] manage tasks outside of task list
+
+The task list isn't very good for tracking tasks as
+they come and go, since it replies on the groaty details
+of toggle buttons and widget activation and such.
+
+We now use it soley for display purposes when necessary
+and otherwise, keep track of the tasks in a separate list.
+
+Also, differentiate single authentication modes from
+multiple authentication modes, so we don't show the task list
+when we don't need to.
+---
+ gui/simple-greeter/gdm-greeter-login-window.c |  396 +++++++++++++------------
+ 1 files changed, 206 insertions(+), 190 deletions(-)
+
+diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
+index 904269c..ac00d62 100644
+--- a/gui/simple-greeter/gdm-greeter-login-window.c
++++ b/gui/simple-greeter/gdm-greeter-login-window.c
+@@ -98,6 +98,7 @@ enum {
+         MODE_TIMED_LOGIN,
+         MODE_SELECTION,
+         MODE_AUTHENTICATION,
++        MODE_MULTIPLE_AUTHENTICATION,
+ };
+ 
+ enum {
+@@ -118,6 +119,8 @@ struct GdmGreeterLoginWindowPrivate
+         guint            is_interactive : 1;
+         guint            user_chooser_loaded : 1;
+         GConfClient     *client;
++        GList           *tasks;
++        GdmTask         *active_task;
+         GList           *tasks_to_enable;
+ 
+         gboolean         banner_message_enabled;
+@@ -179,6 +182,9 @@ static void     gdm_greeter_login_window_start_session_when_ready (GdmGreeterLog
+ static void handle_stopped_conversation (GdmGreeterLoginWindow *login_window,
+                                          const char            *service_name);
+ 
++static void begin_single_service_verification (GdmGreeterLoginWindow *login_window,
++                                               const char            *service_name);
++
+ G_DEFINE_TYPE (GdmGreeterLoginWindow, gdm_greeter_login_window, GTK_TYPE_WINDOW)
+ 
  static void
-+on_service_unavailable (GdmGreeterClient *client,
-+                        DBusMessage      *message)
-+{
-+        emit_string_signal_for_message (client, "ServiceUnavailable", message, SERVICE_UNAVAILABLE);
-+}
+@@ -212,26 +218,22 @@ set_sensitive (GdmGreeterLoginWindow *login_window,
+ static void
+ set_focus (GdmGreeterLoginWindow *login_window)
+ {
+-        GdmTask *task;
+-
+         gdk_window_focus (gtk_widget_get_window (GTK_WIDGET (login_window)), GDK_CURRENT_TIME);
+ 
+-        task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
+-
+-        if (task != NULL && gdm_conversation_focus (GDM_CONVERSATION (task))) {
++        if (login_window->priv->active_task != NULL &&
++            gdm_conversation_focus (GDM_CONVERSATION (login_window->priv->active_task))) {
+                 char *name;
+-                name = gdm_task_get_name (task);
++                name = gdm_task_get_name (login_window->priv->active_task);
+                 g_debug ("GdmGreeterLoginWindow: focusing task %s", name);
+                 g_free (name);
+         } else if (gtk_widget_get_realized (login_window->priv->user_chooser) && ! gtk_widget_has_focus (login_window->priv->user_chooser)) {
+                 gtk_widget_grab_focus (login_window->priv->user_chooser);
+         }
+-        g_object_unref (task);
 +
-+static void
- on_ready (GdmGreeterClient *client,
-           DBusMessage      *message)
+ }
+ 
+ static gboolean
+-set_task_conversation_message (GdmTaskList *task_list,
+-                               GdmTask     *task,
++set_task_conversation_message (GdmTask     *task,
+                                const char  *message)
+ {
+ 
+@@ -246,10 +248,9 @@ set_message (GdmGreeterLoginWindow *login_window,
+ {
+         g_return_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window));
+ 
+-        gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
+-                                    (GdmTaskListForeachFunc)
+-                                    set_task_conversation_message,
+-                                    (gpointer) text);
++        g_list_foreach (login_window->priv->tasks,
++                        (GFunc) set_task_conversation_message,
++                        (gpointer) text);
+ }
+ 
+ static void
+@@ -452,7 +453,6 @@ set_log_in_button_mode (GdmGreeterLoginWindow *login_window,
+         GtkWidget *unlock_button;
+         char      *item;
+         gboolean   in_use;
+-        GdmTask   *task;
+ 
+         in_use = FALSE;
+         item = gdm_chooser_widget_get_active_item (GDM_CHOOSER_WIDGET (login_window->priv->user_chooser));
+@@ -494,20 +494,16 @@ set_log_in_button_mode (GdmGreeterLoginWindow *login_window,
+ 
+         switch (mode) {
+         case LOGIN_BUTTON_HIDDEN:
+-                task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
+-                if (task != NULL) {
+-                        hide_task_actions (task);
+-                        g_object_unref (task);
++                if (login_window->priv->active_task != NULL) {
++                        hide_task_actions (login_window->priv->active_task);
+                 }
+ 
+                 gtk_widget_hide (button);
+                 break;
+         case LOGIN_BUTTON_ANSWER_QUERY:
+-                task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
+-                if (task != NULL) {
+-                        show_task_actions (task);
+-                        grab_default_button_for_task (task);
+-                        g_object_unref (task);
++                if (login_window->priv->active_task != NULL) {
++                        show_task_actions (login_window->priv->active_task);
++                        grab_default_button_for_task (login_window->priv->active_task);
+                 }
+ 
+                 gtk_widget_hide (button);
+@@ -554,6 +550,7 @@ maybe_show_cancel_button (GdmGreeterLoginWindow *login_window)
+                 show = TRUE;
+                 break;
+         case MODE_AUTHENTICATION:
++        case MODE_MULTIPLE_AUTHENTICATION:
+                 if (login_window->priv->num_queries > 1) {
+                         /* if we are inside a pam conversation past
+                            the first step */
+@@ -578,7 +575,7 @@ update_conversation_list_visibility (GdmGreeterLoginWindow *login_window)
+ {
+         int number_of_tasks;
+ 
+-        if (login_window->priv->dialog_mode != MODE_AUTHENTICATION) {
++        if (login_window->priv->dialog_mode != MODE_MULTIPLE_AUTHENTICATION) {
+                 gtk_widget_hide (login_window->priv->conversation_list);
+                 return;
+         }
+@@ -619,6 +616,7 @@ switch_mode (GdmGreeterLoginWindow *login_window,
+                 set_log_in_button_mode (login_window, LOGIN_BUTTON_TIMED_LOGIN);
+                 break;
+         case MODE_AUTHENTICATION:
++        case MODE_MULTIPLE_AUTHENTICATION:
+                 set_log_in_button_mode (login_window, LOGIN_BUTTON_ANSWER_QUERY);
+                 break;
+         default:
+@@ -657,39 +655,36 @@ switch_mode (GdmGreeterLoginWindow *login_window,
+         }
+ }
+ 
+-static gboolean
+-task_has_service_name (GdmTaskList *task_list,
+-                       GdmTask     *task,
+-                       const char  *service_name)
++static GdmTask *
++find_task_with_service_name (GdmGreeterLoginWindow *login_window,
++                             const char            *service_name)
+ {
+-        char *task_service_name;
+-        gboolean has_service_name;
++        GList *node;
+ 
+-        task_service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (task));
++        node = login_window->priv->tasks;
++        while (node != NULL) {
++                GdmTask *task;
++                char *task_service_name;
++                gboolean has_service_name;
+ 
+-        has_service_name = strcmp (service_name, task_service_name) == 0;
+-        g_free (task_service_name);
++                task = GDM_TASK (node->data);
+ 
+-        return has_service_name;
+-}
++                task_service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (task));
++                has_service_name = strcmp (service_name, task_service_name) == 0;
++                g_free (task_service_name);
+ 
+-static GdmTask *
+-find_task_with_service_name (GdmGreeterLoginWindow *login_window,
+-                             const char            *service_name)
+-{
+-        GdmTask *task;
++                if (has_service_name) {
++                        return task;
++                }
+ 
+-        task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
+-                                           (GdmTaskListForeachFunc)
+-                                           task_has_service_name,
+-                                           (gpointer) service_name);
++                node = node->next;
++        }
+ 
+-        return task;
++        return NULL;
+ }
+ 
+ static gboolean
+-reset_task (GdmTaskList           *task_list,
+-            GdmTask               *task,
++reset_task (GdmTask               *task,
+             GdmGreeterLoginWindow *login_window)
  {
-@@ -766,6 +774,8 @@ client_dbus_handle_message (DBusConnection *connection,
-                 on_info (client, message);
-         } else if (dbus_message_is_signal (message, GREETER_SERVER_DBUS_INTERFACE, "Problem")) {
-                 on_problem (client, message);
-+        } else if (dbus_message_is_signal (message, GREETER_SERVER_DBUS_INTERFACE, "ServiceUnavailable")) {
-+                on_service_unavailable (client, message);
-         } else if (dbus_message_is_signal (message, GREETER_SERVER_DBUS_INTERFACE, "Ready")) {
-                 on_ready (client, message);
-         } else if (dbus_message_is_signal (message, GREETER_SERVER_DBUS_INTERFACE, "ConversationStopped")) {
-@@ -999,6 +1009,16 @@ gdm_greeter_client_class_init (GdmGreeterClientClass *klass)
-                               2,
-                               G_TYPE_STRING, G_TYPE_STRING);
+         char *name;
+@@ -700,28 +695,31 @@ reset_task (GdmTaskList           *task_list,
  
-+        gdm_greeter_client_signals[SERVICE_UNAVAILABLE] =
-+                g_signal_new ("service-unavailable",
-+                              G_OBJECT_CLASS_TYPE (object_class),
-+                              G_SIGNAL_RUN_FIRST,
-+                              G_STRUCT_OFFSET (GdmGreeterClientClass, service_unavailable),
-+                              NULL,
-+                              NULL,
-+                              g_cclosure_marshal_VOID__STRING,
-+                              G_TYPE_NONE, 1, G_TYPE_STRING);
-+
-         gdm_greeter_client_signals[READY] =
-                 g_signal_new ("ready",
-                               G_OBJECT_CLASS_TYPE (object_class),
-diff --git a/gui/simple-greeter/gdm-greeter-client.h b/gui/simple-greeter/gdm-greeter-client.h
-index f879307..801bae4 100644
---- a/gui/simple-greeter/gdm-greeter-client.h
-+++ b/gui/simple-greeter/gdm-greeter-client.h
-@@ -59,6 +59,8 @@ typedef struct
-         void (* problem)                 (GdmGreeterClient  *client,
-                                           const char        *service_name,
-                                           const char        *problem);
-+        void (* service_unavailable)     (GdmGreeterClient  *client,
-+                                          const char        *service_name);
-         void (* ready)                   (GdmGreeterClient  *client,
-                                           const char        *service_name);
-         void (* conversation_stopped)    (GdmGreeterClient  *client,
--- 
-1.6.5.2
-
-
-From 593c7ec2900a3aecf79ccf43c2ed4ef363ec4c79 Mon Sep 17 00:00:00 2001
-From: Ray Strode <rstrode at redhat.com>
-Date: Wed, 28 Oct 2009 22:09:45 -0400
-Subject: [PATCH 39/45] Add gdm_task_list_remove_task
-
----
- gui/simple-greeter/gdm-task-list.c |   29 +++++++++++++++++++++++++++++
- gui/simple-greeter/gdm-task-list.h |    3 +++
- 2 files changed, 32 insertions(+), 0 deletions(-)
-
-diff --git a/gui/simple-greeter/gdm-task-list.c b/gui/simple-greeter/gdm-task-list.c
-index be50832..dd77ed6 100644
---- a/gui/simple-greeter/gdm-task-list.c
-+++ b/gui/simple-greeter/gdm-task-list.c
-@@ -211,6 +211,35 @@ gdm_task_list_add_task (GdmTaskList *task_list,
-         }
+         login_window->priv->tasks_to_enable = g_list_remove (login_window->priv->tasks_to_enable, task);
+ 
++        gdm_task_list_remove_task (GDM_TASK_LIST (login_window->priv->conversation_list), task);
+         gdm_conversation_reset (GDM_CONVERSATION (task));
+         return FALSE;
  }
  
-+void
-+gdm_task_list_remove_task (GdmTaskList *task_list,
-+                           GdmTask     *task)
-+{
-+        GtkWidget *image;
-+        GtkWidget *button;
-+        GIcon     *icon;
-+        char      *description;
-+
-+        task_list->priv->tasks = g_list_remove (task_list->priv->tasks, task);
-+
-+        button = g_object_get_data (G_OBJECT (task), "gdm-task-list-button");
+ static gboolean
+-task_is_disabled (GdmTaskList *task_list,
+-                  GdmTask     *task)
+-{
+-        return !gdm_task_is_enabled (task);
+-}
+-
+-static gboolean
+ tasks_are_enabled (GdmGreeterLoginWindow *login_window)
+ {
+-        GdmTask *task;
+ 
+-        task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
+-                                           (GdmTaskListForeachFunc)
+-                                           task_is_disabled,
+-                                           NULL);
++        GList *node;
 +
-+        if (button != NULL) {
-+            g_signal_handlers_disconnect_by_func (G_OBJECT (task),
-+                                                  G_CALLBACK (on_task_enabled),
-+                                                  task_list);
-+            g_signal_handlers_disconnect_by_func (G_OBJECT (task),
-+                                                  G_CALLBACK (on_task_disabled),
-+                                                  task_list);
-+            gtk_widget_destroy (button);
-+            g_object_set_data (G_OBJECT (task), "gdm-task-list-button", NULL);
-+        }
++        node = login_window->priv->tasks;
++        while (node != NULL) {
++                GdmTask *task;
 +
-+        g_object_unref (task);
++                task = GDM_TASK (node->data);
 +
-+        activate_first_available_task (task_list);
-+}
++                if (!gdm_task_is_enabled (task)) {
++                        return FALSE;
++                }
 +
- static void
- gdm_task_list_class_init (GdmTaskListClass *klass)
- {
-diff --git a/gui/simple-greeter/gdm-task-list.h b/gui/simple-greeter/gdm-task-list.h
-index 8bc0c0e..3df5415 100644
---- a/gui/simple-greeter/gdm-task-list.h
-+++ b/gui/simple-greeter/gdm-task-list.h
-@@ -74,6 +74,9 @@ GdmTask *   gdm_task_list_foreach_task (GdmTaskList           *widget,
- void        gdm_task_list_add_task        (GdmTaskList *widget,
-                                            GdmTask     *task);
++                node = node->next;
++        }
  
-+void        gdm_task_list_remove_task        (GdmTaskList *widget,
-+                                              GdmTask     *task);
-+
- int         gdm_task_list_get_number_of_tasks (GdmTaskList *widget);
- G_END_DECLS
+-        return task == NULL;
++        return TRUE;
+ }
  
--- 
-1.6.5.2
-
-
-From a6ce9f2045e3d1f67ad5a61609b05739fed2c505 Mon Sep 17 00:00:00 2001
-From: Ray Strode <rstrode at redhat.com>
-Date: Wed, 28 Oct 2009 21:58:44 -0400
-Subject: [PATCH 40/45] Remove task from task list if unavailable
-
----
- gui/simple-greeter/gdm-greeter-login-window.c |   20 ++++++++++++++++++++
- gui/simple-greeter/gdm-greeter-login-window.h |    3 +++
- gui/simple-greeter/gdm-greeter-session.c      |   14 ++++++++++++++
- 3 files changed, 37 insertions(+), 0 deletions(-)
-
-diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
-index 4dc4aee..065d08b 100644
---- a/gui/simple-greeter/gdm-greeter-login-window.c
-+++ b/gui/simple-greeter/gdm-greeter-login-window.c
-@@ -918,6 +918,26 @@ on_request_timed_login_after_users_loaded (GdmUserChooserWidget  *user_chooser,
-         handle_request_timed_login (login_window);
+ static gboolean
+@@ -735,6 +733,8 @@ can_jump_to_authenticate (GdmGreeterLoginWindow *login_window)
+                 res = FALSE;
+         } else if (login_window->priv->dialog_mode == MODE_AUTHENTICATION) {
+                 res = FALSE;
++        } else if (login_window->priv->dialog_mode == MODE_MULTIPLE_AUTHENTICATION) {
++                res = FALSE;
+         } else if (login_window->priv->user_list_disabled) {
+                 res = (login_window->priv->timed_login_username == NULL);
+         } else {
+@@ -744,39 +744,81 @@ can_jump_to_authenticate (GdmGreeterLoginWindow *login_window)
+         return res;
  }
  
-+gboolean
-+gdm_greeter_login_window_service_unavailable (GdmGreeterLoginWindow *login_window,
-+                                              const char            *service_name)
+-static gboolean
+-begin_task_verification (GdmTaskList           *task_list,
+-                         GdmTask               *task,
+-                         GdmGreeterLoginWindow *login_window)
++static void
++begin_other_verification (GdmGreeterLoginWindow *login_window)
+ {
+-        char *service_name;
++        /* FIXME: we should drop this code and do all OTHER handling
++         * entirely from within the password plugin
++         * (ala how smart card manages its "Smartcard Authentication" item)
++         */
++        begin_single_service_verification (login_window, "gdm-password");
++}
+ 
+-        if (!gdm_task_is_visible (task)) {
+-                return FALSE;
+-        }
++static void
++set_task_active (GdmGreeterLoginWindow *login_window,
++                 GdmTask               *task)
 +{
-+        GdmTask *task;
-+
-+        g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
-+        g_debug ("GdmGreeterLoginWindow: service unavailable: %s", service_name);
++        GtkWidget *container;
++        char *name;
+ 
+-        service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (task));
+-        if (service_name != NULL) {
+-                g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0, service_name);
+-                g_free (service_name);
++        name = gdm_task_get_name (task);
++        g_debug ("GdmGreeterLoginWindow: task '%s' activated", name);
++        g_free (name);
 +
-+        task = find_task_with_service_name (login_window, service_name);
++        container = g_object_get_data (G_OBJECT (task),
++                                       "gdm-greeter-login-window-page-container");
 +
-+        if (task != NULL) {
-+                gdm_task_list_remove_task (GDM_TASK_LIST (login_window->priv->conversation_list),
-+                                           task);
-+                g_object_unref (task);
-+        }
++        if (container == NULL) {
++                GtkWidget *page;
 +
-+        return TRUE;
-+}
++                container = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
++                gtk_container_add (GTK_CONTAINER (login_window->priv->auth_page_box),
++                                   container);
 +
- void
- gdm_greeter_login_window_request_timed_login (GdmGreeterLoginWindow *login_window,
-                                               const char            *username,
-diff --git a/gui/simple-greeter/gdm-greeter-login-window.h b/gui/simple-greeter/gdm-greeter-login-window.h
-index c312a47..041cbc4 100644
---- a/gui/simple-greeter/gdm-greeter-login-window.h
-+++ b/gui/simple-greeter/gdm-greeter-login-window.h
-@@ -94,6 +94,9 @@ gboolean            gdm_greeter_login_window_problem            (GdmGreeterLogin
-                                                                  const char *service_name,
-                                                                  const char *text);
++                page = gdm_conversation_get_page (GDM_CONVERSATION (task));
++                if (page != NULL) {
++                        gtk_container_add (GTK_CONTAINER (container), page);
++                        gtk_widget_show (page);
++                }
++                g_object_set_data (G_OBJECT (task),
++                                   "gdm-greeter-login-window-page-container",
++                                   container);
+         }
  
-+gboolean            gdm_greeter_login_window_service_unavailable (GdmGreeterLoginWindow *login_window,
-+                                                                  const char *service_name);
+-        return FALSE;
++        gtk_widget_show (container);
 +
- void               gdm_greeter_login_window_request_timed_login (GdmGreeterLoginWindow *login_window,
-                                                                  const char            *username,
-                                                                  int                    delay);
-diff --git a/gui/simple-greeter/gdm-greeter-session.c b/gui/simple-greeter/gdm-greeter-session.c
-index 848ea1e..3bf24e8 100644
---- a/gui/simple-greeter/gdm-greeter-session.c
-+++ b/gui/simple-greeter/gdm-greeter-session.c
-@@ -90,6 +90,16 @@ on_problem (GdmGreeterClient  *client,
++        login_window->priv->active_task = task;
++        switch_mode (login_window, login_window->priv->dialog_mode);
  }
  
  static void
-+on_service_unavailable (GdmGreeterClient  *client,
-+                        const char        *service_name,
-+                        GdmGreeterSession *session)
-+{
-+        g_debug ("GdmGreeterSession: Service Unavailable: %s", service_name);
+-begin_verification (GdmGreeterLoginWindow *login_window)
++clear_active_task (GdmGreeterLoginWindow *login_window)
+ {
+-        gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
+-                                    (GdmTaskListForeachFunc)
+-                                    begin_task_verification,
+-                                    login_window);
+ 
+-        switch_mode (login_window, MODE_AUTHENTICATION);
++        GtkWidget *container;
++        GtkActionGroup *actions;
+ 
+-        update_conversation_list_visibility (login_window);
+-}
++        if (login_window->priv->active_task == NULL) {
++                return;
++        }
 +
-+        gdm_greeter_login_window_service_unavailable (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), service_name);
++        container = g_object_get_data (G_OBJECT (login_window->priv->active_task),
++                                       "gdm-greeter-login-window-page-container");
++
++        if (container != NULL) {
++                gtk_widget_hide (container);
++        }
++
++        actions = gdm_conversation_get_actions (GDM_CONVERSATION (login_window->priv->active_task));
++
++        if (actions != NULL) {
++                gtk_action_group_set_sensitive (actions, FALSE);
++                gtk_action_group_set_visible (actions, FALSE);
++                g_object_unref (actions);
++        }
+ 
++        login_window->priv->active_task = NULL;
 +}
+ 
+ static void
+ reset_dialog (GdmGreeterLoginWindow *login_window,
+@@ -811,10 +853,7 @@ reset_dialog (GdmGreeterLoginWindow *login_window,
+                 set_message (login_window, "");
+         }
+ 
+-        gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
+-                                    (GdmTaskListForeachFunc)
+-                                    reset_task,
+-                                    login_window);
++        g_list_foreach (login_window->priv->tasks, (GFunc) reset_task, login_window);
+ 
+         if (can_jump_to_authenticate (login_window)) {
+                 /* If we don't have a user list jump straight to authenticate */
+@@ -822,8 +861,9 @@ reset_dialog (GdmGreeterLoginWindow *login_window,
+ 
+                 g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED],
+                                0, GDM_USER_CHOOSER_USER_OTHER);
+-                begin_verification (login_window);
++                begin_other_verification (login_window);
+         } else {
++                clear_active_task (login_window);
+                 switch_mode (login_window, dialog_mode);
+         }
+ 
+@@ -868,9 +908,9 @@ gdm_greeter_login_window_ready (GdmGreeterLoginWindow *login_window,
+                 if (gdm_chooser_widget_is_loaded (GDM_CHOOSER_WIDGET (login_window->priv->user_chooser))) {
+                         gdm_conversation_set_ready (GDM_CONVERSATION (task));
+                 } else {
+-                        login_window->priv->tasks_to_enable = g_list_prepend (login_window->priv->tasks_to_enable, task);
++                        login_window->priv->tasks_to_enable = g_list_prepend (login_window->priv->tasks_to_enable,
++                                                                              g_object_ref (task));
+                 }
+-                g_object_unref (task);
+         }
+ 
+         set_sensitive (GDM_GREETER_LOGIN_WINDOW (login_window), TRUE);
+@@ -882,7 +922,7 @@ gdm_greeter_login_window_ready (GdmGreeterLoginWindow *login_window,
+                 g_debug ("Starting PAM conversation since user list disabled or no local users");
+                 g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED],
+                                0, GDM_USER_CHOOSER_USER_OTHER);
+-                begin_verification (login_window);
++                begin_other_verification (login_window);
+         }
+ 
+         return TRUE;
+@@ -904,24 +944,37 @@ handle_stopped_conversation (GdmGreeterLoginWindow *login_window,
+                 return;
+         }
+ 
++        if (login_window->priv->dialog_mode == MODE_AUTHENTICATION) {
++                g_debug ("GdmGreeterLoginWindow: conversation failed, starting over");
++                restart_conversations (login_window);
++                return;
++        } else if (login_window->priv->dialog_mode != MODE_MULTIPLE_AUTHENTICATION) {
++                g_warning ("conversation %s stopped when it shouldn't have been running (mode %d)",
++                           service_name, login_window->priv->dialog_mode);
++                restart_conversations (login_window);
++                return;
++        }
 +
-+static void
- on_ready (GdmGreeterClient  *client,
-           const char        *service_name,
-           GdmGreeterSession *session)
-@@ -670,6 +680,10 @@ gdm_greeter_session_init (GdmGreeterSession *session)
-                           G_CALLBACK (on_problem),
-                           session);
-         g_signal_connect (session->priv->client,
-+                          "service-unavailable",
-+                          G_CALLBACK (on_service_unavailable),
-+                          session);
-+        g_signal_connect (session->priv->client,
-                           "ready",
-                           G_CALLBACK (on_ready),
-                           session);
--- 
-1.6.5.2
-
-
-From 949b12b061286aa93279d6bf1811f248d2ceb399 Mon Sep 17 00:00:00 2001
-From: Ray Strode <rstrode at redhat.com>
-Date: Wed, 28 Oct 2009 23:55:00 -0400
-Subject: [PATCH 41/45] Don't add task to UI if it's invisible
-
----
- gui/simple-greeter/gdm-greeter-login-window.c |   14 +++++++++++---
- 1 files changed, 11 insertions(+), 3 deletions(-)
-
-diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
-index 065d08b..0141851 100644
---- a/gui/simple-greeter/gdm-greeter-login-window.c
-+++ b/gui/simple-greeter/gdm-greeter-login-window.c
-@@ -2184,6 +2184,17 @@ gdm_greeter_login_window_add_extension (GdmGreeterLoginWindow *login_window,
+         task = find_task_with_service_name (login_window, service_name);
+ 
+         if (task != NULL) {
+                 gdm_conversation_reset (GDM_CONVERSATION (task));
+ 
+                 g_object_set_data (G_OBJECT (task), "needs-to-be-stopped", GINT_TO_POINTER (FALSE));
+-                g_object_unref (task);
+         }
  
-         g_object_unref (actions);
+         /* If every conversation has failed, then just start over.
+          */
+         task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
  
-+        name = gdm_task_get_name (GDM_TASK (extension));
-+        description = gdm_task_get_description (GDM_TASK (extension));
+-        if (!gdm_task_is_enabled (task)) {
++        if (task == NULL || !gdm_task_is_enabled (task)) {
+                 g_debug ("GdmGreeterLoginWindow: No conversations left, starting over");
+                 restart_conversations (login_window);
+         }
+-        g_object_unref (task);
 +
-+        if (!gdm_task_is_visible (GDM_TASK (extension))) {
-+                g_debug ("GdmGreeterLoginWindow: new extension '%s - %s' won't be added",
-+                         name, description);
-+                g_free (name);
-+                g_free (description);
-+                return;
++        if (task != NULL) {
++                g_object_unref (task);
 +        }
-+
-         g_signal_connect_swapped (GDM_CONVERSATION (extension),
-                                   "answer",
-                                   G_CALLBACK (on_conversation_answer),
-@@ -2197,9 +2208,6 @@ gdm_greeter_login_window_add_extension (GdmGreeterLoginWindow *login_window,
-                                   G_CALLBACK (on_conversation_chose_user),
-                                   login_window);
  
--        name = gdm_task_get_name (GDM_TASK (extension));
--        description = gdm_task_get_description (GDM_TASK (extension));
--
-         g_debug ("GdmGreeterLoginWindow: new extension '%s - %s' added",
-                 name, description);
+         update_conversation_list_visibility (login_window);
+ }
+@@ -937,8 +990,8 @@ gdm_greeter_login_window_conversation_stopped (GdmGreeterLoginWindow *login_wind
  
--- 
-1.6.5.2
-
-
-From baa7dae65b1de218bc3f95f19e1727458cf3619d Mon Sep 17 00:00:00 2001
-From: Ray Strode <rstrode at redhat.com>
-Date: Thu, 29 Oct 2009 00:39:20 -0400
-Subject: [PATCH 42/45] add lame check to see if fingerprint is enabled
-
----
- .../fingerprint/gdm-fingerprint-extension.c        |   35 +++++++++++++++++++-
- 1 files changed, 34 insertions(+), 1 deletions(-)
-
-diff --git a/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c b/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c
-index e1fc0ed..b749ac1 100644
---- a/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c
-+++ b/gui/simple-greeter/plugins/fingerprint/gdm-fingerprint-extension.c
-@@ -197,7 +197,40 @@ gdm_fingerprint_extension_is_choosable (GdmTask *task)
- gboolean
- gdm_fingerprint_extension_is_visible (GdmTask *task)
+         g_debug ("GdmGreeterLoginWindow: conversation '%s' has stopped", service_name);
+ 
+-        task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
+-        if (task != NULL && task_has_service_name (GDM_TASK_LIST (login_window->priv->conversation_list), task, service_name)) {
++        task = find_task_with_service_name (login_window, service_name);
++        if (task != NULL && gdm_task_is_enabled (task)) {
+ 
+                 messages_pending = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (task), "message-pending"));
+         } else {
+@@ -957,8 +1010,7 @@ gdm_greeter_login_window_conversation_stopped (GdmGreeterLoginWindow *login_wind
+ }
+ 
+ static gboolean
+-restart_task_conversation (GdmTaskList           *task_list,
+-                           GdmTask               *task,
++restart_task_conversation (GdmTask               *task,
+                            GdmGreeterLoginWindow *login_window)
  {
--        return TRUE;
-+        char *contents, **lines;
-+        gboolean ret;
-+        guint i;
-+
-+        /* Stolen from gnome-about-me.
-+         *
-+         * FIXME: We should fix pam_fprintd to return authinfo_unavail instead of
-+         * doing this distro specific hack.
-+         */
-+
-+        if (g_file_get_contents ("/etc/sysconfig/authconfig",
-+                                 &contents, NULL, NULL) == FALSE)
-+                return FALSE;
+         char *service_name;
+@@ -987,10 +1039,7 @@ gdm_greeter_login_window_reset (GdmGreeterLoginWindow *login_window)
+         g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
+         reset_dialog (GDM_GREETER_LOGIN_WINDOW (login_window), MODE_SELECTION);
+ 
+-        gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
+-                                    (GdmTaskListForeachFunc)
+-                                    restart_task_conversation,
+-                                    login_window);
++        g_list_foreach (login_window->priv->tasks, (GFunc) restart_task_conversation, login_window);
+ 
+         g_free (login_window->priv->service_name_of_session_ready_to_start);
+         login_window->priv->service_name_of_session_ready_to_start = NULL;
+@@ -1016,7 +1065,6 @@ gdm_greeter_login_window_info (GdmGreeterLoginWindow *login_window,
+                 gdm_conversation_set_message (GDM_CONVERSATION (task),
+                                               text);
+                 show_task_actions (task);
+-                g_object_unref (task);
+         }
+ 
+         return TRUE;
+@@ -1040,7 +1088,6 @@ gdm_greeter_login_window_problem (GdmGreeterLoginWindow *login_window,
+                 gdm_conversation_set_message (GDM_CONVERSATION (task),
+                                               text);
+                 show_task_actions (task);
+-                g_object_unref (task);
+         }
+ 
+         gdk_window_beep (GTK_WIDGET (login_window)->window);
+@@ -1079,9 +1126,19 @@ gdm_greeter_login_window_service_unavailable (GdmGreeterLoginWindow *login_windo
+         task = find_task_with_service_name (login_window, service_name);
+ 
+         if (task != NULL) {
+-                gdm_task_list_remove_task (GDM_TASK_LIST (login_window->priv->conversation_list),
+-                                           task);
+-                g_object_unref (task);
++                GdmTask *active_task;
 +
-+        lines = g_strsplit (contents, "\n", -1);
-+        g_free (contents);
++                gdm_task_set_enabled (task, FALSE);
 +
-+        ret = FALSE;
++                active_task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
 +
-+        for (i = 0; lines[i] ; i++) {
-+                if (g_str_has_prefix (lines[i], "USEFPRINTD=") != FALSE) {
-+                        char *value;
++                if (active_task == task) {
++                        restart_conversations (login_window);
++                }
 +
-+                        value = lines[i] + strlen ("USEFPRINTD=");
-+                        if (g_strcmp0 (value, "yes") == 0) {
-+                                ret = TRUE;
-+                                break;
-+                        }
++                if (active_task != NULL) {
++                        g_object_unref (active_task);
 +                }
-+        }
+         }
+ 
+         return TRUE;
+@@ -1216,7 +1273,6 @@ gdm_greeter_login_window_info_query (GdmGreeterLoginWindow *login_window,
+         if (task != NULL) {
+                 gdm_conversation_ask_question (GDM_CONVERSATION (task),
+                                                text);
+-                g_object_unref (task);
+         }
+ 
+         set_log_in_button_mode (login_window, LOGIN_BUTTON_ANSWER_QUERY);
+@@ -1247,7 +1303,6 @@ gdm_greeter_login_window_secret_info_query (GdmGreeterLoginWindow *login_window,
+         if (task != NULL) {
+                 gdm_conversation_ask_secret (GDM_CONVERSATION (task),
+                                              text);
+-                g_object_unref (task);
+         }
+ 
+         set_log_in_button_mode (login_window, LOGIN_BUTTON_ANSWER_QUERY);
+@@ -1342,8 +1397,7 @@ on_user_chooser_visibility_changed (GdmGreeterLoginWindow *login_window)
+ }
+ 
+ static gboolean
+-begin_task_verification_for_selected_user (GdmTaskList           *task_list,
+-                                           GdmTask               *task,
++begin_task_verification_for_selected_user (GdmTask               *task,
+                                            GdmGreeterLoginWindow *login_window)
+ {
+         char *user_name;
+@@ -1361,6 +1415,9 @@ begin_task_verification_for_selected_user (GdmTaskList           *task_list,
+                 g_free (service_name);
+         }
+ 
++        gdm_task_list_add_task (GDM_TASK_LIST (login_window->priv->conversation_list),
++                                task);
 +
-+        g_strfreev (lines);
+         g_free (user_name);
+         return FALSE;
+ }
+@@ -1408,7 +1465,7 @@ on_users_loaded (GdmUserChooserWidget  *user_chooser,
+                 g_debug ("GdmGreeterLoginWindow: jumping straight to authenticate");
+                 g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED],
+                                0, GDM_USER_CHOOSER_USER_OTHER);
+-                begin_verification (login_window);
++                begin_other_verification (login_window);
+         }
+ }
+ 
+@@ -1416,19 +1473,23 @@ static void
+ choose_user (GdmGreeterLoginWindow *login_window,
+              const char            *user_name)
+ {
++        GdmTask *task;
 +
-+        return ret;
+         g_assert (user_name != NULL);
+         g_debug ("GdmGreeterLoginWindow: user chosen '%s'", user_name);
+ 
+         g_signal_emit (G_OBJECT (login_window), signals[USER_SELECTED],
+                        0, user_name);
+ 
++        g_list_foreach (login_window->priv->tasks,
++                        (GFunc) begin_task_verification_for_selected_user,
++                        login_window);
+ 
+-        gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
+-                                    (GdmTaskListForeachFunc)
+-                                    begin_task_verification_for_selected_user,
+-                                    login_window);
++        task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
++        set_task_active (login_window, task);
++        g_object_unref (task);
+ 
+-        switch_mode (login_window, MODE_AUTHENTICATION);
++        switch_mode (login_window, MODE_MULTIPLE_AUTHENTICATION);
+         update_conversation_list_visibility (login_window);
  }
  
- static void
--- 
-1.6.5.2
-
-
-From 2c41cf9ee83412bb5925d7399e26c2a76d8e26f6 Mon Sep 17 00:00:00 2001
-From: Ray Strode <rstrode at redhat.com>
-Date: Thu, 29 Oct 2009 00:10:40 -0400
-Subject: [PATCH 43/45] don't activate invisible tasks
-
----
- gui/simple-greeter/gdm-task-list.c |    4 ++++
- 1 files changed, 4 insertions(+), 0 deletions(-)
-
-diff --git a/gui/simple-greeter/gdm-task-list.c b/gui/simple-greeter/gdm-task-list.c
-index dd77ed6..c9d7451 100644
---- a/gui/simple-greeter/gdm-task-list.c
-+++ b/gui/simple-greeter/gdm-task-list.c
-@@ -335,6 +335,10 @@ gdm_task_list_set_active_task (GdmTaskList *widget,
-         gboolean   was_sensitive;
-         gboolean   was_activated;
+@@ -1444,35 +1505,34 @@ begin_auto_login (GdmGreeterLoginWindow *login_window)
+         /* just wait for the user to select language and stuff */
+         set_message (login_window, _("Select language and click Log In"));
  
-+        if (!gdm_task_is_visible (task)) {
-+                return FALSE;
-+        }
-+
-         was_sensitive = GTK_WIDGET_SENSITIVE (widget);
-         gtk_widget_set_sensitive (GTK_WIDGET (widget), TRUE);
++        clear_active_task (login_window);
+         switch_mode (login_window, MODE_TIMED_LOGIN);
  
--- 
-1.6.5.2
-
-
-From 9f97661ebdbc37a7bb8f6897dd9cae63ff7f999b Mon Sep 17 00:00:00 2001
-From: Ray Strode <rstrode at redhat.com>
-Date: Thu, 29 Oct 2009 00:46:34 -0400
-Subject: [PATCH 44/45] Add lame check for smart card daemon
-
-We don't want to show the smart card bits if the daemon isn't running
-
-This is just a temporary hack.  We need a better solution.
----
- .../plugins/smartcard/gdm-smartcard-extension.c    |   18 +++++++++++++++++-
- 1 files changed, 17 insertions(+), 1 deletions(-)
-
-diff --git a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c
-index 9967d5f..903e18d 100644
---- a/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c
-+++ b/gui/simple-greeter/plugins/smartcard/gdm-smartcard-extension.c
-@@ -27,6 +27,7 @@
- #include <errno.h>
- #include <fcntl.h>
- #include <stdio.h>
-+#include <stdlib.h>
- #include <sys/types.h>
- #include <unistd.h>
+         show_widget (login_window, "conversation-list", FALSE);
+-        gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
+-                                    (GdmTaskListForeachFunc) reset_task,
+-                                    login_window);
++        g_list_foreach (login_window->priv->tasks,
++                        (GFunc) reset_task,
++                        login_window);
+ }
  
-@@ -312,7 +313,22 @@ gdm_smartcard_extension_is_choosable (GdmTask *task)
- gboolean
- gdm_smartcard_extension_is_visible (GdmTask *task)
+-static gboolean
+-reset_task_if_not_given (GdmTaskList *task_list,
+-                         GdmTask     *task,
++static void
++reset_task_if_not_given (GdmTask     *task,
+                          GdmTask     *given_task)
  {
--        return TRUE;
-+        char *contents;
-+        pid_t pid;
+         if (task == given_task) {
+-                return FALSE;
++                return;
+         }
+ 
+         gdm_conversation_reset (GDM_CONVERSATION (task));
+-        return FALSE;
+ }
+ 
+ static void
+ reset_every_task_but_given_task (GdmGreeterLoginWindow *login_window,
+                                  GdmTask               *task)
+ {
+-        gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
+-                                    (GdmTaskListForeachFunc)
+-                                    reset_task_if_not_given,
+-                                    task);
++        g_list_foreach (login_window->priv->tasks,
++                        (GFunc) reset_task_if_not_given,
++                        task);
 +
-+        if (g_file_get_contents ("/var/run/pcscd.pid",
-+                                 &contents, NULL, NULL) == FALSE) {
-+                return FALSE;
-+        }
+ }
+ 
+ static void
+@@ -1495,11 +1555,10 @@ begin_single_service_verification (GdmGreeterLoginWindow *login_window,
+          */
+         g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0, service_name);
+ 
+-        switch_mode (login_window, MODE_AUTHENTICATION);
+-        gdm_task_list_set_active_task (GDM_TASK_LIST (login_window->priv->conversation_list), task);
+-
+         reset_every_task_but_given_task (login_window, task);
+-        g_object_unref (task);
 +
-+        pid = (pid_t) atoi (contents);
-+        g_free (contents);
++        set_task_active (login_window, task);
++        switch_mode (login_window, MODE_AUTHENTICATION);
+ 
+         show_widget (login_window, "conversation-list", FALSE);
+ }
+@@ -1530,7 +1589,7 @@ on_user_chooser_activated (GdmUserChooserWidget  *user_chooser,
+                 g_debug ("GdmGreeterLoginWindow: Starting all auth conversations");
+                 g_free (item_id);
+ 
+-                begin_verification (login_window);
++                begin_other_verification (login_window);
+         } else if (strcmp (item_id, GDM_USER_CHOOSER_USER_GUEST) == 0) {
+                 /* FIXME: handle guest account stuff */
+                 g_free (item_id);
+@@ -1718,63 +1777,28 @@ static void
+ on_task_activated (GdmGreeterLoginWindow *login_window,
+                    GdmTask               *task)
+ {
+-        GtkWidget *container;
+-        char *name;
+-
+-        name = gdm_task_get_name (task);
+-        g_debug ("GdmGreeterLoginWindow: task '%s' activated", name);
+-        g_free (name);
+-
+-        container = g_object_get_data (G_OBJECT (task),
+-                                       "gdm-greeter-login-window-page-container");
+-
+-        if (container == NULL) {
+-                GtkWidget *page;
+-
+-                container = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
+-                gtk_container_add (GTK_CONTAINER (login_window->priv->auth_page_box),
+-                                   container);
+-
+-                page = gdm_conversation_get_page (GDM_CONVERSATION (task));
+-                if (page != NULL) {
+-                        gtk_container_add (GTK_CONTAINER (container), page);
+-                        gtk_widget_show (page);
+-                }
+-                g_object_set_data (G_OBJECT (task),
+-                                   "gdm-greeter-login-window-page-container",
+-                                   container);
+-        }
+-
+-        gtk_widget_show (container);
+-        switch_mode (login_window, login_window->priv->dialog_mode);
++        set_task_active (login_window, task);
+ }
+ 
+ static void
+ on_task_deactivated (GdmGreeterLoginWindow *login_window,
+                      GdmTask               *task)
+ {
+-        GtkWidget *container;
+         char *name;
+-        GtkActionGroup *actions;
 +
-+        if (pid == 0) {
-+                return FALSE;
++        if (login_window->priv->active_task != task) {
++                g_warning ("inactive task has been deactivated");
++                return;
 +        }
-+
-+        return kill (pid, 0);
+ 
+         name = gdm_task_get_name (task);
+         g_debug ("GdmGreeterLoginWindow: task '%s' now in background", name);
+         g_free (name);
+ 
+-        container = g_object_get_data (G_OBJECT (task),
+-                                       "gdm-greeter-login-window-page-container");
++        clear_active_task (login_window);
+ 
+-        if (container != NULL) {
+-                gtk_widget_hide (container);
+-        }
+-
+-        actions = gdm_conversation_get_actions (GDM_CONVERSATION (task));
+-
+-        if (actions != NULL) {
+-                gtk_action_group_set_sensitive (actions, FALSE);
+-                gtk_action_group_set_visible (actions, FALSE);
+-                g_object_unref (actions);
+-        }
++        login_window->priv->active_task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
++        g_object_unref (login_window->priv->active_task);
  }
  
  static void
+@@ -1879,6 +1903,7 @@ load_theme (GdmGreeterLoginWindow *login_window)
+         box = GTK_WIDGET (gtk_builder_get_object (login_window->priv->builder, "computer-info-event-box"));
+         g_signal_connect (box, "button-press-event", G_CALLBACK (on_computer_info_label_button_press), login_window);
+ 
++        clear_active_task (login_window);
+         switch_mode (login_window, MODE_SELECTION);
+ 
+         gdm_profile_end (NULL);
+@@ -2217,15 +2242,12 @@ on_conversation_chose_user (GdmGreeterLoginWindow *login_window,
+ 
+         /* If we're already authenticating then we can't pick a user
+          */
+-        if (login_window->priv->dialog_mode == MODE_AUTHENTICATION) {
++        if (login_window->priv->dialog_mode == MODE_AUTHENTICATION || login_window->priv->dialog_mode == MODE_MULTIPLE_AUTHENTICATION) {
+                 return FALSE;
+         }
+ 
+-        if (gdm_task_list_set_active_task (GDM_TASK_LIST (login_window->priv->conversation_list),
+-                                           GDM_TASK (conversation))) {
+-                gdm_user_chooser_widget_set_chosen_user_name (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser),
+-                                                              username);
+-        }
++        gdm_user_chooser_widget_set_chosen_user_name (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser),
++                                                      username);
+ 
+         return TRUE;
+ }
+@@ -2249,11 +2271,7 @@ on_conversation_message_set (GdmGreeterLoginWindow *login_window,
+         }
+ 
+         if (login_window->priv->service_name_of_session_ready_to_start != NULL ) {
+-                GdmTask *task;
+-
+-                task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
+-
+-                if (task == GDM_TASK (conversation)) {
++                if (login_window->priv->active_task == GDM_TASK (conversation)) {
+                         gdm_greeter_login_window_start_session (login_window);
+                 }
+         }
+@@ -2429,9 +2447,7 @@ gdm_greeter_login_window_add_extension (GdmGreeterLoginWindow *login_window,
+         g_debug ("GdmGreeterLoginWindow: new extension '%s - %s' added",
+                 name, description);
+ 
+-        gdm_task_list_add_task (GDM_TASK_LIST (login_window->priv->conversation_list),
+-                                GDM_TASK (extension));
+-
++        login_window->priv->tasks = g_list_append (login_window->priv->tasks, extension);
+         service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (extension));
+ 
+         if (gdm_task_is_choosable (GDM_TASK (extension))) {
 -- 
-1.6.5.2
+1.7.2.1
 
 
-From 397a9d2cf77d160bda439578320b04f7b0f26266 Mon Sep 17 00:00:00 2001
+From a37938a440ad84b334ae5a851884030409ccdc22 Mon Sep 17 00:00:00 2001
 From: Ray Strode <rstrode at redhat.com>
-Date: Fri, 6 Nov 2009 13:35:26 -0500
-Subject: [PATCH 45/45] Don't delay login for passwd -d users
+Date: Mon, 9 Aug 2010 18:09:19 -0400
+Subject: [PATCH 35/35] hide task actions more aggressively
 
-Before we'd delay login if timed login was enabled, but
-we should have been checking if it was the reason login
-was happening.
+This fixes "dual login buttons" after the user hits cancel.
 ---
- gui/simple-greeter/gdm-greeter-login-window.c |    2 +-
- 1 files changed, 1 insertions(+), 1 deletions(-)
+ gui/simple-greeter/gdm-greeter-login-window.c |    3 +++
+ 1 files changed, 3 insertions(+), 0 deletions(-)
 
 diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
-index 0141851..2c65e61 100644
+index ac00d62..31e599f 100644
 --- a/gui/simple-greeter/gdm-greeter-login-window.c
 +++ b/gui/simple-greeter/gdm-greeter-login-window.c
-@@ -1013,7 +1013,7 @@ gdm_greeter_login_window_start_session_when_ready (GdmGreeterLoginWindow *login_
-                  * so they can pick language/session.  Will need to refactor things
-                  * a bit so we can share code with timed login.
-                  */
--                if (!login_window->priv->timed_login_enabled) {
-+                if (strcmp (service_name, "gdm-autologin") != 0) {
+@@ -492,6 +492,8 @@ set_log_in_button_mode (GdmGreeterLoginWindow *login_window,
  
-                         g_debug ("GdmGreeterLoginWindow: Okay, we'll start the session anyway,"
-                                  "because the user isn't ever going to get an opportunity to"
+         login_window->priv->current_button = button;
+ 
++        g_list_foreach (login_window->priv->tasks, (GFunc) hide_task_actions, NULL);
++
+         switch (mode) {
+         case LOGIN_BUTTON_HIDDEN:
+                 if (login_window->priv->active_task != NULL) {
+@@ -696,6 +698,7 @@ reset_task (GdmTask               *task,
+         login_window->priv->tasks_to_enable = g_list_remove (login_window->priv->tasks_to_enable, task);
+ 
+         gdm_task_list_remove_task (GDM_TASK_LIST (login_window->priv->conversation_list), task);
++        hide_task_actions (task);
+         gdm_conversation_reset (GDM_CONVERSATION (task));
+         return FALSE;
+ }
 -- 
-1.6.5.2
+1.7.2.1
 
diff --git a/gdm.spec b/gdm.spec
index 4fdc91f..c65e69b 100644
--- a/gdm.spec
+++ b/gdm.spec
@@ -14,8 +14,8 @@
 
 Summary: The GNOME Display Manager
 Name: gdm
-Version: 2.30.2
-Release: 3%{?dist}
+Version: 2.31.90
+Release: 1%{?dist}
 Epoch: 1
 License: GPLv2+
 Group: User Interface/X
@@ -88,17 +88,12 @@ Provides: service(graphical-login) = %{name}
 Requires: audit-libs >= %{libauditver}
 Patch2: plymouth.patch
 
-# https://bugzilla.gnome.org/show_bug.cgi?id=610179
-Patch3: accounts-service.patch
-
 Patch96: gdm-multistack.patch
 # Fedora-specific
 Patch97: gdm-bubble-location.patch
 Patch98: tray-padding.patch
 Patch99: gdm-2.23.1-fedora-logo.patch
 
-Patch101: gdm-libs.patch
-
 %package user-switch-applet
 Summary:   GDM User Switcher Panel Applet
 Group:     User Interface/Desktops
@@ -135,12 +130,10 @@ The GDM fingerprint plugin provides functionality necessary to use a fingerprint
 %prep
 %setup -q
 %patch2 -p1 -b .plymouth
-%patch3 -p1 -b .accounts-service
 %patch96 -p1 -b .multistack
 %patch97 -p1 -b .bubble-location
 %patch98 -p1 -b .tray-padding
 %patch99 -p1 -b .fedora-logo
-%patch101 -p1 -b .libs
 
 autoreconf -i -f
 
@@ -281,8 +274,6 @@ if [ $1 -ge 2 -a -f $custom ] && grep -q /etc/X11/gdm $custom ; then
    sed -i -e 's@/etc/X11/gdm@/etc/gdm at g' $custom
 fi
 
-/usr/sbin/gdm-safe-restart >/dev/null 2>&1 || :
-
 %preun
 %gconf_schema_remove gdm-simple-greeter
 
@@ -331,9 +322,6 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor >&/dev/ull || :
 %{_libexecdir}/gdm-xdmcp-chooser-slave
 %{_sbindir}/gdm
 %{_sbindir}/gdm-binary
-%{_sbindir}/gdm-restart
-%{_sbindir}/gdm-safe-restart
-%{_sbindir}/gdm-stop
 %{_bindir}/gdmflexiserver
 %{_bindir}/gdm-screenshot
 %{_datadir}/gdm/*.ui
@@ -380,6 +368,9 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor >&/dev/ull || :
 %{_libdir}/gdm/simple-greeter/plugins/fingerprint.so
 
 %changelog
+* Tue Aug 17 2010 Ray Strode <rstrode at redhat.com> 2.31.90-1
+- Update to 2.31.90
+
 * Wed Jun 16 2010 Matthias Clasen <mclasen at redhat.com> 2.30.2-3
 - Kill explicit library deps
 


More information about the scm-commits mailing list