summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--debian/changelog16
-rw-r--r--debian/consolekit.postinst12
-rw-r--r--debian/consolekit.prerm3
-rw-r--r--debian/control4
-rw-r--r--debian/patches/series6
-rw-r--r--debian/patches/solaris/ConsoleKit-01-ck-dynamic.diff5499
-rw-r--r--debian/patches/solaris/ConsoleKit-02-add-sunray-type.diff32
-rw-r--r--debian/patches/solaris/ConsoleKit-03-sol-novt.diff9
-rw-r--r--debian/patches/solaris/ConsoleKit-05-fastreboot.diff450
-rw-r--r--debian/patches/solaris/ConsoleKit-06-ck-history.diff61
-rw-r--r--debian/patches/solaris/ConsoleKit-07-suppress-warning.diff13
-rw-r--r--debian/patches/solaris/ConsoleKit-08-vt-switch.diff108
12 files changed, 6211 insertions, 2 deletions
diff --git a/debian/changelog b/debian/changelog
index 9d010ee..1e41d28 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,19 @@
+consolekit (0.4.6-2+dyson1) unstable; urgency=low
+
+ * Package for Dyson
+ * Added build-dep: libscf-dev [illumos-any]
+ * Refresh dbus in postinst
+ * Use pkill in consolekit.prerm (depends on procutils | procps)
+ * Added solaris patches:
+ solaris/ConsoleKit-01-ck-dynamic.diff
+ solaris/ConsoleKit-02-add-sunray-type.diff
+ solaris/ConsoleKit-03-sol-novt.diff
+ solaris/ConsoleKit-06-ck-history.diff
+ solaris/ConsoleKit-07-suppress-warning.diff
+ solaris/ConsoleKit-08-vt-switch.diff
+
+ -- Igor Pashev <pashev.igor@gmail.com> Tue, 30 Jul 2013 18:55:07 +0400
+
consolekit (0.4.6-2) experimental; urgency=low
* Acknowledge non-maintainer upload, thanks Christoph and Petr.
diff --git a/debian/consolekit.postinst b/debian/consolekit.postinst
new file mode 100644
index 0000000..0539665
--- /dev/null
+++ b/debian/consolekit.postinst
@@ -0,0 +1,12 @@
+#!/bin/sh
+set -e
+
+if [ "$1" = "configure" ];
+then
+ if [ -x /usr/bin/smf_present ] && /usr/bin/smf_present;
+ then
+ svcadm -v refresh svc:/system/dbus:default || true
+ else
+ invoke-rc.d dbus reload || true
+ fi
+fi
diff --git a/debian/consolekit.prerm b/debian/consolekit.prerm
index 22a87b8..78d4047 100644
--- a/debian/consolekit.prerm
+++ b/debian/consolekit.prerm
@@ -6,7 +6,8 @@ DAEMON=/usr/sbin/console-kit-daemon
PIDFILE=/var/run/console-kit-daemon.pid
if [ "$1" = remove ]; then
- start-stop-daemon --stop --quiet --oknodo --exec $DAEMON --pidfile $PIDFILE
+ # Until we support SMF in dbus ;-)
+ pkill -f $DAEMON && rm -f $PIDFILE || true
fi
#DEBHELPER#
diff --git a/debian/control b/debian/control
index 582c118..9e4e978 100644
--- a/debian/control
+++ b/debian/control
@@ -16,6 +16,7 @@ Build-Depends: debhelper (>= 9),
libpam0g-dev,
libpolkit-gobject-1-dev (>= 0.92),
zlib1g-dev,
+ libscf-dev [illumos-any],
dh-autoreconf
Standards-Version: 3.9.3
Vcs-Git: git://git.debian.org/git/pkg-utopia/consolekit.git
@@ -25,7 +26,8 @@ Homepage: http://www.freedesktop.org/wiki/Software/ConsoleKit
Package: consolekit
Section: admin
Architecture: any
-Depends: ${shlibs:Depends}, ${misc:Depends}, libck-connector0 (= ${binary:Version}), dbus (>= 1.1.2)
+Depends: ${shlibs:Depends}, ${misc:Depends}, libck-connector0 (= ${binary:Version}), dbus (>= 1.1.2),
+ procutils | procps
Recommends: libpam-ck-connector
Breaks: udev (<< 204-1)
Replaces: udev (<< 204-1)
diff --git a/debian/patches/series b/debian/patches/series
index 7970731..07c1c3e 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,3 +1,9 @@
# Debian patches for consolekit
03-cleanup_console_tags.patch
99-kfreebsd-empty-env.patch
+solaris/ConsoleKit-01-ck-dynamic.diff
+solaris/ConsoleKit-02-add-sunray-type.diff
+solaris/ConsoleKit-03-sol-novt.diff
+solaris/ConsoleKit-06-ck-history.diff
+solaris/ConsoleKit-07-suppress-warning.diff
+solaris/ConsoleKit-08-vt-switch.diff
diff --git a/debian/patches/solaris/ConsoleKit-01-ck-dynamic.diff b/debian/patches/solaris/ConsoleKit-01-ck-dynamic.diff
new file mode 100644
index 0000000..a81a182
--- /dev/null
+++ b/debian/patches/solaris/ConsoleKit-01-ck-dynamic.diff
@@ -0,0 +1,5499 @@
+Index: consolekit/configure.ac
+===================================================================
+--- consolekit.orig/configure.ac 2013-07-30 17:36:13.291172731 +0400
++++ consolekit/configure.ac 2013-07-30 17:36:25.925792848 +0400
+@@ -172,6 +172,18 @@
+ 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 ---------------------------------------------------------------------------
+
+@@ -289,6 +301,14 @@
+ 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 ---------------------------------------------------------------------------
+
+@@ -390,6 +410,8 @@
+ 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
+Index: consolekit/data/00-primary.seat
+===================================================================
+--- consolekit.orig/data/00-primary.seat 2013-07-30 17:36:13.291439182 +0400
++++ consolekit/data/00-primary.seat 2013-07-30 17:36:25.927524649 +0400
+@@ -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;
+Index: consolekit/data/ConsoleKit.conf
+===================================================================
+--- consolekit.orig/data/ConsoleKit.conf 2013-07-30 17:36:13.291383225 +0400
++++ consolekit/data/ConsoleKit.conf 2013-07-30 17:36:25.929928904 +0400
+@@ -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>
+Index: consolekit/data/Makefile.am
+===================================================================
+--- consolekit.orig/data/Makefile.am 2013-07-30 17:36:13.291421776 +0400
++++ consolekit/data/Makefile.am 2013-07-30 17:36:25.942750408 +0400
+@@ -1,5 +1,10 @@
+ NULL =
+
++SUBDIRS = \
++ displays.d \
++ sessions.d \
++ $(NULL)
++
+ dbusconfdir = $(DBUS_SYS_DIR)
+ dbusconf_DATA = ConsoleKit.conf
+
+Index: consolekit/data/displays.d/Headless.display.in
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ consolekit/data/displays.d/Headless.display.in 2013-07-30 17:36:25.944372108 +0400
+@@ -0,0 +1,5 @@
++[Display]
++Type=X11
++
++[X11]
++Exec=@X11_DIR@/Xvfb $display -auth $auth
+Index: consolekit/data/displays.d/Local.display.in
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ consolekit/data/displays.d/Local.display.in 2013-07-30 17:36:25.945611527 +0400
+@@ -0,0 +1,5 @@
++[Display]
++Type=X11
++
++[X11]
++Exec=@X11_DIR@/Xorg $display -br -verbose -auth $auth -nolisten tcp $vt
+Index: consolekit/data/displays.d/LocalVNC.display.in
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ consolekit/data/displays.d/LocalVNC.display.in 2013-07-30 17:36:25.946771424 +0400
+@@ -0,0 +1,5 @@
++[Display]
++Type=X11
++
++[X11]
++Exec=@X11_DIR@/Xvnc $display -auth $auth -query localhost
+Index: consolekit/data/displays.d/Makefile.am
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ consolekit/data/displays.d/Makefile.am 2013-07-30 17:36:25.947926934 +0400
+@@ -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)
+Index: consolekit/data/displays.d/RemoteMachine.display.in
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ consolekit/data/displays.d/RemoteMachine.display.in 2013-07-30 17:36:25.949024199 +0400
+@@ -0,0 +1,5 @@
++[Display]
++Type=X11
++
++[X11]
++Exec=@X11_DIR@/Xorg $display -br -verbose -auth $auth -indirect $vt
+Index: consolekit/data/sessions.d/Headless.session
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ consolekit/data/sessions.d/Headless.session 2013-07-30 17:36:25.950740125 +0400
+@@ -0,0 +1,8 @@
++[Session Entry]
++Name=Headless
++Type=LoginWindow
++Description=Login Window running on headless display
++DisplayTemplate=Headless
++
++[Headless]
++display=:32
+Index: consolekit/data/sessions.d/Local.session
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ consolekit/data/sessions.d/Local.session 2013-07-30 17:36:25.951889788 +0400
+@@ -0,0 +1,9 @@
++[Session Entry]
++Name=Local
++Type=LoginWindow
++Description=Local Login Screen
++DisplayTemplate=Local
++
++[Local]
++display=:0
++vt=vt1
+Index: consolekit/data/sessions.d/LocalVNC.session
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ consolekit/data/sessions.d/LocalVNC.session 2013-07-30 17:36:25.953170561 +0400
+@@ -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
+Index: consolekit/data/sessions.d/Makefile.am
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ consolekit/data/sessions.d/Makefile.am 2013-07-30 17:36:25.954292677 +0400
+@@ -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
+Index: consolekit/data/sessions.d/Remote.session
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ consolekit/data/sessions.d/Remote.session 2013-07-30 17:36:25.955588986 +0400
+@@ -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
+Index: consolekit/doc/dbus/ck-terms.xml
+===================================================================
+--- consolekit.orig/doc/dbus/ck-terms.xml 2013-07-30 17:36:13.291352092 +0400
++++ consolekit/doc/dbus/ck-terms.xml 2013-07-30 17:36:25.957200026 +0400
+@@ -64,4 +64,11 @@
+ </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>
+Index: consolekit/libck-connector/ck-connector.c
+===================================================================
+--- consolekit.orig/libck-connector/ck-connector.c 2013-07-30 17:36:13.292088375 +0400
++++ consolekit/libck-connector/ck-connector.c 2013-07-30 17:36:25.959367679 +0400
+@@ -76,8 +76,11 @@
+ { "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 },
+ };
+Index: consolekit/src/Makefile.am
+===================================================================
+--- consolekit.orig/src/Makefile.am 2013-07-30 17:36:13.291951690 +0400
++++ consolekit/src/Makefile.am 2013-07-30 17:36:25.961655779 +0400
+@@ -115,6 +115,8 @@
+ 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 \
+@@ -130,6 +132,13 @@
+ $(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
+Index: consolekit/src/ck-display-template.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ consolekit/src/ck-display-template.c 2013-07-30 17:36:25.963158743 +0400
+@@ -0,0 +1,341 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
++ *
++ * Authors: halton.huo@sun.com, Ray Strode <rstrode@redhat.com>
++ * 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);
++}
++
+Index: consolekit/src/ck-display-template.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ consolekit/src/ck-display-template.h 2013-07-30 17:36:25.964388080 +0400
+@@ -0,0 +1,57 @@
++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
++ *
++ * Authors: halton.huo@sun.com
++ * 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 */
+Index: consolekit/src/ck-log-event.c
+===================================================================
+--- consolekit.orig/src/ck-log-event.c 2013-07-30 17:36:13.291903394 +0400
++++ consolekit/src/ck-log-event.c 2013-07-30 17:36:25.968884888 +0400
+@@ -79,6 +79,8 @@
+ 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->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_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_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 @@
+
+ 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 @@
+
+ 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 : "",
+@@ -939,7 +947,7 @@
+ }
+
+ 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 ("%s", error->message);
+ goto out;
+@@ -957,6 +965,7 @@
+ 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,7 +1023,7 @@
+ }
+
+ 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 ("%s", error->message);
+ goto out;
+@@ -1032,6 +1041,7 @@
+ 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");
+Index: consolekit/src/ck-log-event.h
+===================================================================
+--- consolekit.orig/src/ck-log-event.h 2013-07-30 17:36:13.291635154 +0400
++++ consolekit/src/ck-log-event.h 2013-07-30 17:36:25.971000725 +0400
+@@ -68,6 +68,7 @@
+ {
+ char *seat_id;
+ int seat_kind;
++ char *seat_type;
+ } CkLogSeatAddedEvent;
+
+ typedef struct
+@@ -81,11 +82,13 @@
+ 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 @@
+ 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;
+Index: consolekit/src/ck-manager.c
+===================================================================
+--- consolekit.orig/src/ck-manager.c 2013-07-30 17:36:13.291934667 +0400
++++ consolekit/src/ck-manager.c 2013-07-30 17:36:25.984038951 +0400
+@@ -45,9 +45,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"
+@@ -57,12 +62,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
+@@ -391,6 +403,7 @@
+ GError *error;
+ char *sid;
+ CkSeatKind seat_kind;
++ char *seat_type;
+
+ memset (&event, 0, sizeof (CkLogEvent));
+
+@@ -400,9 +413,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);
+@@ -412,6 +427,7 @@
+ }
+
+ g_free (sid);
++ g_free (seat_type);
+ }
+
+ static void
+@@ -516,6 +532,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,
+@@ -571,6 +588,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,
+@@ -844,6 +862,8 @@
+ PolkitAuthorizationResult *ret;
+ GError *error;
+
++ g_debug ("CkManager: Ready.");
++
+ error = NULL;
+ ret = polkit_authority_check_authorization_finish (authority, res, &error);
+ if (error != NULL) {
+@@ -974,6 +994,7 @@
+
+ /* filter out GDM user */
+ if (username != NULL && strcmp (username, "gdm") == 0) {
++ g_debug ("CkManager: Session is not real user");
+ ret = FALSE;
+ goto out;
+ }
+@@ -982,6 +1003,7 @@
+ *userp = g_strdup (username);
+ }
+
++ g_debug ("CkManager: Session is real user");
+ ret = TRUE;
+
+ out:
+@@ -1242,6 +1264,7 @@
+ {
+ char *ssid = NULL;
+
++ g_debug ("CkManager: Active session changed.");
+ if (session != NULL) {
+ ck_session_get_id (session, &ssid, NULL);
+ }
+@@ -1261,6 +1284,7 @@
+ {
+ char *ssid = NULL;
+
++ g_debug ("CkManager: Session added.");
+ ck_session_get_id (session, &ssid, NULL);
+
+ ck_manager_dump (manager);
+@@ -1278,6 +1302,7 @@
+ {
+ char *ssid = NULL;
+
++ g_debug ("CkManager: Seat Session removed.");
+ ck_session_get_id (session, &ssid, NULL);
+
+ ck_manager_dump (manager);
+@@ -1293,6 +1318,7 @@
+ GValueArray *device,
+ CkManager *manager)
+ {
++ g_debug ("CkManager: Seat device added.");
+ ck_manager_dump (manager);
+ log_seat_device_added_event (manager, seat, device);
+ }
+@@ -1302,6 +1328,7 @@
+ GValueArray *device,
+ CkManager *manager)
+ {
++ g_debug ("CkManager: Seat device removed.");
+ ck_manager_dump (manager);
+ log_seat_device_removed_event (manager, seat, device);
+ }
+@@ -1329,15 +1356,23 @@
+ }
+
+ 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);
++ }
++
++ g_debug ("CkManager: Add new seat '%s'.", sid);
+
+- 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
+@@ -1362,7 +1397,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);
+
+@@ -1381,6 +1416,8 @@
+ sid = NULL;
+ ck_seat_get_id (seat, &sid, NULL);
+
++ g_debug ("CkManager: Remove seat '%s'", sid);
++
+ /* Need to get the original key/value */
+ res = g_hash_table_lookup_extended (manager->priv->seats,
+ sid,
+@@ -1420,64 +1457,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;
+ }
+
+@@ -1612,36 +1607,52 @@
+ CkSession *session;
+ CkSeat *seat;
+ const char *ssid;
++ char *sid;
+ const char *cookie;
+
++ g_debug ("CkManager: Open session for leader.");
+ 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);
++ g_debug ("CkManager: Creating new session.");
++ session = ck_session_new_with_parameters (ssid,
++ parameters);
++
++ if (session == NULL) {
++ GError *error;
++ g_debug ("CkManager: 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;
++ return;
++ }
++
++ g_hash_table_insert (manager->priv->sessions,
++ g_strdup (ssid),
++ g_object_ref (session));
++
++ } else {
++ g_debug ("CkManager: Using found session.");
++ 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);
+@@ -1863,6 +1874,7 @@
+ {
+ gboolean res;
+
++ g_debug ("CkManager: Generate session for leader.");
+ res = ck_session_leader_collect_parameters (leader,
+ context,
+ (CkSessionLeaderDoneFunc)collect_parameters_cb,
+@@ -1877,11 +1889,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 ("CkManager: 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 ("CkManager: 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;
+@@ -1889,6 +1947,7 @@
+ char *cookie;
+ char *ssid;
+ CkSessionLeader *leader;
++ CkSession *session;
+
+ g_debug ("CkManager: create session for sender: %s", sender);
+
+@@ -1907,9 +1966,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 ("CkManager: Managing existing session ssid: %s", ssid);
++ } else {
++ ssid = generate_session_id (manager);
++ session = NULL;
++ g_debug ("CkManager: Creating new session ssid: %s", ssid);
++ }
+
+ leader = ck_session_leader_new ();
+ ck_session_leader_set_uid (leader, uid);
+@@ -2148,7 +2219,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;
+@@ -2163,7 +2234,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;
+@@ -2180,10 +2251,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);
+
+@@ -2210,6 +2283,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
+@@ -2217,31 +2301,33 @@
+ * 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 */
++ g_debug ("CkManager: Should remove session");
++ 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);
+
+@@ -2249,11 +2335,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;
+ }
+
+@@ -2374,6 +2462,7 @@
+ g_assert (leader != NULL);
+ g_assert (data->service_name != NULL);
+
++ g_debug ("CkManager: Remove leader for connection");
+ name = ck_session_leader_peek_service_name (leader);
+ if (strcmp (name, data->service_name) == 0) {
+ remove_session_for_cookie (data->manager, cookie, NULL);
+@@ -2391,6 +2480,8 @@
+ guint n_removed;
+ RemoveLeaderData data;
+
++ g_debug ("CkManager: Remove sessions for connection");
++
+ data.service_name = service_name;
+ data.manager = manager;
+
+@@ -2426,6 +2517,8 @@
+ manager->priv->pol_ctx = polkit_authority_get ();
+ #endif
+
++ g_debug ("CkManager: Registering manager");
++
+ error = NULL;
+ manager->priv->connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
+ if (manager->priv->connection == NULL) {
+@@ -2471,9 +2564,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),
+@@ -2580,6 +2675,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)
+@@ -2604,16 +2736,321 @@
+ 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_debug ("CkManager: Add seat '%s'.", *sid);
++ 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_debug ("CkManager: Remove seat '%s'.", sid);
++ 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;
++
++ g_debug ("CkManager: Add session");
++ 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;
++
++ g_debug ("CkManager: Remove session.");
++ 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;
++
++ g_debug ("CkManager: Add session from seat.");
++ 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;
+
++ g_debug ("CkManager: Add seat for file.");
+ sid = generate_seat_id (manager);
++ orig_sid = g_strdup (sid);
++ 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);
+
+- seat = ck_seat_new_from_file (sid, filename);
++ add_sessions_from_seat (manager, seat);
++
++ if (seat == NULL) {
++ return;
++ }
+
+ if (seat == NULL) {
+ return;
+@@ -2636,7 +3073,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);
+ }
+@@ -2647,6 +3084,7 @@
+ GDir *d;
+ GError *error;
+ const char *file;
++ GQueue seat_queue;
+
+ error = NULL;
+ d = g_dir_open (CK_SEAT_DIR,
+@@ -2658,17 +3096,26 @@
+ return FALSE;
+ }
+
++ g_queue_init (&seat_queue);
+ while ((file = g_dir_read_name (d)) != NULL) {
+ if (g_str_has_suffix (file, ".seat")) {
+ char *path;
+ path = g_build_filename (CK_SEAT_DIR, file, NULL);
+- add_seat_for_file (manager, path);
+- g_free (path);
++ 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);
++ }
++
+ return TRUE;
+ }
+
+@@ -2704,8 +3151,6 @@
+ (GDestroyNotify) g_object_unref);
+
+ manager->priv->logger = ck_event_logger_new (LOG_FILE);
+-
+- create_seats (manager);
+ }
+
+ static void
+@@ -2750,7 +3195,48 @@
+ g_object_unref (manager_object);
+ return NULL;
+ }
++
++ create_seats (CK_MANAGER (manager_object));
+ }
+
+ return CK_MANAGER (manager_object);
+ }
++
++gboolean
++ck_manager_will_not_respawn (CkManager *manager,
++ const char *ssid,
++ DBusGMethodInvocation *context)
++{
++ GError *error;
++ CkSeat *seat;
++ CkSession *session;
++ char *sid;
++
++ g_debug ("CkManager: Will not respawn: '%s'.", ssid);
++ 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;
++ }
++
++ session_set_remove_on_close (session, FALSE, NULL);
++ ck_session_get_seat_id (session, &sid, NULL);
++ seat = g_hash_table_lookup (manager->priv->seats, sid);
++ g_free (sid);
++
++ ck_seat_no_respawn (seat, session, &error);
++
++ dbus_g_method_return (context);
++ return TRUE;
++}
++
+Index: consolekit/src/ck-manager.h
+===================================================================
+--- consolekit.orig/src/ck-manager.h 2013-07-30 17:36:13.291491197 +0400
++++ consolekit/src/ck-manager.h 2013-07-30 17:36:25.986042859 +0400
+@@ -49,7 +49,8 @@
+ 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_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,31 @@
+ 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);
++gboolean ck_manager_will_not_respawn (CkManager *manager,
++ const char *cookie,
++ DBusGMethodInvocation *context);
++
+ G_END_DECLS
+
+ #endif /* __CK_MANAGER_H */
+Index: consolekit/src/ck-marshal.list
+===================================================================
+--- consolekit.orig/src/ck-marshal.list 2013-07-30 17:36:13.291462772 +0400
++++ consolekit/src/ck-marshal.list 2013-07-30 17:36:25.987229798 +0400
+@@ -1,3 +1,6 @@
+ VOID:UINT,STRING
+ BOOLEAN:POINTER
+ VOID:OBJECT,OBJECT
++VOID:STRING,STRING
++VOID:STRING,BOOLEAN,STRING,POINTER,STRING,POINTER
++VOID:STRING,STRING,STRING,POINTER,STRING,POINTER
+Index: consolekit/src/ck-seat.c
+===================================================================
+--- consolekit.orig/src/ck-seat.c 2013-07-30 17:36:13.291666147 +0400
++++ consolekit/src/ck-seat.c 2013-07-30 17:36:25.994398564 +0400
+@@ -39,21 +39,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;
+
+@@ -62,6 +71,8 @@
+ CkVtMonitor *vt_monitor;
+
+ DBusGConnection *connection;
++
++ DBusGProxy *manager_proxy;
+ };
+
+ enum {
+@@ -73,6 +84,10 @@
+ SESSION_REMOVED_FULL,
+ DEVICE_ADDED,
+ DEVICE_REMOVED,
++ REMOVE_REQUEST,
++ OPEN_SESSION_REQUEST,
++ CLOSE_SESSION_REQUEST,
++ NO_RESPAWN,
+ LAST_SIGNAL
+ };
+
+@@ -80,6 +95,7 @@
+ PROP_0,
+ PROP_ID,
+ PROP_KIND,
++ PROP_TYPE
+ };
+
+ static guint signals [LAST_SIGNAL] = { 0, };
+@@ -286,6 +302,7 @@
+ {
+ CkSession *session;
+ gboolean ret;
++ gboolean is_open;
+
+ g_return_val_if_fail (CK_IS_SEAT (seat), FALSE);
+
+@@ -297,12 +314,410 @@
+ 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) {
++ g_debug ("CkSeat: session is not open. Request open session");
++ ret = ck_seat_request_open_session (seat, session, NULL);
++ dbus_g_method_return (context, NULL);
++ } else {
++ g_debug ("CkSeat: session is open. Activate session");
++ 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 = NULL;
++
++ match = g_match_info_fetch (match_info, 1);
++
++ if (substitution_variables != NULL)
++ 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;
++
++ g_debug ("CkSeat: Request session");
++ 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;
++
++ g_debug ("CkSeat: Open Session Request");
++
++ 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;
++
++ g_debug ("CkSeat: Request Open Session");
++
++ ck_session_is_open (session, &is_open, NULL);
++
++ if (is_open) {
++ g_debug ("CkSeat: Is Open");
++ return TRUE;
++ }
++
++ ck_session_get_under_request (session, &under_request, NULL);
++ if (under_request) {
++ g_debug ("CkSeat: Is Under");
++ 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) {
++ g_debug ("CkSeat: Is Display Template");
++ return TRUE;
++ }
++
++ ck_session_get_session_type (session, &type, NULL);
++
++ if (type == NULL) {
++ g_debug ("CkSeat: Type Is 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_debug ("CkSeat: Display Parms Are 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);
++
++ g_debug ("CkSeat: Emitting Open Request");
++ 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_debug ("CkSeat: Seat Manager Disappeared.");
++
++ 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;
++
++ g_debug ("CkSeat: Seat manage.");
++ 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;
++
++ g_debug ("CkSeat: Seat unmanage.");
++ 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));
++
++ g_debug ("CkSeat: Seat request removal.");
++
++ 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)
+@@ -313,6 +728,8 @@
+ device = NULL;
+ ret = FALSE;
+
++ g_debug ("CkSeat: Session display device.");
++
+ if (session == NULL) {
+ goto out;
+ }
+@@ -485,6 +902,8 @@
+ char *ssid;
+ CkSession *old_session;
+
++ g_debug ("CkSeat: Change active session.");
++
+ if (seat->priv->active_session == session) {
+ return;
+ }
+@@ -514,7 +933,10 @@
+ * must be sent when the database dump is finished it is
+ * important that the '-full' signalled is emitted first. */
+
+- g_signal_emit (seat, signals [ACTIVE_SESSION_CHANGED_FULL], 0, old_session, session);
++ if (CK_IS_SESSION (old_session)) {
++ g_signal_emit (seat, signals [ACTIVE_SESSION_CHANGED_FULL], 0, old_session, session);
++ }
++
+ g_signal_emit (seat, signals [ACTIVE_SESSION_CHANGED], 0, ssid);
+
+ if (old_session != NULL) {
+@@ -525,6 +947,48 @@
+ }
+
+ 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_debug ("CkSeat: Find possible session to activate");
++ 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);
++
++ g_debug ("CkSeat: Session Type %s", session_type);
++
++ if (IS_STR_SET (session_type) &&
++ g_str_equal (session_type, "LoginWindow")) {
++ login_session = value;
++ g_debug ("CkSeat: Setting login_session %s",
++ login_session);
++ g_free (session_type);
++ }
++ }
++
++ if (login_session != NULL) {
++ g_debug ("CkSeat: Login Session is not 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)
+ {
+@@ -536,7 +1000,12 @@
+ 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);
+ }
+@@ -546,12 +1015,20 @@
+ {
+ guint num;
+
+- if (seat->priv->kind != CK_SEAT_KIND_STATIC) {
+- return;
+- }
++ g_debug ("CkSeat: Check to see if we should update active session");
+
+- 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;
+ }
+ }
+
+@@ -560,6 +1037,7 @@
+ DBusGMethodInvocation *context,
+ CkSeat *seat)
+ {
++ g_debug ("CkSeat: Session activate.");
+ _seat_activate_session (seat, session, context);
+
+ /* always return TRUE to indicate that the signal was handled */
+@@ -583,6 +1061,8 @@
+ ssid = NULL;
+ ck_session_get_id (session, &ssid, NULL);
+
++ g_debug ("CkSeat: Removing session '%s'", ssid);
++
+ /* Need to get the original key/value */
+ res = g_hash_table_lookup_extended (seat->priv->sessions,
+ ssid,
+@@ -627,18 +1107,118 @@
+ return ret;
+ }
+
++static void
++emit_session_close_request (CkSeat *seat,
++ const char *ssid)
++{
++ DBusMessage *message;
++ DBusConnection *connection;
++ DBusMessageIter iter;
++
++ g_debug ("CkSeat: Emit Session Close request");
++
++ 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);
++
++ g_debug ("CkSeat: Request close session.");
++ ck_session_get_id (session, &ssid, NULL);
++
++ emit_session_close_request (seat, ssid);
++
++ g_free (ssid);
++
++ return FALSE;
++}
++
++gboolean
++ck_seat_no_respawn (CkSeat *seat,
++ CkSession *session,
++ GError **error)
++{
++ DBusMessage *message;
++ DBusConnection *connection;
++ DBusMessageIter iter;
++ 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);
++
++ g_debug ("CkSeat: No Respawn.");
++ ck_session_get_id (session, &ssid, NULL);
++
++ message = dbus_message_new_signal (seat->priv->id,
++ "org.freedesktop.ConsoleKit.Seat",
++ "NoRespawn");
++
++ 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);
++
++ 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);
+
++ g_debug ("CkSeat: Add session.");
+ 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);
+
+@@ -655,6 +1235,11 @@
+
+ maybe_update_active_session (seat);
+
++ if (ck_seat_is_managed (seat)) {
++ g_debug ("CkSeat: Seat is managed. Request open session");
++ ck_seat_request_open_session (seat, session, NULL);
++ }
++
+ g_free (ssid);
+
+ return TRUE;
+@@ -741,6 +1326,20 @@
+ }
+
+ 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)
+@@ -772,6 +1371,7 @@
+ g_return_val_if_fail (CK_IS_SEAT (seat), FALSE);
+
+ error = NULL;
++ g_debug ("CkSeat: Register seat.");
+ seat->priv->connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
+ if (seat->priv->connection == NULL) {
+ if (error != NULL) {
+@@ -859,6 +1459,14 @@
+ }
+
+ 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,
+@@ -875,6 +1483,9 @@
+ 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;
+@@ -896,7 +1507,10 @@
+ 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 +1622,48 @@
+ g_cclosure_marshal_VOID__BOXED,
+ 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);
++ signals [OPEN_SESSION_REQUEST] = g_signal_new ("open-session-request",
++ G_TYPE_FROM_CLASS (object_class),
++ G_SIGNAL_RUN_LAST,
++ G_STRUCT_OFFSET (CkSeatClass, open_session_request),
++ NULL,
++ NULL,
++ ck_marshal_VOID__STRING_STRING_STRING_POINTER_STRING_POINTER,
++ G_TYPE_NONE,
++ 6,
++ DBUS_TYPE_G_OBJECT_PATH,
++ G_TYPE_STRING,
++ G_TYPE_STRING,
++ CK_DBUS_TYPE_G_STRING_STRING_HASHTABLE,
++ G_TYPE_STRING,
++ CK_DBUS_TYPE_G_STRING_STRING_HASHTABLE,
++ G_TYPE_INVALID);
++ signals [CLOSE_SESSION_REQUEST] = g_signal_new ("close-session-request",
++ G_TYPE_FROM_CLASS (object_class),
++ G_SIGNAL_RUN_LAST,
++ G_STRUCT_OFFSET (CkSeatClass, close_session_request),
++ NULL,
++ NULL,
++ g_cclosure_marshal_VOID__VOID,
++ G_TYPE_NONE,
++ 1, DBUS_TYPE_G_OBJECT_PATH);
++ signals [NO_RESPAWN] = g_signal_new ("no-respawn",
++ G_TYPE_FROM_CLASS (object_class),
++ G_SIGNAL_RUN_LAST,
++ G_STRUCT_OFFSET (CkSeatClass, no_respawn),
++ NULL,
++ NULL,
++ g_cclosure_marshal_VOID__VOID,
++ G_TYPE_NONE, 0);
++/* HERE */
+
+ g_object_class_install_property (object_class,
+ PROP_ID,
+@@ -1025,6 +1681,13 @@
+ 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);
+@@ -1040,6 +1703,7 @@
+ g_free,
+ (GDestroyNotify) g_object_unref);
+ seat->priv->devices = g_ptr_array_new ();
++ seat->priv->manager_proxy = NULL;
+ }
+
+ static void
+@@ -1065,28 +1729,32 @@
+ 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;
+@@ -1101,27 +1769,62 @@
+ 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;
+
++ g_debug ("CkSeat: New seat from file.");
++
+ key_file = g_key_file_new ();
+ error = NULL;
+ res = g_key_file_load_from_file (key_file,
+@@ -1146,9 +1849,52 @@
+ 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);
++ g_debug ("CkSeat: Creating seat %s with %zd devices", *sid, ndevices);
+
+ devices = g_ptr_array_sized_new (ndevices);
+
+@@ -1177,11 +1923,12 @@
+ 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);
+@@ -1356,10 +2103,15 @@
+
+ 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,
+@@ -1371,3 +2123,24 @@
+
+ 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);
++}
+Index: consolekit/src/ck-seat.h
+===================================================================
+--- consolekit.orig/src/ck-seat.h 2013-07-30 17:36:13.291763784 +0400
++++ consolekit/src/ck-seat.h 2013-07-30 17:36:25.996758538 +0400
+@@ -47,6 +47,18 @@
+ {
+ GObjectClass parent_class;
+
++ void (* remove_request) (CkSeat *seat);
++ void (* open_session_request) (CkSeat *seat,
++ const char *ssid,
++ const char *session_type,
++ const char *display_template_name,
++ GHashTable *display_variables,
++ const char *display_type,
++ GHashTable *parameters);
++ void (* close_session_request) (CkSeat *seat,
++ const char *ssid);
++ void (* no_respawn) (CkSeat *seat,
++ const char *ssid);
+ void (* active_session_changed) (CkSeat *seat,
+ const char *ssid);
+ void (* session_added) (CkSeat *seat,
+@@ -57,6 +69,11 @@
+ 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 +101,14 @@
+ 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 +123,31 @@
+ 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 +169,14 @@
+ 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);
++
++gboolean ck_seat_no_respawn (CkSeat *seat,
++ CkSession *session,
++ GError **error);
+
+ G_END_DECLS
+
+Index: consolekit/src/ck-session-leader.c
+===================================================================
+--- consolekit.orig/src/ck-session-leader.c 2013-07-30 17:36:13.291744991 +0400
++++ consolekit/src/ck-session-leader.c 2013-07-30 17:36:25.998222316 +0400
+@@ -237,6 +237,7 @@
+ { "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 },
+ };
+Index: consolekit/src/ck-session.c
+===================================================================
+--- consolekit.orig/src/ck-session.c 2013-07-30 17:36:13.291804906 +0400
++++ consolekit/src/ck-session.c 2013-07-30 17:36:26.007019008 +0400
+@@ -40,6 +40,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))
+
+@@ -57,6 +58,7 @@
+ char *seat_id;
+
+ char *session_type;
++ char *display_type;
+ char *login_session_id;
+ char *display_device;
+ char *x11_display_device;
+@@ -64,8 +66,15 @@
+ 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;
+
+@@ -74,6 +83,8 @@
+ gboolean idle_hint;
+ GTimeVal idle_since_hint;
+
++ gboolean remove_on_close;
++
+ DBusGConnection *connection;
+ DBusGProxy *bus_proxy;
+ };
+@@ -91,17 +102,24 @@
+ 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, };
+@@ -127,7 +145,9 @@
+ register_session (CkSession *session)
+ {
+ GError *error = NULL;
++ GObject *existing_session;
+
++ g_debug ("CkSession: Register session.");
+ error = NULL;
+ session->priv->connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
+ if (session->priv->connection == NULL) {
+@@ -143,6 +163,15 @@
+ 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;
+@@ -301,6 +330,40 @@
+ }
+
+ 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;
++ }
++
++ if (session->priv->remove_on_close == TRUE)
++ g_debug ("CkSession: Setting remove on close to true.");
++ else
++ g_debug ("CkSession: Setting remove on close to false.");
++
++ 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)
+@@ -366,6 +429,7 @@
+ {
+ gboolean res;
+
++ g_debug ("CkSession: Session activate.");
+ g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
+
+ res = FALSE;
+@@ -396,6 +460,8 @@
+ {
+ g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
+
++ g_debug ("CkSession: Session set active.");
++
+ if (session->priv->active != active) {
+ session->priv->active = active;
+ g_signal_emit (session, signals [ACTIVE_CHANGED], 0, active);
+@@ -419,6 +485,68 @@
+ }
+
+ 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 ("CkSession: 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)
+@@ -554,6 +682,20 @@
+ }
+
+ 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)
+@@ -568,6 +710,20 @@
+ }
+
+ 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)
+@@ -596,6 +752,50 @@
+ }
+
+ 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)
+@@ -608,6 +808,21 @@
+ 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,
+@@ -724,6 +939,54 @@
+ 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,
+@@ -741,15 +1004,33 @@
+ 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;
+@@ -774,6 +1055,9 @@
+ 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;
+@@ -797,15 +1081,33 @@
+ 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;
+@@ -830,6 +1132,9 @@
+ 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;
+@@ -881,6 +1186,8 @@
+ static void
+ session_remove_activity_watch (CkSession *session)
+ {
++ g_debug ("CkSession: Remove activity watch.");
++
+ if (session->priv->idle_monitor == NULL) {
+ return;
+ }
+@@ -999,6 +1306,13 @@
+ "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,
+@@ -1008,6 +1322,27 @@
+ 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",
+@@ -1070,6 +1405,14 @@
+ 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));
+
+ dbus_g_object_type_install_info (CK_TYPE_SESSION, &dbus_glib_ck_session_object_info);
+@@ -1080,8 +1423,16 @@
+ {
+ 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
+@@ -1104,6 +1455,7 @@
+ 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->login_session_id);
+ g_free (session->priv->display_device);
+ g_free (session->priv->x11_display_device);
+@@ -1114,16 +1466,138 @@
+ }
+
+ 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;
++
++ g_debug ("CkSession: New session from file.");
++ 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 ("CkSession: 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;
+
++ g_debug ("CkSession: New Session.");
++
++ 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 +1612,80 @@
+ 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 ("CkSession: Unable to extract parameter input");
++ goto cont;
++ }
++
++ if (prop_name == NULL) {
++ g_debug ("CkSession: Skipping NULL parameter");
++ goto cont;
++ }
++
++ if (strcmp (prop_name, "id") == 0
++ || strcmp (prop_name, "cookie") == 0) {
++ g_debug ("CkSession: Skipping restricted parameter: %s", prop_name);
++ goto cont;
++ }
++
++ pspec = g_object_class_find_property (class, prop_name);
++ if (! pspec) {
++ g_debug ("CkSession: Skipping unknown parameter: %s", prop_name);
++ goto cont;
++ }
++
++ if (!(pspec->flags & G_PARAM_WRITABLE)) {
++ g_debug ("CkSession: 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 ("CkSession: 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;
+@@ -1152,6 +1697,8 @@
+ GObjectClass *class;
+ GType object_type;
+
++ g_debug ("CkSession: New session with parameters");
++
+ object_type = CK_TYPE_SESSION;
+ class = g_type_class_ref (object_type);
+
+@@ -1169,12 +1716,6 @@
+ 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 +1800,7 @@
+ 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 +1808,9 @@
+ 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 +1845,10 @@
+ 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 +1861,12 @@
+ "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,
+Index: consolekit/src/ck-session.h
+===================================================================
+--- consolekit.orig/src/ck-session.h 2013-07-30 17:36:13.291600107 +0400
++++ consolekit/src/ck-session.h 2013-07-30 17:36:26.008936807 +0400
+@@ -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 @@
+
+ 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_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_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_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_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_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,
+Index: consolekit/src/org.freedesktop.ConsoleKit.Manager.xml
+===================================================================
+--- consolekit.orig/src/org.freedesktop.ConsoleKit.Manager.xml 2013-07-30 17:36:13.291692225 +0400
++++ consolekit/src/org.freedesktop.ConsoleKit.Manager.xml 2013-07-30 17:36:26.012959052 +0400
+@@ -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>
+@@ -196,6 +213,22 @@
+ </doc:description>
+ </doc:doc>
+ </method>
++
++ <method name="WillNotRespawn">
++ <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</doc:summary>
++ </doc:doc>
++ </arg>
++ <doc:doc>
++ <doc:description>
++ <doc:para>This may be used to set Remove On Close for a Session.
++ </doc:para>
++ </doc:description>
++ </doc:doc>
++ </method>
++
+ <method name="GetSessionForUnixProcess">
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ <arg name="pid" direction="in" type="u">
+@@ -310,12 +343,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.
+Index: consolekit/src/org.freedesktop.ConsoleKit.Seat.xml
+===================================================================
+--- consolekit.orig/src/org.freedesktop.ConsoleKit.Seat.xml 2013-07-30 17:36:13.291561331 +0400
++++ consolekit/src/org.freedesktop.ConsoleKit.Seat.xml 2013-07-30 17:36:26.014234119 +0400
+@@ -100,6 +100,24 @@
+ </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,73 @@
+ </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="NoRespawn">
++ <arg name="ssid" type="o">
++ <doc:doc>
++ <doc:summary>The session id of the session to not respawn</doc:summary>
++ </doc:doc>
++ </arg>
++ <doc:doc>
++ <doc:description>
++ <doc:para>Emitted when ck-seat-tool indicates a session is 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>
+Index: consolekit/src/org.freedesktop.ConsoleKit.Session.xml
+===================================================================
+--- consolekit.orig/src/org.freedesktop.ConsoleKit.Session.xml 2013-07-30 17:36:13.291618394 +0400
++++ consolekit/src/org.freedesktop.ConsoleKit.Session.xml 2013-07-30 17:36:26.016336286 +0400
+@@ -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>
+Index: consolekit/src/strverscmp.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ consolekit/src/strverscmp.c 2013-07-30 17:36:26.017215577 +0400
+@@ -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 <bignolle@ecoledoc.ibp.fr>, 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
+Index: consolekit/src/strverscmp.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ consolekit/src/strverscmp.h 2013-07-30 17:36:26.017980373 +0400
+@@ -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 <bignolle@ecoledoc.ibp.fr>, 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_ */
+Index: consolekit/tools/Makefile.am
+===================================================================
+--- consolekit.orig/tools/Makefile.am 2013-07-30 17:36:13.291276045 +0400
++++ consolekit/tools/Makefile.am 2013-07-30 17:36:26.019127336 +0400
+@@ -54,6 +54,7 @@
+ ck-log-system-start \
+ ck-log-system-restart \
+ ck-log-system-stop \
++ ck-seat-tool \
+ $(NULL)
+
+ ck_launch_session_SOURCES = \
+@@ -83,6 +84,14 @@
+ $(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)
+Index: consolekit/tools/ck-seat-tool.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ consolekit/tools/ck-seat-tool.c 2013-07-30 17:36:26.020839844 +0400
+@@ -0,0 +1,449 @@
++/* -*- 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 <halton.huo@sun.com>
++ *
++ */
++
++#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,
++ "WillNotRespawn",
++ DBUS_TYPE_G_OBJECT_PATH, ssid,
++ G_TYPE_INVALID,
++ G_TYPE_INVALID);
++
++ 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;
++}
+Index: consolekit/tools/list-sessions.c
+===================================================================
+--- consolekit.orig/tools/list-sessions.c 2013-07-30 17:36:13.291313902 +0400
++++ consolekit/tools/list-sessions.c 2013-07-30 17:36:26.022730190 +0400
+@@ -45,6 +45,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,
+@@ -175,6 +192,7 @@
+ char *sid;
+ char *lsid;
+ char *session_type;
++ char *display_type;
+ char *x11_display;
+ char *x11_display_device;
+ char *display_device;
+@@ -183,8 +201,11 @@
+ 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,
+@@ -197,6 +218,7 @@
+ sid = NULL;
+ lsid = NULL;
+ session_type = NULL;
++ display_type = NULL;
+ x11_display = NULL;
+ x11_display_device = NULL;
+ display_device = NULL;
+@@ -208,15 +230,21 @@
+ 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;
+@@ -229,24 +257,49 @@
+ 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);
+@@ -255,9 +308,11 @@
+ 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);
+ }
+
+@@ -367,11 +422,6 @@
+ 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 ();
+
diff --git a/debian/patches/solaris/ConsoleKit-02-add-sunray-type.diff b/debian/patches/solaris/ConsoleKit-02-add-sunray-type.diff
new file mode 100644
index 0000000..94c9ffe
--- /dev/null
+++ b/debian/patches/solaris/ConsoleKit-02-add-sunray-type.diff
@@ -0,0 +1,32 @@
+diff --git a/data/displays.d/Makefile.am b/data/displays.d/Makefile.am
+index 1fab1d2..853744e 100644
+--- a/data/displays.d/Makefile.am
++++ b/data/displays.d/Makefile.am
+@@ -5,6 +5,7 @@ display_in_files = \
+ Local.display.in \
+ RemoteMachine.display.in \
+ LocalVNC.display.in \
++ Sunray.display.in \
+ Headless.display.in
+
+ display_DATA = $(display_in_files:.display.in=.display)
+@@ -15,6 +16,8 @@ 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)|" $< > $@
++Sunray.display: Sunray.display.in Makefile
++ sed -e "s|\@X11_DIR\@|$(X11_DIR)|" $< > $@
+ Headless.display: Headless.display.in Makefile
+ sed -e "s|\@X11_DIR\@|$(X11_DIR)|" $< > $@
+
+diff --git a/data/displays.d/Sunray.display.in b/data/displays.d/Sunray.display.in
+new file mode 100644
+index 0000000..2c0ed38
+--- /dev/null
++++ b/data/displays.d/Sunray.display.in
+@@ -0,0 +1,5 @@
++[Display]
++Type=X11
++
++[X11]
++Exec=/etc/opt/SUNWut/basedir/lib/utxsun $display -auth $auth
diff --git a/debian/patches/solaris/ConsoleKit-03-sol-novt.diff b/debian/patches/solaris/ConsoleKit-03-sol-novt.diff
new file mode 100644
index 0000000..0f7f925
--- /dev/null
+++ b/debian/patches/solaris/ConsoleKit-03-sol-novt.diff
@@ -0,0 +1,9 @@
+diff --git a/data/sessions.d/Local.session b/data/sessions.d/Local.session
+index 9d3b975..2a7b5aa 100644
+--- a/data/sessions.d/Local.session
++++ b/data/sessions.d/Local.session
+@@ -6,4 +6,3 @@ DisplayTemplate=Local
+
+ [Local]
+ display=:0
+-vt=vt1
diff --git a/debian/patches/solaris/ConsoleKit-05-fastreboot.diff b/debian/patches/solaris/ConsoleKit-05-fastreboot.diff
new file mode 100644
index 0000000..a631f09
--- /dev/null
+++ b/debian/patches/solaris/ConsoleKit-05-fastreboot.diff
@@ -0,0 +1,450 @@
+Index: consolekit/configure.ac
+===================================================================
+--- consolekit.orig/configure.ac 2013-07-30 17:36:25.925792848 +0400
++++ consolekit/configure.ac 2013-07-30 17:37:15.103282665 +0400
+@@ -82,10 +82,10 @@
+
+ EXTRA_COMPILE_WARNINGS(yes)
+
+-# Solaris requires libresolv for daemon()
++# Solaris requires libscf
+ case "$host" in
+ *-*-solaris*)
+- AC_CHECK_LIB(resolv, daemon, [CONSOLE_KIT_LIBS="$CONSOLE_KIT_LIBS -lresolv"])
++ AC_CHECK_LIB(scf, daemon, [CONSOLE_KIT_LIBS="$CONSOLE_KIT_LIBS -lscf"])
+ ;;
+ esac
+
+Index: consolekit/data/ConsoleKit.conf
+===================================================================
+--- consolekit.orig/data/ConsoleKit.conf 2013-07-30 17:36:25.929928904 +0400
++++ consolekit/data/ConsoleKit.conf 2013-07-30 17:37:15.117095940 +0400
+@@ -38,6 +38,12 @@
+ send_member="CanStop"/>
+ <allow send_destination="org.freedesktop.ConsoleKit"
+ send_interface="org.freedesktop.ConsoleKit.Manager"
++ send_member="GetAvailableOperatingSystems"/>
++ <allow send_destination="org.freedesktop.ConsoleKit"
++ send_interface="org.freedesktop.ConsoleKit.Manager"
++ send_member="RestartWithParameters"/>
++ <allow send_destination="org.freedesktop.ConsoleKit"
++ send_interface="org.freedesktop.ConsoleKit.Manager"
+ send_member="OpenSession"/>
+ <allow send_destination="org.freedesktop.ConsoleKit"
+ send_interface="org.freedesktop.ConsoleKit.Manager"
+Index: consolekit/src/ck-manager.c
+===================================================================
+--- consolekit.orig/src/ck-manager.c 2013-07-30 17:36:25.984038951 +0400
++++ consolekit/src/ck-manager.c 2013-07-30 17:37:15.124404309 +0400
+@@ -38,6 +38,10 @@
+ #include <dbus/dbus-glib.h>
+ #include <dbus/dbus-glib-lowlevel.h>
+
++#if (defined(sun) && defined(__SVR4))
++#include <libscf_priv.h>
++#endif
++
+ #if defined HAVE_POLKIT
+ #include <polkit/polkit.h>
+ #elif defined ENABLE_RBAC_SHUTDOWN
+@@ -758,13 +762,15 @@
+ }
+
+ typedef void (*AuthorizedCallback) (CkManager *manager,
+- DBusGMethodInvocation *context);
++ DBusGMethodInvocation *context,
++ void *arg);
+
+ typedef struct
+ {
+ CkManager *manager;
+ DBusGMethodInvocation *context;
+ AuthorizedCallback callback;
++ void *arg;
+ } AuthorizedCallbackData;
+
+ static void
+@@ -798,7 +804,7 @@
+ g_error_free (error);
+ }
+ else if (polkit_authorization_result_get_is_authorized (result)) {
+- data->callback (data->manager, data->context);
++ data->callback (data->manager, data->context, data->arg);
+ }
+ else if (polkit_authorization_result_get_is_challenge (result)) {
+ error = g_error_new (CK_MANAGER_ERROR,
+@@ -824,7 +830,8 @@
+ check_polkit_permissions (CkManager *manager,
+ DBusGMethodInvocation *context,
+ const char *action,
+- AuthorizedCallback callback)
++ AuthorizedCallback callback,
++ void *arg)
+ {
+ const char *sender;
+ PolkitSubject *subject;
+@@ -842,6 +849,7 @@
+ data->manager = g_object_ref (manager);
+ data->context = context;
+ data->callback = callback;
++ data->arg = arg;
+
+ polkit_authority_check_authorization (manager->priv->pol_ctx,
+ subject,
+@@ -1051,7 +1059,8 @@
+ check_rbac_permissions (CkManager *manager,
+ DBusGMethodInvocation *context,
+ const char *action,
+- AuthorizedCallback callback)
++ AuthorizedCallback callback,
++ void *arg)
+ {
+ const char *sender;
+ char *username;
+@@ -1088,7 +1097,7 @@
+ g_free (username);
+
+ if (res && callback) {
+- callback (manager, context);
++ callback (manager, context, arg);
+ }
+
+ return res;
+@@ -1097,7 +1106,8 @@
+
+ static void
+ do_restart (CkManager *manager,
+- DBusGMethodInvocation *context)
++ DBusGMethodInvocation *context,
++ void *arg)
+ {
+ GError *error;
+ gboolean res;
+@@ -1148,9 +1158,10 @@
+ g_debug ("ConsoleKit Restart: %s", action);
+
+ #if defined HAVE_POLKIT
+- check_polkit_permissions (manager, context, action, do_restart);
++ check_polkit_permissions (manager, context, action, do_restart, NULL);
+ #elif defined ENABLE_RBAC_SHUTDOWN
+- check_rbac_permissions (manager, context, RBAC_SHUTDOWN_KEY, do_restart);
++ check_rbac_permissions (manager, context, RBAC_SHUTDOWN_KEY, do_restart,
++ NULL);
+ #else
+ g_warning ("Compiled without PolicyKit or RBAC support!");
+ #endif
+@@ -1171,7 +1182,7 @@
+ get_polkit_permissions (manager, action, context);
+ #elif defined ENABLE_RBAC_SHUTDOWN
+ if (check_rbac_permissions (manager, context, RBAC_SHUTDOWN_KEY,
+- NULL)) {
++ NULL, NULL)) {
+ dbus_g_method_return (context, TRUE);
+ } else {
+ dbus_g_method_return (context, FALSE);
+@@ -1183,7 +1194,8 @@
+
+ static void
+ do_stop (CkManager *manager,
+- DBusGMethodInvocation *context)
++ DBusGMethodInvocation *context,
++ void *arg)
+ {
+ GError *error;
+ gboolean res;
+@@ -1224,9 +1236,10 @@
+ }
+
+ #if defined HAVE_POLKIT
+- check_polkit_permissions (manager, context, action, do_stop);
++ check_polkit_permissions (manager, context, action, do_stop, NULL);
+ #elif defined ENABLE_RBAC_SHUTDOWN
+- check_rbac_permissions (manager, context, RBAC_SHUTDOWN_KEY, do_stop);
++ check_rbac_permissions (manager, context, RBAC_SHUTDOWN_KEY, do_stop,
++ NULL);
+ #else
+ g_warning ("Compiled without PolicyKit or RBAC support!");
+ #endif
+@@ -1246,7 +1259,7 @@
+ get_polkit_permissions (manager, action, context);
+ #elif defined ENABLE_RBAC_SHUTDOWN
+ if (check_rbac_permissions (manager, context, RBAC_SHUTDOWN_KEY,
+- NULL)) {
++ NULL, NULL)) {
+ dbus_g_method_return (context, TRUE);
+ } else {
+ dbus_g_method_return (context, FALSE);
+@@ -1256,6 +1269,218 @@
+ return TRUE;
+ }
+
++#define OS_STRUCT_TYPE (dbus_g_type_get_struct ("GValueArray", \
++ G_TYPE_INT, \
++ G_TYPE_STRING, \
++ G_TYPE_STRING, \
++ G_TYPE_STRING, \
++ G_TYPE_BOOLEAN, \
++ G_TYPE_INVALID))
++
++#if (defined(sun) && defined(__SVR4))
++static gint
++parse_output (const gchar *output, GPtrArray **systems)
++{
++ gchar **lines;
++ gint default_id = -1;
++
++ if (output == NULL)
++ return default_id;
++
++ lines = g_strsplit (output, "\n", 0);
++ for (int i = 0; lines[i] != NULL; i++) {
++ gchar *index;
++
++ if (i == 0 || i == 2) {
++ /* We do not care 1st & 2nd line. */
++ continue;
++ } else if (i == 1) {
++ /* default boot menu entry */
++ index = strchr (lines[i], ' ');
++ if (index && (index + 1)) {
++ default_id = atol (index + 1);
++ } else {
++ continue;
++ }
++ } else if (lines[i][0] != NULL && systems) {
++ /* boot menu entries */
++ GValue elem = {0};
++
++ index = strchr (lines[i], ' ');
++ if (index && (index + 1)) {
++ gint id;
++
++ *index = '\0';
++ id = atoi (lines[i]);
++ g_value_init (&elem, OS_STRUCT_TYPE);
++ g_value_take_boxed (&elem,
++ dbus_g_type_specialized_construct (OS_STRUCT_TYPE));
++ dbus_g_type_struct_set (&elem,
++ 0, id,
++ 1, "",
++ 2, "",
++ 3, (index + 1),
++ 4, (default_id == id),
++ G_MAXUINT);
++ g_ptr_array_add (*systems,
++ g_value_get_boxed (&elem));
++ } else {
++ continue;
++ }
++ }
++ }
++ g_strfreev (lines);
++ return default_id;
++}
++
++static gint
++get_available_boot_environment (CkManager *manager,
++ GPtrArray **systems,
++ DBusGMethodInvocation *context)
++{
++ gchar *cmd[] = {"/usr/sbin/bootadm", "list-menu", NULL};
++ gchar *output = NULL;
++ GError *err = NULL;
++ gint status;
++ gint ret = -1;
++
++ g_spawn_sync (NULL, cmd, NULL,
++ G_SPAWN_STDERR_TO_DEV_NULL, NULL,
++ NULL, &output, NULL,
++ &status, &err);
++ if (err) {
++ g_error_free (err);
++ return ret;
++ }
++
++ if (status == 0) {
++ ret = parse_output (output, systems);
++ }
++ if (output)
++ g_free (output);
++ return ret;
++}
++#endif
++
++/*
++ Example:
++ dbus-send --system --dest=org.freedesktop.ConsoleKit \
++ --type=method_call --print-reply --reply-timeout=2000 \
++ /org/freedesktop/ConsoleKit/Manager \
++ org.freedesktop.ConsoleKit.Manager.GetAvailableOperatingSystems
++*/
++gboolean
++ck_manager_get_available_operating_systems (CkManager *manager,
++ DBusGMethodInvocation *context)
++{
++ GPtrArray *systems;
++
++ g_return_val_if_fail (CK_IS_MANAGER (manager), FALSE);
++
++ systems = g_ptr_array_new ();
++#if (defined(sun) && defined(__SVR4))
++ get_available_boot_environment (manager, &systems, context);
++#endif
++ dbus_g_method_return (context, systems);
++
++ return TRUE;
++}
++
++#if (defined(sun) && defined(__SVR4))
++static void
++set_default_boot_entry (CkManager *manager,
++ gint id,
++ DBusGMethodInvocation *context)
++{
++ gint default_id;
++
++ default_id = get_available_boot_environment (manager, NULL, context);
++ if (default_id != id) {
++ gchar *cmd;
++
++ g_debug ("Set default boot entry from %d to %d",
++ default_id, id);
++ cmd = g_strdup_printf ("/usr/sbin/bootadm set-menu default=%d",
++ id);
++ if (g_spawn_command_line_async (cmd, NULL) == FALSE) {
++ g_warning ("Unable to set default boot entry");
++ }
++ g_free (cmd);
++ }
++}
++#endif
++
++static void
++do_restart_with_parameters (CkManager *manager,
++ DBusGMethodInvocation *context,
++ void *parameters)
++{
++#if (defined(sun) && defined(__SVR4))
++ gchar **param;
++
++ if (parameters == NULL)
++ return;
++
++ param = g_strsplit ((gchar*)parameters, " ", 0);
++ for (int i = 0; param[i] != NULL; i++) {
++ if (strncmp (param[i], "id:", 3) == 0) {
++ if (g_ascii_isdigit(param[i][3])) {
++ gint id;
++
++ id = atoi (&param[i][3]);
++ set_default_boot_entry (manager, id, context);
++ }
++#if defined(__x86__) || defined(__x86)
++ } else if (strncmp (param[i], "fast:", 5) == 0) {
++ if (g_ascii_isdigit(param[i][5])) {
++ gint val;
++
++ val = atoi (&param[i][5]);
++ if (val == 1)
++ scf_fastreboot_default_set_transient (1);
++ else if (val == 0)
++ scf_fastreboot_default_set_transient (0);
++ }
++#endif
++ }
++ }
++ g_strfreev (param);
++#endif
++ do_restart (manager, context, 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.RestartWithParameters \
++ string:"id:0 fast:1"
++*/
++gboolean
++ck_manager_restart_with_parameters (CkManager *manager,
++ const gchar *parameters,
++ DBusGMethodInvocation *context)
++{
++ const char *action;
++
++ g_return_val_if_fail (CK_IS_MANAGER (manager), FALSE);
++
++#if defined HAVE_POLKIT
++ if (get_system_num_users (manager) > 1) {
++ action = "org.freedesktop.consolekit.system.restart-multiple-users";
++ } else {
++ action = "org.freedesktop.consolekit.system.restart";
++ }
++ check_polkit_permissions (manager, context, action,
++ do_restart_with_parameters, (void *)parameters);
++#elif defined ENABLE_RBAC_SHUTDOWN
++ check_rbac_permissions (manager, context, RBAC_SHUTDOWN_KEY,
++ do_restart_with_parameters, (void *)parameters);
++#endif
++ return TRUE;
++}
++
+ static void
+ on_seat_active_session_changed_full (CkSeat *seat,
+ CkSession *old_session,
+Index: consolekit/src/ck-manager.h
+===================================================================
+--- consolekit.orig/src/ck-manager.h 2013-07-30 17:36:25.986042859 +0400
++++ consolekit/src/ck-manager.h 2013-07-30 17:37:15.126019561 +0400
+@@ -88,6 +88,11 @@
+ DBusGMethodInvocation *context);
+ gboolean ck_manager_can_restart (CkManager *manager,
+ DBusGMethodInvocation *context);
++gboolean ck_manager_get_available_operating_systems (CkManager *manager,
++ DBusGMethodInvocation *context);
++gboolean ck_manager_restart_with_parameters (CkManager *manager,
++ const gchar *parameters,
++ DBusGMethodInvocation *context);
+ /* Authoritative properties */
+ gboolean ck_manager_open_session (CkManager *manager,
+ DBusGMethodInvocation *context);
+Index: consolekit/src/org.freedesktop.ConsoleKit.Manager.xml
+===================================================================
+--- consolekit.orig/src/org.freedesktop.ConsoleKit.Manager.xml 2013-07-30 17:36:26.012959052 +0400
++++ consolekit/src/org.freedesktop.ConsoleKit.Manager.xml 2013-07-30 17:37:15.127709322 +0400
+@@ -32,6 +32,34 @@
+ <arg name="can_stop" type="b" direction="out"/>
+ </method>
+
++ <method name="GetAvailableOperatingSystems">
++ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
++ <arg name="systems" direction="out" type="a(isssb)">
++ <doc:doc>
++ <doc:summary>An array of available operating systems</doc:summary>
++ </doc:doc>
++ </arg>
++ <doc:doc>
++ <doc:description>
++ <doc:para>This method returns an array of available operating systems.</doc:para>
++ </doc:description>
++ </doc:doc>
++ </method>
++
++ <method name="RestartWithParameters">
++ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
++ <arg name="parameters" direction="in" type="s">
++ <doc:doc>
++ <doc:summary>The parameeters used to restart.</doc:summary>
++ </doc:doc>
++ </arg>
++ <doc:doc>
++ <doc:description>
++ <doc:para>This method initiates a request to restart (ie. reboot) with system specific parameters.</doc:para>
++ </doc:description>
++ </doc:doc>
++ </method>
++
+ <method name="OpenSession">
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ <arg name="cookie" direction="out" type="s">
diff --git a/debian/patches/solaris/ConsoleKit-06-ck-history.diff b/debian/patches/solaris/ConsoleKit-06-ck-history.diff
new file mode 100644
index 0000000..ba9427b
--- /dev/null
+++ b/debian/patches/solaris/ConsoleKit-06-ck-history.diff
@@ -0,0 +1,61 @@
+diff --git a/tools/ck-history.c b/tools/ck-history.c
+index 606106c..e7659d1 100644
+--- a/tools/ck-history.c
++++ b/tools/ck-history.c
+@@ -38,6 +38,8 @@
+
+ #include "ck-log-event.h"
+
++#define IS_STR_SET(x) (x != NULL && x[0] != '\0')
++
+ typedef enum {
+ REPORT_TYPE_SUMMARY = 0,
+ REPORT_TYPE_LAST,
+@@ -550,21 +552,21 @@ print_last_report_record (GList *li
+
+ if (legacy_compat) {
+ g_string_printf (str,
+- "%-8.8s %-12.12s %-16.16s %-16.16s",
+- username,
+- utline != NULL ? utline : "",
+- host != NULL ? host : "",
+- addedtime);
++ "%s\t%s\t%s\t%s",
++ IS_STR_SET (username) ? username : "NULL",
++ IS_STR_SET (utline) ? utline : "NULL",
++ IS_STR_SET (host) ? host : "NULL",
++ IS_STR_SET (addedtime) ? addedtime : "NULL");
+ } else {
+ g_string_printf (str,
+- "%-8.8s %12s %-10.10s %-7.7s %-12.12s %-28.28s %-16.16s",
+- username,
+- session_type,
+- session_id,
+- seat_id,
+- utline,
+- host != NULL ? host : "",
+- addedtime);
++ "%s\t%s\t%s\t%s\t%s\t%s\t%s",
++ IS_STR_SET (username) ? username : "NULL",
++ IS_STR_SET (session_type) ? session_type : "NULL",
++ IS_STR_SET (session_id) ? session_id : "NULL",
++ IS_STR_SET (seat_id) ? seat_id : "NULL",
++ IS_STR_SET (utline) ? utline : "NULL",
++ IS_STR_SET (host) ? host : "NULL",
++ IS_STR_SET (addedtime) ? addedtime : "NULL");
+ }
+
+ g_free (username);
+@@ -611,9 +613,9 @@ print_last_report_record (GList *li
+ }
+
+ g_string_append_printf (str,
+- " %-7.7s %-12.12s",
+- removedtime,
+- duration);
++ "\t%s\t%s",
++ IS_STR_SET (removedtime) ? removedtime : "NULL",
++ IS_STR_SET (duration) ? duration : "NULL");
+
+ g_print ("%s\n", str->str);
+ g_string_free (str, TRUE);
diff --git a/debian/patches/solaris/ConsoleKit-07-suppress-warning.diff b/debian/patches/solaris/ConsoleKit-07-suppress-warning.diff
new file mode 100644
index 0000000..b9d640c
--- /dev/null
+++ b/debian/patches/solaris/ConsoleKit-07-suppress-warning.diff
@@ -0,0 +1,13 @@
+Index: consolekit/src/ck-vt-monitor.c
+===================================================================
+--- consolekit.orig/src/ck-vt-monitor.c 2013-07-30 17:36:08.127232399 +0400
++++ consolekit/src/ck-vt-monitor.c 2013-07-30 17:38:53.256835777 +0400
+@@ -469,7 +469,7 @@
+ res = ck_get_active_console_num (fd, &active);
+ if (! res) {
+ /* FIXME: handle failure */
+- g_warning ("Could not determine active console");
++ g_debug ("Could not determine active console");
+ active = 0;
+ }
+
diff --git a/debian/patches/solaris/ConsoleKit-08-vt-switch.diff b/debian/patches/solaris/ConsoleKit-08-vt-switch.diff
new file mode 100644
index 0000000..6b482dd
--- /dev/null
+++ b/debian/patches/solaris/ConsoleKit-08-vt-switch.diff
@@ -0,0 +1,108 @@
+Index: consolekit/src/ck-seat.c
+===================================================================
+--- consolekit.orig/src/ck-seat.c 2013-07-30 17:35:46.031481292 +0400
++++ consolekit/src/ck-seat.c 2013-07-30 17:35:47.628494929 +0400
+@@ -962,9 +962,32 @@
+ ck_session_is_open (value, &is_open, NULL);
+
+ if (is_open) {
++ GError *vt_error = NULL;
++ char *device;
++ guint num;
++ gboolean ret;
++
+ login_session = NULL;
+- change_active_session (seat, value);
+- break;
++
++ g_debug ("Found open session.");
++
++ switch (seat->priv->kind) {
++ case CK_SEAT_KIND_STATIC:
++ device = NULL;
++ ck_session_get_x11_display_device (value, &device, NULL);
++
++ if (device != NULL) {
++ ret = ck_get_console_num_from_device (device, &num);
++ if (ret) {
++ g_debug ("Activating VT %d", num);
++ ck_vt_monitor_set_active (seat->priv->vt_monitor, num, &vt_error);
++ }
++ }
++ break;
++ case CK_SEAT_KIND_DYNAMIC:
++ change_active_session (seat, value);
++ break;
++ }
+ }
+
+ ck_session_get_session_type (value, &session_type, NULL);
+@@ -1054,6 +1077,11 @@
+ CkSession *orig_session;
+ gboolean res;
+ gboolean ret;
++ GHashTableIter iter;
++ gpointer key, value;
++ gboolean found_login = FALSE;
++ gboolean is_open;
++ char *session_type = NULL;
+
+ g_return_val_if_fail (CK_IS_SEAT (seat), FALSE);
+
+@@ -1093,7 +1121,46 @@
+ g_signal_emit (seat, signals [SESSION_REMOVED], 0, ssid);
+
+ /* try to change the active session */
+- maybe_update_active_session (seat);
++
++ /* On session exit, first try to switch to any active login sessions */
++ g_hash_table_iter_init (&iter, seat->priv->sessions);
++ if (seat->priv->kind == CK_SEAT_KIND_STATIC) {
++ while (seat->priv->kind == CK_SEAT_KIND_STATIC && g_hash_table_iter_next (&iter, &key, &value)) {
++ CkSession *login_session = value;
++ ck_session_get_session_type (login_session, &session_type, NULL);
++ ck_session_is_open (login_session, &is_open, NULL);
++
++ if (is_open && IS_STR_SET (session_type) &&
++ g_str_equal (session_type, "LoginWindow")) {
++ GError *vt_error = NULL;
++ char *device;
++ guint num;
++
++ g_debug ("Found a LoginWindow");
++ device = NULL;
++ ck_session_get_x11_display_device (login_session, &device, NULL);
++
++ if (device != NULL) {
++ ret = ck_get_console_num_from_device (device, &num);
++ if (ret) {
++ g_debug ("Setting active to %d", num);
++ found_login = TRUE;
++ ck_vt_monitor_set_active (seat->priv->vt_monitor, num, &vt_error);
++ } else {
++ g_debug ("The LoginWindow device has no console number, not using.");
++ }
++ } else {
++ g_debug ("The LoginWindow display has no x11 display device, not using.");
++ }
++ }
++ if (session_type != NULL)
++ g_free (session_type);
++ }
++ }
++
++ /* Otherwise, look for an active session */
++ if (found_login == FALSE)
++ maybe_update_active_session (seat);
+
+ if (orig_session != NULL) {
+ g_object_unref (orig_session);
+@@ -1359,8 +1426,6 @@
+ CkSeat *seat)
+ {
+ g_debug ("Active vt changed: %u", num);
+-
+- update_active_vt (seat, num);
+ }
+
+ gboolean