Index: gdm-3.0.0/daemon/gdm-display.c
===================================================================
--- gdm-3.0.0.orig/daemon/gdm-display.c	2010-10-01 13:54:28.000000000 +0200
+++ gdm-3.0.0/daemon/gdm-display.c	2011-04-28 21:17:03.829368891 +0200
@@ -67,6 +67,7 @@ struct GdmDisplayPrivate
 
         gboolean              is_local;
         guint                 finish_idle_id;
+        gboolean              needs_respawn;
 
         GdmSlaveProxy        *slave_proxy;
         DBusGConnection      *connection;
@@ -302,6 +303,20 @@ gdm_display_set_slave_bus_name (GdmDispl
         return ret;
 }
 
+gboolean
+gdm_display_set_needs_respawn (GdmDisplay *display,
+                               gboolean    respawn,
+                               GError    **error)
+{
+        g_return_val_if_fail (GDM_IS_DISPLAY (display), FALSE);
+
+        g_debug ("GdmDisplay: %s respawn on display %s", respawn?"Enabling":"Disabling", display->priv->x11_display_name);
+
+        display->priv->needs_respawn = respawn;
+
+        return TRUE;
+}
+
 static void
 gdm_display_real_get_timed_login_details (GdmDisplay *display,
                                           gboolean   *enabledp,
@@ -728,6 +743,34 @@ gdm_display_unmanage (GdmDisplay *displa
 }
 
 gboolean
+gdm_display_respawn_or_finish (GdmDisplay *display)
+{
+        g_return_val_if_fail (GDM_IS_DISPLAY (display), FALSE);
+
+        if (display->priv->needs_respawn) {
+                int status;
+
+                g_debug ("GdmDisplay: respawning display %s", display->priv->x11_display_name);
+                display->priv->needs_respawn = FALSE;
+
+                gdm_display_unmanage (display);
+
+                status = gdm_display_get_status (display);
+                if (status != GDM_DISPLAY_FAILED) {
+                        gdm_display_manage (display);
+                }
+        } else {
+                /* Since this is called from the children's finish,
+                   don't call it again, only call real_finish. */
+                gdm_display_real_finish (display);
+
+                gdm_display_unmanage (display);
+        }
+
+        return TRUE;
+}
+
+gboolean
 gdm_display_get_id (GdmDisplay         *display,
                     char              **id,
                     GError            **error)
Index: gdm-3.0.0/daemon/gdm-display.h
===================================================================
--- gdm-3.0.0.orig/daemon/gdm-display.h	2010-10-01 13:54:28.000000000 +0200
+++ gdm-3.0.0/daemon/gdm-display.h	2011-04-28 21:17:03.829368891 +0200
@@ -96,6 +96,7 @@ gboolean            gdm_display_prepare
 gboolean            gdm_display_manage                         (GdmDisplay *display);
 gboolean            gdm_display_finish                         (GdmDisplay *display);
 gboolean            gdm_display_unmanage                       (GdmDisplay *display);
+gboolean            gdm_display_respawn_or_finish              (GdmDisplay *display);
 
 
 /* exported to bus */
@@ -140,6 +141,9 @@ gboolean            gdm_display_remove_u
 gboolean            gdm_display_set_slave_bus_name             (GdmDisplay *display,
                                                                 const char *name,
                                                                 GError    **error);
+gboolean            gdm_display_set_needs_respawn              (GdmDisplay *display,
+                                                                gboolean    respawn,
+                                                                GError    **error);
 
 
 G_END_DECLS
Index: gdm-3.0.0/daemon/gdm-display.xml
===================================================================
--- gdm-3.0.0.orig/daemon/gdm-display.xml	2010-10-01 13:54:28.000000000 +0200
+++ gdm-3.0.0/daemon/gdm-display.xml	2011-04-28 21:17:03.829368891 +0200
@@ -35,6 +35,9 @@
     <method name="SetSlaveBusName">
       <arg name="name" direction="in" type="s"/>
     </method>
+    <method name="SetNeedsRespawn">
+      <arg name="respawn" direction="in" type="b"/>
+    </method>
     <method name="GetTimedLoginDetails">
       <arg name="enabled" direction="out" type="b"/>
       <arg name="username" direction="out" type="s"/>
Index: gdm-3.0.0/daemon/gdm-simple-slave.c
===================================================================
--- gdm-3.0.0.orig/daemon/gdm-simple-slave.c	2011-04-28 20:40:41.000000000 +0200
+++ gdm-3.0.0/daemon/gdm-simple-slave.c	2011-04-28 21:17:03.829368891 +0200
@@ -116,6 +116,9 @@ on_session_started (GdmSession       *se
 
         g_debug ("GdmSimpleSlave: session started %d", pid);
 
+        /* Respawn the display when the user session has finished */
+        gdm_slave_set_needs_respawn (GDM_SLAVE (slave), TRUE);
+
         /* Run the PreSession script. gdmslave suspends until script has terminated */
         username = gdm_session_direct_get_username (slave->priv->session);
         if (username != NULL) {
Index: gdm-3.0.0/daemon/gdm-slave.c
===================================================================
--- gdm-3.0.0.orig/daemon/gdm-slave.c	2011-04-28 20:14:05.078895519 +0200
+++ gdm-3.0.0/daemon/gdm-slave.c	2011-04-28 21:19:53.402197886 +0200
@@ -649,6 +649,37 @@ gdm_slave_set_slave_bus_name (GdmSlave *
         return res;
 }
 
+gboolean
+gdm_slave_set_needs_respawn (GdmSlave *slave,
+                             gboolean  respawn)
+{
+        gboolean    res;
+        GError     *error;
+
+        /* Never, ever respawn a nested display */
+        /* if (slave->priv->display_is_nested)
+                respawn = FALSE; */
+
+        error = NULL;
+        res = dbus_g_proxy_call (slave->priv->display_proxy,
+                                 "SetNeedsRespawn",
+                                 &error,
+                                 G_TYPE_BOOLEAN, respawn,
+                                 G_TYPE_INVALID,
+                                 G_TYPE_INVALID);
+
+        if (! res) {
+                if (error != NULL) {
+                        g_warning ("Failed to set respawn on parent display: %s", error->message);
+                        g_error_free (error);
+                } else {
+                        g_warning ("Failed to set respawn on parent display");
+                }
+        }
+
+        return res;
+}
+
 static gboolean
 gdm_slave_real_start (GdmSlave *slave)
 {
Index: gdm-3.0.0/daemon/gdm-slave.h
===================================================================
--- gdm-3.0.0.orig/daemon/gdm-slave.h	2011-04-04 16:37:16.000000000 +0200
+++ gdm-3.0.0/daemon/gdm-slave.h	2011-04-28 21:17:03.829368891 +0200
@@ -72,6 +72,9 @@ gboolean            gdm_slave_add_user_a
 gboolean            gdm_slave_switch_to_user_session (GdmSlave   *slave,
                                                       const char *username);
 
+gboolean            gdm_slave_set_needs_respawn      (GdmSlave *slave,
+                                                      gboolean  respawn);
+
 gboolean            gdm_slave_connect_to_x11_display (GdmSlave   *slave);
 
 void                gdm_slave_set_initial_cursor_position (GdmSlave *slave);
Index: gdm-3.0.0/daemon/gdm-transient-display.c
===================================================================
--- gdm-3.0.0.orig/daemon/gdm-transient-display.c	2010-10-01 13:54:28.000000000 +0200
+++ gdm-3.0.0/daemon/gdm-transient-display.c	2011-04-28 21:17:03.829368891 +0200
@@ -100,12 +100,9 @@ gdm_transient_display_finish (GdmDisplay
 {
         g_return_val_if_fail (GDM_IS_DISPLAY (display), FALSE);
 
-        GDM_DISPLAY_CLASS (gdm_transient_display_parent_class)->finish (display);
+        /* Only respawn if needed. */
 
-        /* we don't restart/remanage transient displays */
-        gdm_display_unmanage (display);
-
-        return TRUE;
+        return gdm_display_respawn_or_finish (display);
 }
 
 static gboolean
Index: gdm-3.0.0/daemon/gdm-static-display.c
===================================================================
--- gdm-3.0.0.orig/daemon/gdm-static-display.c	2011-01-15 03:20:13.000000000 +0100
+++ gdm-3.0.0/daemon/gdm-static-display.c	2011-04-28 21:17:03.833368919 +0200
@@ -98,22 +98,13 @@ gdm_static_display_manage (GdmDisplay *d
 static gboolean
 gdm_static_display_finish (GdmDisplay *display)
 {
-        int status;
-
         g_return_val_if_fail (GDM_IS_DISPLAY (display), FALSE);
 
-        /* Don't call parent's finish since we don't ever
-           want to be put in the FINISHED state */
-
-        /* restart static displays */
-        gdm_display_unmanage (display);
-
-        status = gdm_display_get_status (display);
-        if (status != GDM_DISPLAY_FAILED) {
-                gdm_display_manage (display);
-        }
+        /* Only respawn if needed, even for static displays.
+           Avoids the case where :0 keeps respawning while
+           used for switching to an existing session in e.g. :1. */
 
-        return TRUE;
+        return gdm_display_respawn_or_finish (display);
 }
 
 static gboolean
Index: gdm-3.0.0/daemon/gdm-local-display-factory.c
===================================================================
--- gdm-3.0.0.orig/daemon/gdm-local-display-factory.c	2010-10-01 13:54:28.000000000 +0200
+++ gdm-3.0.0/daemon/gdm-local-display-factory.c	2011-04-28 21:17:03.833368919 +0200
@@ -301,7 +301,6 @@ on_static_display_status_changed (GdmDis
                 gdm_display_store_remove (store, display);
                 /* reset num failures */
                 factory->priv->num_failures = 0;
-                create_display (factory);
                 break;
         case GDM_DISPLAY_FAILED:
                 /* leave the display number in factory->priv->displays
