Blame SOURCES/0050-Allow-sessions-to-register-with-GDM.patch

a1b388
From d6aca6da3ab9c16e907c7f46cf6d7bc2abbc2890 Mon Sep 17 00:00:00 2001
a1b388
From: Iain Lane <iainl@gnome.org>
a1b388
Date: Tue, 7 May 2019 16:00:14 +0100
a1b388
Subject: [PATCH 50/51] Allow sessions to register with GDM
a1b388
MIME-Version: 1.0
a1b388
Content-Type: text/plain; charset=UTF-8
a1b388
Content-Transfer-Encoding: 8bit
a1b388
a1b388
Recording when sessions start, for Wayland → Xorg fallback or
a1b388
transitioning to the user session, is currently done with timeouts.
a1b388
a1b388
This isn't ideal, because on some very slow machines the timeout can be
a1b388
hit before the session has had a chance to fail: if gnome-session takes
a1b388
more than 3 seconds to fail then the session will be considered to have
a1b388
exited rather than failed, and so we don't do Xorg fallback.
a1b388
a1b388
We can do this more reliably if we allow sessions to optionally register
a1b388
themselves with GDM. Then we will know when they've started, so can shut
a1b388
down the greeter or fall back to Xorg as appropriate. The mechanism is
a1b388
that they specify X-GDM-SessionRegisters=true in their file, and then
a1b388
call RegsterSession on the DisplayManager interface on the bus (added in
a1b388
the previous commit) to say that they've started up.
a1b388
a1b388
If X-GDM-SessionRegisters is missing or false, GDM will call the same
a1b388
method for them after 10 seconds.
a1b388
a1b388
Closes: #483
a1b388
---
a1b388
 common/gdm-common.h                |  2 +
a1b388
 daemon/gdm-display.c               | 19 ++-----
a1b388
 daemon/gdm-local-display-factory.c | 49 +++++++++---------
a1b388
 daemon/gdm-session.c               | 47 +++++++++++++++--
a1b388
 daemon/gdm-session.h               |  1 +
a1b388
 daemon/gdm-wayland-session.c       | 81 +++++++++++++++++++++++-------
a1b388
 daemon/gdm-x-session.c             | 81 +++++++++++++++++++++++-------
a1b388
 7 files changed, 201 insertions(+), 79 deletions(-)
a1b388
a1b388
diff --git a/common/gdm-common.h b/common/gdm-common.h
a1b388
index 3fbf07653..7fd6458d7 100644
a1b388
--- a/common/gdm-common.h
a1b388
+++ b/common/gdm-common.h
a1b388
@@ -1,59 +1,61 @@
a1b388
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
a1b388
  *
a1b388
  * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
a1b388
  *
a1b388
  * This library is free software; you can redistribute it and/or
a1b388
  * modify it under the terms of the GNU Library General Public
a1b388
  * License as published by the Free Software Foundation; either
a1b388
  * version 2 of the License, or (at your option) any later version.
a1b388
  *
a1b388
  * This library is distributed in the hope that it will be useful,
a1b388
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
a1b388
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
a1b388
  * Library General Public License for more details.
a1b388
  *
a1b388
  * You should have received a copy of the GNU Library General Public
a1b388
  * License along with this library; if not, write to the
a1b388
  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
a1b388
  * Boston, MA 02110-1301, USA.
a1b388
  */
a1b388
 
a1b388
 #ifndef _GDM_COMMON_H
a1b388
 #define _GDM_COMMON_H
a1b388
 
a1b388
 #include <glib-unix.h>
a1b388
 #include <gio/gio.h>
a1b388
 
a1b388
 #include <pwd.h>
a1b388
 #include <errno.h>
a1b388
 
a1b388
+#define REGISTER_SESSION_TIMEOUT 10
a1b388
+
a1b388
 #define        VE_IGNORE_EINTR(expr) \
a1b388
         do {                         \
a1b388
                 errno = 0;           \
a1b388
                 expr;                \
a1b388
         } while G_UNLIKELY (errno == EINTR);
a1b388
 
a1b388
 GQuark gdm_common_error_quark (void);
a1b388
 #define GDM_COMMON_ERROR gdm_common_error_quark()
a1b388
 
a1b388
 typedef char * (*GdmExpandVarFunc) (const char *var,
a1b388
                                     gpointer user_data);
a1b388
 
a1b388
 G_BEGIN_DECLS
a1b388
 
a1b388
 int            gdm_wait_on_pid           (int pid);
a1b388
 int            gdm_wait_on_and_disown_pid (int pid,
a1b388
                                            int timeout);
a1b388
 int            gdm_signal_pid            (int pid,
a1b388
                                           int signal);
a1b388
 gboolean       gdm_get_pwent_for_name    (const char     *name,
a1b388
                                           struct passwd **pwentp);
a1b388
 
a1b388
 gboolean       gdm_clear_close_on_exec_flag (int fd);
a1b388
 
a1b388
 const char *   gdm_make_temp_dir         (char    *template);
a1b388
 
a1b388
 char          *gdm_generate_random_bytes (gsize          size,
a1b388
                                           GError       **error);
a1b388
 gboolean       gdm_get_login_window_session_id (const char  *seat_id,
a1b388
                                                 char       **session_id);
a1b388
diff --git a/daemon/gdm-display.c b/daemon/gdm-display.c
a1b388
index 09cc2e116..ae20491cd 100644
a1b388
--- a/daemon/gdm-display.c
a1b388
+++ b/daemon/gdm-display.c
a1b388
@@ -39,61 +39,60 @@
a1b388
 
a1b388
 #include "gdm-common.h"
a1b388
 #include "gdm-display.h"
a1b388
 #include "gdm-display-glue.h"
a1b388
 #include "gdm-display-access-file.h"
a1b388
 #include "gdm-launch-environment.h"
a1b388
 
a1b388
 #include "gdm-settings-direct.h"
a1b388
 #include "gdm-settings-keys.h"
a1b388
 
a1b388
 #include "gdm-launch-environment.h"
a1b388
 #include "gdm-dbus-util.h"
a1b388
 
a1b388
 #define GNOME_SESSION_SESSIONS_PATH DATADIR "/gnome-session/sessions"
a1b388
 
a1b388
 #define GDM_DISPLAY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_DISPLAY, GdmDisplayPrivate))
a1b388
 
a1b388
 struct GdmDisplayPrivate
a1b388
 {
a1b388
         char                 *id;
a1b388
         char                 *seat_id;
a1b388
         char                 *session_id;
a1b388
         char                 *session_class;
a1b388
         char                 *session_type;
a1b388
 
a1b388
         char                 *remote_hostname;
a1b388
         int                   x11_display_number;
a1b388
         char                 *x11_display_name;
a1b388
         int                   status;
a1b388
         time_t                creation_time;
a1b388
-        GTimer               *server_timer;
a1b388
 
a1b388
         char                 *x11_cookie;
a1b388
         gsize                 x11_cookie_size;
a1b388
         GdmDisplayAccessFile *access_file;
a1b388
 
a1b388
         guint                 finish_idle_id;
a1b388
 
a1b388
         xcb_connection_t     *xcb_connection;
a1b388
         int                   xcb_screen_number;
a1b388
 
a1b388
         GDBusConnection      *connection;
a1b388
         GdmDisplayAccessFile *user_access_file;
a1b388
 
a1b388
         GdmDBusDisplay       *display_skeleton;
a1b388
         GDBusObjectSkeleton  *object_skeleton;
a1b388
 
a1b388
         /* this spawns and controls the greeter session */
a1b388
         GdmLaunchEnvironment *launch_environment;
a1b388
 
a1b388
         guint                 is_local : 1;
a1b388
         guint                 is_initial : 1;
a1b388
         guint                 allow_timed_login : 1;
a1b388
         guint                 have_existing_user_accounts : 1;
a1b388
         guint                 doing_initial_setup : 1;
a1b388
         guint                 session_registered : 1;
a1b388
 };
a1b388
 
a1b388
 enum {
a1b388
         PROP_0,
a1b388
         PROP_ID,
a1b388
@@ -510,62 +509,60 @@ gdm_display_prepare (GdmDisplay *self)
a1b388
          * asynchronously
a1b388
          */
a1b388
         look_for_existing_users_sync (self);
a1b388
 
a1b388
         self->priv->doing_initial_setup = wants_initial_setup (self);
a1b388
 
a1b388
         g_object_ref (self);
a1b388
         ret = GDM_DISPLAY_GET_CLASS (self)->prepare (self);
a1b388
         g_object_unref (self);
a1b388
 
a1b388
         return ret;
a1b388
 }
a1b388
 
a1b388
 gboolean
a1b388
 gdm_display_manage (GdmDisplay *self)
a1b388
 {
a1b388
         gboolean res;
a1b388
 
a1b388
         g_return_val_if_fail (GDM_IS_DISPLAY (self), FALSE);
a1b388
 
a1b388
         g_debug ("GdmDisplay: Managing display: %s", self->priv->id);
a1b388
 
a1b388
         /* If not explicitly prepared, do it now */
a1b388
         if (self->priv->status == GDM_DISPLAY_UNMANAGED) {
a1b388
                 res = gdm_display_prepare (self);
a1b388
                 if (! res) {
a1b388
                         return FALSE;
a1b388
                 }
a1b388
         }
a1b388
 
a1b388
-        g_timer_start (self->priv->server_timer);
a1b388
-
a1b388
         if (g_strcmp0 (self->priv->session_class, "greeter") == 0) {
a1b388
                 if (GDM_DISPLAY_GET_CLASS (self)->manage != NULL) {
a1b388
                         GDM_DISPLAY_GET_CLASS (self)->manage (self);
a1b388
                 }
a1b388
         }
a1b388
 
a1b388
         return TRUE;
a1b388
 }
a1b388
 
a1b388
 gboolean
a1b388
 gdm_display_finish (GdmDisplay *self)
a1b388
 {
a1b388
         g_return_val_if_fail (GDM_IS_DISPLAY (self), FALSE);
a1b388
 
a1b388
         if (self->priv->finish_idle_id != 0) {
a1b388
                 g_source_remove (self->priv->finish_idle_id);
a1b388
                 self->priv->finish_idle_id = 0;
a1b388
         }
a1b388
 
a1b388
         _gdm_display_set_status (self, GDM_DISPLAY_FINISHED);
a1b388
 
a1b388
         g_debug ("GdmDisplay: finish display");
a1b388
 
a1b388
         return TRUE;
a1b388
 }
a1b388
 
a1b388
 static void
a1b388
 gdm_display_disconnect (GdmDisplay *self)
a1b388
 {
a1b388
         /* These 3 bits are reserved/unused by the X protocol */
a1b388
@@ -576,85 +573,80 @@ gdm_display_disconnect (GdmDisplay *self)
a1b388
 
a1b388
         if (self->priv->xcb_connection == NULL) {
a1b388
                 return;
a1b388
         }
a1b388
 
a1b388
         setup = xcb_get_setup (self->priv->xcb_connection);
a1b388
 
a1b388
         /* resource_id_mask is the bits given to each client for
a1b388
          * addressing resources */
a1b388
         highest_client = (XID) ~unused_bits & ~setup->resource_id_mask;
a1b388
         client_increment = setup->resource_id_mask + 1;
a1b388
 
a1b388
         /* Kill every client but ourselves, then close our own connection
a1b388
          */
a1b388
         for (client = 0;
a1b388
              client <= highest_client;
a1b388
              client += client_increment) {
a1b388
 
a1b388
                 if (client != setup->resource_id_base)
a1b388
                         xcb_kill_client (self->priv->xcb_connection, client);
a1b388
         }
a1b388
 
a1b388
         xcb_flush (self->priv->xcb_connection);
a1b388
 
a1b388
         g_clear_pointer (&self->priv->xcb_connection, xcb_disconnect);
a1b388
 }
a1b388
 
a1b388
 gboolean
a1b388
 gdm_display_unmanage (GdmDisplay *self)
a1b388
 {
a1b388
-        gdouble elapsed;
a1b388
-
a1b388
         g_return_val_if_fail (GDM_IS_DISPLAY (self), FALSE);
a1b388
 
a1b388
         g_debug ("GdmDisplay: unmanage display");
a1b388
 
a1b388
         gdm_display_disconnect (self);
a1b388
 
a1b388
-        g_timer_stop (self->priv->server_timer);
a1b388
-
a1b388
         if (self->priv->user_access_file != NULL) {
a1b388
                 gdm_display_access_file_close (self->priv->user_access_file);
a1b388
                 g_object_unref (self->priv->user_access_file);
a1b388
                 self->priv->user_access_file = NULL;
a1b388
         }
a1b388
 
a1b388
         if (self->priv->access_file != NULL) {
a1b388
                 gdm_display_access_file_close (self->priv->access_file);
a1b388
                 g_object_unref (self->priv->access_file);
a1b388
                 self->priv->access_file = NULL;
a1b388
         }
a1b388
 
a1b388
-        elapsed = g_timer_elapsed (self->priv->server_timer, NULL);
a1b388
-        if (elapsed < 3) {
a1b388
-                g_warning ("GdmDisplay: display lasted %lf seconds", elapsed);
a1b388
+        if (!self->priv->session_registered) {
a1b388
+                g_warning ("GdmDisplay: Session never registered, failing");
a1b388
                 _gdm_display_set_status (self, GDM_DISPLAY_FAILED);
a1b388
         } else {
a1b388
                 _gdm_display_set_status (self, GDM_DISPLAY_UNMANAGED);
a1b388
         }
a1b388
 
a1b388
         return TRUE;
a1b388
 }
a1b388
 
a1b388
 gboolean
a1b388
 gdm_display_get_id (GdmDisplay         *self,
a1b388
                     char              **id,
a1b388
                     GError            **error)
a1b388
 {
a1b388
         g_return_val_if_fail (GDM_IS_DISPLAY (self), FALSE);
a1b388
 
a1b388
         if (id != NULL) {
a1b388
                 *id = g_strdup (self->priv->id);
a1b388
         }
a1b388
 
a1b388
         return TRUE;
a1b388
 }
a1b388
 
a1b388
 gboolean
a1b388
 gdm_display_get_x11_display_name (GdmDisplay   *self,
a1b388
                                   char        **x11_display,
a1b388
                                   GError      **error)
a1b388
 {
a1b388
         g_return_val_if_fail (GDM_IS_DISPLAY (self), FALSE);
a1b388
 
a1b388
         if (x11_display != NULL) {
a1b388
@@ -898,61 +890,61 @@ gdm_display_get_property (GObject        *object,
a1b388
         case PROP_X11_DISPLAY_NAME:
a1b388
                 g_value_set_string (value, self->priv->x11_display_name);
a1b388
                 break;
a1b388
         case PROP_X11_COOKIE:
a1b388
                 g_value_set_string (value, self->priv->x11_cookie);
a1b388
                 break;
a1b388
         case PROP_X11_AUTHORITY_FILE:
a1b388
                 g_value_take_string (value,
a1b388
                                      self->priv->access_file?
a1b388
                                      gdm_display_access_file_get_path (self->priv->access_file) : NULL);
a1b388
                 break;
a1b388
         case PROP_IS_LOCAL:
a1b388
                 g_value_set_boolean (value, self->priv->is_local);
a1b388
                 break;
a1b388
         case PROP_IS_CONNECTED:
a1b388
                 g_value_set_boolean (value, self->priv->xcb_connection != NULL);
a1b388
                 break;
a1b388
         case PROP_LAUNCH_ENVIRONMENT:
a1b388
                 g_value_set_object (value, self->priv->launch_environment);
a1b388
                 break;
a1b388
         case PROP_IS_INITIAL:
a1b388
                 g_value_set_boolean (value, self->priv->is_initial);
a1b388
                 break;
a1b388
         case PROP_HAVE_EXISTING_USER_ACCOUNTS:
a1b388
                 g_value_set_boolean (value, self->priv->have_existing_user_accounts);
a1b388
                 break;
a1b388
         case PROP_DOING_INITIAL_SETUP:
a1b388
                 g_value_set_boolean (value, self->priv->doing_initial_setup);
a1b388
                 break;
a1b388
         case PROP_SESSION_REGISTERED:
a1b388
-                g_value_set_boolean (value, priv->session_registered);
a1b388
+                g_value_set_boolean (value, self->priv->session_registered);
a1b388
                 break;
a1b388
         case PROP_ALLOW_TIMED_LOGIN:
a1b388
                 g_value_set_boolean (value, self->priv->allow_timed_login);
a1b388
                 break;
a1b388
         default:
a1b388
                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
a1b388
                 break;
a1b388
         }
a1b388
 }
a1b388
 
a1b388
 static gboolean
a1b388
 handle_get_id (GdmDBusDisplay        *skeleton,
a1b388
                GDBusMethodInvocation *invocation,
a1b388
                GdmDisplay            *self)
a1b388
 {
a1b388
         char *id;
a1b388
 
a1b388
         gdm_display_get_id (self, &id, NULL);
a1b388
 
a1b388
         gdm_dbus_display_complete_get_id (skeleton, invocation, id);
a1b388
 
a1b388
         g_free (id);
a1b388
         return TRUE;
a1b388
 }
a1b388
 
a1b388
 static gboolean
a1b388
 handle_get_remote_hostname (GdmDBusDisplay        *skeleton,
a1b388
                             GDBusMethodInvocation *invocation,
a1b388
                             GdmDisplay            *self)
a1b388
 {
a1b388
@@ -1251,99 +1243,94 @@ gdm_display_class_init (GdmDisplayClass *klass)
a1b388
                                                                FALSE,
a1b388
                                                                G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
a1b388
 
a1b388
         g_object_class_install_property (object_class,
a1b388
                                          PROP_LAUNCH_ENVIRONMENT,
a1b388
                                          g_param_spec_object ("launch-environment",
a1b388
                                                               NULL,
a1b388
                                                               NULL,
a1b388
                                                               GDM_TYPE_LAUNCH_ENVIRONMENT,
a1b388
                                                               G_PARAM_READWRITE));
a1b388
         g_object_class_install_property (object_class,
a1b388
                                          PROP_STATUS,
a1b388
                                          g_param_spec_int ("status",
a1b388
                                                            "status",
a1b388
                                                            "status",
a1b388
                                                            -1,
a1b388
                                                            G_MAXINT,
a1b388
                                                            GDM_DISPLAY_UNMANAGED,
a1b388
                                                            G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
a1b388
 
a1b388
         g_type_class_add_private (klass, sizeof (GdmDisplayPrivate));
a1b388
 }
a1b388
 
a1b388
 static void
a1b388
 gdm_display_init (GdmDisplay *self)
a1b388
 {
a1b388
 
a1b388
         self->priv = GDM_DISPLAY_GET_PRIVATE (self);
a1b388
 
a1b388
         self->priv->creation_time = time (NULL);
a1b388
-        self->priv->server_timer = g_timer_new ();
a1b388
 }
a1b388
 
a1b388
 static void
a1b388
 gdm_display_finalize (GObject *object)
a1b388
 {
a1b388
         GdmDisplay *self;
a1b388
 
a1b388
         g_return_if_fail (object != NULL);
a1b388
         g_return_if_fail (GDM_IS_DISPLAY (object));
a1b388
 
a1b388
         self = GDM_DISPLAY (object);
a1b388
 
a1b388
         g_return_if_fail (self->priv != NULL);
a1b388
 
a1b388
         g_debug ("GdmDisplay: Finalizing display: %s", self->priv->id);
a1b388
         g_free (self->priv->id);
a1b388
         g_free (self->priv->seat_id);
a1b388
         g_free (self->priv->session_class);
a1b388
         g_free (self->priv->remote_hostname);
a1b388
         g_free (self->priv->x11_display_name);
a1b388
         g_free (self->priv->x11_cookie);
a1b388
 
a1b388
         g_clear_object (&self->priv->display_skeleton);
a1b388
         g_clear_object (&self->priv->object_skeleton);
a1b388
         g_clear_object (&self->priv->connection);
a1b388
 
a1b388
         if (self->priv->access_file != NULL) {
a1b388
                 g_object_unref (self->priv->access_file);
a1b388
         }
a1b388
 
a1b388
         if (self->priv->user_access_file != NULL) {
a1b388
                 g_object_unref (self->priv->user_access_file);
a1b388
         }
a1b388
 
a1b388
-        if (self->priv->server_timer != NULL) {
a1b388
-                g_timer_destroy (self->priv->server_timer);
a1b388
-        }
a1b388
-
a1b388
         G_OBJECT_CLASS (gdm_display_parent_class)->finalize (object);
a1b388
 }
a1b388
 
a1b388
 GDBusObjectSkeleton *
a1b388
 gdm_display_get_object_skeleton (GdmDisplay *self)
a1b388
 {
a1b388
         return self->priv->object_skeleton;
a1b388
 }
a1b388
 
a1b388
 static void
a1b388
 on_launch_environment_session_opened (GdmLaunchEnvironment *launch_environment,
a1b388
                                       GdmDisplay           *self)
a1b388
 {
a1b388
         char       *session_id;
a1b388
 
a1b388
         g_debug ("GdmDisplay: Greeter session opened");
a1b388
         session_id = gdm_launch_environment_get_session_id (launch_environment);
a1b388
         _gdm_display_set_session_id (self, session_id);
a1b388
         g_free (session_id);
a1b388
 }
a1b388
 
a1b388
 static void
a1b388
 on_launch_environment_session_started (GdmLaunchEnvironment *launch_environment,
a1b388
                                        GdmDisplay           *self)
a1b388
 {
a1b388
         g_debug ("GdmDisplay: Greeter started");
a1b388
 }
a1b388
 
a1b388
 static void
a1b388
 self_destruct (GdmDisplay *self)
a1b388
diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c
a1b388
index aae226750..35880563d 100644
a1b388
--- a/daemon/gdm-local-display-factory.c
a1b388
+++ b/daemon/gdm-local-display-factory.c
a1b388
@@ -39,61 +39,60 @@
a1b388
 #include "gdm-settings-keys.h"
a1b388
 #include "gdm-settings-direct.h"
a1b388
 #include "gdm-display-store.h"
a1b388
 #include "gdm-local-display.h"
a1b388
 #include "gdm-legacy-display.h"
a1b388
 
a1b388
 #define GDM_LOCAL_DISPLAY_FACTORY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_LOCAL_DISPLAY_FACTORY, GdmLocalDisplayFactoryPrivate))
a1b388
 
a1b388
 #define GDM_DBUS_PATH                       "/org/gnome/DisplayManager"
a1b388
 #define GDM_LOCAL_DISPLAY_FACTORY_DBUS_PATH GDM_DBUS_PATH "/LocalDisplayFactory"
a1b388
 #define GDM_MANAGER_DBUS_NAME               "org.gnome.DisplayManager.LocalDisplayFactory"
a1b388
 
a1b388
 #define MAX_DISPLAY_FAILURES 5
a1b388
 #define WAIT_TO_FINISH_TIMEOUT 10 /* seconds */
a1b388
 
a1b388
 struct GdmLocalDisplayFactoryPrivate
a1b388
 {
a1b388
         GdmDBusLocalDisplayFactory *skeleton;
a1b388
         GDBusConnection *connection;
a1b388
         GHashTable      *used_display_numbers;
a1b388
 
a1b388
         /* FIXME: this needs to be per seat? */
a1b388
         guint            num_failures;
a1b388
 
a1b388
         guint            seat_new_id;
a1b388
         guint            seat_removed_id;
a1b388
 
a1b388
 #if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
a1b388
         unsigned int     active_vt;
a1b388
         guint            active_vt_watch_id;
a1b388
-        guint            wait_to_finish_timeout_id;
a1b388
 #endif
a1b388
 };
a1b388
 
a1b388
 enum {
a1b388
         PROP_0,
a1b388
 };
a1b388
 
a1b388
 static void     gdm_local_display_factory_class_init    (GdmLocalDisplayFactoryClass *klass);
a1b388
 static void     gdm_local_display_factory_init          (GdmLocalDisplayFactory      *factory);
a1b388
 static void     gdm_local_display_factory_finalize      (GObject                     *object);
a1b388
 
a1b388
 static GdmDisplay *create_display                       (GdmLocalDisplayFactory      *factory,
a1b388
                                                          const char                  *seat_id,
a1b388
                                                          const char                  *session_type,
a1b388
                                                          gboolean                    initial_display);
a1b388
 
a1b388
 static void     on_display_status_changed               (GdmDisplay                  *display,
a1b388
                                                          GParamSpec                  *arg1,
a1b388
                                                          GdmLocalDisplayFactory      *factory);
a1b388
 
a1b388
 static gboolean gdm_local_display_factory_sync_seats    (GdmLocalDisplayFactory *factory);
a1b388
 static gpointer local_display_factory_object = NULL;
a1b388
 static gboolean lookup_by_session_id (const char *id,
a1b388
                                       GdmDisplay *display,
a1b388
                                       gpointer    user_data);
a1b388
 
a1b388
 G_DEFINE_TYPE (GdmLocalDisplayFactory, gdm_local_display_factory, GDM_TYPE_DISPLAY_FACTORY)
a1b388
 
a1b388
 GQuark
a1b388
 gdm_local_display_factory_error_quark (void)
a1b388
@@ -276,60 +275,79 @@ gdm_local_display_factory_create_transient_display (GdmLocalDisplayFactory *fact
a1b388
 static gboolean
a1b388
 finish_display_on_seat_if_waiting (GdmDisplayStore *display_store,
a1b388
                                    GdmDisplay      *display,
a1b388
                                    const char      *seat_id)
a1b388
 {
a1b388
         if (gdm_display_get_status (display) != GDM_DISPLAY_WAITING_TO_FINISH)
a1b388
                 return FALSE;
a1b388
 
a1b388
         g_debug ("GdmLocalDisplayFactory: finish background display\n");
a1b388
         gdm_display_stop_greeter_session (display);
a1b388
         gdm_display_unmanage (display);
a1b388
         gdm_display_finish (display);
a1b388
 
a1b388
         return FALSE;
a1b388
 }
a1b388
 
a1b388
 static void
a1b388
 finish_waiting_displays_on_seat (GdmLocalDisplayFactory *factory,
a1b388
                                  const char             *seat_id)
a1b388
 {
a1b388
         GdmDisplayStore *store;
a1b388
 
a1b388
         store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
a1b388
 
a1b388
         gdm_display_store_foreach (store,
a1b388
                                    (GdmDisplayStoreFunc) finish_display_on_seat_if_waiting,
a1b388
                                    (gpointer)
a1b388
                                    seat_id);
a1b388
 }
a1b388
 
a1b388
+static void
a1b388
+on_session_registered_cb (GObject *gobject,
a1b388
+                          GParamSpec *pspec,
a1b388
+                          gpointer user_data)
a1b388
+{
a1b388
+        GdmDisplay *display = GDM_DISPLAY (gobject);
a1b388
+        GdmLocalDisplayFactory *factory = GDM_LOCAL_DISPLAY_FACTORY (user_data);
a1b388
+        gboolean registered;
a1b388
+
a1b388
+        g_object_get (display, "session-registered", &registered, NULL);
a1b388
+
a1b388
+        if (!registered)
a1b388
+                return;
a1b388
+
a1b388
+        g_debug ("GdmLocalDisplayFactory: session registered on display, looking for any background displays to kill");
a1b388
+
a1b388
+        finish_waiting_displays_on_seat (factory, "seat0");
a1b388
+}
a1b388
+
a1b388
 static void
a1b388
 on_display_status_changed (GdmDisplay             *display,
a1b388
                            GParamSpec             *arg1,
a1b388
                            GdmLocalDisplayFactory *factory)
a1b388
 {
a1b388
         int              status;
a1b388
         int              num;
a1b388
         char            *seat_id = NULL;
a1b388
         char            *session_type = NULL;
a1b388
         char            *session_class = NULL;
a1b388
         gboolean         is_initial = TRUE;
a1b388
         gboolean         is_local = TRUE;
a1b388
 
a1b388
         num = -1;
a1b388
         gdm_display_get_x11_display_number (display, &num, NULL);
a1b388
 
a1b388
         g_object_get (display,
a1b388
                       "seat-id", &seat_id,
a1b388
                       "is-initial", &is_initial,
a1b388
                       "is-local", &is_local,
a1b388
                       "session-type", &session_type,
a1b388
                       "session-class", &session_class,
a1b388
                       NULL);
a1b388
 
a1b388
         status = gdm_display_get_status (display);
a1b388
 
a1b388
         g_debug ("GdmLocalDisplayFactory: display status changed: %d", status);
a1b388
         switch (status) {
a1b388
         case GDM_DISPLAY_FINISHED:
a1b388
                 /* remove the display number from factory->priv->used_display_numbers
a1b388
@@ -359,60 +377,67 @@ on_display_status_changed (GdmDisplay             *display,
a1b388
                 /* Create a new equivalent display if it was static */
a1b388
                 if (is_local) {
a1b388
 
a1b388
                         factory->priv->num_failures++;
a1b388
 
a1b388
                         if (factory->priv->num_failures > MAX_DISPLAY_FAILURES) {
a1b388
                                 /* oh shit */
a1b388
                                 g_warning ("GdmLocalDisplayFactory: maximum number of X display failures reached: check X server log for errors");
a1b388
                         } else {
a1b388
 #ifdef ENABLE_WAYLAND_SUPPORT
a1b388
                                 if (g_strcmp0 (session_type, "wayland") == 0) {
a1b388
                                         g_free (session_type);
a1b388
                                         session_type = NULL;
a1b388
 
a1b388
                                         /* workaround logind race for now
a1b388
                                          * bug 1643874
a1b388
                                          */
a1b388
                                         g_usleep (2 * G_USEC_PER_SEC);
a1b388
                                 }
a1b388
 
a1b388
 #endif
a1b388
                                 create_display (factory, seat_id, session_type, is_initial);
a1b388
                         }
a1b388
                 }
a1b388
                 break;
a1b388
         case GDM_DISPLAY_UNMANAGED:
a1b388
                 break;
a1b388
         case GDM_DISPLAY_PREPARED:
a1b388
                 break;
a1b388
         case GDM_DISPLAY_MANAGED:
a1b388
+#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
a1b388
+                g_signal_connect_object (display,
a1b388
+                                         "notify::session-registered",
a1b388
+                                         G_CALLBACK (on_session_registered_cb),
a1b388
+                                         factory,
a1b388
+                                         0);
a1b388
+#endif
a1b388
                 break;
a1b388
         case GDM_DISPLAY_WAITING_TO_FINISH:
a1b388
                 break;
a1b388
         default:
a1b388
                 g_assert_not_reached ();
a1b388
                 break;
a1b388
         }
a1b388
 
a1b388
         g_free (seat_id);
a1b388
         g_free (session_type);
a1b388
         g_free (session_class);
a1b388
 }
a1b388
 
a1b388
 static gboolean
a1b388
 lookup_by_seat_id (const char *id,
a1b388
                    GdmDisplay *display,
a1b388
                    gpointer    user_data)
a1b388
 {
a1b388
         const char *looking_for = user_data;
a1b388
         char *current;
a1b388
         gboolean res;
a1b388
 
a1b388
         g_object_get (G_OBJECT (display), "seat-id", &current, NULL);
a1b388
 
a1b388
         res = g_strcmp0 (current, looking_for) == 0;
a1b388
 
a1b388
         g_free(current);
a1b388
 
a1b388
         return res;
a1b388
 }
a1b388
@@ -587,100 +612,83 @@ on_seat_new (GDBusConnection *connection,
a1b388
 }
a1b388
 
a1b388
 static void
a1b388
 on_seat_removed (GDBusConnection *connection,
a1b388
                  const gchar     *sender_name,
a1b388
                  const gchar     *object_path,
a1b388
                  const gchar     *interface_name,
a1b388
                  const gchar     *signal_name,
a1b388
                  GVariant        *parameters,
a1b388
                  gpointer         user_data)
a1b388
 {
a1b388
         const char *seat;
a1b388
 
a1b388
         g_variant_get (parameters, "(&s&o)", &seat, NULL);
a1b388
         delete_display (GDM_LOCAL_DISPLAY_FACTORY (user_data), seat);
a1b388
 }
a1b388
 
a1b388
 #if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
a1b388
 static gboolean
a1b388
 lookup_by_session_id (const char *id,
a1b388
                       GdmDisplay *display,
a1b388
                       gpointer    user_data)
a1b388
 {
a1b388
         const char *looking_for = user_data;
a1b388
         const char *current;
a1b388
 
a1b388
         current = gdm_display_get_session_id (display);
a1b388
         return g_strcmp0 (current, looking_for) == 0;
a1b388
 }
a1b388
 
a1b388
-static gboolean
a1b388
-wait_to_finish_timeout (GdmLocalDisplayFactory *factory)
a1b388
-{
a1b388
-        finish_waiting_displays_on_seat (factory, "seat0");
a1b388
-        factory->priv->wait_to_finish_timeout_id = 0;
a1b388
-        return G_SOURCE_REMOVE;
a1b388
-}
a1b388
-
a1b388
 static void
a1b388
 maybe_stop_greeter_in_background (GdmLocalDisplayFactory *factory,
a1b388
                                   GdmDisplay             *display)
a1b388
 {
a1b388
         gboolean doing_initial_setup = FALSE;
a1b388
 
a1b388
         if (gdm_display_get_status (display) != GDM_DISPLAY_MANAGED) {
a1b388
                 g_debug ("GdmLocalDisplayFactory: login window not in managed state, so ignoring");
a1b388
                 return;
a1b388
         }
a1b388
 
a1b388
         g_object_get (G_OBJECT (display),
a1b388
                       "doing-initial-setup", &doing_initial_setup,
a1b388
                       NULL);
a1b388
 
a1b388
         /* we don't ever stop initial-setup implicitly */
a1b388
         if (doing_initial_setup) {
a1b388
                 g_debug ("GdmLocalDisplayFactory: login window is performing initial-setup, so ignoring");
a1b388
                 return;
a1b388
         }
a1b388
 
a1b388
         g_debug ("GdmLocalDisplayFactory: killing login window once its unused");
a1b388
         g_object_set (G_OBJECT (display), "status", GDM_DISPLAY_WAITING_TO_FINISH, NULL);
a1b388
-
a1b388
-        /* We stop the greeter after a timeout to avoid flicker */
a1b388
-        if (factory->priv->wait_to_finish_timeout_id != 0)
a1b388
-                g_source_remove (factory->priv->wait_to_finish_timeout_id);
a1b388
-
a1b388
-        factory->priv->wait_to_finish_timeout_id =
a1b388
-                g_timeout_add_seconds (WAIT_TO_FINISH_TIMEOUT,
a1b388
-                                       (GSourceFunc)wait_to_finish_timeout,
a1b388
-                                       factory);
a1b388
 }
a1b388
 
a1b388
 static gboolean
a1b388
 on_vt_changed (GIOChannel    *source,
a1b388
                GIOCondition   condition,
a1b388
                GdmLocalDisplayFactory *factory)
a1b388
 {
a1b388
         GIOStatus status;
a1b388
         g_autofree char *tty_of_active_vt = NULL;
a1b388
         g_autofree char *login_session_id = NULL;
a1b388
         g_autofree char *active_session_id = NULL;
a1b388
         unsigned int previous_vt, new_vt;
a1b388
         const char *session_type = NULL;
a1b388
         int ret, n_returned;
a1b388
 
a1b388
         g_debug ("GdmLocalDisplayFactory: received VT change event");
a1b388
         g_io_channel_seek_position (source, 0, G_SEEK_SET, NULL);
a1b388
 
a1b388
         if (condition & G_IO_PRI) {
a1b388
                 g_autoptr (GError) error = NULL;
a1b388
                 status = g_io_channel_read_line (source, &tty_of_active_vt, NULL, NULL, &error);
a1b388
 
a1b388
                 if (error != NULL) {
a1b388
                         g_warning ("could not read active VT from kernel: %s", error->message);
a1b388
                 }
a1b388
                 switch (status) {
a1b388
                         case G_IO_STATUS_ERROR:
a1b388
                             return G_SOURCE_REMOVE;
a1b388
                         case G_IO_STATUS_EOF:
a1b388
                             return G_SOURCE_REMOVE;
a1b388
@@ -722,61 +730,60 @@ on_vt_changed (GIOChannel    *source,
a1b388
         factory->priv->active_vt = new_vt;
a1b388
 
a1b388
         /* don't do anything at start up */
a1b388
         if (previous_vt == 0) {
a1b388
                 g_debug ("GdmLocalDisplayFactory: VT is %u at startup",
a1b388
                          factory->priv->active_vt);
a1b388
                 return G_SOURCE_CONTINUE;
a1b388
         }
a1b388
 
a1b388
         g_debug ("GdmLocalDisplayFactory: VT changed from %u to %u",
a1b388
                  previous_vt, factory->priv->active_vt);
a1b388
 
a1b388
         /* if the old VT was running a wayland login screen kill it
a1b388
          */
a1b388
         if (gdm_get_login_window_session_id ("seat0", &login_session_id)) {
a1b388
                 unsigned int login_window_vt;
a1b388
 
a1b388
                 ret = sd_session_get_vt (login_session_id, &login_window_vt);
a1b388
                 if (ret == 0 && login_window_vt != 0) {
a1b388
                         g_debug ("GdmLocalDisplayFactory: VT of login window is %u", login_window_vt);
a1b388
                         if (login_window_vt == previous_vt) {
a1b388
                                 GdmDisplayStore *store;
a1b388
                                 GdmDisplay *display;
a1b388
 
a1b388
                                 g_debug ("GdmLocalDisplayFactory: VT switched from login window");
a1b388
 
a1b388
                                 store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
a1b388
                                 display = gdm_display_store_find (store,
a1b388
                                                                   lookup_by_session_id,
a1b388
                                                                   (gpointer) login_session_id);
a1b388
-
a1b388
                                 if (display != NULL)
a1b388
                                         maybe_stop_greeter_in_background (factory, display);
a1b388
                         } else {
a1b388
                                 g_debug ("GdmLocalDisplayFactory: VT not switched from login window");
a1b388
                         }
a1b388
                 }
a1b388
         }
a1b388
 
a1b388
         /* if user jumped back to initial vt and it's empty put a login screen
a1b388
          * on it (unless a login screen is already running elsewhere, then
a1b388
          * jump to that login screen)
a1b388
          */
a1b388
         if (factory->priv->active_vt != GDM_INITIAL_VT) {
a1b388
                 g_debug ("GdmLocalDisplayFactory: active VT is not initial VT, so ignoring");
a1b388
                 return G_SOURCE_CONTINUE;
a1b388
         }
a1b388
 
a1b388
         if (gdm_local_display_factory_use_wayland ())
a1b388
                 session_type = "wayland";
a1b388
 
a1b388
         g_debug ("GdmLocalDisplayFactory: creating new display on seat0 because of VT change");
a1b388
 
a1b388
         create_display (factory, "seat0", session_type, TRUE);
a1b388
 
a1b388
         return G_SOURCE_CONTINUE;
a1b388
 }
a1b388
 #endif
a1b388
 
a1b388
 static void
a1b388
 gdm_local_display_factory_start_monitor (GdmLocalDisplayFactory *factory)
a1b388
@@ -805,64 +812,60 @@ gdm_local_display_factory_start_monitor (GdmLocalDisplayFactory *factory)
a1b388
                                                                              g_object_unref);
a1b388
 
a1b388
 #if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
a1b388
         io_channel = g_io_channel_new_file ("/sys/class/tty/tty0/active", "r", NULL);
a1b388
 
a1b388
         if (io_channel != NULL) {
a1b388
                 factory->priv->active_vt_watch_id =
a1b388
                         g_io_add_watch (io_channel,
a1b388
                                         G_IO_PRI,
a1b388
                                         (GIOFunc)
a1b388
                                         on_vt_changed,
a1b388
                                         factory);
a1b388
         }
a1b388
 #endif
a1b388
 }
a1b388
 
a1b388
 static void
a1b388
 gdm_local_display_factory_stop_monitor (GdmLocalDisplayFactory *factory)
a1b388
 {
a1b388
         if (factory->priv->seat_new_id) {
a1b388
                 g_dbus_connection_signal_unsubscribe (factory->priv->connection,
a1b388
                                                       factory->priv->seat_new_id);
a1b388
                 factory->priv->seat_new_id = 0;
a1b388
         }
a1b388
         if (factory->priv->seat_removed_id) {
a1b388
                 g_dbus_connection_signal_unsubscribe (factory->priv->connection,
a1b388
                                                       factory->priv->seat_removed_id);
a1b388
                 factory->priv->seat_removed_id = 0;
a1b388
         }
a1b388
 #if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
a1b388
-        if (factory->priv->wait_to_finish_timeout_id != 0) {
a1b388
-                g_source_remove (factory->priv->wait_to_finish_timeout_id);
a1b388
-                factory->priv->wait_to_finish_timeout_id = 0;
a1b388
-        }
a1b388
         if (factory->priv->active_vt_watch_id) {
a1b388
                 g_source_remove (factory->priv->active_vt_watch_id);
a1b388
                 factory->priv->active_vt_watch_id = 0;
a1b388
         }
a1b388
 #endif
a1b388
 }
a1b388
 
a1b388
 static void
a1b388
 on_display_added (GdmDisplayStore        *display_store,
a1b388
                   const char             *id,
a1b388
                   GdmLocalDisplayFactory *factory)
a1b388
 {
a1b388
         GdmDisplay *display;
a1b388
 
a1b388
         display = gdm_display_store_lookup (display_store, id);
a1b388
 
a1b388
         if (display != NULL) {
a1b388
                 g_signal_connect_object (display, "notify::status",
a1b388
                                          G_CALLBACK (on_display_status_changed),
a1b388
                                          factory,
a1b388
                                          0);
a1b388
 
a1b388
                 g_object_weak_ref (G_OBJECT (display), (GWeakNotify)on_display_disposed, factory);
a1b388
         }
a1b388
 }
a1b388
 
a1b388
 static void
a1b388
 on_display_removed (GdmDisplayStore        *display_store,
a1b388
                     GdmDisplay             *display,
a1b388
                     GdmLocalDisplayFactory *factory)
a1b388
diff --git a/daemon/gdm-session.c b/daemon/gdm-session.c
a1b388
index 5b76ba129..540a2534d 100644
a1b388
--- a/daemon/gdm-session.c
a1b388
+++ b/daemon/gdm-session.c
a1b388
@@ -2849,132 +2849,139 @@ on_start_program_cb (GdmDBusWorker *worker,
a1b388
 
a1b388
         self = conversation->session;
a1b388
         service_name = conversation->service_name;
a1b388
 
a1b388
         if (worked) {
a1b388
                 self->priv->session_pid = pid;
a1b388
                 self->priv->session_conversation = conversation;
a1b388
 
a1b388
                 g_debug ("GdmSession: Emitting 'session-started' signal with pid '%d'", pid);
a1b388
                 g_signal_emit (self, signals[SESSION_STARTED], 0, service_name, pid);
a1b388
         } else {
a1b388
                 gdm_session_stop_conversation (self, service_name);
a1b388
 
a1b388
                 g_debug ("GdmSession: Emitting 'session-start-failed' signal");
a1b388
                 g_signal_emit (self, signals[SESSION_START_FAILED], 0, service_name, error->message);
a1b388
         }
a1b388
 }
a1b388
 
a1b388
 void
a1b388
 gdm_session_start_session (GdmSession *self,
a1b388
                            const char *service_name)
a1b388
 {
a1b388
         GdmSessionConversation *conversation;
a1b388
         GdmSessionDisplayMode   display_mode;
a1b388
         gboolean                is_x11 = TRUE;
a1b388
         gboolean                run_launcher = FALSE;
a1b388
         gboolean                allow_remote_connections = FALSE;
a1b388
         gboolean                run_separate_bus = FALSE;
a1b388
         char                   *command;
a1b388
         char                   *program;
a1b388
+        gboolean               register_session;
a1b388
 
a1b388
         g_return_if_fail (GDM_IS_SESSION (self));
a1b388
         g_return_if_fail (self->priv->session_conversation == NULL);
a1b388
 
a1b388
         conversation = find_conversation_by_name (self, service_name);
a1b388
 
a1b388
         if (conversation == NULL) {
a1b388
                 g_warning ("GdmSession: Tried to start session of "
a1b388
                            "nonexistent conversation %s", service_name);
a1b388
                 return;
a1b388
         }
a1b388
 
a1b388
         stop_all_other_conversations (self, conversation, FALSE);
a1b388
 
a1b388
         display_mode = gdm_session_get_display_mode (self);
a1b388
 
a1b388
 #ifdef ENABLE_WAYLAND_SUPPORT
a1b388
         is_x11 = g_strcmp0 (self->priv->session_type, "wayland") != 0;
a1b388
 #endif
a1b388
 
a1b388
         if (display_mode == GDM_SESSION_DISPLAY_MODE_LOGIND_MANAGED ||
a1b388
             display_mode == GDM_SESSION_DISPLAY_MODE_NEW_VT) {
a1b388
                 run_launcher = TRUE;
a1b388
         }
a1b388
 
a1b388
         if (g_strcmp0 (self->priv->display_seat_id, "seat0") != 0 && !run_launcher) {
a1b388
                 run_separate_bus = TRUE;
a1b388
         }
a1b388
 
a1b388
+        register_session = !gdm_session_session_registers (self);
a1b388
+
a1b388
         if (self->priv->selected_program == NULL) {
a1b388
                 gboolean run_xsession_script;
a1b388
 
a1b388
                 command = get_session_command (self);
a1b388
 
a1b388
                 run_xsession_script = !gdm_session_bypasses_xsession (self);
a1b388
 
a1b388
                 if (self->priv->display_is_local) {
a1b388
                         gboolean disallow_tcp = TRUE;
a1b388
                         gdm_settings_direct_get_boolean (GDM_KEY_DISALLOW_TCP, &disallow_tcp);
a1b388
                         allow_remote_connections = !disallow_tcp;
a1b388
                 } else {
a1b388
                         allow_remote_connections = TRUE;
a1b388
                 }
a1b388
 
a1b388
                 if (run_launcher) {
a1b388
                         if (is_x11) {
a1b388
-                                program = g_strdup_printf (LIBEXECDIR "/gdm-x-session %s %s\"%s\"",
a1b388
+                                program = g_strdup_printf (LIBEXECDIR "/gdm-x-session %s%s %s\"%s\"",
a1b388
+                                                           register_session ? "--register-session " : "",
a1b388
                                                            run_xsession_script? "--run-script " : "",
a1b388
                                                            allow_remote_connections? "--allow-remote-connections " : "",
a1b388
                                                            command);
a1b388
                         } else {
a1b388
-                                program = g_strdup_printf (LIBEXECDIR "/gdm-wayland-session \"%s\"",
a1b388
+                                program = g_strdup_printf (LIBEXECDIR "/gdm-wayland-session %s\"%s\"",
a1b388
+                                                           register_session ? "--register-session " : "",
a1b388
                                                            command);
a1b388
                         }
a1b388
                 } else if (run_xsession_script) {
a1b388
                     if (run_separate_bus) {
a1b388
                             program = g_strdup_printf ("dbus-run-session -- " GDMCONFDIR "/Xsession \"%s\"", command);
a1b388
                     } else {
a1b388
                             program = g_strdup_printf (GDMCONFDIR "/Xsession \"%s\"", command);
a1b388
                     }
a1b388
                 } else {
a1b388
                         program = g_strdup (command);
a1b388
                 }
a1b388
 
a1b388
                 g_free (command);
a1b388
         } else {
a1b388
                 if (run_launcher) {
a1b388
                         if (is_x11) {
a1b388
-                            program = g_strdup_printf (LIBEXECDIR "/gdm-x-session \"%s\"",
a1b388
+                            program = g_strdup_printf (LIBEXECDIR "/gdm-x-session %s\"%s\"",
a1b388
+                                                       register_session ? "--register-session " : "",
a1b388
                                                        self->priv->selected_program);
a1b388
                         } else {
a1b388
-                                program = g_strdup_printf (LIBEXECDIR "/gdm-wayland-session \"%s\"",
a1b388
+                                program = g_strdup_printf (LIBEXECDIR "/gdm-wayland-session %s\"%s\"",
a1b388
+                                                           register_session ? "--register-session " : "",
a1b388
                                                            self->priv->selected_program);
a1b388
                         }
a1b388
                 } else {
a1b388
                         if (run_separate_bus) {
a1b388
                                 program = g_strdup_printf ("dbus-run-session -- %s",
a1b388
                                                            self->priv->selected_program);
a1b388
                         } else {
a1b388
                                 program = g_strdup (self->priv->selected_program);
a1b388
                         }
a1b388
                 }
a1b388
         }
a1b388
 
a1b388
         set_up_session_environment (self);
a1b388
         send_environment (self, conversation);
a1b388
 
a1b388
         gdm_dbus_worker_call_start_program (conversation->worker_proxy,
a1b388
                                             program,
a1b388
                                             conversation->worker_cancellable,
a1b388
                                             (GAsyncReadyCallback) on_start_program_cb,
a1b388
                                             conversation);
a1b388
         g_free (program);
a1b388
 }
a1b388
 
a1b388
 static void
a1b388
 stop_all_conversations (GdmSession *self)
a1b388
 {
a1b388
         stop_all_other_conversations (self, NULL, TRUE);
a1b388
 }
a1b388
 
a1b388
 static void
a1b388
@@ -3199,60 +3206,92 @@ gdm_session_is_wayland_session (GdmSession *self)
a1b388
                 }
a1b388
 
a1b388
                 if (full_path != NULL && strstr (full_path, "/wayland-sessions/") != NULL) {
a1b388
                         is_wayland_session = TRUE;
a1b388
                 }
a1b388
         }
a1b388
 
a1b388
 out:
a1b388
         g_debug ("GdmSession: checking if file '%s' is wayland session: %s", filename, is_wayland_session? "yes" : "no");
a1b388
 
a1b388
         return is_wayland_session;
a1b388
 }
a1b388
 #endif
a1b388
 
a1b388
 static void
a1b388
 update_session_type (GdmSession *self)
a1b388
 {
a1b388
 #ifdef ENABLE_WAYLAND_SUPPORT
a1b388
         gboolean is_wayland_session = FALSE;
a1b388
 
a1b388
         is_wayland_session = gdm_session_is_wayland_session (self);
a1b388
 
a1b388
         if (is_wayland_session) {
a1b388
                 set_session_type (self, "wayland");
a1b388
         } else {
a1b388
                 set_session_type (self, NULL);
a1b388
         }
a1b388
 #endif
a1b388
 }
a1b388
 
a1b388
+gboolean
a1b388
+gdm_session_session_registers (GdmSession *self)
a1b388
+{
a1b388
+        g_autoptr(GError) error = NULL;
a1b388
+        g_autoptr(GKeyFile) key_file = NULL;
a1b388
+        gboolean session_registers = FALSE;
a1b388
+        g_autofree char *filename = NULL;
a1b388
+
a1b388
+        g_return_val_if_fail (self != NULL, FALSE);
a1b388
+        g_return_val_if_fail (GDM_IS_SESSION (self), FALSE);
a1b388
+
a1b388
+        filename = get_session_filename (self);
a1b388
+
a1b388
+        key_file = load_key_file_for_file (self, filename, NULL, NULL);
a1b388
+
a1b388
+        session_registers = g_key_file_get_boolean (key_file,
a1b388
+                                                    G_KEY_FILE_DESKTOP_GROUP,
a1b388
+                                                    "X-GDM-SessionRegisters",
a1b388
+                                                    &error);
a1b388
+        if (!session_registers &&
a1b388
+            error != NULL &&
a1b388
+            !g_error_matches (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_KEY_NOT_FOUND)) {
a1b388
+                g_warning ("GdmSession: Couldn't read session file '%s'", filename);
a1b388
+                return FALSE;
a1b388
+        }
a1b388
+
a1b388
+        g_debug ("GdmSession: '%s' %s self", filename,
a1b388
+                 session_registers ? "registers" : "does not register");
a1b388
+
a1b388
+        return session_registers;
a1b388
+}
a1b388
+
a1b388
 gboolean
a1b388
 gdm_session_bypasses_xsession (GdmSession *self)
a1b388
 {
a1b388
         GError     *error;
a1b388
         GKeyFile   *key_file;
a1b388
         gboolean    res;
a1b388
         gboolean    bypasses_xsession = FALSE;
a1b388
         char       *filename = NULL;
a1b388
 
a1b388
         g_return_val_if_fail (self != NULL, FALSE);
a1b388
         g_return_val_if_fail (GDM_IS_SESSION (self), FALSE);
a1b388
 
a1b388
 #ifdef ENABLE_WAYLAND_SUPPORT
a1b388
         if (gdm_session_is_wayland_session (self)) {
a1b388
                 bypasses_xsession = TRUE;
a1b388
                 goto out;
a1b388
         }
a1b388
 #endif
a1b388
 
a1b388
         filename = get_session_filename (self);
a1b388
 
a1b388
         key_file = load_key_file_for_file (self, filename, "x11",  NULL);
a1b388
 
a1b388
         error = NULL;
a1b388
         res = g_key_file_has_key (key_file, G_KEY_FILE_DESKTOP_GROUP, "X-GDM-BypassXsession", NULL);
a1b388
         if (!res) {
a1b388
                 goto out;
a1b388
         } else {
a1b388
                 bypasses_xsession = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, "X-GDM-BypassXsession", &error);
a1b388
                 if (error) {
a1b388
diff --git a/daemon/gdm-session.h b/daemon/gdm-session.h
a1b388
index a22c09543..682d2c99f 100644
a1b388
--- a/daemon/gdm-session.h
a1b388
+++ b/daemon/gdm-session.h
a1b388
@@ -108,60 +108,61 @@ typedef struct
a1b388
         void (* conversation_started)        (GdmSession   *session,
a1b388
                                               const char   *service_name);
a1b388
         void (* conversation_stopped)        (GdmSession   *session,
a1b388
                                               const char   *service_name);
a1b388
         void (* setup_complete)              (GdmSession   *session,
a1b388
                                               const char   *service_name);
a1b388
 } GdmSessionClass;
a1b388
 
a1b388
 GType            gdm_session_get_type                 (void);
a1b388
 
a1b388
 GdmSession      *gdm_session_new                      (GdmSessionVerificationMode verification_mode,
a1b388
                                                        uid_t         allowed_user,
a1b388
                                                        const char   *display_name,
a1b388
                                                        const char   *display_hostname,
a1b388
                                                        const char   *display_device,
a1b388
                                                        const char   *display_seat_id,
a1b388
                                                        const char   *display_x11_authority_file,
a1b388
                                                        gboolean      display_is_local,
a1b388
                                                        const char * const *environment);
a1b388
 uid_t             gdm_session_get_allowed_user       (GdmSession     *session);
a1b388
 void              gdm_session_start_reauthentication (GdmSession *session,
a1b388
                                                       GPid        pid_of_caller,
a1b388
                                                       uid_t       uid_of_caller);
a1b388
 
a1b388
 const char       *gdm_session_get_server_address          (GdmSession     *session);
a1b388
 const char       *gdm_session_get_username                (GdmSession     *session);
a1b388
 const char       *gdm_session_get_display_device          (GdmSession     *session);
a1b388
 const char       *gdm_session_get_display_seat_id         (GdmSession     *session);
a1b388
 const char       *gdm_session_get_session_id              (GdmSession     *session);
a1b388
 gboolean          gdm_session_bypasses_xsession           (GdmSession     *session);
a1b388
+gboolean          gdm_session_session_registers           (GdmSession     *session);
a1b388
 GdmSessionDisplayMode gdm_session_get_display_mode  (GdmSession     *session);
a1b388
 
a1b388
 #ifdef ENABLE_WAYLAND_SUPPORT
a1b388
 void              gdm_session_set_ignore_wayland          (GdmSession *session,
a1b388
                                                            gboolean    ignore_wayland);
a1b388
 #endif
a1b388
 gboolean          gdm_session_start_conversation          (GdmSession *session,
a1b388
                                                            const char *service_name);
a1b388
 void              gdm_session_stop_conversation           (GdmSession *session,
a1b388
                                                            const char *service_name);
a1b388
 const char       *gdm_session_get_conversation_session_id (GdmSession *session,
a1b388
                                                            const char *service_name);
a1b388
 void              gdm_session_setup                       (GdmSession *session,
a1b388
                                                            const char *service_name);
a1b388
 void              gdm_session_setup_for_user              (GdmSession *session,
a1b388
                                                            const char *service_name,
a1b388
                                                            const char *username);
a1b388
 void              gdm_session_setup_for_program           (GdmSession *session,
a1b388
                                                            const char *service_name,
a1b388
                                                            const char *username,
a1b388
                                                            const char *log_file);
a1b388
 void              gdm_session_set_environment_variable    (GdmSession *session,
a1b388
                                                            const char *key,
a1b388
                                                            const char *value);
a1b388
 void              gdm_session_send_environment            (GdmSession *self,
a1b388
                                                            const char *service_name);
a1b388
 void              gdm_session_reset                       (GdmSession *session);
a1b388
 void              gdm_session_cancel                      (GdmSession *session);
a1b388
 void              gdm_session_authenticate                (GdmSession *session,
a1b388
                                                            const char *service_name);
a1b388
diff --git a/daemon/gdm-wayland-session.c b/daemon/gdm-wayland-session.c
a1b388
index 94f49e19c..35679b194 100644
a1b388
--- a/daemon/gdm-wayland-session.c
a1b388
+++ b/daemon/gdm-wayland-session.c
a1b388
@@ -18,68 +18,71 @@
a1b388
  * 02110-1301, USA.
a1b388
  */
a1b388
 #include "config.h"
a1b388
 
a1b388
 #include <locale.h>
a1b388
 #include <sysexits.h>
a1b388
 
a1b388
 #include "gdm-common.h"
a1b388
 #include "gdm-settings-direct.h"
a1b388
 #include "gdm-settings-keys.h"
a1b388
 #include "gdm-log.h"
a1b388
 
a1b388
 #include "gdm-manager-glue.h"
a1b388
 
a1b388
 #include <glib/gi18n.h>
a1b388
 #include <glib/gstdio.h>
a1b388
 #include <glib-unix.h>
a1b388
 #include <glib.h>
a1b388
 
a1b388
 #include <gio/gunixinputstream.h>
a1b388
 
a1b388
 #define BUS_ADDRESS_FILENO (STDERR_FILENO + 1)
a1b388
 
a1b388
 typedef struct
a1b388
 {
a1b388
         GdmSettings  *settings;
a1b388
         GCancellable *cancellable;
a1b388
 
a1b388
         GSubprocess     *bus_subprocess;
a1b388
         GDBusConnection *bus_connection;
a1b388
+        GdmDBusManager  *display_manager_proxy;
a1b388
         char            *bus_address;
a1b388
 
a1b388
         char           **environment;
a1b388
 
a1b388
         GSubprocess  *session_subprocess;
a1b388
         char         *session_command;
a1b388
         int           session_exit_status;
a1b388
 
a1b388
+        guint         register_session_id;
a1b388
+
a1b388
         GMainLoop    *main_loop;
a1b388
 
a1b388
         guint32       debug_enabled : 1;
a1b388
 } State;
a1b388
 
a1b388
 static void
a1b388
 on_bus_finished (GSubprocess  *subprocess,
a1b388
                  GAsyncResult *result,
a1b388
                  State        *state)
a1b388
 {
a1b388
         gboolean cancelled;
a1b388
 
a1b388
         cancelled = !g_subprocess_wait_finish (subprocess, result, NULL);
a1b388
 
a1b388
         if (cancelled) {
a1b388
                 goto out;
a1b388
         }
a1b388
 
a1b388
         if (g_subprocess_get_if_exited (subprocess)) {
a1b388
                 int exit_status;
a1b388
 
a1b388
                 exit_status = g_subprocess_get_exit_status (subprocess);
a1b388
 
a1b388
                 g_debug ("message bus exited with status %d", exit_status);
a1b388
         } else {
a1b388
                 int signal_number;
a1b388
 
a1b388
                 signal_number = g_subprocess_get_term_sig (subprocess);
a1b388
                 g_debug ("message bus was killed with status %d", signal_number);
a1b388
         }
a1b388
@@ -358,140 +361,170 @@ out:
a1b388
 }
a1b388
 
a1b388
 static void
a1b388
 signal_subprocesses (State *state)
a1b388
 {
a1b388
         if (state->session_subprocess != NULL) {
a1b388
                 g_subprocess_send_signal (state->session_subprocess, SIGTERM);
a1b388
         }
a1b388
 
a1b388
         if (state->bus_subprocess != NULL) {
a1b388
                 g_subprocess_send_signal (state->bus_subprocess, SIGTERM);
a1b388
         }
a1b388
 }
a1b388
 
a1b388
 static void
a1b388
 wait_on_subprocesses (State *state)
a1b388
 {
a1b388
         if (state->bus_subprocess != NULL) {
a1b388
                 g_subprocess_wait (state->bus_subprocess, NULL, NULL);
a1b388
         }
a1b388
 
a1b388
         if (state->session_subprocess != NULL) {
a1b388
                 g_subprocess_wait (state->session_subprocess, NULL, NULL);
a1b388
         }
a1b388
 }
a1b388
 
a1b388
 static gboolean
a1b388
 register_display (State        *state,
a1b388
                   GCancellable *cancellable)
a1b388
 {
a1b388
-        GdmDBusManager  *manager = NULL;
a1b388
         GError          *error = NULL;
a1b388
         gboolean         registered = FALSE;
a1b388
         GVariantBuilder  details;
a1b388
 
a1b388
-        manager = gdm_dbus_manager_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
a1b388
-                                                           G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
a1b388
-                                                           G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
a1b388
-                                                           "org.gnome.DisplayManager",
a1b388
-                                                           "/org/gnome/DisplayManager/Manager",
a1b388
-                                                           cancellable,
a1b388
-                                                           &error);
a1b388
-
a1b388
-        if (!manager) {
a1b388
-                g_debug ("could not contact display manager: %s", error->message);
a1b388
-                g_error_free (error);
a1b388
-                goto out;
a1b388
-        }
a1b388
-
a1b388
         g_variant_builder_init (&details, G_VARIANT_TYPE ("a{ss}"));
a1b388
         g_variant_builder_add (&details, "{ss}", "session-type", "wayland");
a1b388
 
a1b388
-        registered = gdm_dbus_manager_call_register_display_sync (manager,
a1b388
+        registered = gdm_dbus_manager_call_register_display_sync (state->display_manager_proxy,
a1b388
                                                                   g_variant_builder_end (&details),
a1b388
                                                                   cancellable,
a1b388
                                                                   &error);
a1b388
         if (error != NULL) {
a1b388
                 g_debug ("Could not register display: %s", error->message);
a1b388
                 g_error_free (error);
a1b388
         }
a1b388
 
a1b388
-out:
a1b388
-        g_clear_object (&manager);
a1b388
         return registered;
a1b388
 }
a1b388
 
a1b388
 static void
a1b388
 init_state (State **state)
a1b388
 {
a1b388
         static State state_allocation;
a1b388
 
a1b388
         *state = &state_allocation;
a1b388
 }
a1b388
 
a1b388
 static void
a1b388
 clear_state (State **out_state)
a1b388
 {
a1b388
         State *state = *out_state;
a1b388
 
a1b388
         g_clear_object (&state->cancellable);
a1b388
         g_clear_object (&state->bus_connection);
a1b388
         g_clear_object (&state->session_subprocess);
a1b388
         g_clear_pointer (&state->environment, g_strfreev);
a1b388
         g_clear_pointer (&state->main_loop, g_main_loop_unref);
a1b388
+        g_clear_handle_id (&state->register_session_id, g_source_remove);
a1b388
         *out_state = NULL;
a1b388
 }
a1b388
 
a1b388
 static gboolean
a1b388
 on_sigterm (State *state)
a1b388
 {
a1b388
         g_cancellable_cancel (state->cancellable);
a1b388
 
a1b388
         if (g_main_loop_is_running (state->main_loop)) {
a1b388
                 g_main_loop_quit (state->main_loop);
a1b388
         }
a1b388
 
a1b388
         return G_SOURCE_CONTINUE;
a1b388
 }
a1b388
 
a1b388
+static gboolean
a1b388
+register_session_timeout_cb (gpointer user_data)
a1b388
+{
a1b388
+        State *state;
a1b388
+        GError *error = NULL;
a1b388
+
a1b388
+        state = (State *) user_data;
a1b388
+
a1b388
+        gdm_dbus_manager_call_register_session_sync (state->display_manager_proxy,
a1b388
+                                                     g_variant_new ("a{sv}", NULL),
a1b388
+                                                     state->cancellable,
a1b388
+                                                     &error);
a1b388
+
a1b388
+        if (error != NULL) {
a1b388
+                g_warning ("Could not register session: %s", error->message);
a1b388
+                g_error_free (error);
a1b388
+        }
a1b388
+
a1b388
+        return G_SOURCE_REMOVE;
a1b388
+}
a1b388
+
a1b388
+static gboolean
a1b388
+connect_to_display_manager (State *state)
a1b388
+{
a1b388
+        g_autoptr (GError) error = NULL;
a1b388
+
a1b388
+        state->display_manager_proxy = gdm_dbus_manager_proxy_new_for_bus_sync (
a1b388
+                G_BUS_TYPE_SYSTEM,
a1b388
+                G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
a1b388
+                "org.gnome.DisplayManager",
a1b388
+                "/org/gnome/DisplayManager/Manager",
a1b388
+                state->cancellable,
a1b388
+                &error);
a1b388
+
a1b388
+        if (state->display_manager_proxy == NULL) {
a1b388
+                g_printerr ("gdm-wayland-session: could not contact display manager: %s\n",
a1b388
+                            error->message);
a1b388
+                return FALSE;
a1b388
+        }
a1b388
+
a1b388
+        return TRUE;
a1b388
+}
a1b388
+
a1b388
 int
a1b388
 main (int    argc,
a1b388
       char **argv)
a1b388
 {
a1b388
         State           *state = NULL;
a1b388
         GOptionContext  *context = NULL;
a1b388
         static char    **args = NULL;
a1b388
         gboolean         debug = FALSE;
a1b388
         gboolean         ret;
a1b388
         int              exit_status = EX_OK;
a1b388
+        static gboolean  register_session = FALSE;
a1b388
+
a1b388
         static GOptionEntry entries []   = {
a1b388
+                { "register-session", 0, 0, G_OPTION_ARG_NONE, &register_session, "Register session after a delay", NULL },
a1b388
                 { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &args, "", "" },
a1b388
                 { NULL }
a1b388
         };
a1b388
 
a1b388
         bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
a1b388
         textdomain (GETTEXT_PACKAGE);
a1b388
         setlocale (LC_ALL, "");
a1b388
 
a1b388
         gdm_log_init ();
a1b388
 
a1b388
         context = g_option_context_new (_("GNOME Display Manager Wayland Session Launcher"));
a1b388
         g_option_context_add_main_entries (context, entries, NULL);
a1b388
 
a1b388
         g_option_context_parse (context, &argc, &argv, NULL);
a1b388
         g_option_context_free (context);
a1b388
 
a1b388
         if (args == NULL || args[0] == NULL || args[1] != NULL) {
a1b388
                 g_warning ("gdm-wayland-session takes one argument (the session)");
a1b388
                 exit_status = EX_USAGE;
a1b388
                 goto out;
a1b388
         }
a1b388
 
a1b388
         init_state (&state);
a1b388
 
a1b388
         state->session_command = args[0];
a1b388
 
a1b388
         state->settings = gdm_settings_new ();
a1b388
         ret = gdm_settings_direct_init (state->settings, DATADIR "/gdm/gdm.schemas", "/");
a1b388
 
a1b388
         if (!ret) {
a1b388
@@ -501,55 +534,67 @@ main (int    argc,
a1b388
         }
a1b388
 
a1b388
         gdm_settings_direct_get_boolean (GDM_KEY_DEBUG, &debug);
a1b388
         state->debug_enabled = debug;
a1b388
 
a1b388
         gdm_log_set_debug (debug);
a1b388
 
a1b388
         state->main_loop = g_main_loop_new (NULL, FALSE);
a1b388
         state->cancellable = g_cancellable_new ();
a1b388
 
a1b388
         g_unix_signal_add (SIGTERM, (GSourceFunc) on_sigterm, state);
a1b388
 
a1b388
         ret = spawn_bus (state, state->cancellable);
a1b388
 
a1b388
         if (!ret) {
a1b388
                 g_printerr ("Unable to run session message bus\n");
a1b388
                 exit_status = EX_SOFTWARE;
a1b388
                 goto out;
a1b388
         }
a1b388
 
a1b388
         import_environment (state, state->cancellable);
a1b388
 
a1b388
         ret = spawn_session (state, state->cancellable);
a1b388
 
a1b388
         if (!ret) {
a1b388
                 g_printerr ("Unable to run session\n");
a1b388
                 exit_status = EX_SOFTWARE;
a1b388
                 goto out;
a1b388
         }
a1b388
 
a1b388
+        if (!connect_to_display_manager (state))
a1b388
+                goto out;
a1b388
+
a1b388
         ret = register_display (state, state->cancellable);
a1b388
 
a1b388
         if (!ret) {
a1b388
                 g_printerr ("Unable to register display with display manager\n");
a1b388
                 exit_status = EX_SOFTWARE;
a1b388
                 goto out;
a1b388
         }
a1b388
 
a1b388
+        if (register_session) {
a1b388
+                g_debug ("gdm-wayland-session: Will register session in %d seconds", REGISTER_SESSION_TIMEOUT);
a1b388
+                state->register_session_id = g_timeout_add_seconds (REGISTER_SESSION_TIMEOUT,
a1b388
+                                                                    register_session_timeout_cb,
a1b388
+                                                                    state);
a1b388
+        } else {
a1b388
+                g_debug ("gdm-wayland-session: Session will register itself");
a1b388
+        }
a1b388
+
a1b388
         g_main_loop_run (state->main_loop);
a1b388
 
a1b388
         /* Only use exit status of session if we're here because it exit */
a1b388
 
a1b388
         if (state->session_subprocess == NULL) {
a1b388
                 exit_status = state->session_exit_status;
a1b388
         }
a1b388
 
a1b388
 out:
a1b388
         if (state != NULL) {
a1b388
                 signal_subprocesses (state);
a1b388
                 wait_on_subprocesses (state);
a1b388
                 clear_state (&state);
a1b388
         }
a1b388
 
a1b388
         return exit_status;
a1b388
 }
a1b388
diff --git a/daemon/gdm-x-session.c b/daemon/gdm-x-session.c
a1b388
index d8e3c7d53..f0082fdc6 100644
a1b388
--- a/daemon/gdm-x-session.c
a1b388
+++ b/daemon/gdm-x-session.c
a1b388
@@ -24,68 +24,71 @@
a1b388
 
a1b388
 #include "gdm-common.h"
a1b388
 #include "gdm-settings-direct.h"
a1b388
 #include "gdm-settings-keys.h"
a1b388
 #include "gdm-log.h"
a1b388
 
a1b388
 #include "gdm-manager-glue.h"
a1b388
 
a1b388
 #include <glib/gi18n.h>
a1b388
 #include <glib/gstdio.h>
a1b388
 #include <glib-unix.h>
a1b388
 #include <glib.h>
a1b388
 #include <gio/gunixinputstream.h>
a1b388
 #include <glib-unix.h>
a1b388
 #include <X11/Xauth.h>
a1b388
 
a1b388
 #define DISPLAY_FILENO (STDERR_FILENO + 1)
a1b388
 #define BUS_ADDRESS_FILENO (DISPLAY_FILENO + 1)
a1b388
 
a1b388
 typedef struct
a1b388
 {
a1b388
         GdmSettings  *settings;
a1b388
         GCancellable *cancellable;
a1b388
 
a1b388
         GSubprocess  *x_subprocess;
a1b388
         char         *auth_file;
a1b388
         char         *display_name;
a1b388
 
a1b388
         GSubprocess     *bus_subprocess;
a1b388
         GDBusConnection *bus_connection;
a1b388
+        GdmDBusManager  *display_manager_proxy;
a1b388
         char            *bus_address;
a1b388
 
a1b388
         char           **environment;
a1b388
 
a1b388
         GSubprocess  *session_subprocess;
a1b388
         char         *session_command;
a1b388
         int           session_exit_status;
a1b388
 
a1b388
+        guint         register_session_id;
a1b388
+
a1b388
         GMainLoop    *main_loop;
a1b388
 
a1b388
         guint32       debug_enabled : 1;
a1b388
 } State;
a1b388
 
a1b388
 static FILE *
a1b388
 create_auth_file (char **filename)
a1b388
 {
a1b388
         char *auth_dir = NULL;
a1b388
         char *auth_file = NULL;
a1b388
         int fd;
a1b388
         FILE *fp = NULL;
a1b388
 
a1b388
         auth_dir = g_build_filename (g_get_user_runtime_dir (),
a1b388
                                      "gdm",
a1b388
                                      NULL);
a1b388
 
a1b388
         g_mkdir_with_parents (auth_dir, 0711);
a1b388
         auth_file = g_build_filename (auth_dir, "Xauthority", NULL);
a1b388
         g_clear_pointer (&auth_dir, g_free);
a1b388
 
a1b388
         fd = g_open (auth_file, O_RDWR | O_CREAT | O_TRUNC, 0700);
a1b388
 
a1b388
         if (fd < 0) {
a1b388
                 g_debug ("could not open %s to store auth cookie: %m",
a1b388
                          auth_file);
a1b388
                 g_clear_pointer (&auth_file, g_free);
a1b388
                 goto out;
a1b388
         }
a1b388
 
a1b388
@@ -711,148 +714,178 @@ signal_subprocesses (State *state)
a1b388
 
a1b388
         if (state->bus_subprocess != NULL) {
a1b388
                 g_subprocess_send_signal (state->bus_subprocess, SIGTERM);
a1b388
         }
a1b388
 
a1b388
         if (state->x_subprocess != NULL) {
a1b388
                 g_subprocess_send_signal (state->x_subprocess, SIGTERM);
a1b388
         }
a1b388
 }
a1b388
 
a1b388
 static void
a1b388
 wait_on_subprocesses (State *state)
a1b388
 {
a1b388
         if (state->x_subprocess != NULL) {
a1b388
                 g_subprocess_wait (state->x_subprocess, NULL, NULL);
a1b388
         }
a1b388
 
a1b388
         if (state->bus_subprocess != NULL) {
a1b388
                 g_subprocess_wait (state->bus_subprocess, NULL, NULL);
a1b388
         }
a1b388
 
a1b388
         if (state->session_subprocess != NULL) {
a1b388
                 g_subprocess_wait (state->session_subprocess, NULL, NULL);
a1b388
         }
a1b388
 }
a1b388
 
a1b388
 static gboolean
a1b388
 register_display (State        *state,
a1b388
                   GCancellable *cancellable)
a1b388
 {
a1b388
-        GdmDBusManager  *manager = NULL;
a1b388
         GError          *error = NULL;
a1b388
         gboolean         registered = FALSE;
a1b388
         GVariantBuilder  details;
a1b388
 
a1b388
-        manager = gdm_dbus_manager_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
a1b388
-                                                           G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
a1b388
-                                                           G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
a1b388
-                                                           "org.gnome.DisplayManager",
a1b388
-                                                           "/org/gnome/DisplayManager/Manager",
a1b388
-                                                           cancellable,
a1b388
-                                                           &error);
a1b388
-
a1b388
-        if (!manager) {
a1b388
-                g_debug ("could not contact display manager: %s", error->message);
a1b388
-                g_error_free (error);
a1b388
-                goto out;
a1b388
-        }
a1b388
-
a1b388
         g_variant_builder_init (&details, G_VARIANT_TYPE ("a{ss}"));
a1b388
         g_variant_builder_add (&details, "{ss}", "session-type", "x11");
a1b388
         g_variant_builder_add (&details, "{ss}", "x11-display-name", state->display_name);
a1b388
 
a1b388
-        registered = gdm_dbus_manager_call_register_display_sync (manager,
a1b388
+        registered = gdm_dbus_manager_call_register_display_sync (state->display_manager_proxy,
a1b388
                                                                   g_variant_builder_end (&details),
a1b388
                                                                   cancellable,
a1b388
                                                                   &error);
a1b388
         if (error != NULL) {
a1b388
                 g_debug ("Could not register display: %s", error->message);
a1b388
                 g_error_free (error);
a1b388
         }
a1b388
 
a1b388
-out:
a1b388
-        g_clear_object (&manager);
a1b388
         return registered;
a1b388
 }
a1b388
 
a1b388
 static void
a1b388
 init_state (State **state)
a1b388
 {
a1b388
         static State state_allocation;
a1b388
 
a1b388
         *state = &state_allocation;
a1b388
 }
a1b388
 
a1b388
 static void
a1b388
 clear_state (State **out_state)
a1b388
 {
a1b388
         State *state = *out_state;
a1b388
 
a1b388
         g_clear_object (&state->cancellable);
a1b388
         g_clear_object (&state->bus_connection);
a1b388
         g_clear_object (&state->session_subprocess);
a1b388
         g_clear_object (&state->x_subprocess);
a1b388
         g_clear_pointer (&state->environment, g_strfreev);
a1b388
         g_clear_pointer (&state->auth_file, g_free);
a1b388
         g_clear_pointer (&state->display_name, g_free);
a1b388
         g_clear_pointer (&state->main_loop, g_main_loop_unref);
a1b388
+        g_clear_handle_id (&state->register_session_id, g_source_remove);
a1b388
         *out_state = NULL;
a1b388
 }
a1b388
 
a1b388
 static gboolean
a1b388
 on_sigterm (State *state)
a1b388
 {
a1b388
         g_cancellable_cancel (state->cancellable);
a1b388
 
a1b388
         if (g_main_loop_is_running (state->main_loop)) {
a1b388
                 g_main_loop_quit (state->main_loop);
a1b388
         }
a1b388
 
a1b388
         return G_SOURCE_CONTINUE;
a1b388
 }
a1b388
 
a1b388
+static gboolean
a1b388
+register_session_timeout_cb (gpointer user_data)
a1b388
+{
a1b388
+        State *state;
a1b388
+        GError *error = NULL;
a1b388
+
a1b388
+        state = (State *) user_data;
a1b388
+
a1b388
+        gdm_dbus_manager_call_register_session_sync (state->display_manager_proxy,
a1b388
+                                                     g_variant_new ("a{sv}", NULL),
a1b388
+                                                     state->cancellable,
a1b388
+                                                     &error);
a1b388
+
a1b388
+        if (error != NULL) {
a1b388
+                g_warning ("Could not register session: %s", error->message);
a1b388
+                g_error_free (error);
a1b388
+        }
a1b388
+
a1b388
+        return G_SOURCE_REMOVE;
a1b388
+}
a1b388
+
a1b388
+static gboolean
a1b388
+connect_to_display_manager (State *state)
a1b388
+{
a1b388
+        g_autoptr (GError) error = NULL;
a1b388
+
a1b388
+        state->display_manager_proxy = gdm_dbus_manager_proxy_new_for_bus_sync (
a1b388
+                G_BUS_TYPE_SYSTEM,
a1b388
+                G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
a1b388
+                "org.gnome.DisplayManager",
a1b388
+                "/org/gnome/DisplayManager/Manager",
a1b388
+                state->cancellable,
a1b388
+                &error);
a1b388
+
a1b388
+        if (state->display_manager_proxy == NULL) {
a1b388
+                g_printerr ("gdm-x-session: could not contact display manager: %s\n",
a1b388
+                            error->message);
a1b388
+                return FALSE;
a1b388
+        }
a1b388
+
a1b388
+        return TRUE;
a1b388
+}
a1b388
+
a1b388
 int
a1b388
 main (int    argc,
a1b388
       char **argv)
a1b388
 {
a1b388
         State           *state = NULL;
a1b388
         GOptionContext  *context = NULL;
a1b388
         static char    **args = NULL;
a1b388
         static gboolean  run_script = FALSE;
a1b388
         static gboolean  allow_remote_connections = FALSE;
a1b388
         gboolean         debug = FALSE;
a1b388
         gboolean         ret;
a1b388
         int              exit_status = EX_OK;
a1b388
+        static gboolean  register_session = FALSE;
a1b388
+
a1b388
         static GOptionEntry entries []   = {
a1b388
                 { "run-script", 'r', 0, G_OPTION_ARG_NONE, &run_script, N_("Run program through /etc/gdm/Xsession wrapper script"), NULL },
a1b388
                 { "allow-remote-connections", 'a', 0, G_OPTION_ARG_NONE, &allow_remote_connections, N_("Listen on TCP socket"), NULL },
a1b388
+                { "register-session", 0, 0, G_OPTION_ARG_NONE, &register_session, "Register session after a delay", NULL },
a1b388
                 { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &args, "", "" },
a1b388
                 { NULL }
a1b388
         };
a1b388
 
a1b388
         bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
a1b388
         textdomain (GETTEXT_PACKAGE);
a1b388
         setlocale (LC_ALL, "");
a1b388
 
a1b388
         gdm_log_init ();
a1b388
 
a1b388
         context = g_option_context_new (_("GNOME Display Manager X Session Launcher"));
a1b388
         g_option_context_add_main_entries (context, entries, NULL);
a1b388
 
a1b388
         g_option_context_parse (context, &argc, &argv, NULL);
a1b388
         g_option_context_free (context);
a1b388
 
a1b388
         if (args == NULL || args[0] == NULL || args[1] != NULL) {
a1b388
                 g_warning ("gdm-x-session takes one argument (the session)");
a1b388
                 exit_status = EX_USAGE;
a1b388
                 goto out;
a1b388
         }
a1b388
 
a1b388
         init_state (&state);
a1b388
 
a1b388
         state->session_command = args[0];
a1b388
 
a1b388
         state->settings = gdm_settings_new ();
a1b388
         ret = gdm_settings_direct_init (state->settings, DATADIR "/gdm/gdm.schemas", "/");
a1b388
 
a1b388
         if (!ret) {
a1b388
@@ -870,63 +903,75 @@ main (int    argc,
a1b388
         state->cancellable = g_cancellable_new ();
a1b388
 
a1b388
         g_unix_signal_add (SIGTERM, (GSourceFunc) on_sigterm, state);
a1b388
 
a1b388
         ret = spawn_x_server (state, allow_remote_connections, state->cancellable);
a1b388
 
a1b388
         if (!ret) {
a1b388
                 g_printerr ("Unable to run X server\n");
a1b388
                 exit_status = EX_SOFTWARE;
a1b388
                 goto out;
a1b388
         }
a1b388
 
a1b388
         ret = spawn_bus (state, state->cancellable);
a1b388
 
a1b388
         if (!ret) {
a1b388
                 g_printerr ("Unable to run session message bus\n");
a1b388
                 exit_status = EX_SOFTWARE;
a1b388
                 goto out;
a1b388
         }
a1b388
 
a1b388
         import_environment (state, state->cancellable);
a1b388
 
a1b388
         ret = update_bus_environment (state, state->cancellable);
a1b388
 
a1b388
         if (!ret) {
a1b388
                 g_printerr ("Unable to update bus environment\n");
a1b388
                 exit_status = EX_SOFTWARE;
a1b388
                 goto out;
a1b388
         }
a1b388
 
a1b388
+        if (!connect_to_display_manager (state))
a1b388
+                goto out;
a1b388
+
a1b388
         ret = register_display (state, state->cancellable);
a1b388
 
a1b388
         if (!ret) {
a1b388
                 g_printerr ("Unable to register display with display manager\n");
a1b388
                 exit_status = EX_SOFTWARE;
a1b388
                 goto out;
a1b388
         }
a1b388
 
a1b388
         ret = spawn_session (state, run_script, state->cancellable);
a1b388
 
a1b388
         if (!ret) {
a1b388
                 g_printerr ("Unable to run session\n");
a1b388
                 exit_status = EX_SOFTWARE;
a1b388
                 goto out;
a1b388
         }
a1b388
 
a1b388
+        if (register_session) {
a1b388
+                g_debug ("gdm-x-session: Will register session in %d seconds", REGISTER_SESSION_TIMEOUT);
a1b388
+                state->register_session_id = g_timeout_add_seconds (REGISTER_SESSION_TIMEOUT,
a1b388
+                                                                    register_session_timeout_cb,
a1b388
+                                                                    state);
a1b388
+        } else {
a1b388
+                g_debug ("gdm-x-session: Session will register itself");
a1b388
+        }
a1b388
+
a1b388
         g_main_loop_run (state->main_loop);
a1b388
 
a1b388
         /* Only use exit status of session if we're here because it exit */
a1b388
 
a1b388
         if (state->session_subprocess == NULL) {
a1b388
                 exit_status = state->session_exit_status;
a1b388
         }
a1b388
 
a1b388
 out:
a1b388
         if (state != NULL) {
a1b388
                 signal_subprocesses (state);
a1b388
                 wait_on_subprocesses (state);
a1b388
                 clear_state (&state);
a1b388
         }
a1b388
 
a1b388
         return exit_status;
a1b388
 }
a1b388
-- 
a1b388
2.27.0
a1b388