patches/ConsoleKit-01-ck-dynamic.diff
author rohinis
Tue, 29 Nov 2011 17:32:55 +0000
branchs11express-2010-11
changeset 22234 c23e64da3e06
parent 20076 25ffad964372
child 21493 2c2f10c95207
permissions -rw-r--r--
2011-11-29 Rohini S <[email protected]> * patches/Python26-22-audio.diff: Fixes CVE-2010-1634 * specs/SUNWPython26.spec: Fixes CR 7085446

diff --git a/configure.ac b/configure.ac
index 117d788..2ff6020 100644
--- a/configure.ac
+++ b/configure.ac
@@ -203,6 +203,18 @@ AM_CONDITIONAL(CK_COMPILE_SOLARIS, test x$CK_BACKEND = xsolaris, [Compiling for
 AC_SUBST(CK_BACKEND)
 
 dnl ---------------------------------------------------------------------------
+dnl Check for X11 DIR
+dnl ---------------------------------------------------------------------------
+
+X11_DIR=`$PKG_CONFIG --variable=bindir xorg-server 2>/dev/null`
+if test "x$X11_DIR" = x; then
+    AC_PATH_PROGS([XSERVER], [Xorg X],,[$PATH:/usr/X11/bin:/usr/bin])
+    test "x$XSERVER" != x && X11_DIR=`dirname "$XSERVER"`
+fi
+test "x$X11_DIR" = x && X11_DIR=$bindir
+AC_SUBST([X11_DIR])
+
+dnl ---------------------------------------------------------------------------
 dnl Check for PAM
 dnl ---------------------------------------------------------------------------
 
@@ -303,6 +315,14 @@ if test "x$enable_inotify" = "xyes" ; then
 fi
 
 dnl ---------------------------------------------------------------------------
+dnl check for strverscmp
+dnl ---------------------------------------------------------------------------
+have_strverscmp=no
+AC_CHECK_FUNCS(strverscmp, [have_strverscmp=yes], [])
+
+AM_CONDITIONAL(USE_SELF_STRVERSCMP, test "x$have_strverscmp" = "xno", [Define if we do not have strverscmp])
+
+dnl ---------------------------------------------------------------------------
 dnl check for RBAC
 dnl ---------------------------------------------------------------------------
 
@@ -401,6 +421,8 @@ tools/linux/Makefile
 tools/freebsd/Makefile
 tools/solaris/Makefile
 data/Makefile
+data/displays.d/Makefile
+data/sessions.d/Makefile
 doc/Makefile
 doc/dbus/ConsoleKit.xml
 doc/dbus/Makefile
diff --git a/data/00-primary.seat b/data/00-primary.seat
index 6e61db4..0632382 100644
--- a/data/00-primary.seat
+++ b/data/00-primary.seat
@@ -1,5 +1,26 @@
 [Seat Entry]
 Version=1.0
 Name=Primary seat
+# Specified Seat ID, if this value is NULL, ConsoleKit will decide one.
+# The ID only contain the ASICC characters "[A-Z][a-z][0-9]_" 
+ID=StaticSeat1
+Description=start one static local display at :0
+
+# Indicate whether to create this seat or not. If it is set true, then CK will
+# not create this seat. Default value is false.
 Hidden=false
-Devices=
\ No newline at end of file
+
+# Indicate input/output devices including keyboard-pointer-video
+# card-monitor-sound-usb devices,
+# This key will not implemented now, it might need be divided into
+# several keys in the future:
+# Pointer=
+# Monitor=
+# VideoCard=
+# Monitor=
+# UsbHub=
+Devices=
+
+# List of sessions to start on the seat, separated by ';'
+# Each session is defined in sessions.d/
+Sessions=Local;
diff --git a/data/ConsoleKit.conf b/data/ConsoleKit.conf
index 948f95f..8cf490a 100644
--- a/data/ConsoleKit.conf
+++ b/data/ConsoleKit.conf
@@ -44,6 +44,9 @@
            send_member="CloseSession"/>
     <allow send_destination="org.freedesktop.ConsoleKit"
            send_interface="org.freedesktop.ConsoleKit.Manager"
+           send_member="GetUnmanagedSeats"/>
+    <allow send_destination="org.freedesktop.ConsoleKit"
+           send_interface="org.freedesktop.ConsoleKit.Manager"
            send_member="GetSeats"/>
     <allow send_destination="org.freedesktop.ConsoleKit"
            send_interface="org.freedesktop.ConsoleKit.Manager"
@@ -69,6 +72,18 @@
     <allow send_destination="org.freedesktop.ConsoleKit"
            send_interface="org.freedesktop.ConsoleKit.Manager"
            send_member="GetSystemIdleSinceHint"/>
+    <allow send_destination="org.freedesktop.ConsoleKit"
+           send_interface="org.freedesktop.ConsoleKit.Manager"
+           send_member="AddSeat"/>
+    <allow send_destination="org.freedesktop.ConsoleKit"
+           send_interface="org.freedesktop.ConsoleKit.Manager"
+           send_member="RemoveSeat"/>
+    <allow send_destination="org.freedesktop.ConsoleKit"
+           send_interface="org.freedesktop.ConsoleKit.Manager"
+           send_member="AddSession"/>
+    <allow send_destination="org.freedesktop.ConsoleKit"
+           send_interface="org.freedesktop.ConsoleKit.Manager"
+           send_member="RemoveSession"/>
 
     <allow send_destination="org.freedesktop.ConsoleKit"
            send_interface="org.freedesktop.ConsoleKit.Seat"
@@ -88,6 +103,9 @@
     <allow send_destination="org.freedesktop.ConsoleKit"
            send_interface="org.freedesktop.ConsoleKit.Seat"
            send_member="ActivateSession"/>
+    <allow send_destination="org.freedesktop.ConsoleKit"
+           send_interface="org.freedesktop.ConsoleKit.Seat"
+           send_member="ManageSeat"/>
 
     <allow send_destination="org.freedesktop.ConsoleKit"
            send_interface="org.freedesktop.ConsoleKit.Session"
@@ -103,6 +121,9 @@
            send_member="GetSessionType"/>
     <allow send_destination="org.freedesktop.ConsoleKit"
            send_interface="org.freedesktop.ConsoleKit.Session"
+           send_member="GetDisplayType"/>
+    <allow send_destination="org.freedesktop.ConsoleKit"
+           send_interface="org.freedesktop.ConsoleKit.Session"
            send_member="GetUser"/>
     <allow send_destination="org.freedesktop.ConsoleKit"
            send_interface="org.freedesktop.ConsoleKit.Session"
@@ -127,6 +148,12 @@
            send_member="IsLocal"/>
     <allow send_destination="org.freedesktop.ConsoleKit"
            send_interface="org.freedesktop.ConsoleKit.Session"
+           send_member="IsDynamic"/>
+    <allow send_destination="org.freedesktop.ConsoleKit"
+           send_interface="org.freedesktop.ConsoleKit.Session"
+           send_member="IsOpen"/>
+    <allow send_destination="org.freedesktop.ConsoleKit"
+           send_interface="org.freedesktop.ConsoleKit.Session"
            send_member="GetCreationTime"/>
     <allow send_destination="org.freedesktop.ConsoleKit"
            send_interface="org.freedesktop.ConsoleKit.Session"
@@ -136,12 +163,11 @@
            send_member="GetIdleHint"/>
     <allow send_destination="org.freedesktop.ConsoleKit"
            send_interface="org.freedesktop.ConsoleKit.Session"
-           send_member="SetIdleHint"/>
-    <allow send_destination="org.freedesktop.ConsoleKit"
-           send_interface="org.freedesktop.ConsoleKit.Session"
            send_member="GetIdleSinceHint"/>
     <allow send_interface="org.freedesktop.ConsoleKit.Session"
            send_member="SetIdleHint"/>
+    <allow send_interface="org.freedesktop.ConsoleKit.Session"
+           send_member="SetRemoveOnClose"/>
   </policy>
 
 </busconfig>
diff --git a/data/Makefile.am b/data/Makefile.am
index 041b431..2054e96 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -1,5 +1,10 @@
 NULL =
 
+SUBDIRS = \
+	displays.d	\
+	sessions.d	\
+        $(NULL)
+
 dbusconfdir = $(DBUS_SYS_DIR)
 dbusconf_DATA = ConsoleKit.conf
 
diff --git a/data/displays.d/Headless.display.in b/data/displays.d/Headless.display.in
new file mode 100644
index 0000000..754d2bf
--- /dev/null
+++ b/data/displays.d/Headless.display.in
@@ -0,0 +1,5 @@
+[Display]
+Type=X11
+
+[X11]
+Exec=@X11_DIR@/Xvfb $display -auth $auth
diff --git a/data/displays.d/Local.display.in b/data/displays.d/Local.display.in
new file mode 100644
index 0000000..b845a7b
--- /dev/null
+++ b/data/displays.d/Local.display.in
@@ -0,0 +1,5 @@
+[Display]
+Type=X11
+
+[X11]
+Exec=@X11_DIR@/Xorg $display -br -verbose -auth $auth -nolisten tcp $vt
diff --git a/data/displays.d/LocalVNC.display.in b/data/displays.d/LocalVNC.display.in
new file mode 100644
index 0000000..6ad336b
--- /dev/null
+++ b/data/displays.d/LocalVNC.display.in
@@ -0,0 +1,5 @@
+[Display]
+Type=X11
+
+[X11]
+Exec=@X11_DIR@/Xvnc $display -auth $auth -query localhost
diff --git a/data/displays.d/Makefile.am b/data/displays.d/Makefile.am
new file mode 100644
index 0000000..1fab1d2
--- /dev/null
+++ b/data/displays.d/Makefile.am
@@ -0,0 +1,29 @@
+NULL =
+
+displaydir = $(sysconfdir)/ConsoleKit/displays.d
+display_in_files = \
+	Local.display.in \
+	RemoteMachine.display.in \
+	LocalVNC.display.in \
+	Headless.display.in
+
+display_DATA = $(display_in_files:.display.in=.display)
+
+Local.display: Local.display.in Makefile
+	sed -e "s|\@X11_DIR\@|$(X11_DIR)|" $< > $@
+RemoteMachine.display: RemoteMachine.display.in Makefile
+	sed -e "s|\@X11_DIR\@|$(X11_DIR)|" $< > $@
+LocalVNC.display: LocalVNC.display.in Makefile
+	sed -e "s|\@X11_DIR\@|$(X11_DIR)|" $< > $@
+Headless.display: Headless.display.in Makefile
+	sed -e "s|\@X11_DIR\@|$(X11_DIR)|" $< > $@
+
+EXTRA_DIST =						\
+	$(display_in_files)				\
+	$(NULL)
+
+MAINTAINERCLEANFILES =			\
+	*~				\
+	Makefile.in
+
+CLEANFILES = $(display_DATA)
diff --git a/data/displays.d/RemoteMachine.display.in b/data/displays.d/RemoteMachine.display.in
new file mode 100644
index 0000000..7c69451
--- /dev/null
+++ b/data/displays.d/RemoteMachine.display.in
@@ -0,0 +1,5 @@
+[Display]
+Type=X11
+
+[X11]
+Exec=@X11_DIR@/Xorg $display -br -verbose -auth $auth -indirect $vt
diff --git a/data/sessions.d/Headless.session b/data/sessions.d/Headless.session
new file mode 100644
index 0000000..d376af9
--- /dev/null
+++ b/data/sessions.d/Headless.session
@@ -0,0 +1,8 @@
+[Session Entry]
+Name=Headless
+Type=LoginWindow
+Description=Login Window running on headless display
+DisplayTemplate=Headless
+
+[Headless]
+display=:32
diff --git a/data/sessions.d/Local.session b/data/sessions.d/Local.session
new file mode 100644
index 0000000..9d3b975
--- /dev/null
+++ b/data/sessions.d/Local.session
@@ -0,0 +1,9 @@
+[Session Entry]
+Name=Local
+Type=LoginWindow
+Description=Local Login Screen
+DisplayTemplate=Local
+
+[Local]
+display=:0
+vt=vt1
diff --git a/data/sessions.d/LocalVNC.session b/data/sessions.d/LocalVNC.session
new file mode 100644
index 0000000..c05802f
--- /dev/null
+++ b/data/sessions.d/LocalVNC.session
@@ -0,0 +1,8 @@
+[Session Entry]
+Name=LocalVNC
+Type=LoginWindow
+Description=Connect to local VNC server running on same machine
+DisplayTemplate=LocalVNC
+
+[LocalVNC]
+display=:64
diff --git a/data/sessions.d/Makefile.am b/data/sessions.d/Makefile.am
new file mode 100644
index 0000000..f17ffdc
--- /dev/null
+++ b/data/sessions.d/Makefile.am
@@ -0,0 +1,16 @@
+NULL =
+
+sessiondir = $(sysconfdir)/ConsoleKit/sessions.d
+session_DATA = \
+	Headless.session		\
+	Local.session			\
+	LocalVNC.session		\
+	Remote.session
+
+EXTRA_DIST =				\
+	$(session_DATA)			\
+	$(NULL)
+
+MAINTAINERCLEANFILES =			\
+	*~				\
+	Makefile.in
diff --git a/data/sessions.d/Remote.session b/data/sessions.d/Remote.session
new file mode 100644
index 0000000..e88f975
--- /dev/null
+++ b/data/sessions.d/Remote.session
@@ -0,0 +1,9 @@
+[Session Entry]
+Name=Remote Chooser
+Type=Remote
+Description=Connect to chooser on nearby remote machine
+DisplayTemplate=RemoteMachine
+
+[RemoteMachine]
+display=:96
+vt=vt10
diff --git a/doc/dbus/ck-terms.xml b/doc/dbus/ck-terms.xml
index d3d544d..1b43ca6 100644
--- a/doc/dbus/ck-terms.xml
+++ b/doc/dbus/ck-terms.xml
@@ -64,4 +64,11 @@ True, hardware, multi-seat capabilities will be added in a later release.
     </para>
   </sect1>
 
+  <sect1>
+    <title>Seat manager</title>
+    <para>
+The seat manager is the process responsible for starting and stopping sessions on a seat.
+    </para>
+  </sect1>
+
 </chapter>
diff --git a/libck-connector/ck-connector.c b/libck-connector/ck-connector.c
index 7f6f87f..87a7d4a 100644
--- a/libck-connector/ck-connector.c
+++ b/libck-connector/ck-connector.c
@@ -76,8 +76,11 @@ static struct {
         { "display-device",     DBUS_TYPE_STRING },
         { "x11-display-device", DBUS_TYPE_STRING },
         { "x11-display",        DBUS_TYPE_STRING },
+        { "seat-id",            DBUS_TYPE_STRING },
+        { "session",            DBUS_TYPE_STRING },
         { "remote-host-name",   DBUS_TYPE_STRING },
         { "session-type",       DBUS_TYPE_STRING },
+        { "display-type",       DBUS_TYPE_STRING },
         { "is-local",           DBUS_TYPE_BOOLEAN },
         { "unix-user",          DBUS_TYPE_INT32 },
 };
diff --git a/src/Makefile.am b/src/Makefile.am
index 6ab05c8..97a59ef 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -107,6 +107,8 @@ console_kit_daemon_SOURCES =	\
 	ck-file-monitor.h	\
 	ck-job.h		\
 	ck-job.c		\
+	ck-display-template.h	\
+	ck-display-template.c	\
 	ck-seat.h		\
 	ck-seat.c		\
 	ck-session-leader.h	\
@@ -122,6 +124,13 @@ console_kit_daemon_SOURCES =	\
 	$(BUILT_SOURCES)	\
 	$(NULL)
 
+if USE_SELF_STRVERSCMP
+console_kit_daemon_SOURCES +=	\
+	strverscmp.c		\
+	strverscmp.h		\
+	$(NULL)
+endif
+
 if ENABLE_INOTIFY
 FILE_MONITOR_BACKEND = ck-file-monitor-inotify.c
 else
diff --git a/src/ck-display-template.c b/src/ck-display-template.c
new file mode 100644
index 0000000..9206103
--- /dev/null
+++ b/src/ck-display-template.c
@@ -0,0 +1,341 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Authors: [email protected], Ray Strode <[email protected]>
+ * Copyright (C) 2009 Sun Microsystems, Inc.
+ *                    Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <glib.h>
+#include <glib-object.h>
+
+#include "ck-display-template.h"
+
+#define CK_DISPLAY_TEMPLATE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CK_TYPE_DISPLAY_TEMPLATE, CkDisplayTemplatePrivate))
+
+#define CK_DISPLAY_TEMPLATES_DIR     SYSCONFDIR "/ConsoleKit/displays.d"
+
+struct CkDisplayTemplatePrivate
+{
+        char            *name;
+        char            *type;
+        GHashTable      *parameters;
+};
+
+enum {
+        PROP_0,
+        PROP_NAME,
+        PROP_TYPE,
+        PROP_PARAMETERS,
+};
+
+static void     ck_display_template_class_init  (CkDisplayTemplateClass *klass);
+static void     ck_display_template_init        (CkDisplayTemplate      *display);
+static void     ck_display_template_finalize    (GObject            *object);
+static gboolean ck_display_template_load        (CkDisplayTemplate      *display);
+
+static GHashTable *ck_display_templates;
+
+G_DEFINE_TYPE (CkDisplayTemplate, ck_display_template, G_TYPE_OBJECT)
+
+static void
+_ck_display_template_set_name (CkDisplayTemplate  *display,
+                               const char     *name)
+{
+        g_free (display->priv->name);
+        display->priv->name = g_strdup (name);
+}
+
+static void
+_ck_display_template_set_type_string (CkDisplayTemplate  *display,
+                                      const char     *type)
+{
+        g_free (display->priv->type);
+        display->priv->type = g_strdup (type);
+}
+
+static void
+_ck_display_template_set_parameters (CkDisplayTemplate  *display,
+                                     GHashTable     *parameters)
+{
+        if (display->priv->parameters != NULL) {
+                g_hash_table_unref (display->priv->parameters);
+        }
+
+        if (parameters == NULL) {
+                display->priv->parameters = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                                                   (GDestroyNotify) g_free,
+                                                                   (GDestroyNotify) g_free);
+        } else {
+                display->priv->parameters = g_hash_table_ref (parameters);
+        }
+}
+
+static void
+ck_display_template_set_property (GObject      *object,
+                                  guint         prop_id,
+                                  const GValue *value,
+                                  GParamSpec   *pspec)
+{
+        CkDisplayTemplate *self;
+
+        self = CK_DISPLAY_TEMPLATE (object);
+
+        switch (prop_id) {
+        case PROP_NAME:
+                _ck_display_template_set_name (self, g_value_get_string (value));
+                break;
+        case PROP_TYPE:
+                _ck_display_template_set_type_string (self, g_value_get_string (value));
+                break;
+        case PROP_PARAMETERS:
+                _ck_display_template_set_parameters (self, g_value_get_boxed (value));
+                break;
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+        }
+}
+
+static void
+ck_display_template_get_property (GObject    *object,
+                                  guint       prop_id,
+                                  GValue     *value,
+                                  GParamSpec *pspec)
+{
+        CkDisplayTemplate *self;
+
+        self = CK_DISPLAY_TEMPLATE (object);
+
+        switch (prop_id) {
+        case PROP_NAME:
+                g_value_set_string (value, self->priv->name);
+                break;
+        case PROP_TYPE:
+                g_value_set_string (value, self->priv->type);
+                break;
+        case PROP_PARAMETERS:
+                g_value_set_boxed (value, self->priv->parameters);
+                break;
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+        }
+}
+
+static void
+ck_display_template_class_init (CkDisplayTemplateClass *klass)
+{
+        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
+
+        object_class->get_property = ck_display_template_get_property;
+        object_class->set_property = ck_display_template_set_property;
+        object_class->finalize = ck_display_template_finalize;
+
+        g_object_class_install_property (object_class,
+                                         PROP_NAME,
+                                         g_param_spec_string ("name",
+                                                              "display type name",
+                                                              "display type name",
+                                                              NULL,
+                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+        g_object_class_install_property (object_class,
+                                         PROP_TYPE,
+                                         g_param_spec_string ("type",
+                                                              "type",
+                                                              "Type",
+                                                              NULL,
+                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+        g_object_class_install_property (object_class,
+                                         PROP_PARAMETERS,
+                                         g_param_spec_boxed ("parameters",
+                                                              "Parameters",
+                                                              "Parameters",
+                                                              G_TYPE_HASH_TABLE,
+                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+        g_type_class_add_private (klass, sizeof (CkDisplayTemplatePrivate));
+}
+
+static void
+ck_display_template_init (CkDisplayTemplate *display)
+{
+        display->priv = CK_DISPLAY_TEMPLATE_GET_PRIVATE (display);
+
+        display->priv->name = NULL;
+        display->priv->type = NULL;
+        display->priv->parameters = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                                           (GDestroyNotify) g_free,
+                                                           (GDestroyNotify) g_free);
+}
+
+static void
+ck_display_template_finalize (GObject *object)
+{
+        CkDisplayTemplate *display;
+
+        g_return_if_fail (object != NULL);
+        g_return_if_fail (CK_IS_DISPLAY_TEMPLATE (object));
+
+        display = CK_DISPLAY_TEMPLATE (object);
+
+        g_return_if_fail (display->priv != NULL);
+
+        g_free (display->priv->name);
+        g_free (display->priv->type);
+        g_hash_table_unref (display->priv->parameters);
+
+        G_OBJECT_CLASS (ck_display_template_parent_class)->finalize (object);
+}
+
+static gboolean
+ck_display_template_load (CkDisplayTemplate *display)
+{
+        GKeyFile   *key_file;
+        const char *name;
+        char       *group;
+        char       *filename;
+        gboolean    hidden;
+        char       *type;
+        gboolean    res;
+        GError     *error;
+        char      **type_keys;
+        GHashTable *parameters;
+
+        name = ck_display_template_get_name (display);
+
+        g_return_val_if_fail (name && !g_str_equal (name, ""), FALSE);
+
+        filename = g_strdup_printf ("%s/%s.display", CK_DISPLAY_TEMPLATES_DIR, name);
+
+        key_file = g_key_file_new ();
+
+        error = NULL;
+        res = g_key_file_load_from_file (key_file,
+                                         filename,
+                                         G_KEY_FILE_NONE,
+                                         &error);
+        if (! res) {
+                g_warning ("Unable to load display from file %s: %s", filename, error->message);
+                g_error_free (error);
+                return FALSE;
+        }
+        g_free (filename);
+
+        group = g_key_file_get_start_group (key_file);
+
+        if (group == NULL || strcmp (group, "Display") != 0) {
+                g_warning ("Not a display type file: %s", filename);
+                g_free (group);
+                g_key_file_free (key_file);
+                return FALSE;
+        }
+
+        hidden = g_key_file_get_boolean (key_file, group, "Hidden", NULL);
+
+        type = g_key_file_get_string (key_file, group, "Type", NULL);
+
+        if (type == NULL) {
+                g_warning ("Unable to read type from display file");
+                g_free (group);
+                g_key_file_free (key_file);
+                return FALSE;
+        }
+
+        display->priv->type = type;
+
+        parameters = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                            (GDestroyNotify) g_free,
+                                            (GDestroyNotify) g_free);
+
+        type_keys = g_key_file_get_keys (key_file, type, NULL, NULL);
+
+        if (type_keys != NULL) {
+                int        i;
+                for (i = 0; type_keys[i] != NULL; i++) {
+                        char   *string;
+
+                        string = g_key_file_get_string (key_file, type, type_keys[i], NULL);
+                        g_hash_table_insert (parameters, g_strdup (type_keys[i]), string);
+                }
+                g_strfreev (type_keys);
+        }
+
+        _ck_display_template_set_parameters (display, parameters);
+        g_hash_table_unref (parameters);
+
+        g_free (group);
+        g_key_file_free (key_file);
+        return TRUE;
+}
+
+CkDisplayTemplate *
+ck_display_template_get_from_name (const char *name)
+{
+        CkDisplayTemplate *display_template;
+
+        if (ck_display_templates == NULL) {
+                ck_display_templates = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                                          (GDestroyNotify) g_free,
+                                                          (GDestroyNotify) g_object_unref);
+        }
+
+        display_template = g_hash_table_lookup (ck_display_templates, name);
+
+        if (display_template == NULL) {
+                GObject *object;
+
+                object = g_object_new (CK_TYPE_DISPLAY_TEMPLATE,
+                                       "name", name,
+                                       NULL);
+
+                if (!ck_display_template_load (CK_DISPLAY_TEMPLATE (object))) {
+                        g_object_unref (object);
+                        return NULL;
+                }
+
+                g_hash_table_insert (ck_display_templates, g_strdup (name), object);
+                display_template = CK_DISPLAY_TEMPLATE (object);
+        }
+
+        return g_object_ref (display_template);
+}
+
+G_CONST_RETURN char*
+ck_display_template_get_name (CkDisplayTemplate   *display)
+{
+        g_return_val_if_fail (CK_IS_DISPLAY_TEMPLATE (display), NULL);
+
+        return display->priv->name;
+}
+
+G_CONST_RETURN char *
+ck_display_template_get_type_string (CkDisplayTemplate  *display)
+{
+        return display->priv->type;
+}
+
+GHashTable *
+ck_display_template_get_parameters (CkDisplayTemplate   *display)
+{
+        g_return_val_if_fail (CK_IS_DISPLAY_TEMPLATE (display), NULL);
+
+        return g_hash_table_ref (display->priv->parameters);
+}
+
diff --git a/src/ck-display-template.h b/src/ck-display-template.h
new file mode 100644
index 0000000..fa74e67
--- /dev/null
+++ b/src/ck-display-template.h
@@ -0,0 +1,57 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Authors: [email protected]
+ * Copyright (C) 2009 Sun Microsystems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef __CK_DISPLAY_TEMPLATE_H
+#define __CK_DISPLAY_TEMPLATE_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define CK_TYPE_DISPLAY_TEMPLATE         (ck_display_template_get_type ())
+#define CK_DISPLAY_TEMPLATE(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), CK_TYPE_DISPLAY_TEMPLATE, CkDisplayTemplate))
+#define CK_DISPLAY_TEMPLATE_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), CK_TYPE_DISPLAY_TEMPLATE, CkDisplayTemplateClass))
+#define CK_IS_DISPLAY_TEMPLATE(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), CK_TYPE_DISPLAY_TEMPLATE))
+#define CK_IS_DISPLAY_TEMPLATE_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), CK_TYPE_DISPLAY_TEMPLATE))
+#define CK_DISPLAY_TEMPLATE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CK_TYPE_DISPLAY_TEMPLATE, CkDisplayTemplateClass))
+
+typedef struct CkDisplayTemplatePrivate CkDisplayTemplatePrivate;
+
+typedef struct
+{
+        GObject        parent;
+        CkDisplayTemplatePrivate *priv;
+} CkDisplayTemplate;
+
+typedef struct
+{
+        GObjectClass   parent_class;
+} CkDisplayTemplateClass;
+
+GType                 ck_display_template_get_type            (void);
+CkDisplayTemplate   * ck_display_template_get_from_name       (const char      *name);
+G_CONST_RETURN char * ck_display_template_get_name            (CkDisplayTemplate   *display);
+G_CONST_RETURN char * ck_display_template_get_type_string     (CkDisplayTemplate   *display);
+GHashTable          * ck_display_template_get_parameters      (CkDisplayTemplate   *display);
+
+G_END_DECLS
+
+#endif /* __CK_DISPLAY_TEMPLATE_H */
diff --git a/src/ck-log-event.c b/src/ck-log-event.c
index 66f439c..d13a0f8 100644
--- a/src/ck-log-event.c
+++ b/src/ck-log-event.c
@@ -79,6 +79,8 @@ event_seat_session_added_free (CkLogSeatSessionAddedEvent *event)
         event->session_id = NULL;
         g_free (event->session_type);
         event->session_type = NULL;
+        g_free (event->display_type);
+        event->display_type = NULL;
         g_free (event->session_x11_display);
         event->session_x11_display = NULL;
         g_free (event->session_x11_display_device);
@@ -103,6 +105,8 @@ event_seat_session_removed_free (CkLogSeatSessionRemovedEvent *event)
         event->session_id = NULL;
         g_free (event->session_type);
         event->session_type = NULL;
+        g_free (event->display_type);
+        event->display_type = NULL;
         g_free (event->session_x11_display);
         event->session_x11_display = NULL;
         g_free (event->session_x11_display_device);
@@ -213,6 +217,7 @@ event_seat_session_added_copy (CkLogSeatSessionAddedEvent *event,
         event_copy->seat_id = g_strdup (event->seat_id);
         event_copy->session_id = g_strdup (event->session_id);
         event_copy->session_type = g_strdup (event->session_type);
+        event_copy->display_type = g_strdup (event->display_type);
         event_copy->session_x11_display = g_strdup (event->session_x11_display);
         event_copy->session_x11_display_device = g_strdup (event->session_x11_display_device);
         event_copy->session_display_device = g_strdup (event->session_display_device);
@@ -232,6 +237,7 @@ event_seat_session_removed_copy (CkLogSeatSessionRemovedEvent *event,
         event_copy->seat_id = g_strdup (event->seat_id);
         event_copy->session_id = g_strdup (event->session_id);
         event_copy->session_type = g_strdup (event->session_type);
+        event_copy->display_type = g_strdup (event->display_type);
         event_copy->session_x11_display = g_strdup (event->session_x11_display);
         event_copy->session_x11_display_device = g_strdup (event->session_x11_display_device);
         event_copy->session_display_device = g_strdup (event->session_display_device);
@@ -415,10 +421,11 @@ add_log_for_seat_session_added (GString    *str,
 
         e = (CkLogSeatSessionAddedEvent *)event;
         g_string_append_printf (str,
-                                "seat-id='%s' session-id='%s' session-type='%s' session-x11-display='%s' session-x11-display-device='%s' session-display-device='%s' session-remote-host-name='%s' session-is-local=%s session-unix-user=%u session-creation-time='%s'",
+                                "seat-id='%s' session-id='%s' session-type='%s' display-type='%s' session-x11-display='%s' session-x11-display-device='%s' session-display-device='%s' session-remote-host-name='%s' session-is-local=%s session-unix-user=%u session-creation-time='%s'",
                                 e->seat_id ? e->seat_id : "",
                                 e->session_id ? e->session_id : "",
                                 e->session_type ? e->session_type : "",
+                                e->display_type ? e->display_type : "",
                                 e->session_x11_display ? e->session_x11_display : "",
                                 e->session_x11_display_device ? e->session_x11_display_device : "",
                                 e->session_display_device ? e->session_display_device : "",
@@ -436,10 +443,11 @@ add_log_for_seat_session_removed (GString    *str,
 
         e = (CkLogSeatSessionRemovedEvent *)event;
         g_string_append_printf (str,
-                                "seat-id='%s' session-id='%s' session-type='%s' session-x11-display='%s' session-x11-display-device='%s' session-display-device='%s' session-remote-host-name='%s' session-is-local=%s session-unix-user=%u session-creation-time='%s'",
+                                "seat-id='%s' session-id='%s' session-type='%s' display-type='%s' session-x11-display='%s' session-x11-display-device='%s' session-display-device='%s' session-remote-host-name='%s' session-is-local=%s session-unix-user=%u session-creation-time='%s'",
                                 e->seat_id ? e->seat_id : "",
                                 e->session_id ? e->session_id : "",
                                 e->session_type ? e->session_type : "",
+                                e->display_type ? e->display_type : "",
                                 e->session_x11_display ? e->session_x11_display : "",
                                 e->session_x11_display_device ? e->session_x11_display_device : "",
                                 e->session_display_device ? e->session_display_device : "",
@@ -721,7 +729,7 @@ parse_log_for_seat_added (const GString *str,
         error = NULL;
         re = g_regex_new ("seat-id='(?P<seatid>[a-zA-Z0-9/]+)' seat-kind=(?P<sessionid>[0-9]*)", 0, 0, &error);
         if (re == NULL) {
-                g_warning (error->message);
+                g_warning ("%s", error->message);
                 goto out;
         }
 
@@ -781,7 +789,7 @@ parse_log_for_seat_removed (const GString *str,
         error = NULL;
         re = g_regex_new ("seat-id='(?P<seatid>[a-zA-Z0-9/]+)' seat-kind=(?P<sessionid>[0-9]*)", 0, 0, &error);
         if (re == NULL) {
-                g_warning (error->message);
+                g_warning ("%s", error->message);
                 goto out;
         }
 
@@ -887,7 +895,7 @@ parse_log_for_system_start (const GString *str,
         error = NULL;
         re = g_regex_new ("(kernel-release='(?P<release>[^']+)')?[ ]?(boot-arguments='(?P<arguments>.*)')?", 0, 0, &error);
         if (re == NULL) {
-                g_warning (error->message);
+                g_warning ("%s", error->message);
                 goto out;
         }
 
@@ -939,9 +947,9 @@ parse_log_for_seat_session_added (const GString *str,
         }
 
         error = NULL;
-        re = g_regex_new ("seat-id='(?P<seatid>[a-zA-Z0-9/]+)' session-id='(?P<sessionid>[a-zA-Z0-9/]+)' session-type='(?P<sessiontype>[a-zA-Z0-9 ]*)' session-x11-display='(?P<sessionx11display>[0-9a-zA-Z.:]*)' session-x11-display-device='(?P<sessionx11displaydevice>[^']*)' session-display-device='(?P<sessiondisplaydevice>[^']*)' session-remote-host-name='(?P<sessionremovehostname>[^']*)' session-is-local=(?P<sessionislocal>[a-zA-Z]*) session-unix-user=(?P<sessionunixuser>[0-9]*) session-creation-time='(?P<sessioncreationtime>[^']*)'", 0, 0, &error);
+        re = g_regex_new ("seat-id='(?P<seatid>[a-zA-Z0-9/]+)' session-id='(?P<sessionid>[a-zA-Z0-9/]+)' session-type='(?P<sessiontype>[a-zA-Z0-9 ]*)' display-type='(?P<displaytype>[a-zA-Z0-9 ]*)' session-x11-display='(?P<sessionx11display>[0-9a-zA-Z.:]*)' session-x11-display-device='(?P<sessionx11displaydevice>[^']*)' session-display-device='(?P<sessiondisplaydevice>[^']*)' session-remote-host-name='(?P<sessionremovehostname>[^']*)' session-is-local=(?P<sessionislocal>[a-zA-Z]*) session-unix-user=(?P<sessionunixuser>[0-9]*) session-creation-time='(?P<sessioncreationtime>[^']*)'", 0, 0, &error);
         if (re == NULL) {
-                g_warning (error->message);
+                g_warning ("%s", error->message);
                 goto out;
         }
 
@@ -957,6 +965,7 @@ parse_log_for_seat_session_added (const GString *str,
         e->seat_id = g_match_info_fetch_named (match_info, "seatid");
         e->session_id = g_match_info_fetch_named (match_info, "sessionid");
         e->session_type = g_match_info_fetch_named (match_info, "sessiontype");
+        e->display_type = g_match_info_fetch_named (match_info, "displaytype");
         e->session_x11_display = g_match_info_fetch_named (match_info, "sessionx11display");
         e->session_x11_display_device = g_match_info_fetch_named (match_info, "sessionx11displaydevice");
         e->session_display_device = g_match_info_fetch_named (match_info, "sessiondisplaydevice");
@@ -1014,9 +1023,9 @@ parse_log_for_seat_session_removed (const GString *str,
         }
 
         error = NULL;
-        re = g_regex_new ("seat-id='(?P<seatid>[a-zA-Z0-9/]+)' session-id='(?P<sessionid>[a-zA-Z0-9/]+)' session-type='(?P<sessiontype>[a-zA-Z0-9 ]*)' session-x11-display='(?P<sessionx11display>[0-9a-zA-Z.:]*)' session-x11-display-device='(?P<sessionx11displaydevice>[^']*)' session-display-device='(?P<sessiondisplaydevice>[^']*)' session-remote-host-name='(?P<sessionremovehostname>[^']*)' session-is-local=(?P<sessionislocal>[a-zA-Z]*) session-unix-user=(?P<sessionunixuser>[0-9]*) session-creation-time='(?P<sessioncreationtime>[^']*)'", 0, 0, &error);
+        re = g_regex_new ("seat-id='(?P<seatid>[a-zA-Z0-9/]+)' session-id='(?P<sessionid>[a-zA-Z0-9/]+)' session-type='(?P<sessiontype>[a-zA-Z0-9 ]*)' display-type='(?P<displaytype>[a-zA-Z0-9 ]*)' session-x11-display='(?P<sessionx11display>[0-9a-zA-Z.:]*)' session-x11-display-device='(?P<sessionx11displaydevice>[^']*)' session-display-device='(?P<sessiondisplaydevice>[^']*)' session-remote-host-name='(?P<sessionremovehostname>[^']*)' session-is-local=(?P<sessionislocal>[a-zA-Z]*) session-unix-user=(?P<sessionunixuser>[0-9]*) session-creation-time='(?P<sessioncreationtime>[^']*)'", 0, 0, &error);
         if (re == NULL) {
-                g_warning (error->message);
+                g_warning ("%s", error->message);
                 goto out;
         }
 
@@ -1032,6 +1041,7 @@ parse_log_for_seat_session_removed (const GString *str,
         e->seat_id = g_match_info_fetch_named (match_info, "seatid");
         e->session_id = g_match_info_fetch_named (match_info, "sessionid");
         e->session_type = g_match_info_fetch_named (match_info, "sessiontype");
+        e->display_type = g_match_info_fetch_named (match_info, "displaytype");
         e->session_x11_display = g_match_info_fetch_named (match_info, "sessionx11display");
         e->session_x11_display_device = g_match_info_fetch_named (match_info, "sessionx11displaydevice");
         e->session_display_device = g_match_info_fetch_named (match_info, "sessiondisplaydevice");
@@ -1090,7 +1100,7 @@ parse_log_for_seat_active_session_changed (const GString *str,
         error = NULL;
         re = g_regex_new ("seat-id='(?P<seatid>[a-zA-Z0-9/]+)' session-id='(?P<sessionid>[a-zA-Z0-9/]*)'", 0, 0, &error);
         if (re == NULL) {
-                g_warning (error->message);
+                g_warning ("%s", error->message);
                 goto out;
         }
 
@@ -1142,7 +1152,7 @@ parse_log_for_seat_device_added (const GString *str,
         error = NULL;
         re = g_regex_new ("seat-id='(?P<seatid>[a-zA-Z0-9/]+)' device-id='(?P<deviceid>[^']+)' device-type='(?P<devicetype>[^']+)'", 0, 0, &error);
         if (re == NULL) {
-                g_warning (error->message);
+                g_warning ("%s", error->message);
                 goto out;
         }
 
@@ -1195,7 +1205,7 @@ parse_log_for_seat_device_removed (const GString *str,
         error = NULL;
         re = g_regex_new ("seat-id='(?P<seatid>[a-zA-Z0-9/]+)' device-id='(?P<deviceid>[^']+)' device-type='(?P<devicetype>[^']+)'", 0, 0, &error);
         if (re == NULL) {
-                g_warning (error->message);
+                g_warning ("%s", error->message);
                 goto out;
         }
 
diff --git a/src/ck-log-event.h b/src/ck-log-event.h
index 65571f0..2d4ed4e 100644
--- a/src/ck-log-event.h
+++ b/src/ck-log-event.h
@@ -68,6 +68,7 @@ typedef struct
 {
         char *seat_id;
         int   seat_kind;
+        char *seat_type;
 } CkLogSeatAddedEvent;
 
 typedef struct
@@ -81,11 +82,13 @@ typedef struct
         char    *seat_id;
         char    *session_id;
         char    *session_type;
+        char    *display_type;
         char    *session_x11_display;
         char    *session_x11_display_device;
         char    *session_display_device;
         char    *session_remote_host_name;
         gboolean session_is_local;
+        gboolean session_is_dynamic;
         guint    session_unix_user;
         char    *session_creation_time;
 } CkLogSeatSessionAddedEvent;
@@ -95,11 +98,13 @@ typedef struct
         char    *seat_id;
         char    *session_id;
         char    *session_type;
+        char    *display_type;
         char    *session_x11_display;
         char    *session_x11_display_device;
         char    *session_display_device;
         char    *session_remote_host_name;
         gboolean session_is_local;
+        gboolean session_is_dynamic;
         guint    session_unix_user;
         char    *session_creation_time;
 } CkLogSeatSessionRemovedEvent;
--- ConsoleKit-0.4.1/src/ck-manager.c.1	2010-09-06 17:41:32.942210394 +0800
+++ ConsoleKit-0.4.1/src/ck-manager.c	2010-09-06 17:41:56.671280731 +0800
@@ -46,9 +46,14 @@
 #include <secdb.h>
 #endif
 
+#ifndef HAVE_STRVERSCMP
+#include "strverscmp.h"
+#endif
+
 #include "ck-manager.h"
 #include "ck-manager-glue.h"
 #include "ck-seat.h"
+#include "ck-display-template.h"
 #include "ck-session-leader.h"
 #include "ck-session.h"
 #include "ck-marshal.h"
@@ -58,12 +63,19 @@
 
 #define CK_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CK_TYPE_MANAGER, CkManagerPrivate))
 
+#define CK_TYPE_PARAMETER_STRUCT (dbus_g_type_get_struct ("GValueArray", \
+                                                          G_TYPE_STRING, \
+                                                          G_TYPE_VALUE, \
+                                                          G_TYPE_INVALID))
+
 #define CK_SEAT_DIR          SYSCONFDIR "/ConsoleKit/seats.d"
 #define LOG_FILE             LOCALSTATEDIR "/log/ConsoleKit/history"
 #define CK_DBUS_PATH         "/org/freedesktop/ConsoleKit"
 #define CK_MANAGER_DBUS_PATH CK_DBUS_PATH "/Manager"
 #define CK_MANAGER_DBUS_NAME "org.freedesktop.ConsoleKit.Manager"
 
+#define IS_STR_SET(x) (x != NULL && x[0] != '\0')
+
 struct CkManagerPrivate
 {
 #ifdef HAVE_POLKIT
@@ -392,6 +404,7 @@
         GError            *error;
         char              *sid;
         CkSeatKind         seat_kind;
+        char              *seat_type;
 
         memset (&event, 0, sizeof (CkLogEvent));
 
@@ -401,9 +414,11 @@
         sid = NULL;
         ck_seat_get_id (seat, &sid, NULL);
         ck_seat_get_kind (seat, &seat_kind, NULL);
+        ck_seat_get_type_string (seat, &seat_type, NULL);
 
         event.event.seat_added.seat_id = (char *)get_object_id_basename (sid);
         event.event.seat_added.seat_kind = (int)seat_kind;
+        event.event.seat_added.seat_type = (char *)seat_type;
 
         error = NULL;
         res = ck_event_logger_queue_event (manager->priv->logger, &event, &error);
@@ -413,6 +428,7 @@
         }
 
         g_free (sid);
+        g_free (seat_type);
 }
 
 static void
@@ -517,6 +533,7 @@
         if (session != NULL) {
                 g_object_get (session,
                               "session-type", &event.event.seat_session_added.session_type,
+                              "display-type", &event.event.seat_session_added.display_type,
                               "x11-display", &event.event.seat_session_added.session_x11_display,
                               "x11-display-device", &event.event.seat_session_added.session_x11_display_device,
                               "display-device", &event.event.seat_session_added.session_display_device,
@@ -572,6 +589,7 @@
         if (session != NULL) {
                 g_object_get (session,
                               "session-type", &event.event.seat_session_removed.session_type,
+                              "display-type", &event.event.seat_session_removed.display_type,
                               "x11-display", &event.event.seat_session_removed.session_x11_display,
                               "x11-display-device", &event.event.seat_session_removed.session_x11_display_device,
                               "display-device", &event.event.seat_session_removed.session_display_device,
@@ -1311,15 +1329,21 @@
 }
 
 static CkSeat *
-add_new_seat (CkManager *manager,
-              CkSeatKind kind)
+add_new_seat (CkManager  *manager,
+              const char *give_sid,
+              CkSeatKind  kind,
+              const char *type)
 {
         char   *sid;
         CkSeat *seat;
 
-        sid = generate_seat_id (manager);
+        if (IS_STR_SET (give_sid)) {
+                sid = g_strdup (give_sid);
+        } else {
+                sid = generate_seat_id (manager);
+        }
 
-        seat = ck_seat_new (sid, kind);
+        seat = ck_seat_new (sid, kind, type);
 
         /* First we connect our own signals to the seat, followed by
          * the D-Bus signal hookup to make sure we can first dump the
@@ -1344,7 +1368,7 @@
         ck_seat_run_programs (seat, NULL, NULL, "seat_added");
 
         g_debug ("Emitting seat-added: %s", sid);
-        g_signal_emit (manager, signals [SEAT_ADDED], 0, sid);
+        g_signal_emit (manager, signals [SEAT_ADDED], 0, sid, type);
 
         log_seat_added_event (manager, seat);
 
@@ -1402,64 +1426,22 @@
         g_free (sid);
 }
 
-#define IS_STR_SET(x) (x != NULL && x[0] != '\0')
-
 static CkSeat *
 find_seat_for_session (CkManager *manager,
                        CkSession *session)
 {
         CkSeat  *seat;
-        gboolean is_static_x11;
-        gboolean is_static_text;
-        char    *display_device;
-        char    *x11_display_device;
-        char    *x11_display;
-        char    *remote_host_name;
-        gboolean is_local;
-
-        is_static_text = FALSE;
-        is_static_x11 = FALSE;
-
-        seat = NULL;
-        display_device = NULL;
-        x11_display_device = NULL;
-        x11_display = NULL;
-        remote_host_name = NULL;
-        is_local = FALSE;
-
-        /* FIXME: use matching to group entries? */
-
-        ck_session_get_display_device (session, &display_device, NULL);
-        ck_session_get_x11_display_device (session, &x11_display_device, NULL);
-        ck_session_get_x11_display (session, &x11_display, NULL);
-        ck_session_get_remote_host_name (session, &remote_host_name, NULL);
-        ck_session_is_local (session, &is_local, NULL);
-
-        if (IS_STR_SET (x11_display)
-            && IS_STR_SET (x11_display_device)
-            && ! IS_STR_SET (remote_host_name)
-            && is_local == TRUE) {
-                is_static_x11 = TRUE;
-        } else if (! IS_STR_SET (x11_display)
-                   && ! IS_STR_SET (x11_display_device)
-                   && IS_STR_SET (display_device)
-                   && ! IS_STR_SET (remote_host_name)
-                   && is_local == TRUE) {
-                is_static_text = TRUE;
-        }
+        char    *sid = NULL;
+
+        ck_session_get_seat_id (session, &sid, NULL);
 
-        if (is_static_x11 || is_static_text) {
-                char *sid;
+        if (! IS_STR_SET (sid)) {
                 sid = g_strdup_printf ("%s/Seat%u", CK_DBUS_PATH, 1);
-                seat = g_hash_table_lookup (manager->priv->seats, sid);
-                g_free (sid);
         }
 
-        g_free (display_device);
-        g_free (x11_display_device);
-        g_free (x11_display);
-        g_free (remote_host_name);
+        seat = g_hash_table_lookup (manager->priv->seats, sid);
 
+        g_free (sid);
         return seat;
 }
 
@@ -1594,36 +1576,49 @@
         CkSession   *session;
         CkSeat      *seat;
         const char  *ssid;
+        char        *sid;
         const char  *cookie;
 
         ssid = ck_session_leader_peek_session_id (leader);
         cookie = ck_session_leader_peek_cookie (leader);
 
-        session = ck_session_new_with_parameters (ssid,
-                                                  cookie,
-                                                  parameters);
+        session = g_hash_table_lookup (manager->priv->sessions, ssid);
 
         if (session == NULL) {
-                GError *error;
-                g_debug ("Unable to create new session");
-                error = g_error_new (CK_MANAGER_ERROR,
-                                     CK_MANAGER_ERROR_GENERAL,
-                                     "Unable to create new session");
-                dbus_g_method_return_error (context, error);
-                g_error_free (error);
+                session = ck_session_new_with_parameters (ssid,
+                                                          parameters);
 
-                return;
+                if (session == NULL) {
+                        GError *error;
+                        g_debug ("Unable to create new session");
+                        error = g_error_new (CK_MANAGER_ERROR,
+                                             CK_MANAGER_ERROR_GENERAL,
+                                             "Unable to create new session");
+                        dbus_g_method_return_error (context, error);
+                        g_error_free (error);
+
+                        return;
+                }
+
+                g_hash_table_insert (manager->priv->sessions,
+                                     g_strdup (ssid),
+                                     g_object_ref (session));
+
+        } else {
+                ck_session_set_parameters (session, parameters);
         }
 
-        g_hash_table_insert (manager->priv->sessions,
-                             g_strdup (ssid),
-                             g_object_ref (session));
+        ck_session_set_cookie (session, cookie, NULL);
+        ck_session_set_is_open (session, TRUE, NULL);
 
         /* Add to seat */
         seat = find_seat_for_session (manager, session);
         if (seat == NULL) {
+                sid = NULL;
+                ck_session_get_seat_id (session, &sid, NULL);
                 /* create a new seat */
-                seat = add_new_seat (manager, CK_SEAT_KIND_DYNAMIC);
+                seat = add_new_seat (manager, sid, CK_SEAT_KIND_DYNAMIC, "Default");
+                g_free (sid);
         }
 
         ck_seat_add_session (seat, session, NULL);
@@ -1697,11 +1692,57 @@
         }
 }
 
+static char *
+check_parameters_for_ssid (const GPtrArray *parameters)
+{
+        int i;
+
+        if (parameters == NULL) {
+                return NULL;
+        }
+
+        for (i = 0; i < parameters->len; i++) {
+                GValue   val_struct = { 0, };
+                char    *prop_name;
+                gboolean res;
+
+                g_value_init (&val_struct, CK_TYPE_PARAMETER_STRUCT);
+                g_value_set_static_boxed (&val_struct, g_ptr_array_index (parameters, i));
+
+                res = dbus_g_type_struct_get (&val_struct,
+                                              0, &prop_name,
+                                              G_MAXUINT);
+                if (! res) {
+                        g_debug ("Unable to read parameter name");
+                        continue;
+                }
+
+                if (prop_name != NULL && strcmp (prop_name, "session") == 0) {
+                        GValue   prop_val = { 0, };
+                        GValue  *session_val;
+
+                        g_value_init (&prop_val, G_TYPE_VALUE);
+                        res = dbus_g_type_struct_get_member (&val_struct, 1, &prop_val);
+
+                        if (! res) {
+                                g_debug ("Unable to read parameter value");
+                                continue;
+                        }
+
+                        session_val = g_value_get_boxed (&prop_val);
+
+                        return g_value_dup_string (session_val);
+                }
+        }
+
+        return NULL;
+}
+
 static gboolean
-create_session_for_sender (CkManager             *manager,
-                           const char            *sender,
-                           const GPtrArray       *parameters,
-                           DBusGMethodInvocation *context)
+open_session_for_sender (CkManager             *manager,
+                         const char            *sender,
+                         const GPtrArray       *parameters,
+                         DBusGMethodInvocation *context)
 {
         pid_t           pid;
         uid_t           uid;
@@ -1709,6 +1750,7 @@
         char            *cookie;
         char            *ssid;
         CkSessionLeader *leader;
+        CkSession       *session;
 
         g_debug ("CkManager: create session for sender: %s", sender);
 
@@ -1727,9 +1769,21 @@
         }
 
         cookie = generate_session_cookie (manager);
-        ssid = generate_session_id (manager);
 
-        g_debug ("Creating new session ssid: %s", ssid);
+        ssid = check_parameters_for_ssid (parameters);
+
+        if (IS_STR_SET (ssid)) {
+                session = g_hash_table_lookup (manager->priv->sessions, ssid);
+
+                /* FIXME: Need to verify that the session belongs to a seat
+                 * managed by the sender
+                 */
+                g_debug ("Managing existing session ssid: %s", ssid);
+        } else {
+                ssid = generate_session_id (manager);
+                session = NULL;
+                g_debug ("Creating new session ssid: %s", ssid);
+        }
 
         leader = ck_session_leader_new ();
         ck_session_leader_set_uid (leader, uid);
@@ -1967,7 +2021,7 @@
         gboolean ret;
 
         sender = dbus_g_method_get_sender (context);
-        ret = create_session_for_sender (manager, sender, NULL, context);
+        ret = open_session_for_sender (manager, sender, NULL, context);
         g_free (sender);
 
         return ret;
@@ -1982,7 +2036,7 @@
         gboolean ret;
 
         sender = dbus_g_method_get_sender (context);
-        ret = create_session_for_sender (manager, sender, parameters, context);
+        ret = open_session_for_sender (manager, sender, parameters, context);
         g_free (sender);
 
         return ret;
@@ -1999,10 +2053,12 @@
         char            *sid;
         gboolean         res;
         gboolean         ret;
+        gboolean         should_remove_session;
 
         ret = FALSE;
         orig_ssid = NULL;
         orig_session = NULL;
+        should_remove_session = FALSE;
 
         g_debug ("Removing session for cookie: %s", cookie);
 
@@ -2029,6 +2085,17 @@
                 goto out;
         }
 
+        ck_session_set_is_open (orig_session, FALSE, NULL);
+        ck_session_set_cookie (orig_session, NULL, NULL);
+        ck_session_set_active (orig_session, FALSE, NULL);
+        ck_session_set_unix_user (orig_session, 0, NULL);
+        ck_session_set_x11_display (orig_session, NULL, NULL);
+        ck_session_set_x11_display_device (orig_session, NULL, NULL);
+        ck_session_set_display_device (orig_session, NULL, NULL);
+        ck_session_set_login_session_id (orig_session, NULL, NULL);
+        ck_session_set_remote_host_name (orig_session, NULL, NULL);
+        ck_session_set_under_request (orig_session, FALSE, NULL);
+
         /* Must keep a reference to the session in the manager until
          * all events for seats are cleared.  So don't remove
          * or steal the session from the master list until
@@ -2036,31 +2103,32 @@
          * for seat removals doesn't work.
          */
 
-        /* remove from seat */
-        sid = NULL;
-        ck_session_get_seat_id (orig_session, &sid, NULL);
-        if (sid != NULL) {
-                CkSeat *seat;
-                seat = g_hash_table_lookup (manager->priv->seats, sid);
-                if (seat != NULL) {
-                        CkSeatKind kind;
-
-                        ck_seat_remove_session (seat, orig_session, NULL);
-
-                        kind = CK_SEAT_KIND_STATIC;
-                        /* if dynamic seat has no sessions then remove it */
-                        ck_seat_get_kind (seat, &kind, NULL);
-                        if (kind == CK_SEAT_KIND_DYNAMIC) {
-                                remove_seat (manager, seat);
+        ck_session_get_remove_on_close (orig_session, &should_remove_session, NULL);
+
+        if (should_remove_session) {
+                /* remove from seat */
+                sid = NULL;
+                ck_session_get_seat_id (orig_session, &sid, NULL);
+                if (sid != NULL) {
+                        CkSeat *seat;
+                        seat = g_hash_table_lookup (manager->priv->seats, sid);
+                        if (seat != NULL) {
+                                CkSeatKind kind;
+
+                                ck_seat_remove_session (seat, orig_session, NULL);
+
+                                kind = CK_SEAT_KIND_STATIC;
+                                /* if dynamic seat has no sessions then remove it */
+                                ck_seat_get_kind (seat, &kind, NULL);
                         }
                 }
-        }
-        g_free (sid);
+                g_free (sid);
 
-        /* Remove the session from the list but don't call
-         * unref until we are done with it */
-        g_hash_table_steal (manager->priv->sessions,
-                            ck_session_leader_peek_session_id (leader));
+                /* Remove the session from the list but don't call
+                 * unref until we are done with it */
+                g_hash_table_steal (manager->priv->sessions,
+                                    ck_session_leader_peek_session_id (leader));
+        }
 
         ck_manager_dump (manager);
 
@@ -2068,11 +2136,13 @@
 
         ret = TRUE;
  out:
-        if (orig_session != NULL) {
-                g_object_unref (orig_session);
-        }
-        g_free (orig_ssid);
+        if (should_remove_session) {
+                if (orig_session != NULL) {
+                        g_object_unref (orig_session);
+                }
 
+                g_free (orig_ssid);
+        }
         return ret;
 }
 
@@ -2290,9 +2360,11 @@
                               G_STRUCT_OFFSET (CkManagerClass, seat_added),
                               NULL,
                               NULL,
-                              g_cclosure_marshal_VOID__BOXED,
+                              ck_marshal_VOID__STRING_STRING,
                               G_TYPE_NONE,
-                              1, DBUS_TYPE_G_OBJECT_PATH);
+                              2,
+                              G_TYPE_STRING,
+                              G_TYPE_STRING);
         signals [SEAT_REMOVED] =
                 g_signal_new ("seat-removed",
                               G_TYPE_FROM_CLASS (object_class),
@@ -2399,6 +2471,43 @@
 }
 
 static void
+listify_unmanaged_seat_ids (char       *id,
+                            CkSeat     *seat,
+                            GPtrArray **array)
+{
+        if (ck_seat_is_managed (seat)) {
+                return;
+        }
+
+        g_ptr_array_add (*array, g_strdup (id));
+}
+
+
+/*
+  Example:
+  dbus-send --system --dest=org.freedesktop.ConsoleKit \
+  --type=method_call --print-reply --reply-timeout=2000 \
+  /org/freedesktop/ConsoleKit/Manager \
+  org.freedesktop.ConsoleKit.Manager.GetUnmanagedSeats
+*/
+gboolean
+ck_manager_get_unmanaged_seats (CkManager  *manager,
+                                GPtrArray **seats,
+                                GError    **error)
+{
+        g_return_val_if_fail (CK_IS_MANAGER (manager), FALSE);
+
+        if (seats == NULL) {
+                return FALSE;
+        }
+
+        *seats = g_ptr_array_new ();
+        g_hash_table_foreach (manager->priv->seats, (GHFunc)listify_unmanaged_seat_ids, seats);
+
+        return TRUE;
+}
+
+static void
 listify_session_ids (char       *id,
                      CkSession  *session,
                      GPtrArray **array)
@@ -2423,16 +2532,315 @@
         return TRUE;
 }
 
+/*
+  Example:
+  dbus-send --system --dest=org.freedesktop.ConsoleKit \
+  --type=method_call --print-reply --reply-timeout=2000 \
+  /org/freedesktop/ConsoleKit/Manager \
+  org.freedesktop.ConsoleKit.Manager.AddSeat string:Default
+*/
+gboolean
+ck_manager_add_seat (CkManager  *manager,
+                     const char *type,
+                     char      **sid,
+                     GError    **error)
+{
+        CkSeat    *seat;
+                
+        g_return_val_if_fail (CK_IS_MANAGER (manager), FALSE);
+
+        seat = add_new_seat (manager, NULL, CK_SEAT_KIND_DYNAMIC, type);
+
+        if (!ck_seat_get_id (seat, sid, error)) {
+                return FALSE;
+        }
+
+        return TRUE;
+}
+
+/*
+  Example:
+  dbus-send --system --dest=org.freedesktop.ConsoleKit \
+  --type=method_call --print-reply --reply-timeout=2000 \
+  /org/freedesktop/ConsoleKit/Manager \
+  org.freedesktop.ConsoleKit.Manager.AddSeatById \
+  objpath:/org/freedesktop/ConsoleKit/SeatTest \
+*/
+gboolean
+ck_manager_add_seat_by_id (CkManager  *manager,
+                           const char *type,
+                           const char *sid,
+                           GError    **error) 
+{
+        CkSeat    *seat;
+
+        g_return_val_if_fail (CK_IS_MANAGER (manager), FALSE);
+
+        seat = add_new_seat (manager, sid, CK_SEAT_KIND_DYNAMIC, type);
+
+        return !(seat == NULL);
+}
+
+/*
+  Example:
+  dbus-send --system --dest=org.freedesktop.ConsoleKit \
+  --type=method_call --print-reply --reply-timeout=2000 \
+  /org/freedesktop/ConsoleKit/Manager \
+  org.freedesktop.ConsoleKit.Manager.RemoveSeat \
+  obj:/org/freedesktop/ConsoleKit/Seat2
+*/
+gboolean
+ck_manager_remove_seat (CkManager             *manager,
+                        const char            *sid,
+                        DBusGMethodInvocation *context)
+{
+        CkSeat     *seat = NULL;
+        CkSeatKind kind;
+
+        g_return_val_if_fail (CK_IS_MANAGER (manager), FALSE);
+
+        seat = g_hash_table_lookup (manager->priv->seats, sid);
+
+        if (seat == NULL) {
+                GError *error;
+
+                error = g_error_new (CK_SEAT_ERROR,
+                                     CK_SEAT_ERROR_GENERAL,
+                                     _("Seat '%s' doesn't exist"),
+                                     sid);
+
+                dbus_g_method_return_error (context, error);
+                g_error_free (error);
+
+                return FALSE;
+        }
+
+        ck_seat_get_kind (seat, &kind, NULL);
+
+        if (kind == CK_SEAT_KIND_STATIC) {
+                GError *error;
+
+                error = g_error_new (CK_SEAT_ERROR,
+                                     CK_SEAT_ERROR_GENERAL,
+                                     _("Seat '%s' is static and can't be removed"),
+                                     sid);
+
+                dbus_g_method_return_error (context, error);
+                g_error_free (error);
+
+                return FALSE;
+        }
+
+        if (ck_seat_is_managed (seat)) {
+                ck_seat_request_removal (seat);
+        } else {
+                remove_seat (manager, seat);
+        }
+
+        return TRUE;
+}
+
+/*
+  Example:
+  dbus-send --system --dest=org.freedesktop.ConsoleKit \
+  --type=method_call --print-reply --reply-timeout=2000 \
+  /org/freedesktop/ConsoleKit/Manager \
+  org.freedesktop.ConsoleKit.Manager.AddSession \
+  objpath:/org/freedesktop/ConsoleKit/Seat2 \
+  string:"LoginWindow" \
+  dict:string:string:"vt","vt9","display",":123"
+*/
+gboolean
+ck_manager_add_session (CkManager             *manager,
+                        const char            *sid,
+                        const char            *type,
+                        const char            *display_type,
+                        GHashTable            *variables,
+                        DBusGMethodInvocation *context)
+{
+        CkSeat    *seat;
+        CkSession *session;
+        char      *ssid;
+
+        seat = g_hash_table_lookup (manager->priv->seats, sid);
+
+        if (seat == NULL) {
+                GError *error;
+
+                error = g_error_new (CK_SEAT_ERROR,
+                                     CK_SEAT_ERROR_GENERAL, 
+                                     _("Seat '%s' doesn't exist"),
+                                     sid);
+
+                dbus_g_method_return_error (context, error);
+                g_error_free (error);
+
+                return FALSE;
+        }
+
+        ssid = generate_session_id (manager);
+
+        session = ck_session_new (ssid, type, display_type, variables);
+
+        if (session == NULL) {
+                GError *error;
+
+                error = g_error_new (CK_SEAT_ERROR, 
+                                     CK_SEAT_ERROR_GENERAL,
+                                     _("Session could not be added to seat '%s'"),
+                                     sid);
+
+                dbus_g_method_return_error (context, error);
+                g_error_free (error);
+
+                return FALSE;
+        }
+
+        ck_session_set_seat_id (session, sid, NULL);
+        if (IS_STR_SET (type) && g_str_equal (type, "LoginWindow")) {
+                session_set_remove_on_close (session, FALSE, NULL);
+        } else {
+                session_set_remove_on_close (session, TRUE, NULL);
+        }
+
+        ck_seat_add_session (seat, session, NULL);
+
+        g_hash_table_insert (manager->priv->sessions,
+                             ssid,
+                             session);
+
+        dbus_g_method_return (context, ssid);
+        return TRUE;
+}
+
+/*
+  Example:
+  dbus-send --system --dest=org.freedesktop.ConsoleKit \
+  --type=method_call --print-reply --reply-timeout=2000 \
+  /org/freedesktop/ConsoleKit/Manager \
+  org.freedesktop.ConsoleKit.Manager.RemoveSession \
+  objpath:/org/freedesktop/ConsoleKit/Session2
+*/
+gboolean
+ck_manager_remove_session (CkManager             *manager,
+                           const char            *ssid,
+                           DBusGMethodInvocation *context)
+{
+        CkSession *session;
+        CkSeat *seat;
+        GError *error; 
+        char *sid;
+        gboolean is_open;
+
+        session = g_hash_table_lookup (manager->priv->sessions, ssid);
+
+        if (session == NULL) {
+                GError *error;
+
+                error = g_error_new (CK_SEAT_ERROR,
+                                     CK_SEAT_ERROR_GENERAL,
+                                     _("Session '%s' doesn't exist"),
+                                     ssid);
+
+                dbus_g_method_return_error (context, error);
+                g_error_free (error);
+
+                return FALSE;
+        }
+
+        ck_session_get_seat_id (session, &sid, NULL);
+        seat = g_hash_table_lookup (manager->priv->seats, sid);
+        g_free (sid);
+
+        if (seat == NULL) {
+                g_warning ("Session '%s' is not associated with a seat", ssid);
+                g_hash_table_remove (manager->priv->sessions, ssid);
+                return TRUE;
+        }
+
+        error = NULL;
+
+        ck_session_is_open (session, &is_open, NULL);
+        session_set_remove_on_close (session, TRUE, NULL);
+
+        /* We'll let the seat manager close us when it's ready
+         */
+        if (ck_seat_is_managed (seat) && is_open) {
+                ck_seat_request_close_session (seat, session, NULL);
+                dbus_g_method_return (context);
+
+                return TRUE;
+        }
+
+        if (!ck_seat_remove_session (seat, session, &error)) {
+                if (error == NULL) {
+                        return TRUE;
+                }
+                
+                dbus_g_method_return_error (context, error);
+                g_error_free (error);
+                return FALSE;
+        }
+        
+        g_hash_table_remove (manager->priv->sessions, ssid);
+        dbus_g_method_return (context);
+        return TRUE;
+}
+ 
+static void
+add_sessions_from_seat (CkManager *manager,
+                        CkSeat    *seat)
+{
+        GPtrArray *sessions;
+        int i;
+
+        ck_seat_get_sessions (seat, &sessions, NULL);
+
+        for (i = 0; i < sessions->len; i++) {
+                char *ssid;
+                CkSession *session; 
+
+                ssid = g_ptr_array_index (sessions, i);
+                session = ck_seat_get_session (seat, ssid);
+
+                g_hash_table_insert (manager->priv->sessions,
+                                     ssid,
+                                     session);
+        }
+
+        g_ptr_array_free (sessions, TRUE);
+}
+
 static void
 add_seat_for_file (CkManager  *manager,
                    const char *filename)
 {
         char   *sid;
+        char   *orig_sid;
         CkSeat *seat;
 
         sid = generate_seat_id (manager);
+        orig_sid = g_strdup (sid);
+        seat = ck_seat_new_from_file (&sid, filename);
 
-        seat = ck_seat_new_from_file (sid, filename);
+        if (seat == NULL) {
+                /* returns null if connection to bus fails */
+                g_free (sid);
+                g_free (orig_sid);
+                manager->priv->seat_serial--;
+                return;
+        }
+
+        if (!g_str_equal (orig_sid, sid)) {
+                manager->priv->seat_serial--;
+        }
+        g_free (orig_sid);
+
+        add_sessions_from_seat (manager, seat);
+
+        if (seat == NULL) {
+                return;
+        }
 
         connect_seat_signals (manager, seat);
         if (!ck_seat_register (seat)) {
@@ -2451,7 +2859,7 @@
         ck_seat_run_programs (seat, NULL, NULL, "seat_added");
 
         g_debug ("Emitting seat-added: %s", sid);
-        g_signal_emit (manager, signals [SEAT_ADDED], 0, sid);
+        g_signal_emit (manager, signals [SEAT_ADDED], 0, sid, "Default");
 
         log_seat_added_event (manager, seat);
 }
@@ -2462,6 +2870,7 @@
         GDir       *d;
         GError     *error;
         const char *file;
+        GQueue      seat_queue;
 
         error = NULL;
         d = g_dir_open (CK_SEAT_DIR,
@@ -2473,15 +2882,26 @@
                 return FALSE;
         }
 
+        g_queue_init (&seat_queue);
         while ((file = g_dir_read_name (d)) != NULL) {
                 char *path;
                 path = g_build_filename (CK_SEAT_DIR, file, NULL);
+                g_queue_push_tail (&seat_queue, path);
+        }
+        g_dir_close (d);
+
+        g_queue_sort (&seat_queue, (GCompareDataFunc) strverscmp, NULL);
+
+        while (!g_queue_is_empty (&seat_queue)) {
+                char *path;
+
+                path = g_queue_pop_head (&seat_queue);
+
                 add_seat_for_file (manager, path);
+
                 g_free (path);
         }
 
-        g_dir_close (d);
-
         return TRUE;
 }
 
@@ -2517,8 +2937,6 @@
                                                         (GDestroyNotify) g_object_unref);
 
         manager->priv->logger = ck_event_logger_new (LOG_FILE);
-
-        create_seats (manager);
 }
 
 static void
@@ -2563,6 +2981,8 @@
                         g_object_unref (manager_object);
                         return NULL;
                 }
+
+                create_seats (CK_MANAGER (manager_object));
         }
 
         return CK_MANAGER (manager_object);
diff --git a/src/ck-manager.h b/src/ck-manager.h
index 4bd56e8..4304e71 100644
--- a/src/ck-manager.h
+++ b/src/ck-manager.h
@@ -49,7 +49,8 @@ typedef struct
         GObjectClass   parent_class;
 
         void          (* seat_added)               (CkManager  *manager,
-                                                    const char *sid);
+                                                    const char *sid,
+                                                    const char *type);
         void          (* seat_removed)             (CkManager  *manager,
                                                     const char *sid);
         void          (* system_idle_hint_changed) (CkManager  *manager,
@@ -96,6 +97,9 @@ gboolean            ck_manager_get_sessions                   (CkManager
 gboolean            ck_manager_get_seats                      (CkManager             *manager,
                                                                GPtrArray            **seats,
                                                                GError               **error);
+gboolean            ck_manager_get_unmanaged_seats            (CkManager             *manager,
+                                                               GPtrArray            **seats,
+                                                               GError               **error);
 gboolean            ck_manager_close_session                  (CkManager             *manager,
                                                                const char            *cookie,
                                                                DBusGMethodInvocation *context);
@@ -128,6 +132,28 @@ gboolean            ck_manager_open_session_with_parameters   (CkManager
                                                                const GPtrArray       *parameters,
                                                                DBusGMethodInvocation *context);
 
+gboolean            ck_manager_add_seat                       (CkManager             *manager,
+                                                               const char            *type,
+                                                               char                 **sid,
+                                                               GError               **error);
+gboolean            ck_manager_add_seat_by_id                 (CkManager             *manager,
+                                                               const char            *type,
+                                                               const char            *sid,
+                                                               GError               **error);
+gboolean            ck_manager_remove_seat                    (CkManager             *manager,
+                                                               const char            *sid,
+                                                               DBusGMethodInvocation *context);
+
+gboolean            ck_manager_add_session                    (CkManager             *manager,
+                                                               const char            *sid,
+                                                               const char            *type,
+                                                               const char            *display_type,
+                                                               GHashTable            *parameters,
+                                                               DBusGMethodInvocation *context);
+gboolean            ck_manager_remove_session                  (CkManager             *manager,
+                                                                const char            *ssid,
+                                                                DBusGMethodInvocation *context);
+
 G_END_DECLS
 
 #endif /* __CK_MANAGER_H */
diff --git a/src/ck-marshal.list b/src/ck-marshal.list
index 7f60efc..f8029a6 100644
--- a/src/ck-marshal.list
+++ b/src/ck-marshal.list
@@ -1,3 +1,5 @@
 VOID:UINT,STRING
 BOOLEAN:POINTER
+VOID:STRING,STRING
+VOID:STRING,BOOLEAN,STRING,POINTER,STRING,POINTER
 VOID:OBJECT,OBJECT
diff --git a/src/ck-seat.c b/src/ck-seat.c
index af7db59..dd2a387 100644
--- a/src/ck-seat.c
+++ b/src/ck-seat.c
@@ -40,21 +40,30 @@
 #include "ck-seat-glue.h"
 #include "ck-marshal.h"
 
+#include "ck-display-template.h"
 #include "ck-session.h"
 #include "ck-vt-monitor.h"
 #include "ck-run-programs.h"
 
 #define CK_SEAT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CK_TYPE_SEAT, CkSeatPrivate))
 
+#define CK_SESSION_DIR SYSCONFDIR "/ConsoleKit/sessions.d"
+
 #define CK_DBUS_PATH "/org/freedesktop/ConsoleKit"
 #define CK_DBUS_NAME "org.freedesktop.ConsoleKit"
 
 #define NONULL_STRING(x) ((x) != NULL ? (x) : "")
+#define N_ELEMENTS(arr)  (sizeof (arr) / sizeof ((arr)[0]))
+
+#define IS_STR_SET(x) (x != NULL && x[0] != '\0')
+
+#define CK_DBUS_TYPE_G_STRING_STRING_HASHTABLE (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_STRING))
 
 struct CkSeatPrivate
 {
         char            *id;
         CkSeatKind       kind;
+        char            *type;
         GHashTable      *sessions;
         GPtrArray       *devices;
 
@@ -63,6 +72,8 @@ struct CkSeatPrivate
         CkVtMonitor     *vt_monitor;
 
         DBusGConnection *connection;
+
+        DBusGProxy      *manager_proxy;
 };
 
 enum {
@@ -74,6 +85,7 @@ enum {
         SESSION_REMOVED_FULL,
         DEVICE_ADDED,
         DEVICE_REMOVED,
+        REMOVE_REQUEST,
         LAST_SIGNAL
 };
 
@@ -81,6 +93,7 @@ enum {
         PROP_0,
         PROP_ID,
         PROP_KIND,
+        PROP_TYPE
 };
 
 static guint signals [LAST_SIGNAL] = { 0, };
@@ -287,6 +300,7 @@ ck_seat_activate_session (CkSeat                *seat,
 {
         CkSession *session;
         gboolean   ret;
+        gboolean   is_open;
 
         g_return_val_if_fail (CK_IS_SEAT (seat), FALSE);
 
@@ -298,12 +312,390 @@ ck_seat_activate_session (CkSeat                *seat,
                 session = g_hash_table_lookup (seat->priv->sessions, ssid);
         }
 
-        ret = _seat_activate_session (seat, session, context);
+        ck_session_is_open (session, &is_open, NULL);
+        if (!is_open) {
+                ret = ck_seat_request_open_session (seat, session, NULL);
+                dbus_g_method_return (context, NULL);
+        } else {
+                ret = _seat_activate_session (seat, session, context);
+        }
 
         return ret;
 }
 
 static gboolean
+on_substitution_match (const GMatchInfo *match_info,
+                       GString          *result,
+                       GHashTable       *substitution_variables)
+{
+        char *match;
+        char *value;
+
+        match = g_match_info_fetch (match_info, 1);
+
+        value = g_hash_table_lookup (substitution_variables, match);
+
+        if (value != NULL) {
+                g_string_append (result, value);
+        } else {
+                char *original_string;
+
+                original_string = g_match_info_fetch (match_info, 0);
+                g_string_append (result, original_string);
+                g_free (original_string);
+        }
+        g_free (match);
+
+        return FALSE;
+}
+
+static char *
+apply_substitutions (const char *value,
+                     GHashTable *substitution_variables)
+{
+        GRegex *expression;
+        char *expanded_string;
+
+        expression = g_regex_new ("\\$([^[:space:]]+)", 0, 0, NULL);
+        expanded_string = g_regex_replace_eval (expression,
+                                                value,
+                                                -1, 0, 0,
+                                                (GRegexEvalCallback)
+                                                on_substitution_match,
+                                                substitution_variables,
+                                                NULL);
+
+        if (expanded_string == NULL) {
+                expanded_string = g_strdup (value);
+        }
+
+        return expanded_string;
+}
+
+static GHashTable *
+get_evaluated_parameter_map (GHashTable    *parameters,
+                             GHashTable    *substitution_variables)
+{
+        GHashTable *evaluated_parameters;
+        GHashTableIter iter;
+        gpointer key, value;
+
+        evaluated_parameters = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                                      (GDestroyNotify) g_free,
+                                                      (GDestroyNotify) g_free);
+
+        g_hash_table_iter_init (&iter, parameters);
+        while (g_hash_table_iter_next (&iter, &key, &value)) {
+                char *expanded_string;
+
+                expanded_string = apply_substitutions ((char *) value,
+                                                       substitution_variables);
+
+                g_hash_table_insert (evaluated_parameters,
+                                     g_strdup ((char *) key),
+                                     expanded_string);
+        }
+
+        return evaluated_parameters;
+}
+
+static void
+request_session (gpointer key,
+                 gpointer value,
+                 gpointer user_data)
+{
+        CkSeat      *seat = CK_SEAT (user_data);
+        CkSession   *session = (CkSession *) value;
+
+        ck_session_set_ever_open (session, FALSE, NULL);
+        ck_session_set_under_request (session, FALSE, NULL);
+        ck_seat_request_open_session (seat, session, NULL);
+}
+
+static void
+append_hash_table_to_dbus_message_iter (DBusMessageIter *iter,
+                                        GHashTable      *hash_table)
+{
+        GHashTableIter hash_table_iter;
+        gpointer key, value;
+        DBusMessageIter array_iter;
+
+        dbus_message_iter_open_container (iter,
+                                          DBUS_TYPE_ARRAY,
+                                          DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                                          DBUS_TYPE_STRING_AS_STRING
+                                          DBUS_TYPE_STRING_AS_STRING
+                                          DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+                                          &array_iter);
+
+
+        g_hash_table_iter_init (&hash_table_iter, hash_table);
+        while (g_hash_table_iter_next (&hash_table_iter, &key, &value)) {
+                DBusMessageIter dict_iter;
+
+                dbus_message_iter_open_container (&array_iter,
+                                                  DBUS_TYPE_DICT_ENTRY,
+                                                  NULL,
+                                                  &dict_iter);
+
+                dbus_message_iter_append_basic (&dict_iter, DBUS_TYPE_STRING, &key);
+                dbus_message_iter_append_basic (&dict_iter, DBUS_TYPE_STRING, &value);
+                dbus_message_iter_close_container (&array_iter, &dict_iter);
+        }
+        dbus_message_iter_close_container (iter, &array_iter);
+}
+
+static void
+emit_session_open_request (CkSeat     *seat,
+                          const char *ssid,
+                          const char *session_type,
+                          const char *display_template_name,
+                          GHashTable *display_variables,
+                          const char *display_type,
+                          GHashTable *evaluated_parameters)
+{
+        DBusMessage    *message;
+        DBusConnection *connection;
+        DBusMessageIter iter;
+
+        if (!ck_seat_is_managed (seat))
+                return;
+
+        message = dbus_message_new_signal (seat->priv->id,
+                                           "org.freedesktop.ConsoleKit.Seat",
+                                           "OpenSessionRequest");
+
+        dbus_message_set_destination (message,
+                                      dbus_g_proxy_get_bus_name (seat->priv->manager_proxy));
+
+        dbus_message_iter_init_append (message, &iter);
+        dbus_message_iter_append_basic (&iter, DBUS_TYPE_OBJECT_PATH, &ssid);
+        dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &session_type);
+        dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &display_template_name);
+        append_hash_table_to_dbus_message_iter (&iter, display_variables);
+        dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &display_type);
+        append_hash_table_to_dbus_message_iter (&iter, evaluated_parameters);
+
+        connection = dbus_bus_get (DBUS_BUS_SYSTEM, NULL);
+        dbus_connection_send (connection, message, NULL);
+        dbus_connection_unref (connection);
+        dbus_message_unref (message);
+}
+
+gboolean
+ck_seat_request_open_session (CkSeat                *seat,
+                              CkSession             *session,
+                              GError               **error)
+{
+        char        *ssid;
+        char        *type;
+        CkDisplayTemplate *display_template;
+        GHashTable  *display_variables;
+        GHashTable  *display_parameters;
+        GHashTable  *evaluated_parameters;
+        gboolean    is_open;
+        gboolean    ever_open;
+        gboolean    under_request;
+
+        ck_session_is_open (session, &is_open, NULL);
+
+        if (is_open) {
+                return TRUE;
+        }
+
+        ck_session_get_under_request (session, &under_request, NULL);
+        if (under_request) {
+                return TRUE;
+        }
+
+        ck_session_set_under_request (session, TRUE, NULL);
+
+        ck_session_get_ever_open (session, &ever_open, NULL);
+
+        display_template = ck_session_get_display_template (session);
+
+        if (display_template == NULL) {
+                return TRUE;
+        }
+
+        ck_session_get_session_type (session, &type, NULL);
+
+        if (type == NULL) {
+                g_object_unref (display_template);
+                return TRUE;
+        }
+
+        /* substitute $display $vt etc */
+        display_variables = ck_session_get_display_variables (session);
+        display_parameters = ck_display_template_get_parameters (display_template);
+
+        if (display_parameters == NULL) {
+                g_free (type);
+                g_object_unref (display_template);
+                g_hash_table_unref (display_variables);
+                return TRUE;
+        }
+
+        if (!ever_open) {
+                evaluated_parameters = get_evaluated_parameter_map (display_parameters, display_variables);
+        } else {
+                evaluated_parameters = get_evaluated_parameter_map (display_parameters, NULL);
+        }
+
+        g_hash_table_unref (display_parameters);
+
+        ck_session_get_id (session, &ssid, NULL);
+
+        emit_session_open_request (seat, ssid, type,
+                                   ck_display_template_get_name (display_template),
+                                   display_variables,
+                                   ck_display_template_get_type_string (display_template),
+                                   evaluated_parameters);
+
+        g_free (ssid);
+        g_free (type);
+        g_hash_table_unref (evaluated_parameters);
+        g_hash_table_unref (display_variables);
+        g_object_unref (display_template);
+
+        return TRUE;
+}
+
+static void
+on_seat_manager_disappeared (CkSeat *seat)
+{
+        g_signal_handlers_disconnect_by_func (seat->priv->manager_proxy,
+                                              G_CALLBACK (on_seat_manager_disappeared),
+                                              seat);
+        g_object_unref (seat->priv->manager_proxy);
+        seat->priv->manager_proxy = NULL;
+
+        /* FIXME: should probably emit a signal so a new display manager
+         * knows that the seat is now unmanaged
+         *
+         * (maybe only if its kind is static?)
+         */
+}
+
+gboolean
+ck_seat_manage (CkSeat                *seat,
+                DBusGMethodInvocation *context)
+{
+        char *sender_name;
+
+        sender_name = dbus_g_method_get_sender (context);
+
+        if (seat->priv->manager_proxy != NULL) {
+                GError *error;
+                const char   *existing_manager_name;
+
+                existing_manager_name = dbus_g_proxy_get_bus_name (seat->priv->manager_proxy);
+
+                if (existing_manager_name == NULL) {
+                        g_warning ("Seat manager lacks bus unique name");
+                        existing_manager_name = "<unknown>";
+                }
+
+                error = g_error_new (CK_SEAT_ERROR,
+                                     CK_SEAT_ERROR_GENERAL,
+                                     _("Seat already managed (by '%s')"),
+                                     existing_manager_name);
+
+                dbus_g_method_return_error (context, error);
+                g_error_free (error);
+                return FALSE;
+        }
+
+        /* FIXME: We pass in a bogus object path (the path we use on this side of
+         * the pipe) and interface here.
+         *
+         * We only use the proxy to watch for when the other side disappears, not
+         * for communicating with it.  All communication is one-way using signals.
+         */
+        seat->priv->manager_proxy = dbus_g_proxy_new_for_name (seat->priv->connection,
+
+                                                               sender_name,
+                                                               seat->priv->id,
+                                                               "org.freedesktop.ConsoleKit.SeatManager");
+        g_free (sender_name);
+
+        g_signal_connect_swapped (seat->priv->manager_proxy,
+                                  "destroy",
+                                  G_CALLBACK (on_seat_manager_disappeared),
+                                  seat);
+
+        g_hash_table_foreach (seat->priv->sessions, request_session, seat);
+
+        dbus_g_method_return (context);
+        return TRUE;
+}
+
+gboolean
+ck_seat_unmanage (CkSeat                *seat,
+                  DBusGMethodInvocation *context)
+{
+        GError *error;
+        const char   *existing_manager_name;
+        char *sender_name;
+
+        if (seat->priv->manager_proxy == NULL) {
+                GError *error;
+
+                error = g_error_new (CK_SEAT_ERROR,
+                                     CK_SEAT_ERROR_GENERAL,
+                                     _("Seat not managed"));
+
+                dbus_g_method_return_error (context, error);
+                g_error_free (error);
+                return FALSE;
+        }
+
+        sender_name = dbus_g_method_get_sender (context);
+        existing_manager_name = dbus_g_proxy_get_bus_name (seat->priv->manager_proxy);
+
+        if (strcmp (sender_name, existing_manager_name) != 0) {
+
+            error = g_error_new (CK_SEAT_ERROR,
+                                 CK_SEAT_ERROR_GENERAL,
+                                 _("Seat managed by '%s' not '%s'"),
+                                 existing_manager_name,
+                                 sender_name);
+
+            dbus_g_method_return_error (context, error);
+            g_error_free (error);
+
+            return FALSE;
+        }
+
+        on_seat_manager_disappeared (seat);
+
+        dbus_g_method_return (context);
+        return TRUE;
+}
+
+void
+ck_seat_request_removal (CkSeat *seat)
+{
+        DBusMessage    *message;
+        DBusConnection *connection;
+
+        g_return_if_fail (CK_IS_SEAT (seat));
+        g_return_if_fail (ck_seat_is_managed (seat));
+
+        message = dbus_message_new_signal (seat->priv->id,
+                                           "org.freedesktop.ConsoleKit.Seat",
+                                           "RemoveRequest");
+
+        dbus_message_set_destination (message,
+                                      dbus_g_proxy_get_bus_name (seat->priv->manager_proxy));
+
+        connection = dbus_bus_get (DBUS_BUS_SYSTEM, NULL);
+        dbus_connection_send (connection, message, NULL);
+        dbus_connection_unref (connection);
+        dbus_message_unref (message);
+}
+
+static gboolean
 match_session_display_device (const char *key,
                               CkSession  *session,
                               const char *display_device)
@@ -526,6 +918,41 @@ change_active_session (CkSeat    *seat,
 }
 
 static void
+find_possible_session_to_activate (CkSeat *seat)
+{
+        GHashTableIter iter;
+        gpointer       key, value;
+        gboolean       is_open;
+        char          *session_type = NULL;
+        CkSession     *login_session = NULL;
+
+        g_hash_table_iter_init (&iter, seat->priv->sessions);
+        while (g_hash_table_iter_next (&iter, &key, &value)) {
+
+                ck_session_is_open (value, &is_open, NULL);
+
+                if (is_open) {
+                        login_session = NULL;
+                        change_active_session (seat, value);
+                        break;
+                }
+
+                ck_session_get_session_type (value, &session_type, NULL);
+                if (IS_STR_SET (session_type) &&
+                    g_str_equal (session_type, "LoginWindow")) {
+                        login_session = value;
+                        g_free (session_type);
+                }
+        }
+
+        if (login_session != NULL) {
+                ck_session_set_ever_open (login_session, FALSE, NULL);
+                ck_seat_request_open_session (seat, login_session, NULL);
+        }
+
+}
+
+static void
 update_active_vt (CkSeat *seat,
                   guint   num)
 {
@@ -537,7 +964,12 @@ update_active_vt (CkSeat *seat,
         g_debug ("Active device: %s", device);
 
         session = find_session_for_display_device (seat, device);
-        change_active_session (seat, session);
+
+        if (session == NULL) {
+                find_possible_session_to_activate (seat);
+        } else {
+                change_active_session (seat, session);
+        }
 
         g_free (device);
 }
@@ -547,12 +979,18 @@ maybe_update_active_session (CkSeat *seat)
 {
         guint num;
 
-        if (seat->priv->kind != CK_SEAT_KIND_STATIC) {
-                return;
-        }
-
-        if (ck_vt_monitor_get_active (seat->priv->vt_monitor, &num, NULL)) {
-                update_active_vt (seat, num);
+        switch (seat->priv->kind){
+        case CK_SEAT_KIND_STATIC:
+                if (ck_vt_monitor_get_active (seat->priv->vt_monitor,
+                                              &num, NULL)) {
+                        update_active_vt (seat, num);
+                }
+                break;
+        case CK_SEAT_KIND_DYNAMIC:
+                find_possible_session_to_activate (seat);
+                break;
+        default:
+                break;
         }
 }
 
@@ -628,18 +1066,77 @@ ck_seat_remove_session (CkSeat         *seat,
         return ret;
 }
 
+static void
+emit_session_close_request (CkSeat     *seat,
+                            const char *ssid)
+{
+        DBusMessage    *message;
+        DBusConnection *connection;
+        DBusMessageIter iter;
+
+        message = dbus_message_new_signal (seat->priv->id,
+                                           "org.freedesktop.ConsoleKit.Seat",
+                                           "CloseSessionRequest");
+
+        dbus_message_set_destination (message,
+                                      dbus_g_proxy_get_bus_name (seat->priv->manager_proxy));
+
+        dbus_message_iter_init_append (message, &iter);
+        dbus_message_iter_append_basic (&iter, DBUS_TYPE_OBJECT_PATH, &ssid);
+
+        connection = dbus_bus_get (DBUS_BUS_SYSTEM, NULL);
+        dbus_connection_send (connection, message, NULL);
+        dbus_connection_unref (connection);
+        dbus_message_unref (message);
+}
+
+gboolean
+ck_seat_request_close_session (CkSeat                *seat,
+                               CkSession             *session,
+                               GError               **error)
+{
+        char      *ssid;
+
+        g_return_val_if_fail (CK_IS_SEAT (seat), FALSE);
+        g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
+        g_return_val_if_fail (ck_seat_is_managed (seat), FALSE);
+
+        ck_session_get_id (session, &ssid, NULL);
+
+        emit_session_close_request (seat, ssid);
+
+        g_free (ssid);
+
+        return FALSE;
+}
+
 gboolean
 ck_seat_add_session (CkSeat         *seat,
                      CkSession      *session,
                      GError        **error)
 {
         char *ssid;
+        GHashTableIter iter;
+        gpointer key, value;
+        gboolean found;
 
         g_return_val_if_fail (CK_IS_SEAT (seat), FALSE);
 
         ck_session_get_id (session, &ssid, NULL);
 
-        g_hash_table_insert (seat->priv->sessions, g_strdup (ssid), g_object_ref (session));
+        found = FALSE;
+        g_hash_table_iter_init (&iter, seat->priv->sessions);
+        while (g_hash_table_iter_next (&iter, &key, &value)) {
+                if (g_str_equal ((gchar *)key, ssid)) {
+                        found = TRUE;
+                        break;
+                }
+        }
+
+        if (! found)
+                g_hash_table_insert (seat->priv->sessions, g_strdup (ssid), g_object_ref (session));
+        else
+                g_object_ref (session);
 
         ck_session_set_seat_id (session, seat->priv->id, NULL);
 
@@ -656,6 +1153,10 @@ ck_seat_add_session (CkSeat         *seat,
 
         maybe_update_active_session (seat);
 
+        if (ck_seat_is_managed (seat)) {
+                ck_seat_request_open_session (seat, session, NULL);
+        }
+
         g_free (ssid);
 
         return TRUE;
@@ -742,6 +1243,20 @@ ck_seat_get_kind (CkSeat        *seat,
 }
 
 gboolean
+ck_seat_get_type_string (CkSeat                *seat,
+                         char                 **type,
+                         GError               **error)
+{
+        g_return_val_if_fail (CK_IS_SEAT (seat), FALSE);
+
+        if (type != NULL) {
+                *type = g_strdup (seat->priv->type);
+        }
+
+        return TRUE;
+}
+
+gboolean
 ck_seat_get_id (CkSeat         *seat,
                 char          **id,
                 GError        **error)
@@ -858,6 +1373,14 @@ _ck_seat_set_kind (CkSeat    *seat,
 }
 
 static void
+_ck_seat_set_type_string (CkSeat         *seat,
+                          const char     *type)
+{
+        g_free (seat->priv->type);
+        seat->priv->type = g_strdup (type);
+}
+
+static void
 ck_seat_set_property (GObject            *object,
                       guint               prop_id,
                       const GValue       *value,
@@ -874,6 +1397,9 @@ ck_seat_set_property (GObject            *object,
         case PROP_KIND:
                 _ck_seat_set_kind (self, g_value_get_enum (value));
                 break;
+        case PROP_TYPE:
+                _ck_seat_set_type_string (self, g_value_get_string (value));
+                break;
         default:
                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                 break;
@@ -895,7 +1421,10 @@ ck_seat_get_property (GObject    *object,
                 g_value_set_string (value, self->priv->id);
                 break;
         case PROP_KIND:
-                g_value_set_string (value, self->priv->id);
+                g_value_set_enum (value, self->priv->kind);
+                break;
+        case PROP_TYPE:
+                g_value_set_string (value, self->priv->type);
                 break;
         default:
                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -1008,6 +1537,15 @@ ck_seat_class_init (CkSeatClass *klass)
                                                  G_TYPE_NONE,
                                                  1, CK_TYPE_DEVICE);
 
+        signals [REMOVE_REQUEST] = g_signal_new ("remove-request",
+                                                  G_TYPE_FROM_CLASS (object_class),
+                                                  G_SIGNAL_RUN_LAST,
+                                                  G_STRUCT_OFFSET (CkSeatClass, remove_request),
+                                                  NULL,
+                                                  NULL,
+                                                  g_cclosure_marshal_VOID__VOID,
+                                                  G_TYPE_NONE, 0);
+
         g_object_class_install_property (object_class,
                                          PROP_ID,
                                          g_param_spec_string ("id",
@@ -1024,6 +1562,13 @@ ck_seat_class_init (CkSeatClass *klass)
                                                             CK_SEAT_KIND_DYNAMIC,
                                                             G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
+        g_object_class_install_property (object_class,
+                                         PROP_TYPE,
+                                         g_param_spec_string ("type",
+                                                              "type",
+                                                              "type",
+                                                              NULL,
+                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
         g_type_class_add_private (klass, sizeof (CkSeatPrivate));
 
         dbus_g_object_type_install_info (CK_TYPE_SEAT, &dbus_glib_ck_seat_object_info);
@@ -1039,6 +1584,7 @@ ck_seat_init (CkSeat *seat)
                                                       g_free,
                                                       (GDestroyNotify) g_object_unref);
         seat->priv->devices = g_ptr_array_new ();
+        seat->priv->manager_proxy = NULL;
 }
 
 static void
@@ -1064,28 +1610,32 @@ ck_seat_finalize (GObject *object)
         g_ptr_array_free (seat->priv->devices, TRUE);
         g_hash_table_destroy (seat->priv->sessions);
         g_free (seat->priv->id);
+        g_free (seat->priv->type);
 
         G_OBJECT_CLASS (ck_seat_parent_class)->finalize (object);
 }
 
 CkSeat *
 ck_seat_new (const char *sid,
-             CkSeatKind  kind)
+             CkSeatKind  kind,
+             const char *type)
 {
         GObject *object;
 
         object = g_object_new (CK_TYPE_SEAT,
                                "id", sid,
                                "kind", kind,
+                               "type", type,
                                NULL);
 
         return CK_SEAT (object);
 }
 
 CkSeat *
-ck_seat_new_with_devices (const char *sid,
-                          CkSeatKind  kind,
-                          GPtrArray  *devices)
+ck_seat_new_with_devices_and_sessions (const char *sid,
+                                       CkSeatKind  kind,
+                                       GPtrArray  *devices,
+                                       GPtrArray  *sessions)
 {
         GObject *object;
         int      i;
@@ -1100,24 +1650,57 @@ ck_seat_new_with_devices (const char *sid,
                         ck_seat_add_device (CK_SEAT (object), g_ptr_array_index (devices, i), NULL);
                 }
         }
+        if (sessions != NULL) {
+                for (i = 0; i < sessions->len; i++) {
+                        ck_seat_add_session (CK_SEAT (object), g_ptr_array_index (sessions, i), NULL);
+                }
+        }
+
 
         return CK_SEAT (object);
 }
 
+static char *
+generate_static_session_id (const char *sid,
+                            const char *session_name)
+{
+        const char *seat_name;
+        char *ssid;
+
+        seat_name = strrchr (sid, '/');
+
+        if (seat_name == NULL) {
+                g_warning ("Seat id '%s' lacks a /", sid);
+                seat_name = sid;
+        } else {
+                seat_name++;
+        }
+
+        ssid = g_strdup_printf ("%s/Session%s%s",
+                                CK_DBUS_PATH, seat_name,
+                                session_name);
+
+        return ssid;
+}
+
 CkSeat *
-ck_seat_new_from_file (const char *sid,
+ck_seat_new_from_file (char       **sid,
                        const char *path)
 {
-        GKeyFile  *key_file;
-        gboolean   res;
-        GError    *error;
-        char      *group;
-        CkSeat    *seat;
-        gboolean   hidden;
-        GPtrArray *devices;
-        char     **device_list;
-        gsize      ndevices;
-        gsize      i;
+        GKeyFile      *key_file;
+        gboolean       res;
+        GError        *error;
+        char          *group;
+        CkSeat        *seat;
+        char          *read_sid;
+        gboolean       hidden;
+        GPtrArray     *sessions;
+        char         **session_list;
+        gsize          nsessions;
+        GPtrArray     *devices;
+        char         **device_list;
+        gsize          ndevices;
+        gsize          i;
 
         seat = NULL;
 
@@ -1145,6 +1728,49 @@ ck_seat_new_from_file (const char *sid,
                 goto out;
         }
 
+        read_sid = g_key_file_get_string (key_file, group, "ID", NULL);
+        if (IS_STR_SET (read_sid)) {
+                g_free (*sid);
+                *sid = g_strdup_printf ("%s/%s", CK_DBUS_PATH, read_sid);
+        } else {
+                g_free (read_sid);
+        }
+
+        session_list = g_key_file_get_string_list (key_file, group, "Sessions", &nsessions, NULL);
+
+        sessions = g_ptr_array_sized_new (nsessions);
+
+        for (i = 0; i < nsessions; i++) {
+                char *path;
+                char *file;
+                char *ssid;
+                CkSession *session;
+
+                file = g_strconcat (session_list[i], ".session", NULL);
+                path = g_build_filename (CK_SESSION_DIR, file, NULL);
+                g_free (file);
+
+                /* FIXME: we should probably use the same naming pool as
+                 * sessions generated from ck-manager.  We mangle the name
+                 * here so we don't clash with names from ck-manager
+                 */
+                ssid = generate_static_session_id (*sid, session_list[i]);
+
+                session = ck_session_new_from_file (ssid, path);
+
+                if (session == NULL) {
+                        g_warning ("Unable to load session from file %s", path);
+                        g_free (path);
+                        continue;
+                }
+                g_free (path);
+                ck_session_set_seat_id (session, *sid, NULL);
+
+                g_ptr_array_add (sessions, session);
+        }
+
+        g_strfreev (session_list);
+
         device_list = g_key_file_get_string_list (key_file, group, "Devices", &ndevices, NULL);
 
         g_debug ("Creating seat %s with %zd devices", sid, ndevices);
@@ -1176,11 +1802,12 @@ ck_seat_new_from_file (const char *sid,
                 g_strfreev (split);
         }
         g_strfreev (device_list);
-        g_free (group);
 
-        seat = ck_seat_new_with_devices (sid, CK_SEAT_KIND_STATIC, devices);
+        seat = ck_seat_new_with_devices_and_sessions (*sid, CK_SEAT_KIND_STATIC, devices, sessions);
         g_ptr_array_free (devices, TRUE);
 
+        g_free (group);
+
 out:
 
         g_key_file_free (key_file);
@@ -1355,10 +1982,15 @@ ck_seat_dump (CkSeat   *seat,
 
                 error = NULL;
                 if (! ck_session_get_id (seat->priv->active_session, &session_id, &error)) {
-                        g_warning ("Cannot get session id for active session on seat %s: %s",
-                                   seat->priv->id,
-                                   error->message);
-                        g_error_free (error);
+                        if (error) {
+                                g_warning ("Cannot get session id for active session on seat %s: %s",
+                                           seat->priv->id,
+                                           error->message);
+                                g_error_free (error);
+                        } else {
+                                g_warning ("Cannot get session id for active session on seat %s",
+                                           seat->priv->id);
+                        }
                 } else {
                         g_key_file_set_string (key_file,
                                                group_name,
@@ -1370,3 +2002,24 @@ ck_seat_dump (CkSeat   *seat,
 
         g_free (group_name);
 }
+
+gboolean
+ck_seat_is_managed (CkSeat *seat)
+{
+        return seat->priv->manager_proxy != NULL;
+}
+
+CkSession *
+ck_seat_get_session (CkSeat                *seat,
+                     const char            *ssid)
+{
+        CkSession *session;
+
+        session = g_hash_table_lookup (seat->priv->sessions, ssid);
+
+        if (session == NULL) {
+                return NULL;
+        }
+
+        return g_object_ref (session);
+}
diff --git a/src/ck-seat.h b/src/ck-seat.h
index fb9a955..6276021 100644
--- a/src/ck-seat.h
+++ b/src/ck-seat.h
@@ -47,6 +47,7 @@ typedef struct
 {
         GObjectClass   parent_class;
 
+        void          (* remove_request)         (CkSeat      *seat);
         void          (* active_session_changed) (CkSeat      *seat,
                                                   const char  *ssid);
         void          (* session_added)          (CkSeat      *seat,
@@ -57,6 +58,11 @@ typedef struct
                                                   GValueArray *device);
         void          (* device_removed)         (CkSeat      *seat,
                                                   GValueArray *device);
+        void          (* session_to_add)         (CkSeat      *seat,
+                                                  gboolean     is_dynamic,
+                                                  const char  *command);
+        void          (* session_to_remove)      (CkSeat      *seat,
+                                                  int          display_number);
 } CkSeatClass;
 
 typedef enum
@@ -84,12 +90,14 @@ typedef enum
 GQuark              ck_seat_error_quark         (void);
 GType               ck_seat_get_type            (void);
 CkSeat            * ck_seat_new                 (const char            *sid,
-                                                 CkSeatKind             kind);
-CkSeat            * ck_seat_new_from_file       (const char            *sid,
-                                                 const char            *path);
-CkSeat            * ck_seat_new_with_devices    (const char            *sid,
                                                  CkSeatKind             kind,
-                                                 GPtrArray             *devices);
+                                                 const char            *type);
+CkSeat            * ck_seat_new_from_file       (char                 **sid,
+                                                 const char            *path);
+CkSeat            * ck_seat_new_with_devices_and_sessions    (const char            *sid,
+                                                              CkSeatKind             kind,
+                                                              GPtrArray             *devices,
+                                                              GPtrArray             *sessions);
 
 gboolean            ck_seat_register            (CkSeat                *seat);
 
@@ -104,18 +112,31 @@ void                ck_seat_dump                (CkSeat                *seat,
 gboolean            ck_seat_get_kind            (CkSeat                *seat,
                                                  CkSeatKind            *kind,
                                                  GError               **error);
+gboolean            ck_seat_get_type_string     (CkSeat                *seat,
+                                                 char                 **type,
+                                                 GError               **error);
 gboolean            ck_seat_add_session         (CkSeat                *seat,
                                                  CkSession             *session,
                                                  GError               **error);
 gboolean            ck_seat_remove_session      (CkSeat                *seat,
                                                  CkSession             *session,
                                                  GError               **error);
+gboolean            ck_seat_request_open_session (CkSeat                *seat,
+                                                  CkSession             *session,
+                                                  GError               **error);
+gboolean            ck_seat_request_close_session (CkSeat                *seat,
+                                                   CkSession             *session,
+                                                   GError               **error);
 gboolean            ck_seat_add_device          (CkSeat                *seat,
                                                  GValueArray           *device,
                                                  GError               **error);
 gboolean            ck_seat_remove_device       (CkSeat                *seat,
                                                  GValueArray           *device,
                                                  GError               **error);
+gboolean            ck_seat_is_managed          (CkSeat                *seat);
+CkSession          *ck_seat_get_session         (CkSeat                *seat,
+                                                 const char            *ssid);
+void                ck_seat_request_removal     (CkSeat                *seat);
 
 /* exported methods */
 gboolean            ck_seat_get_id                (CkSeat                *seat,
@@ -137,6 +158,10 @@ gboolean            ck_seat_can_activate_sessions (CkSeat                *seat,
 gboolean            ck_seat_activate_session      (CkSeat                *seat,
                                                    const char            *ssid,
                                                    DBusGMethodInvocation *context);
+gboolean            ck_seat_manage                (CkSeat                *seat,
+                                                   DBusGMethodInvocation *context);
+gboolean            ck_seat_unmanage              (CkSeat                *seat,
+                                                   DBusGMethodInvocation *context);
 
 G_END_DECLS
 
diff --git a/src/ck-session-leader.c b/src/ck-session-leader.c
index 3702602..908d2bb 100644
--- a/src/ck-session-leader.c
+++ b/src/ck-session-leader.c
@@ -238,6 +238,7 @@ static struct {
         { "x11-display",        add_param_string },
         { "remote-host-name",   add_param_string },
         { "session-type",       add_param_string },
+        { "display-type",       add_param_string },
         { "is-local",           add_param_boolean },
         { "unix-user",          add_param_int },
 };
diff --git a/src/ck-session.c b/src/ck-session.c
index d8db9dd..0354dd5 100644
--- a/src/ck-session.c
+++ b/src/ck-session.c
@@ -41,6 +41,7 @@
 #include "ck-session-glue.h"
 #include "ck-marshal.h"
 #include "ck-run-programs.h"
+#include "ck-display-template.h"
 
 #define CK_SESSION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CK_TYPE_SESSION, CkSessionPrivate))
 
@@ -58,6 +59,7 @@ struct CkSessionPrivate
         char            *seat_id;
 
         char            *session_type;
+        char            *display_type;
         char            *login_session_id;
         char            *display_device;
         char            *x11_display_device;
@@ -65,8 +67,15 @@ struct CkSessionPrivate
         char            *remote_host_name;
         guint            uid;
 
+        CkDisplayTemplate *display_template;
+        GHashTable      *display_variables;
+
         gboolean         active;
         gboolean         is_local;
+        gboolean         is_open;
+        gboolean         ever_open;
+        gboolean         under_request;
+        GMutex          *mutex_under_request;
 
         GTimeVal         creation_time;
 
@@ -75,6 +84,8 @@ struct CkSessionPrivate
         gboolean         idle_hint;
         GTimeVal         idle_since_hint;
 
+        gboolean         remove_on_close;
+
         DBusGConnection *connection;
         DBusGProxy      *bus_proxy;
 };
@@ -92,17 +103,24 @@ enum {
         PROP_0,
         PROP_ID,
         PROP_COOKIE,
+        PROP_SEAT_ID,
         PROP_USER,
         PROP_UNIX_USER,
         PROP_X11_DISPLAY,
         PROP_X11_DISPLAY_DEVICE,
         PROP_DISPLAY_DEVICE,
         PROP_SESSION_TYPE,
+        PROP_DISPLAY_TYPE,
+        PROP_DISPLAY_TEMPLATE,
+        PROP_DISPLAY_VARIABLES,
         PROP_REMOTE_HOST_NAME,
         PROP_LOGIN_SESSION_ID,
         PROP_IS_LOCAL,
+        PROP_IS_OPEN,
+        PROP_EVER_OPEN,
         PROP_ACTIVE,
         PROP_IDLE_HINT,
+        PROP_REMOVE_ON_CLOSE,
 };
 
 static guint signals [LAST_SIGNAL] = { 0, };
@@ -128,6 +146,7 @@ static gboolean
 register_session (CkSession *session)
 {
         GError *error = NULL;
+        GObject *existing_session;
 
         error = NULL;
         session->priv->connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
@@ -144,6 +163,15 @@ register_session (CkSession *session)
                                                               DBUS_PATH_DBUS,
                                                               DBUS_INTERFACE_DBUS);
 
+        existing_session = dbus_g_connection_lookup_g_object (session->priv->connection,
+                                                              session->priv->id);
+
+        if (existing_session != NULL) {
+                g_warning ("Session '%s' was registered twice!",
+                           session->priv->id);
+                return FALSE;
+        }
+
         dbus_g_connection_register_g_object (session->priv->connection, session->priv->id, G_OBJECT (session));
 
         return TRUE;
@@ -302,6 +330,35 @@ ck_session_set_idle_hint (CkSession             *session,
 }
 
 gboolean
+session_set_remove_on_close (CkSession      *session,
+                             gboolean        remove_on_close,
+                             GError        **error)
+{
+        g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
+
+        if (session->priv->remove_on_close != remove_on_close) {
+                session->priv->remove_on_close = remove_on_close;
+        }
+
+        return TRUE;
+}
+
+/*
+  Example:
+  dbus-send --system --dest=org.freedesktop.ConsoleKit \
+  --type=method_call --print-reply --reply-timeout=2000 \
+  /org/freedesktop/ConsoleKit/Session1 \
+  org.freedesktop.ConsoleKit.Session.SetRemoveOnClose boolean:TRUE
+*/
+gboolean
+ck_session_set_remove_on_close (CkSession             *session,
+                                gboolean               remove_on_close,
+                                DBusGMethodInvocation *context)
+{
+        return session_set_remove_on_close (session, remove_on_close, NULL);
+}
+
+gboolean
 ck_session_get_idle_hint (CkSession *session,
                           gboolean  *idle_hint,
                           GError   **error)
@@ -420,6 +477,68 @@ ck_session_set_is_local (CkSession      *session,
 }
 
 gboolean
+ck_session_set_is_open (CkSession    *session,
+                        gboolean      is_open,
+                        GError      **error)
+{
+        g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
+
+        if (session->priv->is_open != is_open) {
+                session->priv->is_open = is_open;
+                session->priv->ever_open = TRUE;
+        }
+
+        return TRUE;
+}
+
+gboolean
+ck_session_set_ever_open (CkSession    *session,
+                          gboolean      ever_open,
+                          GError      **error)
+{
+        g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
+
+        if (session->priv->ever_open != ever_open) {
+                session->priv->ever_open = ever_open;
+        }
+
+        return TRUE;
+}
+
+static gboolean
+timeout_for_under_request (gpointer data)
+{
+        CkSession *session = CK_SESSION (data);
+        g_mutex_lock (session->priv->mutex_under_request);
+        session->priv->under_request = FALSE;
+        g_mutex_unlock (session->priv->mutex_under_request);
+
+        g_debug ("timeout for under request of session %s", session->priv->id);
+        return FALSE;
+}
+
+gboolean
+ck_session_set_under_request (CkSession    *session,
+                              gboolean      under_request,
+                              GError      **error)
+{
+        g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
+
+        g_mutex_lock (session->priv->mutex_under_request);
+        if (!under_request) {
+                session->priv->under_request = FALSE;
+        } else {
+                if (!session->priv->under_request) {
+                        session->priv->under_request = TRUE;
+                        g_timeout_add_seconds (1, timeout_for_under_request, session);
+                }
+        }
+        g_mutex_unlock (session->priv->mutex_under_request);
+
+        return TRUE;
+}
+
+gboolean
 ck_session_get_id (CkSession      *session,
                    char          **id,
                    GError        **error)
@@ -555,6 +674,20 @@ ck_session_get_creation_time (CkSession      *session,
 }
 
 gboolean
+ck_session_get_remove_on_close (CkSession   *session,
+                                gboolean    *remove_on_close,
+                                GError     **error)
+{
+        g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
+
+        if (remove_on_close != NULL) {
+                *remove_on_close = session->priv->remove_on_close;
+        }
+
+        return TRUE;
+}
+
+gboolean
 ck_session_get_session_type (CkSession      *session,
                              char          **type,
                              GError        **error)
@@ -569,6 +702,20 @@ ck_session_get_session_type (CkSession      *session,
 }
 
 gboolean
+ck_session_get_display_type (CkSession      *session,
+                             char          **type,
+                             GError        **error)
+{
+        g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
+
+        if (type != NULL) {
+                *type = g_strdup (session->priv->display_type);
+        }
+
+        return TRUE;
+}
+
+gboolean
 ck_session_is_active (CkSession      *session,
                       gboolean       *active,
                       GError        **error)
@@ -597,6 +744,50 @@ ck_session_is_local (CkSession      *session,
 }
 
 gboolean
+ck_session_is_open (CkSession      *session,
+                    gboolean       *open,
+                    GError        **error)
+{
+        g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
+
+        if (open != NULL) {
+                *open = session->priv->is_open;
+        }
+
+        return TRUE;
+}
+
+gboolean
+ck_session_get_ever_open (CkSession      *session,
+                          gboolean       *open,
+                          GError        **error)
+{
+        g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
+
+        if (open != NULL) {
+                *open = session->priv->ever_open;
+        }
+
+        return TRUE;
+}
+
+gboolean
+ck_session_get_under_request (CkSession      *session,
+                              gboolean       *under_request,
+                              GError        **error)
+{
+        g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
+
+        if (under_request != NULL) {
+                g_mutex_lock (session->priv->mutex_under_request);
+                *under_request = session->priv->under_request;
+                g_mutex_unlock (session->priv->mutex_under_request);
+        }
+
+        return TRUE;
+}
+
+gboolean
 ck_session_set_id (CkSession      *session,
                    const char     *id,
                    GError        **error)
@@ -609,6 +800,21 @@ ck_session_set_id (CkSession      *session,
         return TRUE;
 }
 
+static void
+ck_session_set_display_variables (CkSession  *session,
+                                  GHashTable *display_variables)
+{
+        if (session->priv->display_variables != NULL) {
+                g_hash_table_unref (session->priv->display_variables);
+        }
+
+        if (display_variables != NULL) {
+                session->priv->display_variables = g_hash_table_ref (display_variables);
+        } else {
+                session->priv->display_variables = NULL;
+        }
+}
+
 gboolean
 ck_session_set_cookie (CkSession      *session,
                        const char     *cookie,
@@ -725,6 +931,54 @@ ck_session_set_session_type (CkSession      *session,
         return TRUE;
 }
 
+gboolean
+ck_session_set_display_type (CkSession      *session,
+                             const char     *type,
+                             GError        **error)
+{
+        g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
+
+        g_free (session->priv->display_type);
+        session->priv->display_type = g_strdup (type);
+
+        return TRUE;
+}
+
+static gboolean
+ck_session_set_display_template (CkSession      *session,
+                             CkDisplayTemplate  *display_template,
+                             GError        **error)
+{
+        g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
+
+        if (session->priv->display_template != NULL) {
+                g_object_unref (session->priv->display_template);
+        }
+
+        if (display_template != NULL) {
+                session->priv->display_template = g_object_ref (display_template);
+                ck_session_set_display_type (session, ck_display_template_get_name (display_template), error);
+        } else {
+                session->priv->display_template = NULL;
+        }
+
+        return TRUE;
+}
+
+GHashTable *
+ck_session_get_display_variables (CkSession *session)
+{
+        return g_hash_table_ref (session->priv->display_variables);
+}
+
+CkDisplayTemplate *
+ck_session_get_display_template (CkSession      *session)
+{
+        g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
+
+        return g_object_ref (session->priv->display_template);
+}
+
 static void
 ck_session_set_property (GObject            *object,
                          guint               prop_id,
@@ -742,15 +996,33 @@ ck_session_set_property (GObject            *object,
         case PROP_IS_LOCAL:
                 ck_session_set_is_local (self, g_value_get_boolean (value), NULL);
                 break;
+        case PROP_IS_OPEN:
+                ck_session_set_is_open (self, g_value_get_boolean (value), NULL);
+                break;
+        case PROP_EVER_OPEN:
+                ck_session_set_ever_open (self, g_value_get_boolean (value), NULL);
+                break;
         case PROP_ID:
                 ck_session_set_id (self, g_value_get_string (value), NULL);
                 break;
         case PROP_COOKIE:
                 ck_session_set_cookie (self, g_value_get_string (value), NULL);
                 break;
+        case PROP_SEAT_ID:
+                ck_session_set_seat_id (self, g_value_get_string (value), NULL);
+                break;
         case PROP_SESSION_TYPE:
                 ck_session_set_session_type (self, g_value_get_string (value), NULL);
                 break;
+        case PROP_DISPLAY_TYPE:
+                ck_session_set_display_type (self, g_value_get_string (value), NULL);
+                break;
+        case PROP_DISPLAY_TEMPLATE:
+                ck_session_set_display_template (self, g_value_get_object (value), NULL);
+                break;
+        case PROP_DISPLAY_VARIABLES:
+                ck_session_set_display_variables (self, g_value_get_boxed (value));
+                break;
         case PROP_X11_DISPLAY:
                 ck_session_set_x11_display (self, g_value_get_string (value), NULL);
                 break;
@@ -775,6 +1047,9 @@ ck_session_set_property (GObject            *object,
         case PROP_IDLE_HINT:
                 session_set_idle_hint_internal (self, g_value_get_boolean (value));
                 break;
+        case PROP_REMOVE_ON_CLOSE:
+                session_set_remove_on_close (self, g_value_get_boolean (value), NULL);
+                break;
         default:
                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                 break;
@@ -798,15 +1073,33 @@ ck_session_get_property (GObject    *object,
         case PROP_IS_LOCAL:
                 g_value_set_boolean (value, self->priv->is_local);
                 break;
+        case PROP_IS_OPEN:
+                g_value_set_boolean (value, self->priv->is_open);
+                break;
+        case PROP_EVER_OPEN:
+                g_value_set_boolean (value, self->priv->ever_open);
+                break;
         case PROP_ID:
                 g_value_set_string (value, self->priv->id);
                 break;
         case PROP_COOKIE:
                 g_value_set_string (value, self->priv->cookie);
                 break;
+        case PROP_SEAT_ID:
+                g_value_set_string (value, self->priv->seat_id);
+                break;
         case PROP_SESSION_TYPE:
                 g_value_set_string (value, self->priv->session_type);
                 break;
+        case PROP_DISPLAY_TYPE:
+                g_value_set_string (value, self->priv->display_type);
+                break;
+        case PROP_DISPLAY_TEMPLATE:
+                g_value_set_object (value, self->priv->display_template);
+                break;
+        case PROP_DISPLAY_VARIABLES:
+                g_value_set_boxed (value, self->priv->display_variables);
+                break;
         case PROP_X11_DISPLAY:
                 g_value_set_string (value, self->priv->x11_display);
                 break;
@@ -831,6 +1124,9 @@ ck_session_get_property (GObject    *object,
         case PROP_IDLE_HINT:
                 g_value_set_boolean (value, self->priv->idle_hint);
                 break;
+        case PROP_REMOVE_ON_CLOSE:
+                g_value_set_boolean (value, self->priv->remove_on_close);
+                break;
         default:
                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                 break;
@@ -1000,6 +1296,13 @@ ck_session_class_init (CkSessionClass *klass)
                                                               "cookie",
                                                               NULL,
                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+        g_object_class_install_property (object_class,
+                                         PROP_SEAT_ID,
+                                         g_param_spec_string ("seat-id",
+                                                              "seat id",
+                                                              "seat id",
+                                                              NULL,
+                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
         g_object_class_install_property (object_class,
                                          PROP_SESSION_TYPE,
@@ -1009,6 +1312,27 @@ ck_session_class_init (CkSessionClass *klass)
                                                               NULL,
                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
         g_object_class_install_property (object_class,
+                                         PROP_DISPLAY_TYPE,
+                                         g_param_spec_string ("display-type",
+                                                              "session-type",
+                                                              "session type",
+                                                              NULL,
+                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+        g_object_class_install_property (object_class,
+                                         PROP_DISPLAY_TEMPLATE,
+                                         g_param_spec_object ("display-template",
+                                                              "Display Template",
+                                                              "The display template",
+                                                              CK_TYPE_DISPLAY_TEMPLATE,
+                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+        g_object_class_install_property (object_class,
+                                         PROP_DISPLAY_VARIABLES,
+                                         g_param_spec_boxed ("display-variables",
+                                                             "Display Variables",
+                                                             "Display type specific variables",
+                                                             G_TYPE_HASH_TABLE,
+                                                             G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+        g_object_class_install_property (object_class,
                                          PROP_LOGIN_SESSION_ID,
                                          g_param_spec_string ("login-session-id",
                                                               "login-session-id",
@@ -1064,12 +1388,19 @@ ck_session_class_init (CkSessionClass *klass)
                                                             0,
                                                             G_PARAM_READWRITE));
         g_object_class_install_property (object_class,
-                                         PROP_ACTIVE,
+                                         PROP_IDLE_HINT,
                                          g_param_spec_boolean ("idle-hint",
                                                                NULL,
                                                                NULL,
                                                                FALSE,
                                                                G_PARAM_READWRITE));
+        g_object_class_install_property (object_class,
+                                         PROP_REMOVE_ON_CLOSE,
+                                         g_param_spec_boolean ("remove-on-close",
+                                                               NULL,
+                                                               NULL,
+                                                               FALSE,
+                                                               G_PARAM_READWRITE));
 
         g_type_class_add_private (klass, sizeof (CkSessionPrivate));
 
@@ -1081,8 +1412,16 @@ ck_session_init (CkSession *session)
 {
         session->priv = CK_SESSION_GET_PRIVATE (session);
 
+        session->priv->display_variables = g_hash_table_new_full (g_str_hash,
+                                                                  g_str_equal,
+                                                                  (GDestroyNotify) g_free,
+                                                                  (GDestroyNotify) g_free);
+
         /* FIXME: should we have a property for this? */
         g_get_current_time (&session->priv->creation_time);
+
+        if (!session->priv->mutex_under_request)
+                session->priv->mutex_under_request = g_mutex_new ();
 }
 
 static void
@@ -1105,6 +1444,7 @@ ck_session_finalize (GObject *object)
         g_free (session->priv->cookie);
         g_free (session->priv->seat_id);
         g_free (session->priv->session_type);
+        g_free (session->priv->display_type);
         g_free (session->priv->x11_display);
         g_free (session->priv->display_device);
         g_free (session->priv->x11_display_device);
@@ -1114,16 +1454,135 @@ ck_session_finalize (GObject *object)
 }
 
 CkSession *
+ck_session_new_from_file (const char *ssid,
+                          const char *path)
+{
+        GKeyFile  *key_file;
+        gboolean   res;
+        GError    *error;
+        char      *group;
+        char      *name;
+        gboolean   hidden;
+        char      *type;
+        char      *display_template_string;
+        CkSession *session;
+        GHashTable *display_variables;
+        char     **type_keys;
+
+        key_file = g_key_file_new ();
+        error = NULL;
+        res = g_key_file_load_from_file (key_file,
+                                         path,
+                                         G_KEY_FILE_NONE,
+                                         &error);
+
+        if (! res) {
+                g_warning ("Unable to load sessions from file %s: %s",
+                           path, error->message);
+                g_error_free (error);
+                return NULL;
+        }
+
+        group = g_key_file_get_start_group (key_file);
+        if (group == NULL || strcmp (group, "Session Entry") != 0) {
+                g_warning ("Not a session file: %s", path);
+                g_key_file_free (key_file);
+                return NULL;
+        }
+
+        hidden = g_key_file_get_boolean (key_file, group, "Hidden", NULL);
+
+        if (hidden) {
+                g_debug ("Session is hidden");
+                g_free (group);
+                g_key_file_free (key_file);
+                return NULL;
+        }
+
+        name = g_key_file_get_string (key_file, group, "Name", NULL);
+
+        if (name == NULL) {
+                g_warning ("Session file %s doesn't contain a name", path);
+                g_free (group);
+                g_key_file_free (key_file);
+                return NULL;
+        }
+
+        type = g_key_file_get_string (key_file, group, "Type", NULL);
+
+        if (type == NULL) {
+                g_warning ("Session file %s doesn't contain a type", path);
+                g_free (group);
+                g_key_file_free (key_file);
+                return NULL;
+        }
+
+        display_template_string = g_key_file_get_string (key_file, group, "DisplayTemplate", NULL);
+
+        if (display_template_string == NULL) {
+                g_warning ("Session file %s doesn't contain a display type", path);
+                g_free (group);
+                g_key_file_free (key_file);
+                return NULL;
+        }
+
+        /* Find a group in the key file named after the display type and stuff
+         * all its entries into a hash table for later.
+         *
+         * Those keys are for things like the display number and the vt to
+         * run X with.
+         */
+        display_variables = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                                   (GDestroyNotify) g_free,
+                                                   (GDestroyNotify) g_free);
+        type_keys = g_key_file_get_keys (key_file, display_template_string, NULL, NULL);
+
+        if (type_keys != NULL) {
+                int i;
+                for (i = 0; type_keys[i] != NULL; i++) {
+                        char    *string;
+                        string = g_key_file_get_string (key_file, display_template_string, type_keys[i], NULL);
+
+                        g_hash_table_insert (display_variables, g_strdup (type_keys[i]), string);
+                }
+                g_strfreev (type_keys);
+        }
+
+        session = ck_session_new (ssid, type, display_template_string, display_variables);
+
+        g_free (display_template_string);
+        g_free (group);
+        g_free (type);
+        g_hash_table_unref (display_variables);
+
+        return session;
+}
+
+CkSession *
 ck_session_new (const char *ssid,
-                const char *cookie)
+                const char *type,
+                const char *display_template_string,
+                GHashTable *display_variables)
 {
+        CkDisplayTemplate *display_template;
         GObject *object;
         gboolean res;
 
+        display_template = ck_display_template_get_from_name (display_template_string);
+
+        if (display_template == NULL) {
+                g_warning ("Unable to load display type %s", display_template_string);
+                return NULL;
+        }
+
         object = g_object_new (CK_TYPE_SESSION,
                                "id", ssid,
-                               "cookie", cookie,
+                               "session-type", type,
+                               "display-type", display_template_string,
+                               "display-template", display_template,
+                               "display-variables", display_variables,
                                NULL);
+
         res = register_session (CK_SESSION (object));
         if (! res) {
                 g_object_unref (object);
@@ -1138,9 +1597,80 @@ ck_session_new (const char *ssid,
                                                           G_TYPE_VALUE, \
                                                           G_TYPE_INVALID))
 
+void
+ck_session_set_parameters (CkSession       *session,
+                           const GPtrArray *parameters)
+{
+        int           i;
+        GObjectClass *class;
+        GType         object_type;
+
+        object_type = CK_TYPE_SESSION;
+        class = g_type_class_ref (object_type);
+        for (i = 0; i < parameters->len; i++) {
+                gboolean    res;
+                GValue      val_struct = { 0, };
+                GValue      value = { 0, };
+                char       *prop_name;
+                GValue     *prop_val;
+                GParamSpec *pspec;
+
+                g_value_init (&val_struct, CK_TYPE_PARAMETER_STRUCT);
+                g_value_set_static_boxed (&val_struct, g_ptr_array_index (parameters, i));
+
+                res = dbus_g_type_struct_get (&val_struct,
+                                              0, &prop_name,
+                                              1, &prop_val,
+                                              G_MAXUINT);
+                if (! res) {
+                        g_debug ("Unable to extract parameter input");
+                        goto cont;
+                }
+
+                if (prop_name == NULL) {
+                        g_debug ("Skipping NULL parameter");
+                        goto cont;
+                }
+
+                if (strcmp (prop_name, "id") == 0
+                    || strcmp (prop_name, "cookie") == 0) {
+                        g_debug ("Skipping restricted parameter: %s", prop_name);
+                        goto cont;
+                }
+
+                pspec = g_object_class_find_property (class, prop_name);
+                if (! pspec) {
+                        g_debug ("Skipping unknown parameter: %s", prop_name);
+                        goto cont;
+                }
+
+                if (!(pspec->flags & G_PARAM_WRITABLE)) {
+                        g_debug ("property '%s' is not writable", pspec->name);
+                        goto cont;
+                }
+
+                g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
+                res = g_value_transform (prop_val, &value);
+                if (! res) {
+                        g_debug ("unable to transform property value for '%s'", pspec->name);
+                        goto cont;
+                }
+
+                g_object_set_property (G_OBJECT (session), prop_name, &value);
+                g_value_unset (&value);
+        cont:
+                g_free (prop_name);
+                if (prop_val != NULL) {
+                        g_value_unset (prop_val);
+                        g_free (prop_val);
+                }
+        }
+
+        g_type_class_unref (class);
+}
+
 CkSession *
 ck_session_new_with_parameters (const char      *ssid,
-                                const char      *cookie,
                                 const GPtrArray *parameters)
 {
         GObject      *object;
@@ -1169,12 +1699,6 @@ ck_session_new_with_parameters (const char      *ssid,
         g_value_set_string (&params[n_params].value, ssid);
         n_params++;
 
-        params[n_params].name = g_strdup ("cookie");
-        params[n_params].value.g_type = 0;
-        g_value_init (&params[n_params].value, G_TYPE_STRING);
-        g_value_set_string (&params[n_params].value, cookie);
-        n_params++;
-
         if (parameters != NULL) {
                 for (i = 0; i < parameters->len; i++) {
                         gboolean    res;
@@ -1259,7 +1783,7 @@ ck_session_run_programs (CkSession  *session,
                          const char *action)
 {
         int   n;
-        char *extra_env[11]; /* be sure to adjust this as needed */
+        char *extra_env[12]; /* be sure to adjust this as needed */
 
         n = 0;
 
@@ -1267,6 +1791,9 @@ ck_session_run_programs (CkSession  *session,
         if (session->priv->session_type != NULL) {
                 extra_env[n++] = g_strdup_printf ("CK_SESSION_TYPE=%s", session->priv->session_type);
         }
+        if (session->priv->display_type != NULL) {
+                extra_env[n++] = g_strdup_printf ("CK_SESSION_DISPLAY_TYPE=%s", session->priv->display_type);
+        }
         extra_env[n++] = g_strdup_printf ("CK_SESSION_SEAT_ID=%s", session->priv->seat_id);
         extra_env[n++] = g_strdup_printf ("CK_SESSION_USER_UID=%d", session->priv->uid);
         if (session->priv->display_device != NULL && strlen (session->priv->display_device) > 0) {
@@ -1301,6 +1828,10 @@ ck_session_dump (CkSession *session,
         char *s;
         char *group_name;
 
+        if (!session->priv->is_open) {
+                return;
+        }
+
         group_name = g_strdup_printf ("Session %s", session->priv->id);
         g_key_file_set_integer (key_file, group_name, "uid", session->priv->uid);
         g_key_file_set_string (key_file,
@@ -1313,6 +1844,12 @@ ck_session_dump (CkSession *session,
                                        "type",
                                        NONULL_STRING (session->priv->session_type));
         }
+        if (session->priv->display_type != NULL) {
+                g_key_file_set_string (key_file,
+                                       group_name,
+                                       "display_type",
+                                       NONULL_STRING (session->priv->display_type));
+        }
         if (session->priv->login_session_id != NULL && strlen (session->priv->login_session_id) > 0) {
                 g_key_file_set_string (key_file,
                                        group_name,
diff --git a/src/ck-session.h b/src/ck-session.h
index b6b565b..a24d0a8 100644
--- a/src/ck-session.h
+++ b/src/ck-session.h
@@ -25,6 +25,8 @@
 #include <glib-object.h>
 #include <dbus/dbus-glib.h>
 
+#include "ck-display-template.h"
+
 G_BEGIN_DECLS
 
 #define CK_TYPE_SESSION         (ck_session_get_type ())
@@ -68,10 +70,15 @@ typedef enum
 
 GQuark              ck_session_error_quark            (void);
 GType               ck_session_get_type               (void);
+CkSession         * ck_session_new_from_file          (const char            *ssid,
+                                                       const char            *path);
 CkSession         * ck_session_new                    (const char            *ssid,
-                                                       const char            *cookie);
+                                                       const char            *type,
+                                                       const char            *display_type_string,
+                                                       GHashTable            *display_variables);
 CkSession         * ck_session_new_with_parameters    (const char            *ssid,
-                                                       const char            *cookie,
+                                                       const GPtrArray       *parameters);
+void                ck_session_set_parameters         (CkSession             *session,
                                                        const GPtrArray       *parameters);
 
 void                ck_session_dump                   (CkSession             *session,
@@ -86,6 +93,15 @@ gboolean            ck_session_set_active             (CkSession             *se
 gboolean            ck_session_set_is_local           (CkSession             *session,
                                                        gboolean               is_local,
                                                        GError               **error);
+gboolean            ck_session_set_is_open            (CkSession             *session,
+                                                       gboolean               is_open,
+                                                       GError               **error);
+gboolean            ck_session_set_ever_open          (CkSession             *session,
+                                                       gboolean               ever_open,
+                                                       GError               **error);
+gboolean            ck_session_set_under_request      (CkSession             *session,
+                                                       gboolean               under_request,
+                                                       GError               **error);
 gboolean            ck_session_set_id                 (CkSession             *session,
                                                        const char            *ssid,
                                                        GError               **error);
@@ -116,6 +132,11 @@ gboolean            ck_session_set_remote_host_name   (CkSession             *se
 gboolean            ck_session_set_session_type       (CkSession             *session,
                                                        const char            *type,
                                                        GError               **error);
+gboolean            ck_session_set_display_type       (CkSession             *session,
+                                                       const char            *type,
+                                                       GError               **error);
+GHashTable         *ck_session_get_display_variables  (CkSession             *session);
+CkDisplayTemplate  *ck_session_get_display_template   (CkSession             *session);
 
 /* Exported methods */
 
@@ -132,6 +153,15 @@ gboolean            ck_session_is_active              (CkSession             *se
 gboolean            ck_session_is_local               (CkSession             *session,
                                                        gboolean              *local,
                                                        GError               **error);
+gboolean            ck_session_is_open                (CkSession             *session,
+                                                       gboolean              *open,
+                                                       GError               **error);
+gboolean            ck_session_get_ever_open          (CkSession             *session,
+                                                       gboolean              *open,
+                                                       GError               **error);
+gboolean            ck_session_get_under_request      (CkSession             *session,
+                                                       gboolean              *under_request,
+                                                       GError               **error);
 gboolean            ck_session_get_unix_user          (CkSession             *session,
                                                        guint                 *uid,
                                                        GError               **error);
@@ -150,12 +180,18 @@ gboolean            ck_session_get_login_session_id   (CkSession             *se
 gboolean            ck_session_get_session_type       (CkSession             *session,
                                                        char                 **type,
                                                        GError               **error);
+gboolean            ck_session_get_display_type       (CkSession             *session,
+                                                       char                 **type,
+                                                       GError               **error);
 gboolean            ck_session_get_remote_host_name   (CkSession             *session,
                                                        char                 **host_name,
                                                        GError               **error);
 gboolean            ck_session_get_creation_time      (CkSession             *session,
                                                        char                 **iso8601_datetime,
                                                        GError               **error);
+gboolean            ck_session_get_remove_on_close    (CkSession             *session,
+                                                       gboolean              *remove_on_close,
+                                                       GError               **error);
 /*deprecated*/
 gboolean            ck_session_get_user               (CkSession             *session,
                                                        guint                 *uid,
@@ -171,6 +207,12 @@ gboolean            ck_session_get_idle_since_hint    (CkSession             *se
 gboolean            ck_session_set_idle_hint          (CkSession             *session,
                                                        gboolean               idle_hint,
                                                        DBusGMethodInvocation *context);
+gboolean            session_set_remove_on_close       (CkSession             *session,
+                                                       gboolean               remove_on_close,
+                                                       GError               **error);
+gboolean            ck_session_set_remove_on_close    (CkSession             *session,
+                                                       gboolean               remove_on_close,
+                                                       DBusGMethodInvocation *context);
 
 /* Privileged actions */
 gboolean            ck_session_activate               (CkSession             *session,
diff --git a/src/main.c b/src/main.c
index b8f698f..f685026 100644
--- a/src/main.c
+++ b/src/main.c
@@ -283,7 +283,7 @@ main (int    argc,
         res = g_option_context_parse (context, &argc, &argv, &error);
         g_option_context_free (context);
         if (! res) {
-                g_warning (error->message);
+                g_warning ("%s", error->message);
                 g_error_free (error);
                 goto out;
         }
diff --git a/src/org.freedesktop.ConsoleKit.Manager.xml b/src/org.freedesktop.ConsoleKit.Manager.xml
index f903b55..34a6d04 100644
--- a/src/org.freedesktop.ConsoleKit.Manager.xml
+++ b/src/org.freedesktop.ConsoleKit.Manager.xml
@@ -160,6 +160,23 @@
       </doc:doc>
     </method>
 
+    <method name="GetUnmanagedSeats">
+      <arg name="seats" direction="out" type="ao">
+        <doc:doc>
+          <doc:summary>an array of unmanaged Seat IDs</doc:summary>
+        </doc:doc>
+      </arg>
+      <doc:doc>
+        <doc:description>
+          <doc:para>This gets a list of the unmanaged <doc:ref type="interface" to="Seat">Seats</doc:ref>
+          that are statically configured under /etc/ConsoleKit/seats.d</doc:para>
+          <doc:para>Each Seat ID is an D-Bus object path for the object that implements the
+          <doc:ref type="interface" to="Seat">Seat</doc:ref> interface.</doc:para>
+        </doc:description>
+        <doc:seealso><doc:ref type="interface" to="Seat">org.freedesktop.ConsoleKit.Seat</doc:ref></doc:seealso>
+      </doc:doc>
+    </method>
+
     <method name="GetSessions">
       <arg name="sessions" direction="out" type="ao">
         <doc:doc>
@@ -310,12 +327,115 @@
       </doc:doc>
     </method>
 
+    <method name="AddSeat">
+      <arg name="type" type="s" direction="in">
+        <doc:doc>
+          <doc:summary>The type of seat to add</doc:summary>
+        </doc:doc>
+      </arg>
+      <arg name="sid" type="o" direction="out">
+        <doc:doc>
+          <doc:summary>The Seat ID of the added seat</doc:summary>
+        </doc:doc>
+      </arg>
+      <doc:doc>
+        <doc:description>
+          <doc:para>This method is to create a new seat
+          </doc:para>
+        </doc:description>
+      </doc:doc>
+    </method>
+    <method name="AddSeatById">
+      <arg name="type" type="s" direction="in">
+        <doc:doc>
+          <doc:summary>The type of seat to add</doc:summary>
+        </doc:doc>
+      </arg>
+      <arg name="sid" type="o" direction="in">
+        <doc:doc>
+          <doc:summary>The Seat ID of to be added seat</doc:summary>
+        </doc:doc>
+      </arg>
+      <doc:doc>
+        <doc:description>
+          <doc:para>This method is to create a new seat by specify given sid
+          </doc:para>
+        </doc:description>
+      </doc:doc>
+    </method>
+    <method name="RemoveSeat">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+      <arg name="sid" type="o" direction="in">
+        <doc:doc>
+          <doc:summary>The Seat ID of the seat to remove</doc:summary>
+        </doc:doc>
+      </arg>
+      <doc:doc>
+        <doc:description>
+          <doc:para>This method is to remove a seat
+          </doc:para>
+        </doc:description>
+      </doc:doc>
+    </method>
+    <method name="AddSession">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+      <arg name="sid" type="o">
+        <doc:doc>
+          <doc:summary>The seat to add the session to</doc:summary>
+        </doc:doc>
+      </arg>
+      <arg name="type" type="s">
+        <doc:doc>
+          <doc:summary>The type of session to run (e.g. "LoginWindow", "Chooser", etc)</doc:summary>
+        </doc:doc>
+      </arg>
+      <arg name="display_type" type="s">
+        <doc:doc>
+          <doc:summary>The name of the display type to use (defined in displays.d)</doc:summary>
+        </doc:doc>
+      </arg>
+      <arg name="variables" type="a{ss}">
+        <doc:doc>
+          <doc:summary>Session type specific parameters</doc:summary>
+        </doc:doc>
+      </arg>
+      <arg name="ssid" direction="out" type="o">
+        <doc:doc>
+          <doc:summary>Session ID</doc:summary>
+        </doc:doc>
+      </arg>
+      <doc:doc>
+        <doc:description>
+          <doc:para>Request a new session gets added to seat.</doc:para>
+        </doc:description>
+      </doc:doc>
+    </method>
+    <method name="RemoveSession">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+      <arg name="ssid" type="o" direction="in">
+        <doc:doc>
+          <doc:summary>The session id of the session to remove</doc:summary>
+        </doc:doc>
+      </arg>
+      <doc:doc>
+        <doc:description>
+          <doc:para>This method is to remove a session from a seat
+          </doc:para>
+        </doc:description>
+      </doc:doc>
+    </method>
+
     <signal name="SeatAdded">
       <arg name="sid" type="o">
         <doc:doc>
           <doc:summary>The Seat ID for the added seat</doc:summary>
         </doc:doc>
       </arg>
+      <arg name="type" type="s">
+        <doc:doc>
+          <doc:summary>The type of seat added.</doc:summary>
+        </doc:doc>
+      </arg>
       <doc:doc>
         <doc:description>
           <doc:para>Emitted when a Seat has been added to the system.
diff --git a/src/org.freedesktop.ConsoleKit.Seat.xml b/src/org.freedesktop.ConsoleKit.Seat.xml
index d95990b..1f6c46f 100644
--- a/src/org.freedesktop.ConsoleKit.Seat.xml
+++ b/src/org.freedesktop.ConsoleKit.Seat.xml
@@ -100,6 +100,24 @@ seat at a time.</doc:para>
       </doc:doc>
     </method>
 
+    <method name="Manage">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+      <doc:doc>
+        <doc:description>
+          <doc:para>Attempt to create unmanaged sessions for this seat.</doc:para>
+        </doc:description>
+      </doc:doc>
+    </method>
+
+    <method name="Unmanage">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+      <doc:doc>
+        <doc:description>
+          <doc:para>Stop managing seat.</doc:para>
+        </doc:description>
+      </doc:doc>
+    </method>
+
     <signal name="ActiveSessionChanged">
       <arg name="ssid" type="o">
         <doc:doc>
@@ -160,5 +178,61 @@ seat at a time.</doc:para>
         </doc:description>
       </doc:doc>
     </signal>
+    <signal name="OpenSessionRequest">
+      <arg name="ssid" type="o">
+        <doc:doc>
+          <doc:summary>The session id of the session to add</doc:summary>
+        </doc:doc>
+      </arg>
+      <arg name="session_type" type="s">
+        <doc:doc>
+          <doc:summary>The type of session to run (e.g. "LoginWindow", "Chooser", etc)</doc:summary>
+        </doc:doc>
+      </arg>
+      <arg name="display_template_name" type="s">
+        <doc:doc>
+          <doc:summary>The name of display template </doc:summary>
+        </doc:doc>
+      </arg>
+      <arg name="parameters" type="a{ss}">
+        <doc:doc>
+          <doc:summary>Session type specific parameters</doc:summary>
+        </doc:doc>
+      </arg>
+      <arg name="display_type" type="s">
+        <doc:doc>
+          <doc:summary>The type of display to use (e.g. "X11", "Command", "XDMCP", etc)</doc:summary>
+        </doc:doc>
+      </arg>
+      <arg name="display_parameters" type="a{ss}">
+        <doc:doc>
+          <doc:summary>Display type specific parameters</doc:summary>
+        </doc:doc>
+      </arg>
+      <doc:doc>
+        <doc:description>
+          <doc:para>Emitted when a new session should get added to the seat.</doc:para>
+        </doc:description>
+      </doc:doc>
+    </signal>
+    <signal name="CloseSessionRequest">
+      <arg name="ssid" type="o">
+        <doc:doc>
+          <doc:summary>The session id of the session to remove</doc:summary>
+        </doc:doc>
+      </arg>
+      <doc:doc>
+        <doc:description>
+          <doc:para>Emitted when a session with given display number need to be removed.</doc:para>
+        </doc:description>
+      </doc:doc>
+    </signal>
+    <signal name="RemoveRequest">
+      <doc:doc>
+        <doc:description>
+          <doc:para>Emitted when seat needs to get removed.</doc:para>
+        </doc:description>
+      </doc:doc>
+    </signal>
   </interface>
 </node>
diff --git a/src/org.freedesktop.ConsoleKit.Session.xml b/src/org.freedesktop.ConsoleKit.Session.xml
index b6e1cdb..2652058 100644
--- a/src/org.freedesktop.ConsoleKit.Session.xml
+++ b/src/org.freedesktop.ConsoleKit.Session.xml
@@ -52,6 +52,19 @@
         <doc:seealso><doc:ref type="property" to="Session:session-type">session-type</doc:ref></doc:seealso>
       </doc:doc>
     </method>
+    <method name="GetDisplayType">
+      <arg name="type" direction="out" type="s">
+        <doc:doc>
+          <doc:summary>Display type</doc:summary>
+        </doc:doc>
+      </arg>
+      <doc:doc>
+        <doc:description>
+          <doc:para>Returns the display type of the session.</doc:para>
+        </doc:description>
+        <doc:seealso><doc:ref type="property" to="Session:display-type">display-type</doc:ref></doc:seealso>
+      </doc:doc>
+    </method>
     <method name="GetUser">
       <arg name="uid" direction="out" type="u">
         <doc:doc>
@@ -174,6 +187,18 @@
         <doc:seealso><doc:ref type="property" to="Session:is-local">is-local</doc:ref></doc:seealso>
       </doc:doc>
     </method>
+    <method name="IsOpen">
+      <arg name="open" direction="out" type="b">
+        <doc:doc>
+          <doc:summary>TRUE if the session is open, otherwise FALSE</doc:summary>
+        </doc:doc>
+      </arg>
+      <doc:doc>
+        <doc:description><doc:para>Returns whether the session is open</doc:para>
+        </doc:description>
+        <doc:seealso><doc:ref type="property" to="Session:is-open">is-open</doc:ref></doc:seealso>
+      </doc:doc>
+    </method>
     <method name="GetCreationTime">
       <arg name="iso8601_datetime" type="s" direction="out">
         <doc:doc>
@@ -275,6 +300,21 @@
         </doc:description>
       </doc:doc>
     </method>
+    <method name="SetRemoveOnClose">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+      <arg name="remove_on_close" type="b" direction="in">
+        <doc:doc>
+          <doc:summary>boolean value to set the remove-on-close to</doc:summary>
+        </doc:doc>
+      </arg>
+      <doc:doc>
+        <doc:description>
+          <doc:para>This may be used by the session to indicate that
+          it should be respawn or not when it is closed.
+          </doc:para>
+        </doc:description>
+      </doc:doc>
+    </method>
 
     <signal name="ActiveChanged">
       <arg name="is_active" type="b">
@@ -317,6 +357,19 @@
       </doc:doc>
     </signal>
 
+    <property name="session" type="o" access="readwrite">
+      <doc:doc>
+        <doc:description>
+          <doc:para>The id of the session.</doc:para>
+          <doc:para>
+          The object path of the session.  Typically this is set by a session leader during a call to the
+          <doc:ref type="method" to="Manager.OpenSessionWithParameters">OpenSessionWithParameters</doc:ref> method, when
+          opening a session in response to the <doc:ref type="signal" to="Seat::OpenSessionRequest">OpenSessionRequest</doc:ref>
+          signal.
+          </doc:para>
+        </doc:description>
+      </doc:doc>
+    </property>
     <property name="unix-user" type="u" access="readwrite">
       <doc:doc>
         <doc:description>
@@ -342,6 +395,16 @@
         </doc:description>
       </doc:doc>
     </property>
+    <property name="display-type" type="s" access="readwrite">
+      <doc:doc>
+        <doc:description>
+          <doc:para>The display type of the session.</doc:para>
+          <doc:para>Indicate the display template name. All the display template configuration
+          files are under /etc/ConsoleKit/displays.d/.
+          </doc:para>
+        </doc:description>
+      </doc:doc>
+    </property>
     <property name="remote-host-name" type="s" access="readwrite">
       <doc:doc>
         <doc:description>
@@ -396,6 +459,19 @@
         </doc:description>
       </doc:doc>
     </property>
+    <property name="is-open" type="b" access="readwrite">
+      <doc:doc>
+        <doc:description>
+          <doc:para>
+          Whether the session is open</doc:para>
+          <doc:para>Sessions added from static configuration or in direct response to a call to
+          the <doc:ref type="method" to="Manager.AddSession">AddSession</doc:ref> method are initialally
+          closed and aren't open until a call to the <doc:ref type="method" to="Manager.OpenSessionWithParameters">OpenSessionWithParameters</doc:ref>
+          method.
+          </doc:para>
+        </doc:description>
+      </doc:doc>
+    </property>
     <property name="is-local" type="b" access="readwrite">
       <doc:doc>
         <doc:description>
@@ -408,6 +484,14 @@
         </doc:description>
       </doc:doc>
     </property>
+    <property name="is-dynamic" type="b" access="readwrite">
+      <doc:doc>
+        <doc:description>
+          <doc:para>
+          Whether the session is dynamic</doc:para>
+        </doc:description>
+      </doc:doc>
+    </property>
     <property name="idle-hint" type="b" access="readwrite">
       <doc:doc>
         <doc:description>
@@ -430,6 +514,14 @@
         </doc:description>
       </doc:doc>
     </property>
+    <property name="remove-on-close" type="b" access="readwrite">
+      <doc:doc>
+        <doc:description>
+          <doc:para>
+          Whether the session respawn when it is closed</doc:para>
+        </doc:description>
+      </doc:doc>
+    </property>
 
   </interface>
 </node>
diff --git a/src/strverscmp.c b/src/strverscmp.c
new file mode 100644
index 0000000..f077651
--- /dev/null
+++ b/src/strverscmp.c
@@ -0,0 +1,131 @@
+/* Compare strings while treating digits characters numerically.
+   Copyright (C) 1997, 2000, 2002, 2004, 2006 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jean-François Bignolles <[email protected]>, 1997.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#if !_LIBC
+# include <config.h>
+#endif
+
+#include <string.h>
+#include <ctype.h>
+
+/* states: S_N: normal, S_I: comparing integral part, S_F: comparing
+           fractional parts, S_Z: idem but with leading Zeroes only */
+#define S_N    0x0
+#define S_I    0x4
+#define S_F    0x8
+#define S_Z    0xC
+
+/* result_type: CMP: return diff; LEN: compare using len_diff/diff */
+#define CMP    2
+#define LEN    3
+
+
+/* ISDIGIT differs from isdigit, as follows:
+   - Its arg may be any int or unsigned int; it need not be an unsigned char
+     or EOF.
+   - It's typically faster.
+   POSIX says that only '0' through '9' are digits.  Prefer ISDIGIT to
+   isdigit unless it's important to use the locale's definition
+   of `digit' even when the host does not conform to POSIX.  */
+#define ISDIGIT(c) ((unsigned int) (c) - '0' <= 9)
+
+#undef __strverscmp
+#undef strverscmp
+
+#ifndef weak_alias
+# define __strverscmp strverscmp
+#endif
+
+/* Compare S1 and S2 as strings holding indices/version numbers,
+   returning less than, equal to or greater than zero if S1 is less than,
+   equal to or greater than S2 (for more info, see the texinfo doc).
+*/
+
+int
+__strverscmp (const char *s1, const char *s2)
+{
+  const unsigned char *p1 = (const unsigned char *) s1;
+  const unsigned char *p2 = (const unsigned char *) s2;
+  unsigned char c1, c2;
+  int state;
+  int diff;
+
+  /* Symbol(s)    0       [1-9]   others  (padding)
+     Transition   (10) 0  (01) d  (00) x  (11) -   */
+  static const unsigned int next_state[] =
+  {
+      /* state    x    d    0    - */
+      /* S_N */  S_N, S_I, S_Z, S_N,
+      /* S_I */  S_N, S_I, S_I, S_I,
+      /* S_F */  S_N, S_F, S_F, S_F,
+      /* S_Z */  S_N, S_F, S_Z, S_Z
+  };
+
+  static const int result_type[] =
+  {
+      /* state   x/x  x/d  x/0  x/-  d/x  d/d  d/0  d/-
+                 0/x  0/d  0/0  0/-  -/x  -/d  -/0  -/- */
+
+      /* S_N */  CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP,
+                 CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP,
+      /* S_I */  CMP, -1,  -1,  CMP,  1,  LEN, LEN, CMP,
+                  1,  LEN, LEN, CMP, CMP, CMP, CMP, CMP,
+      /* S_F */  CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP,
+                 CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP,
+      /* S_Z */  CMP,  1,   1,  CMP, -1,  CMP, CMP, CMP,
+                 -1,  CMP, CMP, CMP
+  };
+
+  if (p1 == p2)
+    return 0;
+
+  c1 = *p1++;
+  c2 = *p2++;
+  /* Hint: '0' is a digit too.  */
+  state = S_N | ((c1 == '0') + (ISDIGIT (c1) != 0));
+
+  while ((diff = c1 - c2) == 0 && c1 != '\0')
+    {
+      state = next_state[state];
+      c1 = *p1++;
+      c2 = *p2++;
+      state |= (c1 == '0') + (ISDIGIT (c1) != 0);
+    }
+
+  state = result_type[state << 2 | ((c2 == '0') + (ISDIGIT (c2) != 0))];
+
+  switch (state)
+    {
+    case CMP:
+      return diff;
+
+    case LEN:
+      while (ISDIGIT (*p1++))
+	if (!ISDIGIT (*p2++))
+	  return 1;
+
+      return ISDIGIT (*p2) ? -1 : diff;
+
+    default:
+      return state;
+    }
+}
+#ifdef weak_alias
+weak_alias (__strverscmp, strverscmp)
+#endif
diff --git a/src/strverscmp.h b/src/strverscmp.h
new file mode 100644
index 0000000..48670c8
--- /dev/null
+++ b/src/strverscmp.h
@@ -0,0 +1,25 @@
+/* Compare strings while treating digits characters numerically.
+   Copyright (C) 1997, 2000, 2002, 2004, 2006 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jean-François Bignolles <[email protected]>, 1997.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#ifndef STRVERSCMP_H_
+# define STRVERSCMP_H_
+
+int strverscmp (const char *, const char *);
+
+#endif /* not STRVERSCMP_H_ */
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 13c191f..fa16c68 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -54,6 +54,7 @@ sbin_PROGRAMS = \
 	ck-log-system-start		\
 	ck-log-system-restart		\
 	ck-log-system-stop		\
+	ck-seat-tool			\
 	$(NULL)
 
 ck_launch_session_SOURCES =		\
@@ -83,6 +84,14 @@ ck_history_LDADD =			\
 	$(top_builddir)/src/libck-event-log.la	\
 	$(NULL)
 
+ck_seat_tool_SOURCES =			\
+	ck-seat-tool.c			\
+	$(NULL)
+
+ck_seat_tool_LDADD =			\
+	$(CONSOLE_KIT_LIBS)		\
+	$(NULL)
+
 ck_log_system_start_SOURCES =		\
 	ck-log-system-start.c		\
 	$(NULL)
diff --git a/tools/ck-seat-tool.c b/tools/ck-seat-tool.c
new file mode 100644
index 0000000..0879d0d
--- /dev/null
+++ b/tools/ck-seat-tool.c
@@ -0,0 +1,443 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2009 Sun Microsystems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Authors: Halton Huo <[email protected]>
+ *
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <strings.h>
+#include <glib/gi18n.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#define CK_NAME              "org.freedesktop.ConsoleKit"
+#define CK_PATH              "/org/freedesktop/ConsoleKit"
+#define CK_INTERFACE         "org.freedesktop.ConsoleKit"
+#define CK_MANAGER_PATH      "/org/freedesktop/ConsoleKit/Manager"
+#define CK_MANAGER_INTERFACE "org.freedesktop.ConsoleKit.Manager"
+#define CK_SEAT_INTERFACE    "org.freedesktop.ConsoleKit.Seat"
+#define CK_SESSION_INTERFACE "org.freedesktop.ConsoleKit.Session"
+
+#define CK_DBUS_TYPE_G_STRING_STRING_HASHTABLE (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_STRING))
+
+#define IS_STR_SET(x) (x != NULL && x[0] != '\0')
+#define CK_PATH_PREFIX       "/org/freedesktop/ConsoleKit/"
+
+static gboolean  add = FALSE;
+static gboolean  delete = FALSE;
+static gboolean  show_version = FALSE;
+static char     *session_type = NULL;
+static char     *display_type = NULL;
+static char     *seat_id = NULL;
+static char     *session_id = NULL;
+static gchar   **remaining_args = NULL;
+
+static const GOptionEntry options [] = {
+        { "add", 'a', 0, G_OPTION_ARG_NONE, &add, N_("Add a new session"), NULL},
+        { "session-type", '\0', 0, G_OPTION_ARG_STRING, &session_type, N_("Specify session type when adding a session. Default is LoginWindow."), NULL},
+        { "display-type", '\0', 0, G_OPTION_ARG_STRING, &display_type, N_("Specify display type under <etc>/ConsoleKit/displays.d/ when adding a session."), NULL},
+        { "seat-id", '\0', 0, G_OPTION_ARG_STRING, &seat_id, N_("Specify seat id when adding a session. If not given, create a new seat."), NULL},
+        { G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_STRING_ARRAY, &remaining_args, N_("Specify values of variables in display type. For example display=:10"), NULL },
+        { "delete", 'd', 0, G_OPTION_ARG_NONE, &delete, N_("Delete a session"), NULL},
+        { "session-id", '\0', 0, G_OPTION_ARG_STRING, &session_id, N_("Specify session id when deleting a session"), NULL},
+        { "version", 'V', 0, G_OPTION_ARG_NONE, &show_version, N_("Version of this application"), NULL },
+        { NULL }
+};
+
+static void
+add_session (DBusGConnection  *connection)
+{
+        DBusGProxy *mgr_proxy = NULL;
+        DBusGProxy *seat_proxy = NULL;
+        GError     *error = NULL;
+        gboolean    res;
+        char       *sid = NULL;
+        GPtrArray  *seats;
+        char       *ssid = NULL;
+        int         i;
+        gboolean    found;
+        char       *sstype = NULL;
+        GHashTable *variables = NULL;
+
+        if (! IS_STR_SET (session_type)) {
+                sstype = g_strdup ("LoginWindow");
+        } else {
+                sstype = g_strdup (session_type);
+        }
+
+        mgr_proxy = dbus_g_proxy_new_for_name (connection,
+                                               CK_NAME,
+                                               CK_MANAGER_PATH,
+                                               CK_MANAGER_INTERFACE);
+        if (mgr_proxy == NULL) {
+                return;
+        }
+
+        if (! IS_STR_SET(seat_id)) {
+
+                /* If seat id is not given, create a new seat */
+                error = NULL;
+                res = dbus_g_proxy_call (mgr_proxy,
+                                         "AddSeat",
+                                         &error,
+                                         G_TYPE_STRING, "Default",
+                                         G_TYPE_INVALID,
+                                         DBUS_TYPE_G_OBJECT_PATH, &sid,
+                                         G_TYPE_INVALID);
+                if (!res) {
+                        g_warning ("Unable to add seat: %s", error->message);
+                        g_error_free (error);
+                        g_object_unref (mgr_proxy);
+                        return;
+                }
+
+        } else {
+                if (!g_str_has_prefix (seat_id, CK_PATH_PREFIX)) {
+                        sid = g_strdup_printf ("%s%s", CK_PATH_PREFIX, seat_id);
+                } else {
+                        sid = g_strdup (seat_id);
+                }
+                /* Check whether seat is existing, if not, try to create it. */
+
+                error = NULL;
+                res = dbus_g_proxy_call (mgr_proxy,
+                                         "GetSeats",
+                                         &error,
+                                         G_TYPE_INVALID,
+                                         dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH),
+                                         &seats,
+                                         G_TYPE_INVALID);
+                if (!res) {
+                        g_warning ("Unable to get seat list: %s", error->message);
+                        g_error_free (error);
+                        g_object_unref (mgr_proxy);
+                        return;
+                }
+
+                found = FALSE;
+                for (i = 0; i < seats->len; i++) {
+                        char *tmp_sid;
+
+                        tmp_sid = g_ptr_array_index (seats, i);
+                        if (g_str_equal (sid, tmp_sid)) {
+                                found = TRUE;
+                                g_free (tmp_sid);
+                                break;
+                        }
+
+                        g_free (tmp_sid);
+                }
+
+                if (! found) {
+                        error = NULL;
+                        res = dbus_g_proxy_call (mgr_proxy,
+                                                 "AddSeatById",
+                                                 &error,
+                                                 G_TYPE_STRING, "Default",
+                                                 DBUS_TYPE_G_OBJECT_PATH, sid,
+                                                 G_TYPE_INVALID,
+                                                 G_TYPE_INVALID);
+                        if (!res) {
+                                g_warning ("Unable to add seat: %s", error->message);
+                                g_error_free (error);
+                                g_object_unref (mgr_proxy);
+                                return;
+                        }
+                }
+        }
+
+        seat_proxy = dbus_g_proxy_new_for_name (connection,
+                                                CK_NAME,
+                                                sid,
+                                                CK_SEAT_INTERFACE);
+
+        if (seat_proxy == NULL) {
+                g_warning ("Failed to talk to seat '%s'", sid);
+                g_object_unref (mgr_proxy);
+                return;
+        }
+
+        variables = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                           (GDestroyNotify) g_free,
+                                           (GDestroyNotify) g_free);
+
+        if (remaining_args) {
+                for (i = 0; i < G_N_ELEMENTS (remaining_args); i++) {
+                        char **arr;
+
+                        /* split var=value */
+                        arr = g_strsplit (remaining_args [i], "=", 2);
+                        if (arr[0] && arr[1]) {
+                                g_hash_table_insert (variables,
+                                                     g_strdup(arr[0]),
+                                                     g_strdup (arr[1]));
+                        }
+                        g_strfreev (arr);
+                }
+        }
+
+        error = NULL;
+        res = dbus_g_proxy_call (mgr_proxy,
+                                 "AddSession",
+                                 &error,
+                                 DBUS_TYPE_G_OBJECT_PATH, sid,
+                                 G_TYPE_STRING, sstype,
+                                 G_TYPE_STRING, display_type,
+                                 CK_DBUS_TYPE_G_STRING_STRING_HASHTABLE, variables,
+                                 G_TYPE_INVALID,
+                                 DBUS_TYPE_G_OBJECT_PATH, &ssid,
+                                 G_TYPE_INVALID);
+
+        if (!res) {
+                g_warning ("Unable to add dynamic session: %s", error->message);
+                g_error_free (error);
+        } else {
+                dbus_g_proxy_call_no_reply (seat_proxy,
+                                            "Manage",
+                                            G_TYPE_INVALID,
+                                            G_TYPE_INVALID);
+                g_print ("Seat %s with session %s has been added\n", sid, ssid);
+        }
+
+        g_object_unref (seat_proxy);
+        g_object_unref (mgr_proxy);
+}
+
+static gboolean
+is_session_on_seat (DBusGConnection *connection,
+                    const char      *sid,
+                    const char      *ssid,
+                    gboolean        *is_last_session)
+{
+
+        DBusGProxy *seat_proxy = NULL;
+        GPtrArray  *sessions = NULL;
+        char       *ssid_tmp = NULL;
+        gboolean    res;
+        gboolean    retval = FALSE;
+        int         i;
+        GError     *error = NULL;
+
+        seat_proxy = dbus_g_proxy_new_for_name (connection,
+                                                CK_NAME,
+                                                sid,
+                                                CK_SEAT_INTERFACE);
+
+        if (seat_proxy == NULL) {
+                g_warning ("Failed to talk to seat '%s'", sid);
+                return FALSE;
+        }
+
+        error = NULL;
+        res = dbus_g_proxy_call (seat_proxy,
+                                 "GetSessions",
+                                 &error,
+                                 G_TYPE_INVALID,
+                                 dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH),
+                                 &sessions,
+                                 G_TYPE_INVALID);
+        if (! res) {
+                g_warning ("Failed to get list of sessions for %s: %s", sid, error->message);
+                g_error_free (error);
+                g_object_unref (seat_proxy);
+                return FALSE;
+        }
+
+        for (i = 0; i < sessions->len; i++) {
+
+                ssid_tmp = g_ptr_array_index (sessions, i);
+
+                if (g_str_equal (ssid, ssid_tmp)) {
+                        retval = TRUE;
+                        break;
+                }
+
+                g_free (ssid_tmp);
+                ssid_tmp = NULL;
+        }
+
+        if (is_last_session != NULL) {
+                *is_last_session = sessions->len == 1;
+        }
+
+        g_ptr_array_free (sessions, TRUE);
+        g_object_unref (seat_proxy);
+
+        return retval;
+}
+
+static char *
+find_seat_id_from_session_id (DBusGConnection *connection,
+                              DBusGProxy      *proxy,
+                              const char      *ssid,
+                              gboolean        *is_last_session)
+{
+        GError     *error;
+        GPtrArray  *seats;
+        int         i;
+        char       *sid;
+        gboolean    res;
+
+        error = NULL;
+        res = dbus_g_proxy_call (proxy,
+                                 "GetSeats",
+                                 &error,
+                                 G_TYPE_INVALID,
+                                 dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH),
+                                 &seats,
+                                 G_TYPE_INVALID);
+
+        if (! res) {
+                g_warning ("Failed to get list of seats: %s", error->message);
+                g_error_free (error);
+                return NULL;
+        }
+
+        for (i = 0; i < seats->len; i++) {
+
+                sid = g_ptr_array_index (seats, i);
+                if (is_session_on_seat (connection, sid, ssid, is_last_session)) {
+                        break;
+                }
+
+                g_free (sid);
+        }
+        g_ptr_array_free (seats, TRUE);
+
+        return sid;
+}
+
+static void
+delete_session (DBusGConnection *connection)
+{
+        DBusGProxy *proxy;
+        char       *ssid;
+        char       *sid;
+        gboolean    is_last_session;
+
+        if (!g_str_has_prefix (session_id, CK_PATH_PREFIX)) {
+                ssid = g_strdup_printf ("%s%s", CK_PATH_PREFIX, session_id);
+        } else {
+                ssid = g_strdup (session_id);
+        }
+
+        proxy = dbus_g_proxy_new_for_name (connection,
+                                           CK_NAME,
+                                           CK_MANAGER_PATH,
+                                           CK_MANAGER_INTERFACE);
+        if (proxy == NULL) {
+                return;
+        }
+
+        sid = find_seat_id_from_session_id (connection, proxy, ssid, &is_last_session);
+
+        dbus_g_proxy_call_no_reply (proxy,
+                                   "RemoveSession",
+                                   DBUS_TYPE_G_OBJECT_PATH, ssid,
+                                   G_TYPE_INVALID,
+                                   G_TYPE_INVALID);
+
+        if (is_last_session) {
+                dbus_g_proxy_call_no_reply (proxy,
+                                           "RemoveSeat",
+                                           DBUS_TYPE_G_OBJECT_PATH, sid,
+                                           G_TYPE_INVALID,
+                                           G_TYPE_INVALID);
+        }
+
+        g_object_unref (proxy);
+}
+
+int
+main (int argc, char *argv[])
+{
+        DBusGConnection *connection;
+        GOptionContext  *ctx;
+        GError          *error = NULL;
+        gboolean         res;
+
+        g_type_init ();
+
+        /* Option parsing */
+        ctx = g_option_context_new (_("- Manage dynamic sessions"));
+        g_option_context_add_main_entries (ctx, options, GETTEXT_PACKAGE);
+        res = g_option_context_parse (ctx, &argc, &argv, &error);
+
+        if (!res) {
+                if (error) {
+                        g_warning ("%s", error->message);
+                        g_error_free (error);
+                }
+                exit (1);
+        }
+
+        g_option_context_free (ctx);    
+
+        if (show_version) {
+                g_print ("%s %s\n", argv[0], VERSION);
+                exit (0);
+        }
+
+        if (add && delete) {
+                g_warning ("Can not specify -a and -d at the same time!");
+                exit (1);
+        }
+
+        if (!add && !delete) {
+                g_warning ("Must specify -a, -d!");
+                exit (1);
+        }
+
+        if (delete && (! IS_STR_SET (session_id))) {
+                g_warning ("You must specify session id for deleting a session. You can get all sessions by ck-list-sessions");
+                exit (1);
+        }
+
+        if (add && (! IS_STR_SET (display_type)) ) {
+                g_warning ("You must specify display type for adding a session. You can get all display types under <etc>/ConsoleKit/displays.d/");
+                g_warning ("Invalid display type!");
+                exit (1);
+        }
+
+        error = NULL;
+        connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
+        if (connection == NULL) {
+                g_message ("Failed to connect to the D-Bus daemon: %s", error->message);
+                g_error_free (error);
+                exit (1);
+        }
+
+
+        if (add) {
+                add_session (connection);
+        } else if (delete) {
+                delete_session (connection);
+        } else {
+                g_warning ("Invaild parameters!");
+                exit (1);
+        }
+
+        return 0;
+}
diff --git a/tools/list-sessions.c b/tools/list-sessions.c
index 3933772..cc69d57 100644
--- a/tools/list-sessions.c
+++ b/tools/list-sessions.c
@@ -46,6 +46,23 @@
 #define CK_SEAT_INTERFACE    "org.freedesktop.ConsoleKit.Seat"
 #define CK_SESSION_INTERFACE "org.freedesktop.ConsoleKit.Session"
 
+#define IS_STR_SET(x) (x != NULL && x[0] != '\0')
+
+typedef struct CkSessionOutput {
+        char    *prop_name;
+        char    *prop_value;
+} CkSessionOutput;
+
+static gboolean do_all = FALSE;
+static gboolean do_version = FALSE;
+static char *do_format = NULL;
+static GOptionEntry entries [] = {
+        { "all", 'a', 0, G_OPTION_ARG_NONE, &do_all, N_("List all sessions. If not given, only list open sessions"), NULL },
+        { "format", 'f', 0, G_OPTION_ARG_STRING, &do_format, N_("Prints information according to the given format"), NULL },
+        { "version", 'V', 0, G_OPTION_ARG_NONE, &do_version, N_("Version of this application"), NULL },
+        { NULL }
+};
+
 static gboolean
 get_uint (DBusGProxy *proxy,
           const char *method,
@@ -176,6 +193,7 @@ list_session (DBusGConnection *connection,
         char       *sid;
         char       *lsid;
         char       *session_type;
+        char       *display_type;
         char       *x11_display;
         char       *x11_display_device;
         char       *display_device;
@@ -184,8 +202,11 @@ list_session (DBusGConnection *connection,
         char       *idle_since_hint;
         gboolean    is_active;
         gboolean    is_local;
+        gboolean    is_open;
         char       *short_sid;
         const char *short_ssid;
+        char      **format_arr = NULL;
+        int         i, j;
 
         proxy = dbus_g_proxy_new_for_name (connection,
                                            CK_NAME,
@@ -198,6 +219,7 @@ list_session (DBusGConnection *connection,
         sid = NULL;
         lsid = NULL;
         session_type = NULL;
+        display_type = NULL;
         x11_display = NULL;
         x11_display_device = NULL;
         display_device = NULL;
@@ -209,15 +231,21 @@ list_session (DBusGConnection *connection,
         get_path (proxy, "GetSeatId", &sid);
         get_string (proxy, "GetLoginSessionId", &lsid);
         get_string (proxy, "GetSessionType", &session_type);
+        get_string (proxy, "GetDisplayType", &display_type);
         get_string (proxy, "GetX11Display", &x11_display);
         get_string (proxy, "GetX11DisplayDevice", &x11_display_device);
         get_string (proxy, "GetDisplayDevice", &display_device);
         get_string (proxy, "GetRemoteHostName", &remote_host_name);
+        get_boolean (proxy, "IsOpen", &is_open);
         get_boolean (proxy, "IsActive", &is_active);
         get_boolean (proxy, "IsLocal", &is_local);
         get_string (proxy, "GetCreationTime", &creation_time);
         get_string (proxy, "GetIdleSinceHint", &idle_since_hint);
 
+        if (!do_all && !is_open) {
+                return;
+        }
+
         realname = get_real_name (uid);
 
         short_sid = sid;
@@ -230,24 +258,49 @@ list_session (DBusGConnection *connection,
                 short_ssid = ssid + strlen (CK_PATH) + 1;
         }
 
-        printf ("%s:\n\tunix-user = '%d'\n\trealname = '%s'\n\tseat = '%s'\n\tsession-type = '%s'\n\tactive = %s\n\tx11-display = '%s'\n\tx11-display-device = '%s'\n\tdisplay-device = '%s'\n\tremote-host-name = '%s'\n\tis-local = %s\n\ton-since = '%s'\n\tlogin-session-id = '%s'",
-                short_ssid,
-                uid,
-                realname,
-                short_sid,
-                session_type,
-                is_active ? "TRUE" : "FALSE",
-                x11_display,
-                x11_display_device,
-                display_device,
-                remote_host_name,
-                is_local ? "TRUE" : "FALSE",
-                creation_time,
-                lsid);
-        if (idle_since_hint != NULL && idle_since_hint[0] != '\0') {
-                printf ("\n\tidle-since-hint = '%s'", idle_since_hint);
+        CkSessionOutput output[] = {
+                {"session-id", g_strdup (short_ssid)},
+                {"unix-user", g_strdup_printf ("%d", uid)},
+                {"realname", g_strdup (realname)},
+                {"seat", g_strdup (short_sid)},
+                {"session-type", g_strdup (session_type)},
+                {"display-type", g_strdup (display_type)},
+                {"open", is_open ? "TRUE" : "FALSE"},
+                {"active", is_active ? "TRUE" : "FALSE"},
+                {"x11-display", g_strdup (x11_display)},
+                {"x11-display-device", g_strdup (x11_display_device)},
+                {"display-device", g_strdup (display_device)},
+                {"remote-host-name", g_strdup (remote_host_name)},
+                {"is-local", is_local ? "TRUE" : "FALSE"},
+                {"on-since", g_strdup (creation_time)},
+                {"login-session-id", g_strdup (lsid)},
+                {"idle-since-hint", g_strdup (idle_since_hint)},
+        };
+
+        if (IS_STR_SET (do_format)) {
+                format_arr = g_strsplit (do_format, ",", -1);
+
+                for (i = 0; format_arr[i] != NULL; ++i) {
+                        for (j = 0; j < G_N_ELEMENTS (output); j++) {
+                                if (g_str_equal (format_arr[i], output[j].prop_name)) {
+                                        printf ("'%s'\t", output[j].prop_value);
+                                        break;
+                                }
+                        }
+                }
+                printf ("\n");
+                g_strfreev (format_arr);
+
+        } else {
+                for (j = 0; j < G_N_ELEMENTS (output); j++) {
+                        if (g_str_equal (output[j].prop_name, "session-id"))
+                                printf ("%s:\n", output[j].prop_value);
+                        else
+                                printf ("\t%s = '%s'\n",
+                                        output[j].prop_name,
+                                        output[j].prop_value);
+                }
         }
-        printf ("\n");
 
         g_free (idle_since_hint);
         g_free (creation_time);
@@ -256,9 +309,11 @@ list_session (DBusGConnection *connection,
         g_free (sid);
         g_free (lsid);
         g_free (session_type);
+        g_free (display_type);
         g_free (x11_display);
         g_free (x11_display_device);
         g_free (display_device);
+
         g_object_unref (proxy);
 }
 
@@ -368,11 +423,6 @@ main (int    argc,
         GOptionContext *context;
         gboolean        retval;
         GError         *error = NULL;
-        static gboolean do_version = FALSE;
-        static GOptionEntry entries [] = {
-                { "version", 'V', 0, G_OPTION_ARG_NONE, &do_version, N_("Version of this application"), NULL },
-                { NULL }
-        };
 
         g_type_init ();