[gdm/wip/wayland-rebase: 7/8] daemon: support launching sessions on separate VT



commit 3a92a3b69d997f0a9b4626601e28279219ef6680
Author: Ray Strode <rstrode redhat com>
Date:   Mon Sep 16 17:19:26 2013 -0400

    daemon: support launching sessions on separate VT
    
    If an xsession file sets X-GDM-NeedsVT to true, then GDM will
    now automatically allocate a new VT for that session and jump to
    it before starting the session.  Once the session completes, the
    worker will automatically jump back to the VT it started on.
    
    This will be useful for getting mutter-launch to be able to launch
    a gnome-shell wayland sesssion.  Longer term, I think mutter-launch
    will go away and its functionality will get moved into logind.

 daemon/gdm-display.c          |   47 ++++++++++++++
 daemon/gdm-display.h          |    8 +++
 daemon/gdm-manager.c          |   53 ++++++++++++++++
 daemon/gdm-session-worker.c   |  135 +++++++++++++++++++++++++++++++++++++++-
 daemon/gdm-session-worker.xml |    3 +
 daemon/gdm-session.c          |   58 ++++++++++++++++++
 daemon/gdm-session.h          |    1 +
 daemon/gdm-simple-slave.c     |   11 +++
 daemon/gdm-slave.c            |   27 ++++++++
 daemon/gdm-slave.h            |    1 +
 daemon/gdm-slave.xml          |    3 +
 11 files changed, 343 insertions(+), 4 deletions(-)
---
diff --git a/daemon/gdm-display.c b/daemon/gdm-display.c
index 07240e9..2b23492 100644
--- a/daemon/gdm-display.c
+++ b/daemon/gdm-display.c
@@ -1709,6 +1709,53 @@ gdm_display_start_initial_session_finish (GdmDisplay    *display,
 }
 
 static void
+on_slave_initial_session_reset (GdmDBusSlave *slave,
+                                GAsyncResult *result,
+                                GTask        *task)
+{
+        GError *error = NULL;
+
+        if (!gdm_dbus_slave_call_reset_initial_session_finish (slave, result, &error)) {
+                g_task_return_error (task, error);
+                return;
+        }
+
+        g_debug ("GdmDisplay: slave reset initial session");
+
+        g_task_return_boolean (task, TRUE);
+}
+
+void
+gdm_display_reset_initial_session (GdmDisplay *display,
+                                   GCancellable *cancellable,
+                                   GAsyncReadyCallback callback,
+                                   gpointer user_data)
+{
+        GTask *task;
+
+        task = g_task_new (display, cancellable, callback, user_data);
+
+        gdm_dbus_slave_call_reset_initial_session (display->priv->slave_proxy,
+                                                   cancellable,
+                                                   (GAsyncReadyCallback)
+                                                   on_slave_initial_session_reset,
+                                                   task);
+}
+
+gboolean
+gdm_display_reset_initial_session_finish (GdmDisplay *display,
+                                          GAsyncResult *result,
+                                          GError **error)
+{
+        gboolean outcome;
+
+        outcome = g_task_propagate_boolean (G_TASK (result), error);
+        g_object_unref (G_OBJECT (result));
+
+        return outcome;
+}
+
+static void
 on_slave_initial_session_stopped (GdmDBusSlave *slave,
                                   GAsyncResult *result,
                                   GTask        *task)
diff --git a/daemon/gdm-display.h b/daemon/gdm-display.h
index 391c2dd..ee62020 100644
--- a/daemon/gdm-display.h
+++ b/daemon/gdm-display.h
@@ -161,6 +161,14 @@ void                gdm_display_start_initial_session           (GdmDisplay *dis
 gboolean            gdm_display_start_initial_session_finish    (GdmDisplay *display,
                                                                  GAsyncResult *result,
                                                                  GError **error);
+void                gdm_display_reset_initial_session           (GdmDisplay *display,
+                                                                 GCancellable *cancellable,
+                                                                 GAsyncReadyCallback callback,
+                                                                 gpointer user_data);
+
+gboolean            gdm_display_reset_initial_session_finish    (GdmDisplay *display,
+                                                                 GAsyncResult *result,
+                                                                 GError **error);
 void                gdm_display_stop_initial_session           (GdmDisplay   *display,
                                                                 const char   *username,
                                                                 GCancellable *cancellable,
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index 6624e85..ebc8200 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -105,6 +105,9 @@ static void     gdm_manager_finalize    (GObject         *object);
 static void     on_initial_session_set_up (GdmDisplay   *display,
                                            GAsyncResult *result,
                                            GdmManager   *manager);
+static void on_initial_session_started (GdmDisplay   *display,
+                                        GAsyncResult *result,
+                                        GdmManager   *manager);
 static void create_session_for_display (GdmManager *manager,
                                         GdmDisplay *display,
                                         uid_t       allowed_user);
@@ -820,6 +823,22 @@ start_user_session (GdmManager *manager,
 }
 
 static void
+reset_session (GdmManager *manager,
+               GdmSession *session)
+{
+        GdmDisplay *display;
+        uid_t allowed_uid;
+
+        allowed_uid = gdm_session_get_allowed_user (session);
+
+        display = get_display_for_session (manager, session);
+        g_object_set_data (G_OBJECT (display), "gdm-session", NULL);
+        g_object_set_data (G_OBJECT (session), "gdm-display", NULL);
+
+        create_session_for_display (manager, display, allowed_uid);
+}
+
+static void
 on_initial_session_stopped (GdmDisplay   *display,
                             GAsyncResult *result,
                             StartUserSessionOperation *operation)
@@ -841,11 +860,31 @@ on_initial_session_stopped (GdmDisplay   *display,
         start_user_session (operation->manager, display, operation);
 }
 
+static void
+on_initial_session_reset (GdmDisplay   *display,
+                          GAsyncResult *result)
+{
+        GError *error = NULL;
+        gboolean reset;
+
+        reset = gdm_display_reset_initial_session_finish (display, result, &error);
+
+        if (!reset) {
+                g_warning ("Couldn't reset initial session on display: %s",
+                           error->message);
+                g_error_free (error);
+                gdm_display_unmanage (display);
+                gdm_display_finish (display);
+                return;
+        }
+}
+
 static gboolean
 on_start_user_session (StartUserSessionOperation *operation)
 {
         gboolean migrated;
         gboolean fail_if_already_switched = TRUE;
+        gboolean needs_vt;
 
         g_debug ("GdmManager: start or jump to session");
 
@@ -854,6 +893,7 @@ on_start_user_session (StartUserSessionOperation *operation)
          * start a session on it.
          */
         migrated = switch_to_compatible_user_session (operation->manager, operation->session, 
fail_if_already_switched);
+        needs_vt = gdm_session_needs_vt (operation->session);
 
         g_debug ("GdmManager: migrated: %d", migrated);
         if (migrated) {
@@ -863,6 +903,19 @@ on_start_user_session (StartUserSessionOperation *operation)
                    user switching. */
                 gdm_session_reset (operation->session);
                 destroy_start_user_session_operation (operation);
+        } else if (needs_vt) {
+                GdmDisplay *display;
+
+                g_debug ("GdmManager: session needs own VT, reinstating login screen on this VT");
+                /* if we're going to run on a different VT, reset this display for a login screen */
+                reset_session (operation->manager, operation->session);
+                display = get_display_for_session (operation->manager, operation->session);
+                gdm_display_reset_initial_session (display,
+                                                   NULL,
+                                                   (GAsyncReadyCallback)
+                                                   on_initial_session_reset,
+                                                   NULL);
+                start_user_session (operation->manager, NULL, operation);
         } else {
                 GdmDisplay *display;
                 char *username;
diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c
index 62d44a2..3a85413 100644
--- a/daemon/gdm-session-worker.c
+++ b/daemon/gdm-session-worker.c
@@ -54,6 +54,10 @@
 #include <systemd/sd-journal.h>
 #endif
 
+#include <sys/vt.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
 #ifdef HAVE_SELINUX
 #include <selinux/selinux.h>
 #endif /* HAVE_SELINUX */
@@ -152,12 +156,16 @@ struct GdmSessionWorkerPrivate
         gboolean          password_is_required;
 
         int               cred_flags;
+        int               login_vt;
+        int               session_vt;
+        int               session_tty_fd;
 
         char            **arguments;
         guint32           cancelled : 1;
         guint32           timed_out : 1;
         guint32           is_program_session : 1;
         guint32           is_reauth_session : 1;
+        guint32           session_needs_vt : 1;
         guint32           display_is_local : 1;
         guint             state_change_idle_id;
 
@@ -949,6 +957,23 @@ gdm_session_worker_stop_auditor (GdmSessionWorker *worker)
 }
 
 static void
+jump_to_vt (GdmSessionWorker  *worker,
+            int                vt_number)
+{
+        int fd;
+
+        fd = open ("/dev/tty0", O_RDWR | O_NOCTTY);
+        if (ioctl(fd, VT_ACTIVATE, vt_number) < 0) {
+                g_debug ("GdmSessionWorker: couldn't initiate jump to VT %d: %s",
+                         vt_number, g_strerror (errno));
+        } else if (ioctl (fd, VT_WAITACTIVE, vt_number) < 0) {
+                g_debug ("GdmSessionWorker: couldn't finalize jump to VT %d: %s",
+                         vt_number, g_strerror (errno));
+        }
+        close(fd);
+}
+
+static void
 gdm_session_worker_uninitialize_pam (GdmSessionWorker *worker,
                                      int               status)
 {
@@ -977,6 +1002,13 @@ gdm_session_worker_uninitialize_pam (GdmSessionWorker *worker,
 
         gdm_session_worker_stop_auditor (worker);
 
+        if (worker->priv->login_vt != worker->priv->session_vt) {
+                jump_to_vt (worker, worker->priv->login_vt);
+        }
+
+        worker->priv->login_vt = 0;
+        worker->priv->session_vt = 0;
+
         g_debug ("GdmSessionWorker: state NONE");
         worker->priv->state = GDM_SESSION_WORKER_STATE_NONE;
 }
@@ -1757,6 +1789,11 @@ gdm_session_worker_start_session (GdmSessionWorker  *worker,
 
         error_code = PAM_SUCCESS;
 
+        if (worker->priv->session_vt != worker->priv->login_vt) {
+                gdm_session_worker_set_environment_variable (worker, "DISPLAY", NULL);
+                jump_to_vt (worker, worker->priv->session_vt);
+        }
+
         session_pid = fork ();
 
         if (session_pid < 0) {
@@ -1774,9 +1811,15 @@ gdm_session_worker_start_session (GdmSessionWorker  *worker,
                 int    stdin_fd = -1, stdout_fd = -1, stderr_fd = -1;
                 gboolean has_journald = FALSE;
 
-                stdin_fd = open ("/dev/null", O_RDWR);
-                dup2 (stdin_fd, STDIN_FILENO);
-                close (stdin_fd);
+                if (worker->priv->session_tty_fd > 0) {
+                        dup2 (worker->priv->session_tty_fd, STDIN_FILENO);
+                        close (worker->priv->session_tty_fd);
+                        worker->priv->session_tty_fd = -1;
+                } else {
+                        stdin_fd = open ("/dev/null", O_RDWR);
+                        dup2 (stdin_fd, STDIN_FILENO);
+                        close (stdin_fd);
+                }
 
 #ifdef ENABLE_SYSTEMD_JOURNAL
                 has_journald = sd_booted() > 0;
@@ -1887,6 +1930,11 @@ gdm_session_worker_start_session (GdmSessionWorker  *worker,
                 _exit (127);
         }
 
+        if (worker->priv->session_tty_fd > 0) {
+                close (worker->priv->session_tty_fd);
+                worker->priv->session_tty_fd = -1;
+        }
+
         /* If we end up execing again, make sure we don't use the executable context set up
          * by pam_selinux durin pam_open_session
          */
@@ -1914,6 +1962,59 @@ gdm_session_worker_start_session (GdmSessionWorker  *worker,
 }
 
 static gboolean
+set_up_for_new_vt (GdmSessionWorker *worker)
+{
+        int fd;
+        char vt_string[256] = "", tty_string[256] = "";
+        struct vt_stat vt_state = { 0 };
+        int session_vt = 0;
+
+        fd = open ("/dev/tty0", O_RDWR | O_NOCTTY);
+
+        if (fd < 0) {
+                g_debug ("GdmSessionWorker: couldn't open VT master: %s",
+                         g_strerror (errno));
+                return FALSE;
+        }
+
+        if (ioctl (fd, VT_GETSTATE, &vt_state) < 0) {
+                g_debug ("GdmSessionWorker: couldn't get current VT: %s",
+                         g_strerror (errno));
+                goto fail;
+        }
+
+        if (ioctl(fd, VT_OPENQRY, &session_vt) < 0) {
+                g_debug ("GdmSessionWorker: couldn't open new VT: %s",
+                         g_strerror (errno));
+                goto fail;
+        }
+
+        worker->priv->login_vt = vt_state.v_active;
+        worker->priv->session_vt = session_vt;
+
+        close (fd);
+        fd = -1;
+
+        g_assert (session_vt > 0);
+
+        g_snprintf(vt_string, 256, "%d", session_vt);
+        g_snprintf(tty_string, 256, "/dev/tty%d", session_vt);
+
+        gdm_session_worker_set_environment_variable (worker,
+                                                     "XDG_VTNR",
+                                                     vt_string);
+
+        worker->priv->session_tty_fd = open (tty_string, O_RDWR | O_NOCTTY);
+        pam_set_item (worker->priv->pam_handle, PAM_TTY, tty_string);
+
+        return TRUE;
+
+fail:
+        close (fd);
+        return FALSE;
+}
+
+static gboolean
 set_up_for_current_vt (GdmSessionWorker  *worker,
                        GError           **error)
 {
@@ -1991,7 +2092,19 @@ gdm_session_worker_open_session (GdmSessionWorker  *worker,
         g_assert (worker->priv->state == GDM_SESSION_WORKER_STATE_ACCOUNT_DETAILS_SAVED);
         g_assert (geteuid () == 0);
 
-        set_up_for_current_vt (worker, NULL);
+        if (worker->priv->session_needs_vt) {
+                if (!set_up_for_new_vt (worker)) {
+                        g_set_error (error,
+                                     GDM_SESSION_WORKER_ERROR,
+                                     GDM_SESSION_WORKER_ERROR_OPENING_SESSION,
+                                     "Unable to open VT");
+                        return FALSE;
+                }
+        } else {
+                if (!set_up_for_current_vt (worker, error)) {
+                        return FALSE;
+                }
+        }
 
         flags = 0;
 
@@ -2142,6 +2255,19 @@ gdm_session_worker_handle_set_session_type (GdmDBusWorker         *object,
 }
 
 static gboolean
+gdm_session_worker_handle_set_session_needs_vt (GdmDBusWorker         *object,
+                                                GDBusMethodInvocation *invocation,
+                                                gboolean               needs_vt)
+{
+        GdmSessionWorker *worker = GDM_SESSION_WORKER (object);
+
+        g_debug ("GdmSessionWorker: session needs VT: %s", needs_vt? "yes" : "no");
+        worker->priv->session_needs_vt = needs_vt;
+        gdm_dbus_worker_complete_set_session_needs_vt (object, invocation);
+        return TRUE;
+}
+
+static gboolean
 gdm_session_worker_handle_set_language_name (GdmDBusWorker         *object,
                                              GDBusMethodInvocation *invocation,
                                              const char            *language_name)
@@ -2924,6 +3050,7 @@ worker_interface_init (GdmDBusWorkerIface *interface)
         interface->handle_set_language_name = gdm_session_worker_handle_set_language_name;
         interface->handle_set_session_name = gdm_session_worker_handle_set_session_name;
         interface->handle_set_session_type = gdm_session_worker_handle_set_session_type;
+        interface->handle_set_session_needs_vt = gdm_session_worker_handle_set_session_needs_vt;
         interface->handle_set_environment_variable = gdm_session_worker_handle_set_environment_variable;
         interface->handle_start_program = gdm_session_worker_handle_start_program;
         interface->handle_start_reauthentication = gdm_session_worker_handle_start_reauthentication;
diff --git a/daemon/gdm-session-worker.xml b/daemon/gdm-session-worker.xml
index 4595ac7..98b2fdb 100644
--- a/daemon/gdm-session-worker.xml
+++ b/daemon/gdm-session-worker.xml
@@ -16,6 +16,9 @@
     <method name="SetSessionType">
       <arg name="session_type" direction="in" type="s"/>
     </method>
+    <method name="SetSessionNeedsVT">
+      <arg name="needs_vt" direction="in" type="b"/>
+    </method>
     <method name="SetEnvironmentVariable">
       <arg name="name" direction="in" type="s"/>
       <arg name="value" direction="in" type="s"/>
diff --git a/daemon/gdm-session.c b/daemon/gdm-session.c
index 6eb989d..9bd1764 100644
--- a/daemon/gdm-session.c
+++ b/daemon/gdm-session.c
@@ -2653,6 +2653,10 @@ gdm_session_bypasses_xsession (GdmSession *self)
         g_return_val_if_fail (self != NULL, FALSE);
         g_return_val_if_fail (GDM_IS_SESSION (self), FALSE);
 
+        if (gdm_session_needs_vt (self)) {
+                return TRUE;
+        }
+
         filename = g_strdup_printf ("%s.desktop", get_session_name (self));
 
         key_file = g_key_file_new ();
@@ -2689,6 +2693,54 @@ out:
         return bypasses_xsession;
 }
 
+gboolean
+gdm_session_needs_vt (GdmSession *self)
+{
+        GError     *error;
+        GKeyFile   *key_file;
+        gboolean    res;
+        gboolean    needs_vt = FALSE;
+        char       *filename;
+
+        g_return_val_if_fail (self != NULL, FALSE);
+        g_return_val_if_fail (GDM_IS_SESSION (self), FALSE);
+
+        filename = g_strdup_printf ("%s.desktop", get_session_name (self));
+
+        key_file = g_key_file_new ();
+        error = NULL;
+        res = g_key_file_load_from_dirs (key_file,
+                                         filename,
+                                         get_system_session_dirs (),
+                                         NULL,
+                                         G_KEY_FILE_NONE,
+                                         &error);
+        if (! res) {
+                g_debug ("GdmSession: File '%s' not found: %s", filename, error->message);
+                goto out;
+        }
+
+        error = NULL;
+        res = g_key_file_has_key (key_file, G_KEY_FILE_DESKTOP_GROUP, "X-GDM-NeedsVT", NULL);
+        if (!res) {
+                goto out;
+        } else {
+                needs_vt = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, "X-GDM-NeedsVT", 
&error);
+                if (error) {
+                        needs_vt = FALSE;
+                        g_error_free (error);
+                        goto out;
+                }
+                if (needs_vt) {
+                        g_debug ("GdmSession: Session %s runs on its own VT", filename);
+                }
+        }
+
+out:
+        g_free (filename);
+        return needs_vt;
+}
+
 void
 gdm_session_select_program (GdmSession *self,
                             const char *text)
@@ -2724,6 +2776,7 @@ gdm_session_select_session (GdmSession *self,
 {
         GHashTableIter iter;
         gpointer key, value;
+        gboolean needs_vt;
 
         g_free (self->priv->selected_session);
 
@@ -2733,6 +2786,8 @@ gdm_session_select_session (GdmSession *self,
                 self->priv->selected_session = g_strdup (text);
         }
 
+        needs_vt = gdm_session_needs_vt (self);
+
         g_hash_table_iter_init (&iter, self->priv->conversations);
         while (g_hash_table_iter_next (&iter, &key, &value)) {
                 GdmSessionConversation *conversation;
@@ -2742,6 +2797,9 @@ gdm_session_select_session (GdmSession *self,
                 gdm_dbus_worker_call_set_session_name (conversation->worker_proxy,
                                                        get_session_name (self),
                                                        NULL, NULL, NULL);
+                gdm_dbus_worker_call_set_session_needs_vt (conversation->worker_proxy,
+                                                           needs_vt,
+                                                           NULL, NULL, NULL);
         }
 }
 
diff --git a/daemon/gdm-session.h b/daemon/gdm-session.h
index 944cb10..6518edd 100644
--- a/daemon/gdm-session.h
+++ b/daemon/gdm-session.h
@@ -110,6 +110,7 @@ char             *gdm_session_get_display_device          (GdmSession     *sessi
 char             *gdm_session_get_display_seat_id         (GdmSession     *session);
 char             *gdm_session_get_session_id              (GdmSession     *session);
 gboolean          gdm_session_bypasses_xsession           (GdmSession     *session);
+gboolean          gdm_session_needs_vt                    (GdmSession     *session);
 
 void              gdm_session_start_conversation          (GdmSession *session,
                                                            const char *service_name);
diff --git a/daemon/gdm-simple-slave.c b/daemon/gdm-simple-slave.c
index bd4151b..8761c27 100644
--- a/daemon/gdm-simple-slave.c
+++ b/daemon/gdm-simple-slave.c
@@ -774,6 +774,16 @@ gdm_simple_slave_start_initial_session (GdmSlave *slave)
         }
 }
 
+static void
+gdm_simple_slave_reset_initial_session (GdmSlave *slave)
+{
+        GdmSimpleSlave *self = GDM_SIMPLE_SLAVE (slave);
+
+        if (self->priv->greeter_environment != NULL) {
+                gdm_launch_environment_reset (GDM_LAUNCH_ENVIRONMENT (self->priv->greeter_environment));
+        }
+}
+
 static gboolean
 idle_connect_to_display (GdmSimpleSlave *slave)
 {
@@ -1041,6 +1051,7 @@ gdm_simple_slave_class_init (GdmSimpleSlaveClass *klass)
         slave_class->stop = gdm_simple_slave_stop;
         slave_class->set_up_initial_session = gdm_simple_slave_set_up_initial_session;
         slave_class->start_initial_session = gdm_simple_slave_start_initial_session;
+        slave_class->reset_initial_session = gdm_simple_slave_reset_initial_session;
         slave_class->stop_initial_session = gdm_simple_slave_stop_initial_session;
 
         g_type_class_add_private (klass, sizeof (GdmSimpleSlavePrivate));
diff --git a/daemon/gdm-slave.c b/daemon/gdm-slave.c
index 06d857c..de512eb 100644
--- a/daemon/gdm-slave.c
+++ b/daemon/gdm-slave.c
@@ -1203,6 +1203,29 @@ handle_start_initial_session (GdmDBusSlave          *skeleton,
 }
 
 static gboolean
+handle_reset_initial_session (GdmDBusSlave          *skeleton,
+                              GDBusMethodInvocation *invocation,
+                              GdmSlave              *slave)
+{
+        GdmSlaveClass *slave_class;
+
+        slave_class = GDM_SLAVE_GET_CLASS (slave);
+        if (slave_class->reset_initial_session == NULL) {
+                g_dbus_method_invocation_return_dbus_error (invocation,
+                                                            "org.gnome.DisplayManager.Slave.Unsupported",
+                                                            "Connections to the slave are not supported by 
this slave");
+                return TRUE;
+        }
+
+        slave_class->reset_initial_session (slave);
+
+        gdm_dbus_slave_complete_reset_initial_session (skeleton, invocation);
+
+        return TRUE;
+}
+
+
+static gboolean
 handle_stop_initial_session (GdmDBusSlave          *skeleton,
                              GDBusMethodInvocation *invocation,
                              const char            *username,
@@ -1251,6 +1274,10 @@ register_slave (GdmSlave *slave)
                           G_CALLBACK (handle_start_initial_session),
                           slave);
         g_signal_connect (slave->priv->skeleton,
+                          "handle-reset-initial-session",
+                          G_CALLBACK (handle_reset_initial_session),
+                          slave);
+        g_signal_connect (slave->priv->skeleton,
                           "handle-stop-initial-session",
                           G_CALLBACK (handle_stop_initial_session),
                           slave);
diff --git a/daemon/gdm-slave.h b/daemon/gdm-slave.h
index e3264f8..14c9ff7 100644
--- a/daemon/gdm-slave.h
+++ b/daemon/gdm-slave.h
@@ -53,6 +53,7 @@ typedef struct
         void     (* set_up_initial_session) (GdmSlave    *slave,
                                              char       **username);
         void     (* start_initial_session) (GdmSlave  *slave);
+        void     (* reset_initial_session) (GdmSlave  *slave);
         void     (* stop_initial_session) (GdmSlave   *slave,
                                            const char *username);
 
diff --git a/daemon/gdm-slave.xml b/daemon/gdm-slave.xml
index 3f563b4..6e9e2d1 100644
--- a/daemon/gdm-slave.xml
+++ b/daemon/gdm-slave.xml
@@ -11,6 +11,9 @@
     <method name="StartInitialSession">
     </method>
 
+    <method name="ResetInitialSession">
+    </method>
+
     <method name="StopInitialSession">
       <arg name="username" type="s" direction="in" />
     </method>


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