Home | History | Annotate | Download | only in patches
      1 diff --git a/configure.ac b/configure.ac
      2 index 117d788..2ff6020 100644
      3 --- a/configure.ac
      4 +++ b/configure.ac
      5 @@ -203,6 +203,18 @@ AM_CONDITIONAL(CK_COMPILE_SOLARIS, test x$CK_BACKEND = xsolaris, [Compiling for
      6  AC_SUBST(CK_BACKEND)
      7  
      8  dnl ---------------------------------------------------------------------------
      9 +dnl Check for X11 DIR
     10 +dnl ---------------------------------------------------------------------------
     11 +
     12 +X11_DIR=`$PKG_CONFIG --variable=bindir xorg-server 2>/dev/null`
     13 +if test "x$X11_DIR" = x; then
     14 +    AC_PATH_PROGS([XSERVER], [Xorg X],,[$PATH:/usr/X11/bin:/usr/bin])
     15 +    test "x$XSERVER" != x && X11_DIR=`dirname "$XSERVER"`
     16 +fi
     17 +test "x$X11_DIR" = x && X11_DIR=$bindir
     18 +AC_SUBST([X11_DIR])
     19 +
     20 +dnl ---------------------------------------------------------------------------
     21  dnl Check for PAM
     22  dnl ---------------------------------------------------------------------------
     23  
     24 @@ -303,6 +315,14 @@ if test "x$enable_inotify" = "xyes" ; then
     25  fi
     26  
     27  dnl ---------------------------------------------------------------------------
     28 +dnl check for strverscmp
     29 +dnl ---------------------------------------------------------------------------
     30 +have_strverscmp=no
     31 +AC_CHECK_FUNCS(strverscmp, [have_strverscmp=yes], [])
     32 +
     33 +AM_CONDITIONAL(USE_SELF_STRVERSCMP, test "x$have_strverscmp" = "xno", [Define if we do not have strverscmp])
     34 +
     35 +dnl ---------------------------------------------------------------------------
     36  dnl check for RBAC
     37  dnl ---------------------------------------------------------------------------
     38  
     39 @@ -401,6 +421,8 @@ tools/linux/Makefile
     40  tools/freebsd/Makefile
     41  tools/solaris/Makefile
     42  data/Makefile
     43 +data/displays.d/Makefile
     44 +data/sessions.d/Makefile
     45  doc/Makefile
     46  doc/dbus/ConsoleKit.xml
     47  doc/dbus/Makefile
     48 diff --git a/data/00-primary.seat b/data/00-primary.seat
     49 index 6e61db4..0632382 100644
     50 --- a/data/00-primary.seat
     51 +++ b/data/00-primary.seat
     52 @@ -1,5 +1,26 @@
     53  [Seat Entry]
     54  Version=1.0
     55  Name=Primary seat
     56 +# Specified Seat ID, if this value is NULL, ConsoleKit will decide one.
     57 +# The ID only contain the ASICC characters "[A-Z][a-z][0-9]_" 
     58 +ID=StaticSeat1
     59 +Description=start one static local display at :0
     60 +
     61 +# Indicate whether to create this seat or not. If it is set true, then CK will
     62 +# not create this seat. Default value is false.
     63  Hidden=false
     64 -Devices=
     65 \ No newline at end of file
     66 +
     67 +# Indicate input/output devices including keyboard-pointer-video
     68 +# card-monitor-sound-usb devices,
     69 +# This key will not implemented now, it might need be divided into
     70 +# several keys in the future:
     71 +# Pointer=
     72 +# Monitor=
     73 +# VideoCard=
     74 +# Monitor=
     75 +# UsbHub=
     76 +Devices=
     77 +
     78 +# List of sessions to start on the seat, separated by ';'
     79 +# Each session is defined in sessions.d/
     80 +Sessions=Local;
     81 diff --git a/data/ConsoleKit.conf b/data/ConsoleKit.conf
     82 index 948f95f..8cf490a 100644
     83 --- a/data/ConsoleKit.conf
     84 +++ b/data/ConsoleKit.conf
     85 @@ -44,6 +44,9 @@
     86             send_member="CloseSession"/>
     87      <allow send_destination="org.freedesktop.ConsoleKit"
     88             send_interface="org.freedesktop.ConsoleKit.Manager"
     89 +           send_member="GetUnmanagedSeats"/>
     90 +    <allow send_destination="org.freedesktop.ConsoleKit"
     91 +           send_interface="org.freedesktop.ConsoleKit.Manager"
     92             send_member="GetSeats"/>
     93      <allow send_destination="org.freedesktop.ConsoleKit"
     94             send_interface="org.freedesktop.ConsoleKit.Manager"
     95 @@ -69,6 +72,18 @@
     96      <allow send_destination="org.freedesktop.ConsoleKit"
     97             send_interface="org.freedesktop.ConsoleKit.Manager"
     98             send_member="GetSystemIdleSinceHint"/>
     99 +    <allow send_destination="org.freedesktop.ConsoleKit"
    100 +           send_interface="org.freedesktop.ConsoleKit.Manager"
    101 +           send_member="AddSeat"/>
    102 +    <allow send_destination="org.freedesktop.ConsoleKit"
    103 +           send_interface="org.freedesktop.ConsoleKit.Manager"
    104 +           send_member="RemoveSeat"/>
    105 +    <allow send_destination="org.freedesktop.ConsoleKit"
    106 +           send_interface="org.freedesktop.ConsoleKit.Manager"
    107 +           send_member="AddSession"/>
    108 +    <allow send_destination="org.freedesktop.ConsoleKit"
    109 +           send_interface="org.freedesktop.ConsoleKit.Manager"
    110 +           send_member="RemoveSession"/>
    111  
    112      <allow send_destination="org.freedesktop.ConsoleKit"
    113             send_interface="org.freedesktop.ConsoleKit.Seat"
    114 @@ -88,6 +103,9 @@
    115      <allow send_destination="org.freedesktop.ConsoleKit"
    116             send_interface="org.freedesktop.ConsoleKit.Seat"
    117             send_member="ActivateSession"/>
    118 +    <allow send_destination="org.freedesktop.ConsoleKit"
    119 +           send_interface="org.freedesktop.ConsoleKit.Seat"
    120 +           send_member="ManageSeat"/>
    121  
    122      <allow send_destination="org.freedesktop.ConsoleKit"
    123             send_interface="org.freedesktop.ConsoleKit.Session"
    124 @@ -103,6 +121,9 @@
    125             send_member="GetSessionType"/>
    126      <allow send_destination="org.freedesktop.ConsoleKit"
    127             send_interface="org.freedesktop.ConsoleKit.Session"
    128 +           send_member="GetDisplayType"/>
    129 +    <allow send_destination="org.freedesktop.ConsoleKit"
    130 +           send_interface="org.freedesktop.ConsoleKit.Session"
    131             send_member="GetUser"/>
    132      <allow send_destination="org.freedesktop.ConsoleKit"
    133             send_interface="org.freedesktop.ConsoleKit.Session"
    134 @@ -127,6 +148,12 @@
    135             send_member="IsLocal"/>
    136      <allow send_destination="org.freedesktop.ConsoleKit"
    137             send_interface="org.freedesktop.ConsoleKit.Session"
    138 +           send_member="IsDynamic"/>
    139 +    <allow send_destination="org.freedesktop.ConsoleKit"
    140 +           send_interface="org.freedesktop.ConsoleKit.Session"
    141 +           send_member="IsOpen"/>
    142 +    <allow send_destination="org.freedesktop.ConsoleKit"
    143 +           send_interface="org.freedesktop.ConsoleKit.Session"
    144             send_member="GetCreationTime"/>
    145      <allow send_destination="org.freedesktop.ConsoleKit"
    146             send_interface="org.freedesktop.ConsoleKit.Session"
    147 @@ -136,12 +163,11 @@
    148             send_member="GetIdleHint"/>
    149      <allow send_destination="org.freedesktop.ConsoleKit"
    150             send_interface="org.freedesktop.ConsoleKit.Session"
    151 -           send_member="SetIdleHint"/>
    152 -    <allow send_destination="org.freedesktop.ConsoleKit"
    153 -           send_interface="org.freedesktop.ConsoleKit.Session"
    154             send_member="GetIdleSinceHint"/>
    155      <allow send_interface="org.freedesktop.ConsoleKit.Session"
    156             send_member="SetIdleHint"/>
    157 +    <allow send_interface="org.freedesktop.ConsoleKit.Session"
    158 +           send_member="SetRemoveOnClose"/>
    159    </policy>
    160  
    161  </busconfig>
    162 diff --git a/data/Makefile.am b/data/Makefile.am
    163 index 041b431..2054e96 100644
    164 --- a/data/Makefile.am
    165 +++ b/data/Makefile.am
    166 @@ -1,5 +1,10 @@
    167  NULL =
    168  
    169 +SUBDIRS = \
    170 +	displays.d	\
    171 +	sessions.d	\
    172 +        $(NULL)
    173 +
    174  dbusconfdir = $(DBUS_SYS_DIR)
    175  dbusconf_DATA = ConsoleKit.conf
    176  
    177 diff --git a/data/displays.d/Headless.display.in b/data/displays.d/Headless.display.in
    178 new file mode 100644
    179 index 0000000..754d2bf
    180 --- /dev/null
    181 +++ b/data/displays.d/Headless.display.in
    182 @@ -0,0 +1,5 @@
    183 +[Display]
    184 +Type=X11
    185 +
    186 +[X11]
    187 +Exec=@X11_DIR@/Xvfb $display -auth $auth
    188 diff --git a/data/displays.d/Local.display.in b/data/displays.d/Local.display.in
    189 new file mode 100644
    190 index 0000000..b845a7b
    191 --- /dev/null
    192 +++ b/data/displays.d/Local.display.in
    193 @@ -0,0 +1,5 @@
    194 +[Display]
    195 +Type=X11
    196 +
    197 +[X11]
    198 +Exec=@X11_DIR@/Xorg $display -br -verbose -auth $auth -nolisten tcp $vt
    199 diff --git a/data/displays.d/LocalVNC.display.in b/data/displays.d/LocalVNC.display.in
    200 new file mode 100644
    201 index 0000000..6ad336b
    202 --- /dev/null
    203 +++ b/data/displays.d/LocalVNC.display.in
    204 @@ -0,0 +1,5 @@
    205 +[Display]
    206 +Type=X11
    207 +
    208 +[X11]
    209 +Exec=@X11_DIR@/Xvnc $display -auth $auth -query localhost
    210 diff --git a/data/displays.d/Makefile.am b/data/displays.d/Makefile.am
    211 new file mode 100644
    212 index 0000000..1fab1d2
    213 --- /dev/null
    214 +++ b/data/displays.d/Makefile.am
    215 @@ -0,0 +1,29 @@
    216 +NULL =
    217 +
    218 +displaydir = $(sysconfdir)/ConsoleKit/displays.d
    219 +display_in_files = \
    220 +	Local.display.in \
    221 +	RemoteMachine.display.in \
    222 +	LocalVNC.display.in \
    223 +	Headless.display.in
    224 +
    225 +display_DATA = $(display_in_files:.display.in=.display)
    226 +
    227 +Local.display: Local.display.in Makefile
    228 +	sed -e "s|\@X11_DIR\@|$(X11_DIR)|" $< > $@
    229 +RemoteMachine.display: RemoteMachine.display.in Makefile
    230 +	sed -e "s|\@X11_DIR\@|$(X11_DIR)|" $< > $@
    231 +LocalVNC.display: LocalVNC.display.in Makefile
    232 +	sed -e "s|\@X11_DIR\@|$(X11_DIR)|" $< > $@
    233 +Headless.display: Headless.display.in Makefile
    234 +	sed -e "s|\@X11_DIR\@|$(X11_DIR)|" $< > $@
    235 +
    236 +EXTRA_DIST =						\
    237 +	$(display_in_files)				\
    238 +	$(NULL)
    239 +
    240 +MAINTAINERCLEANFILES =			\
    241 +	*~				\
    242 +	Makefile.in
    243 +
    244 +CLEANFILES = $(display_DATA)
    245 diff --git a/data/displays.d/RemoteMachine.display.in b/data/displays.d/RemoteMachine.display.in
    246 new file mode 100644
    247 index 0000000..7c69451
    248 --- /dev/null
    249 +++ b/data/displays.d/RemoteMachine.display.in
    250 @@ -0,0 +1,5 @@
    251 +[Display]
    252 +Type=X11
    253 +
    254 +[X11]
    255 +Exec=@X11_DIR@/Xorg $display -br -verbose -auth $auth -indirect $vt
    256 diff --git a/data/sessions.d/Headless.session b/data/sessions.d/Headless.session
    257 new file mode 100644
    258 index 0000000..d376af9
    259 --- /dev/null
    260 +++ b/data/sessions.d/Headless.session
    261 @@ -0,0 +1,8 @@
    262 +[Session Entry]
    263 +Name=Headless
    264 +Type=LoginWindow
    265 +Description=Login Window running on headless display
    266 +DisplayTemplate=Headless
    267 +
    268 +[Headless]
    269 +display=:32
    270 diff --git a/data/sessions.d/Local.session b/data/sessions.d/Local.session
    271 new file mode 100644
    272 index 0000000..9d3b975
    273 --- /dev/null
    274 +++ b/data/sessions.d/Local.session
    275 @@ -0,0 +1,9 @@
    276 +[Session Entry]
    277 +Name=Local
    278 +Type=LoginWindow
    279 +Description=Local Login Screen
    280 +DisplayTemplate=Local
    281 +
    282 +[Local]
    283 +display=:0
    284 +vt=vt1
    285 diff --git a/data/sessions.d/LocalVNC.session b/data/sessions.d/LocalVNC.session
    286 new file mode 100644
    287 index 0000000..c05802f
    288 --- /dev/null
    289 +++ b/data/sessions.d/LocalVNC.session
    290 @@ -0,0 +1,8 @@
    291 +[Session Entry]
    292 +Name=LocalVNC
    293 +Type=LoginWindow
    294 +Description=Connect to local VNC server running on same machine
    295 +DisplayTemplate=LocalVNC
    296 +
    297 +[LocalVNC]
    298 +display=:64
    299 diff --git a/data/sessions.d/Makefile.am b/data/sessions.d/Makefile.am
    300 new file mode 100644
    301 index 0000000..f17ffdc
    302 --- /dev/null
    303 +++ b/data/sessions.d/Makefile.am
    304 @@ -0,0 +1,16 @@
    305 +NULL =
    306 +
    307 +sessiondir = $(sysconfdir)/ConsoleKit/sessions.d
    308 +session_DATA = \
    309 +	Headless.session		\
    310 +	Local.session			\
    311 +	LocalVNC.session		\
    312 +	Remote.session
    313 +
    314 +EXTRA_DIST =				\
    315 +	$(session_DATA)			\
    316 +	$(NULL)
    317 +
    318 +MAINTAINERCLEANFILES =			\
    319 +	*~				\
    320 +	Makefile.in
    321 diff --git a/data/sessions.d/Remote.session b/data/sessions.d/Remote.session
    322 new file mode 100644
    323 index 0000000..e88f975
    324 --- /dev/null
    325 +++ b/data/sessions.d/Remote.session
    326 @@ -0,0 +1,9 @@
    327 +[Session Entry]
    328 +Name=Remote Chooser
    329 +Type=Remote
    330 +Description=Connect to chooser on nearby remote machine
    331 +DisplayTemplate=RemoteMachine
    332 +
    333 +[RemoteMachine]
    334 +display=:96
    335 +vt=vt10
    336 diff --git a/doc/dbus/ck-terms.xml b/doc/dbus/ck-terms.xml
    337 index d3d544d..1b43ca6 100644
    338 --- a/doc/dbus/ck-terms.xml
    339 +++ b/doc/dbus/ck-terms.xml
    340 @@ -64,4 +64,11 @@ True, hardware, multi-seat capabilities will be added in a later release.
    341      </para>
    342    </sect1>
    343  
    344 +  <sect1>
    345 +    <title>Seat manager</title>
    346 +    <para>
    347 +The seat manager is the process responsible for starting and stopping sessions on a seat.
    348 +    </para>
    349 +  </sect1>
    350 +
    351  </chapter>
    352 diff --git a/libck-connector/ck-connector.c b/libck-connector/ck-connector.c
    353 index 7f6f87f..87a7d4a 100644
    354 --- a/libck-connector/ck-connector.c
    355 +++ b/libck-connector/ck-connector.c
    356 @@ -76,8 +76,11 @@ static struct {
    357          { "display-device",     DBUS_TYPE_STRING },
    358          { "x11-display-device", DBUS_TYPE_STRING },
    359          { "x11-display",        DBUS_TYPE_STRING },
    360 +        { "seat-id",            DBUS_TYPE_STRING },
    361 +        { "session",            DBUS_TYPE_STRING },
    362          { "remote-host-name",   DBUS_TYPE_STRING },
    363          { "session-type",       DBUS_TYPE_STRING },
    364 +        { "display-type",       DBUS_TYPE_STRING },
    365          { "is-local",           DBUS_TYPE_BOOLEAN },
    366          { "unix-user",          DBUS_TYPE_INT32 },
    367  };
    368 diff --git a/src/Makefile.am b/src/Makefile.am
    369 index 6ab05c8..97a59ef 100644
    370 --- a/src/Makefile.am
    371 +++ b/src/Makefile.am
    372 @@ -107,6 +107,8 @@ console_kit_daemon_SOURCES =	\
    373  	ck-file-monitor.h	\
    374  	ck-job.h		\
    375  	ck-job.c		\
    376 +	ck-display-template.h	\
    377 +	ck-display-template.c	\
    378  	ck-seat.h		\
    379  	ck-seat.c		\
    380  	ck-session-leader.h	\
    381 @@ -122,6 +124,13 @@ console_kit_daemon_SOURCES =	\
    382  	$(BUILT_SOURCES)	\
    383  	$(NULL)
    384  
    385 +if USE_SELF_STRVERSCMP
    386 +console_kit_daemon_SOURCES +=	\
    387 +	strverscmp.c		\
    388 +	strverscmp.h		\
    389 +	$(NULL)
    390 +endif
    391 +
    392  if ENABLE_INOTIFY
    393  FILE_MONITOR_BACKEND = ck-file-monitor-inotify.c
    394  else
    395 diff --git a/src/ck-display-template.c b/src/ck-display-template.c
    396 new file mode 100644
    397 index 0000000..9206103
    398 --- /dev/null
    399 +++ b/src/ck-display-template.c
    400 @@ -0,0 +1,341 @@
    401 +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
    402 + *
    403 + * Authors: halton.huo (a] sun.com, Ray Strode <rstrode (a] redhat.com>
    404 + * Copyright (C) 2009 Sun Microsystems, Inc.
    405 + *                    Red Hat, Inc.
    406 + *
    407 + * This program is free software; you can redistribute it and/or modify
    408 + * it under the terms of the GNU General Public License as published by
    409 + * the Free Software Foundation; either version 2 of the License, or
    410 + * (at your option) any later version.
    411 + *
    412 + * This program is distributed in the hope that it will be useful,
    413 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    414 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    415 + * GNU General Public License for more details.
    416 + *
    417 + * You should have received a copy of the GNU General Public License
    418 + * along with this program; if not, write to the Free Software
    419 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
    420 + *
    421 + */
    422 +
    423 +#include "config.h"
    424 +
    425 +#include <string.h>
    426 +#include <glib.h>
    427 +#include <glib-object.h>
    428 +
    429 +#include "ck-display-template.h"
    430 +
    431 +#define CK_DISPLAY_TEMPLATE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CK_TYPE_DISPLAY_TEMPLATE, CkDisplayTemplatePrivate))
    432 +
    433 +#define CK_DISPLAY_TEMPLATES_DIR     SYSCONFDIR "/ConsoleKit/displays.d"
    434 +
    435 +struct CkDisplayTemplatePrivate
    436 +{
    437 +        char            *name;
    438 +        char            *type;
    439 +        GHashTable      *parameters;
    440 +};
    441 +
    442 +enum {
    443 +        PROP_0,
    444 +        PROP_NAME,
    445 +        PROP_TYPE,
    446 +        PROP_PARAMETERS,
    447 +};
    448 +
    449 +static void     ck_display_template_class_init  (CkDisplayTemplateClass *klass);
    450 +static void     ck_display_template_init        (CkDisplayTemplate      *display);
    451 +static void     ck_display_template_finalize    (GObject            *object);
    452 +static gboolean ck_display_template_load        (CkDisplayTemplate      *display);
    453 +
    454 +static GHashTable *ck_display_templates;
    455 +
    456 +G_DEFINE_TYPE (CkDisplayTemplate, ck_display_template, G_TYPE_OBJECT)
    457 +
    458 +static void
    459 +_ck_display_template_set_name (CkDisplayTemplate  *display,
    460 +                               const char     *name)
    461 +{
    462 +        g_free (display->priv->name);
    463 +        display->priv->name = g_strdup (name);
    464 +}
    465 +
    466 +static void
    467 +_ck_display_template_set_type_string (CkDisplayTemplate  *display,
    468 +                                      const char     *type)
    469 +{
    470 +        g_free (display->priv->type);
    471 +        display->priv->type = g_strdup (type);
    472 +}
    473 +
    474 +static void
    475 +_ck_display_template_set_parameters (CkDisplayTemplate  *display,
    476 +                                     GHashTable     *parameters)
    477 +{
    478 +        if (display->priv->parameters != NULL) {
    479 +                g_hash_table_unref (display->priv->parameters);
    480 +        }
    481 +
    482 +        if (parameters == NULL) {
    483 +                display->priv->parameters = g_hash_table_new_full (g_str_hash, g_str_equal,
    484 +                                                                   (GDestroyNotify) g_free,
    485 +                                                                   (GDestroyNotify) g_free);
    486 +        } else {
    487 +                display->priv->parameters = g_hash_table_ref (parameters);
    488 +        }
    489 +}
    490 +
    491 +static void
    492 +ck_display_template_set_property (GObject      *object,
    493 +                                  guint         prop_id,
    494 +                                  const GValue *value,
    495 +                                  GParamSpec   *pspec)
    496 +{
    497 +        CkDisplayTemplate *self;
    498 +
    499 +        self = CK_DISPLAY_TEMPLATE (object);
    500 +
    501 +        switch (prop_id) {
    502 +        case PROP_NAME:
    503 +                _ck_display_template_set_name (self, g_value_get_string (value));
    504 +                break;
    505 +        case PROP_TYPE:
    506 +                _ck_display_template_set_type_string (self, g_value_get_string (value));
    507 +                break;
    508 +        case PROP_PARAMETERS:
    509 +                _ck_display_template_set_parameters (self, g_value_get_boxed (value));
    510 +                break;
    511 +        default:
    512 +                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
    513 +                break;
    514 +        }
    515 +}
    516 +
    517 +static void
    518 +ck_display_template_get_property (GObject    *object,
    519 +                                  guint       prop_id,
    520 +                                  GValue     *value,
    521 +                                  GParamSpec *pspec)
    522 +{
    523 +        CkDisplayTemplate *self;
    524 +
    525 +        self = CK_DISPLAY_TEMPLATE (object);
    526 +
    527 +        switch (prop_id) {
    528 +        case PROP_NAME:
    529 +                g_value_set_string (value, self->priv->name);
    530 +                break;
    531 +        case PROP_TYPE:
    532 +                g_value_set_string (value, self->priv->type);
    533 +                break;
    534 +        case PROP_PARAMETERS:
    535 +                g_value_set_boxed (value, self->priv->parameters);
    536 +                break;
    537 +        default:
    538 +                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
    539 +                break;
    540 +        }
    541 +}
    542 +
    543 +static void
    544 +ck_display_template_class_init (CkDisplayTemplateClass *klass)
    545 +{
    546 +        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
    547 +
    548 +        object_class->get_property = ck_display_template_get_property;
    549 +        object_class->set_property = ck_display_template_set_property;
    550 +        object_class->finalize = ck_display_template_finalize;
    551 +
    552 +        g_object_class_install_property (object_class,
    553 +                                         PROP_NAME,
    554 +                                         g_param_spec_string ("name",
    555 +                                                              "display type name",
    556 +                                                              "display type name",
    557 +                                                              NULL,
    558 +                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
    559 +        g_object_class_install_property (object_class,
    560 +                                         PROP_TYPE,
    561 +                                         g_param_spec_string ("type",
    562 +                                                              "type",
    563 +                                                              "Type",
    564 +                                                              NULL,
    565 +                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
    566 +        g_object_class_install_property (object_class,
    567 +                                         PROP_PARAMETERS,
    568 +                                         g_param_spec_boxed ("parameters",
    569 +                                                              "Parameters",
    570 +                                                              "Parameters",
    571 +                                                              G_TYPE_HASH_TABLE,
    572 +                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
    573 +        g_type_class_add_private (klass, sizeof (CkDisplayTemplatePrivate));
    574 +}
    575 +
    576 +static void
    577 +ck_display_template_init (CkDisplayTemplate *display)
    578 +{
    579 +        display->priv = CK_DISPLAY_TEMPLATE_GET_PRIVATE (display);
    580 +
    581 +        display->priv->name = NULL;
    582 +        display->priv->type = NULL;
    583 +        display->priv->parameters = g_hash_table_new_full (g_str_hash, g_str_equal,
    584 +                                                           (GDestroyNotify) g_free,
    585 +                                                           (GDestroyNotify) g_free);
    586 +}
    587 +
    588 +static void
    589 +ck_display_template_finalize (GObject *object)
    590 +{
    591 +        CkDisplayTemplate *display;
    592 +
    593 +        g_return_if_fail (object != NULL);
    594 +        g_return_if_fail (CK_IS_DISPLAY_TEMPLATE (object));
    595 +
    596 +        display = CK_DISPLAY_TEMPLATE (object);
    597 +
    598 +        g_return_if_fail (display->priv != NULL);
    599 +
    600 +        g_free (display->priv->name);
    601 +        g_free (display->priv->type);
    602 +        g_hash_table_unref (display->priv->parameters);
    603 +
    604 +        G_OBJECT_CLASS (ck_display_template_parent_class)->finalize (object);
    605 +}
    606 +
    607 +static gboolean
    608 +ck_display_template_load (CkDisplayTemplate *display)
    609 +{
    610 +        GKeyFile   *key_file;
    611 +        const char *name;
    612 +        char       *group;
    613 +        char       *filename;
    614 +        gboolean    hidden;
    615 +        char       *type;
    616 +        gboolean    res;
    617 +        GError     *error;
    618 +        char      **type_keys;
    619 +        GHashTable *parameters;
    620 +
    621 +        name = ck_display_template_get_name (display);
    622 +
    623 +        g_return_val_if_fail (name && !g_str_equal (name, ""), FALSE);
    624 +
    625 +        filename = g_strdup_printf ("%s/%s.display", CK_DISPLAY_TEMPLATES_DIR, name);
    626 +
    627 +        key_file = g_key_file_new ();
    628 +
    629 +        error = NULL;
    630 +        res = g_key_file_load_from_file (key_file,
    631 +                                         filename,
    632 +                                         G_KEY_FILE_NONE,
    633 +                                         &error);
    634 +        if (! res) {
    635 +                g_warning ("Unable to load display from file %s: %s", filename, error->message);
    636 +                g_error_free (error);
    637 +                return FALSE;
    638 +        }
    639 +        g_free (filename);
    640 +
    641 +        group = g_key_file_get_start_group (key_file);
    642 +
    643 +        if (group == NULL || strcmp (group, "Display") != 0) {
    644 +                g_warning ("Not a display type file: %s", filename);
    645 +                g_free (group);
    646 +                g_key_file_free (key_file);
    647 +                return FALSE;
    648 +        }
    649 +
    650 +        hidden = g_key_file_get_boolean (key_file, group, "Hidden", NULL);
    651 +
    652 +        type = g_key_file_get_string (key_file, group, "Type", NULL);
    653 +
    654 +        if (type == NULL) {
    655 +                g_warning ("Unable to read type from display file");
    656 +                g_free (group);
    657 +                g_key_file_free (key_file);
    658 +                return FALSE;
    659 +        }
    660 +
    661 +        display->priv->type = type;
    662 +
    663 +        parameters = g_hash_table_new_full (g_str_hash, g_str_equal,
    664 +                                            (GDestroyNotify) g_free,
    665 +                                            (GDestroyNotify) g_free);
    666 +
    667 +        type_keys = g_key_file_get_keys (key_file, type, NULL, NULL);
    668 +
    669 +        if (type_keys != NULL) {
    670 +                int        i;
    671 +                for (i = 0; type_keys[i] != NULL; i++) {
    672 +                        char   *string;
    673 +
    674 +                        string = g_key_file_get_string (key_file, type, type_keys[i], NULL);
    675 +                        g_hash_table_insert (parameters, g_strdup (type_keys[i]), string);
    676 +                }
    677 +                g_strfreev (type_keys);
    678 +        }
    679 +
    680 +        _ck_display_template_set_parameters (display, parameters);
    681 +        g_hash_table_unref (parameters);
    682 +
    683 +        g_free (group);
    684 +        g_key_file_free (key_file);
    685 +        return TRUE;
    686 +}
    687 +
    688 +CkDisplayTemplate *
    689 +ck_display_template_get_from_name (const char *name)
    690 +{
    691 +        CkDisplayTemplate *display_template;
    692 +
    693 +        if (ck_display_templates == NULL) {
    694 +                ck_display_templates = g_hash_table_new_full (g_str_hash, g_str_equal,
    695 +                                                          (GDestroyNotify) g_free,
    696 +                                                          (GDestroyNotify) g_object_unref);
    697 +        }
    698 +
    699 +        display_template = g_hash_table_lookup (ck_display_templates, name);
    700 +
    701 +        if (display_template == NULL) {
    702 +                GObject *object;
    703 +
    704 +                object = g_object_new (CK_TYPE_DISPLAY_TEMPLATE,
    705 +                                       "name", name,
    706 +                                       NULL);
    707 +
    708 +                if (!ck_display_template_load (CK_DISPLAY_TEMPLATE (object))) {
    709 +                        g_object_unref (object);
    710 +                        return NULL;
    711 +                }
    712 +
    713 +                g_hash_table_insert (ck_display_templates, g_strdup (name), object);
    714 +                display_template = CK_DISPLAY_TEMPLATE (object);
    715 +        }
    716 +
    717 +        return g_object_ref (display_template);
    718 +}
    719 +
    720 +G_CONST_RETURN char*
    721 +ck_display_template_get_name (CkDisplayTemplate   *display)
    722 +{
    723 +        g_return_val_if_fail (CK_IS_DISPLAY_TEMPLATE (display), NULL);
    724 +
    725 +        return display->priv->name;
    726 +}
    727 +
    728 +G_CONST_RETURN char *
    729 +ck_display_template_get_type_string (CkDisplayTemplate  *display)
    730 +{
    731 +        return display->priv->type;
    732 +}
    733 +
    734 +GHashTable *
    735 +ck_display_template_get_parameters (CkDisplayTemplate   *display)
    736 +{
    737 +        g_return_val_if_fail (CK_IS_DISPLAY_TEMPLATE (display), NULL);
    738 +
    739 +        return g_hash_table_ref (display->priv->parameters);
    740 +}
    741 +
    742 diff --git a/src/ck-display-template.h b/src/ck-display-template.h
    743 new file mode 100644
    744 index 0000000..fa74e67
    745 --- /dev/null
    746 +++ b/src/ck-display-template.h
    747 @@ -0,0 +1,57 @@
    748 +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
    749 + *
    750 + * Authors: halton.huo (a] sun.com
    751 + * Copyright (C) 2009 Sun Microsystems, Inc.
    752 + *
    753 + * This program is free software; you can redistribute it and/or modify
    754 + * it under the terms of the GNU General Public License as published by
    755 + * the Free Software Foundation; either version 2 of the License, or
    756 + * (at your option) any later version.
    757 + *
    758 + * This program is distributed in the hope that it will be useful,
    759 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    760 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    761 + * GNU General Public License for more details.
    762 + *
    763 + * You should have received a copy of the GNU General Public License
    764 + * along with this program; if not, write to the Free Software
    765 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
    766 + *
    767 + */
    768 +
    769 +#ifndef __CK_DISPLAY_TEMPLATE_H
    770 +#define __CK_DISPLAY_TEMPLATE_H
    771 +
    772 +#include <glib-object.h>
    773 +
    774 +G_BEGIN_DECLS
    775 +
    776 +#define CK_TYPE_DISPLAY_TEMPLATE         (ck_display_template_get_type ())
    777 +#define CK_DISPLAY_TEMPLATE(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), CK_TYPE_DISPLAY_TEMPLATE, CkDisplayTemplate))
    778 +#define CK_DISPLAY_TEMPLATE_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), CK_TYPE_DISPLAY_TEMPLATE, CkDisplayTemplateClass))
    779 +#define CK_IS_DISPLAY_TEMPLATE(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), CK_TYPE_DISPLAY_TEMPLATE))
    780 +#define CK_IS_DISPLAY_TEMPLATE_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), CK_TYPE_DISPLAY_TEMPLATE))
    781 +#define CK_DISPLAY_TEMPLATE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CK_TYPE_DISPLAY_TEMPLATE, CkDisplayTemplateClass))
    782 +
    783 +typedef struct CkDisplayTemplatePrivate CkDisplayTemplatePrivate;
    784 +
    785 +typedef struct
    786 +{
    787 +        GObject        parent;
    788 +        CkDisplayTemplatePrivate *priv;
    789 +} CkDisplayTemplate;
    790 +
    791 +typedef struct
    792 +{
    793 +        GObjectClass   parent_class;
    794 +} CkDisplayTemplateClass;
    795 +
    796 +GType                 ck_display_template_get_type            (void);
    797 +CkDisplayTemplate   * ck_display_template_get_from_name       (const char      *name);
    798 +G_CONST_RETURN char * ck_display_template_get_name            (CkDisplayTemplate   *display);
    799 +G_CONST_RETURN char * ck_display_template_get_type_string     (CkDisplayTemplate   *display);
    800 +GHashTable          * ck_display_template_get_parameters      (CkDisplayTemplate   *display);
    801 +
    802 +G_END_DECLS
    803 +
    804 +#endif /* __CK_DISPLAY_TEMPLATE_H */
    805 diff --git a/src/ck-log-event.c b/src/ck-log-event.c
    806 index 66f439c..510b18e 100644
    807 --- a/src/ck-log-event.c
    808 +++ b/src/ck-log-event.c
    809 @@ -79,6 +79,8 @@ event_seat_session_added_free (CkLogSeatSessionAddedEvent *event)
    810          event->session_id = NULL;
    811          g_free (event->session_type);
    812          event->session_type = NULL;
    813 +        g_free (event->display_type);
    814 +        event->display_type = NULL;
    815          g_free (event->session_x11_display);
    816          event->session_x11_display = NULL;
    817          g_free (event->session_x11_display_device);
    818 @@ -103,6 +105,8 @@ event_seat_session_removed_free (CkLogSeatSessionRemovedEvent *event)
    819          event->session_id = NULL;
    820          g_free (event->session_type);
    821          event->session_type = NULL;
    822 +        g_free (event->display_type);
    823 +        event->display_type = NULL;
    824          g_free (event->session_x11_display);
    825          event->session_x11_display = NULL;
    826          g_free (event->session_x11_display_device);
    827 @@ -213,6 +217,7 @@ event_seat_session_added_copy (CkLogSeatSessionAddedEvent *event,
    828          event_copy->seat_id = g_strdup (event->seat_id);
    829          event_copy->session_id = g_strdup (event->session_id);
    830          event_copy->session_type = g_strdup (event->session_type);
    831 +        event_copy->display_type = g_strdup (event->display_type);
    832          event_copy->session_x11_display = g_strdup (event->session_x11_display);
    833          event_copy->session_x11_display_device = g_strdup (event->session_x11_display_device);
    834          event_copy->session_display_device = g_strdup (event->session_display_device);
    835 @@ -232,6 +237,7 @@ event_seat_session_removed_copy (CkLogSeatSessionRemovedEvent *event,
    836          event_copy->seat_id = g_strdup (event->seat_id);
    837          event_copy->session_id = g_strdup (event->session_id);
    838          event_copy->session_type = g_strdup (event->session_type);
    839 +        event_copy->display_type = g_strdup (event->display_type);
    840          event_copy->session_x11_display = g_strdup (event->session_x11_display);
    841          event_copy->session_x11_display_device = g_strdup (event->session_x11_display_device);
    842          event_copy->session_display_device = g_strdup (event->session_display_device);
    843 @@ -415,10 +421,11 @@ add_log_for_seat_session_added (GString    *str,
    844  
    845          e = (CkLogSeatSessionAddedEvent *)event;
    846          g_string_append_printf (str,
    847 -                                "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'",
    848 +                                "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'",
    849                                  e->seat_id ? e->seat_id : "",
    850                                  e->session_id ? e->session_id : "",
    851                                  e->session_type ? e->session_type : "",
    852 +                                e->display_type ? e->display_type : "",
    853                                  e->session_x11_display ? e->session_x11_display : "",
    854                                  e->session_x11_display_device ? e->session_x11_display_device : "",
    855                                  e->session_display_device ? e->session_display_device : "",
    856 @@ -436,10 +443,11 @@ add_log_for_seat_session_removed (GString    *str,
    857  
    858          e = (CkLogSeatSessionRemovedEvent *)event;
    859          g_string_append_printf (str,
    860 -                                "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'",
    861 +                                "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'",
    862                                  e->seat_id ? e->seat_id : "",
    863                                  e->session_id ? e->session_id : "",
    864                                  e->session_type ? e->session_type : "",
    865 +                                e->display_type ? e->display_type : "",
    866                                  e->session_x11_display ? e->session_x11_display : "",
    867                                  e->session_x11_display_device ? e->session_x11_display_device : "",
    868                                  e->session_display_device ? e->session_display_device : "",
    869 @@ -939,7 +947,7 @@ parse_log_for_seat_session_added (const GString *str,
    870          }
    871  
    872          error = NULL;
    873 -        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);
    874 +        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);
    875          if (re == NULL) {
    876                  g_warning (error->message);
    877                  goto out;
    878 @@ -957,6 +965,7 @@ parse_log_for_seat_session_added (const GString *str,
    879          e->seat_id = g_match_info_fetch_named (match_info, "seatid");
    880          e->session_id = g_match_info_fetch_named (match_info, "sessionid");
    881          e->session_type = g_match_info_fetch_named (match_info, "sessiontype");
    882 +        e->display_type = g_match_info_fetch_named (match_info, "displaytype");
    883          e->session_x11_display = g_match_info_fetch_named (match_info, "sessionx11display");
    884          e->session_x11_display_device = g_match_info_fetch_named (match_info, "sessionx11displaydevice");
    885          e->session_display_device = g_match_info_fetch_named (match_info, "sessiondisplaydevice");
    886 @@ -1014,7 +1023,7 @@ parse_log_for_seat_session_removed (const GString *str,
    887          }
    888  
    889          error = NULL;
    890 -        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);
    891 +        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);
    892          if (re == NULL) {
    893                  g_warning (error->message);
    894                  goto out;
    895 @@ -1032,6 +1041,7 @@ parse_log_for_seat_session_removed (const GString *str,
    896          e->seat_id = g_match_info_fetch_named (match_info, "seatid");
    897          e->session_id = g_match_info_fetch_named (match_info, "sessionid");
    898          e->session_type = g_match_info_fetch_named (match_info, "sessiontype");
    899 +        e->display_type = g_match_info_fetch_named (match_info, "displaytype");
    900          e->session_x11_display = g_match_info_fetch_named (match_info, "sessionx11display");
    901          e->session_x11_display_device = g_match_info_fetch_named (match_info, "sessionx11displaydevice");
    902          e->session_display_device = g_match_info_fetch_named (match_info, "sessiondisplaydevice");
    903 diff --git a/src/ck-log-event.h b/src/ck-log-event.h
    904 index 65571f0..2d4ed4e 100644
    905 --- a/src/ck-log-event.h
    906 +++ b/src/ck-log-event.h
    907 @@ -68,6 +68,7 @@ typedef struct
    908  {
    909          char *seat_id;
    910          int   seat_kind;
    911 +        char *seat_type;
    912  } CkLogSeatAddedEvent;
    913  
    914  typedef struct
    915 @@ -81,11 +82,13 @@ typedef struct
    916          char    *seat_id;
    917          char    *session_id;
    918          char    *session_type;
    919 +        char    *display_type;
    920          char    *session_x11_display;
    921          char    *session_x11_display_device;
    922          char    *session_display_device;
    923          char    *session_remote_host_name;
    924          gboolean session_is_local;
    925 +        gboolean session_is_dynamic;
    926          guint    session_unix_user;
    927          char    *session_creation_time;
    928  } CkLogSeatSessionAddedEvent;
    929 @@ -95,11 +98,13 @@ typedef struct
    930          char    *seat_id;
    931          char    *session_id;
    932          char    *session_type;
    933 +        char    *display_type;
    934          char    *session_x11_display;
    935          char    *session_x11_display_device;
    936          char    *session_display_device;
    937          char    *session_remote_host_name;
    938          gboolean session_is_local;
    939 +        gboolean session_is_dynamic;
    940          guint    session_unix_user;
    941          char    *session_creation_time;
    942  } CkLogSeatSessionRemovedEvent;
    943 diff --git a/src/ck-manager.c b/src/ck-manager.c
    944 index d436a06..47c1945 100644
    945 --- a/src/ck-manager.c
    946 +++ b/src/ck-manager.c
    947 @@ -46,9 +46,14 @@
    948  #include <secdb.h>
    949  #endif
    950  
    951 +#ifndef HAVE_STRVERSCMP
    952 +#include "strverscmp.h"
    953 +#endif
    954 +
    955  #include "ck-manager.h"
    956  #include "ck-manager-glue.h"
    957  #include "ck-seat.h"
    958 +#include "ck-display-template.h"
    959  #include "ck-session-leader.h"
    960  #include "ck-session.h"
    961  #include "ck-marshal.h"
    962 @@ -58,12 +63,19 @@
    963  
    964  #define CK_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CK_TYPE_MANAGER, CkManagerPrivate))
    965  
    966 +#define CK_TYPE_PARAMETER_STRUCT (dbus_g_type_get_struct ("GValueArray", \
    967 +                                                          G_TYPE_STRING, \
    968 +                                                          G_TYPE_VALUE, \
    969 +                                                          G_TYPE_INVALID))
    970 +
    971  #define CK_SEAT_DIR          SYSCONFDIR "/ConsoleKit/seats.d"
    972  #define LOG_FILE             LOCALSTATEDIR "/log/ConsoleKit/history"
    973  #define CK_DBUS_PATH         "/org/freedesktop/ConsoleKit"
    974  #define CK_MANAGER_DBUS_PATH CK_DBUS_PATH "/Manager"
    975  #define CK_MANAGER_DBUS_NAME "org.freedesktop.ConsoleKit.Manager"
    976  
    977 +#define IS_STR_SET(x) (x != NULL && x[0] != '\0')
    978 +
    979  struct CkManagerPrivate
    980  {
    981  #ifdef HAVE_POLKIT
    982 @@ -392,6 +404,7 @@ log_seat_added_event (CkManager  *manager,
    983          GError            *error;
    984          char              *sid;
    985          CkSeatKind         seat_kind;
    986 +        char              *seat_type;
    987  
    988          memset (&event, 0, sizeof (CkLogEvent));
    989  
    990 @@ -401,9 +414,11 @@ log_seat_added_event (CkManager  *manager,
    991          sid = NULL;
    992          ck_seat_get_id (seat, &sid, NULL);
    993          ck_seat_get_kind (seat, &seat_kind, NULL);
    994 +        ck_seat_get_type_string (seat, &seat_type, NULL);
    995  
    996          event.event.seat_added.seat_id = (char *)get_object_id_basename (sid);
    997          event.event.seat_added.seat_kind = (int)seat_kind;
    998 +        event.event.seat_added.seat_type = (char *)seat_type;
    999  
   1000          error = NULL;
   1001          res = ck_event_logger_queue_event (manager->priv->logger, &event, &error);
   1002 @@ -413,6 +428,7 @@ log_seat_added_event (CkManager  *manager,
   1003          }
   1004  
   1005          g_free (sid);
   1006 +        g_free (seat_type);
   1007  }
   1008  
   1009  static void
   1010 @@ -517,6 +533,7 @@ log_seat_session_added_event (CkManager  *manager,
   1011          if (session != NULL) {
   1012                  g_object_get (session,
   1013                                "session-type", &event.event.seat_session_added.session_type,
   1014 +                              "display-type", &event.event.seat_session_added.display_type,
   1015                                "x11-display", &event.event.seat_session_added.session_x11_display,
   1016                                "x11-display-device", &event.event.seat_session_added.session_x11_display_device,
   1017                                "display-device", &event.event.seat_session_added.session_display_device,
   1018 @@ -572,6 +589,7 @@ log_seat_session_removed_event (CkManager  *manager,
   1019          if (session != NULL) {
   1020                  g_object_get (session,
   1021                                "session-type", &event.event.seat_session_removed.session_type,
   1022 +                              "display-type", &event.event.seat_session_removed.display_type,
   1023                                "x11-display", &event.event.seat_session_removed.session_x11_display,
   1024                                "x11-display-device", &event.event.seat_session_removed.session_x11_display_device,
   1025                                "display-device", &event.event.seat_session_removed.session_display_device,
   1026 @@ -1324,15 +1342,21 @@ disconnect_seat_signals (CkManager *manager,
   1027  }
   1028  
   1029  static CkSeat *
   1030 -add_new_seat (CkManager *manager,
   1031 -              CkSeatKind kind)
   1032 +add_new_seat (CkManager  *manager,
   1033 +              const char *give_sid,
   1034 +              CkSeatKind  kind,
   1035 +              const char *type)
   1036  {
   1037          char   *sid;
   1038          CkSeat *seat;
   1039  
   1040 -        sid = generate_seat_id (manager);
   1041 +        if (IS_STR_SET (give_sid)) {
   1042 +                sid = g_strdup (give_sid);
   1043 +        } else {
   1044 +                sid = generate_seat_id (manager);
   1045 +        }
   1046  
   1047 -        seat = ck_seat_new (sid, kind);
   1048 +        seat = ck_seat_new (sid, kind, type);
   1049  
   1050          /* First we connect our own signals to the seat, followed by
   1051           * the D-Bus signal hookup to make sure we can first dump the
   1052 @@ -1357,7 +1381,7 @@ add_new_seat (CkManager *manager,
   1053          ck_seat_run_programs (seat, NULL, NULL, "seat_added");
   1054  
   1055          g_debug ("Emitting seat-added: %s", sid);
   1056 -        g_signal_emit (manager, signals [SEAT_ADDED], 0, sid);
   1057 +        g_signal_emit (manager, signals [SEAT_ADDED], 0, sid, type);
   1058  
   1059          log_seat_added_event (manager, seat);
   1060  
   1061 @@ -1415,64 +1439,22 @@ remove_seat (CkManager *manager,
   1062          g_free (sid);
   1063  }
   1064  
   1065 -#define IS_STR_SET(x) (x != NULL && x[0] != '\0')
   1066 -
   1067  static CkSeat *
   1068  find_seat_for_session (CkManager *manager,
   1069                         CkSession *session)
   1070  {
   1071          CkSeat  *seat;
   1072 -        gboolean is_static_x11;
   1073 -        gboolean is_static_text;
   1074 -        char    *display_device;
   1075 -        char    *x11_display_device;
   1076 -        char    *x11_display;
   1077 -        char    *remote_host_name;
   1078 -        gboolean is_local;
   1079 -
   1080 -        is_static_text = FALSE;
   1081 -        is_static_x11 = FALSE;
   1082 -
   1083 -        seat = NULL;
   1084 -        display_device = NULL;
   1085 -        x11_display_device = NULL;
   1086 -        x11_display = NULL;
   1087 -        remote_host_name = NULL;
   1088 -        is_local = FALSE;
   1089 -
   1090 -        /* FIXME: use matching to group entries? */
   1091 -
   1092 -        ck_session_get_display_device (session, &display_device, NULL);
   1093 -        ck_session_get_x11_display_device (session, &x11_display_device, NULL);
   1094 -        ck_session_get_x11_display (session, &x11_display, NULL);
   1095 -        ck_session_get_remote_host_name (session, &remote_host_name, NULL);
   1096 -        ck_session_is_local (session, &is_local, NULL);
   1097 -
   1098 -        if (IS_STR_SET (x11_display)
   1099 -            && IS_STR_SET (x11_display_device)
   1100 -            && ! IS_STR_SET (remote_host_name)
   1101 -            && is_local == TRUE) {
   1102 -                is_static_x11 = TRUE;
   1103 -        } else if (! IS_STR_SET (x11_display)
   1104 -                   && ! IS_STR_SET (x11_display_device)
   1105 -                   && IS_STR_SET (display_device)
   1106 -                   && ! IS_STR_SET (remote_host_name)
   1107 -                   && is_local == TRUE) {
   1108 -                is_static_text = TRUE;
   1109 -        }
   1110 -
   1111 -        if (is_static_x11 || is_static_text) {
   1112 -                char *sid;
   1113 +        char    *sid = NULL;
   1114 +
   1115 +        ck_session_get_seat_id (session, &sid, NULL);
   1116 +
   1117 +        if (! IS_STR_SET (sid)) {
   1118                  sid = g_strdup_printf ("%s/Seat%u", CK_DBUS_PATH, 1);
   1119 -                seat = g_hash_table_lookup (manager->priv->seats, sid);
   1120 -                g_free (sid);
   1121          }
   1122  
   1123 -        g_free (display_device);
   1124 -        g_free (x11_display_device);
   1125 -        g_free (x11_display);
   1126 -        g_free (remote_host_name);
   1127 +        seat = g_hash_table_lookup (manager->priv->seats, sid);
   1128  
   1129 +        g_free (sid);
   1130          return seat;
   1131  }
   1132  
   1133 @@ -1612,31 +1594,40 @@ open_session_for_leader (CkManager             *manager,
   1134          ssid = ck_session_leader_peek_session_id (leader);
   1135          cookie = ck_session_leader_peek_cookie (leader);
   1136  
   1137 -        session = ck_session_new_with_parameters (ssid,
   1138 -                                                  cookie,
   1139 -                                                  parameters);
   1140 +        session = g_hash_table_lookup (manager->priv->sessions, ssid);
   1141  
   1142          if (session == NULL) {
   1143 -                GError *error;
   1144 -                g_debug ("Unable to create new session");
   1145 -                error = g_error_new (CK_MANAGER_ERROR,
   1146 -                                     CK_MANAGER_ERROR_GENERAL,
   1147 -                                     "Unable to create new session");
   1148 -                dbus_g_method_return_error (context, error);
   1149 -                g_error_free (error);
   1150 +                session = ck_session_new_with_parameters (ssid,
   1151 +                                                          parameters);
   1152 +
   1153 +                if (session == NULL) {
   1154 +                        GError *error;
   1155 +                        g_debug ("Unable to create new session");
   1156 +                        error = g_error_new (CK_MANAGER_ERROR,
   1157 +                                             CK_MANAGER_ERROR_GENERAL,
   1158 +                                             "Unable to create new session");
   1159 +                        dbus_g_method_return_error (context, error);
   1160 +                        g_error_free (error);
   1161  
   1162 -                return;
   1163 +                        return;
   1164 +                }
   1165 +
   1166 +                g_hash_table_insert (manager->priv->sessions,
   1167 +                                     g_strdup (ssid),
   1168 +                                     g_object_ref (session));
   1169 +
   1170 +        } else {
   1171 +                ck_session_set_parameters (session, parameters);
   1172          }
   1173  
   1174 -        g_hash_table_insert (manager->priv->sessions,
   1175 -                             g_strdup (ssid),
   1176 -                             g_object_ref (session));
   1177 +        ck_session_set_cookie (session, cookie, NULL);
   1178 +        ck_session_set_is_open (session, TRUE, NULL);
   1179  
   1180          /* Add to seat */
   1181          seat = find_seat_for_session (manager, session);
   1182          if (seat == NULL) {
   1183                  /* create a new seat */
   1184 -                seat = add_new_seat (manager, CK_SEAT_KIND_DYNAMIC);
   1185 +                seat = add_new_seat (manager, NULL, CK_SEAT_KIND_DYNAMIC, "Default");
   1186          }
   1187  
   1188          ck_seat_add_session (seat, session, NULL);
   1189 @@ -1710,11 +1701,57 @@ generate_session_for_leader (CkManager             *manager,
   1190          }
   1191  }
   1192  
   1193 +static char *
   1194 +check_parameters_for_ssid (const GPtrArray *parameters)
   1195 +{
   1196 +        int i;
   1197 +
   1198 +        if (parameters == NULL) {
   1199 +                return NULL;
   1200 +        }
   1201 +
   1202 +        for (i = 0; i < parameters->len; i++) {
   1203 +                GValue   val_struct = { 0, };
   1204 +                char    *prop_name;
   1205 +                gboolean res;
   1206 +
   1207 +                g_value_init (&val_struct, CK_TYPE_PARAMETER_STRUCT);
   1208 +                g_value_set_static_boxed (&val_struct, g_ptr_array_index (parameters, i));
   1209 +
   1210 +                res = dbus_g_type_struct_get (&val_struct,
   1211 +                                              0, &prop_name,
   1212 +                                              G_MAXUINT);
   1213 +                if (! res) {
   1214 +                        g_debug ("Unable to read parameter name");
   1215 +                        continue;
   1216 +                }
   1217 +
   1218 +                if (prop_name != NULL && strcmp (prop_name, "session") == 0) {
   1219 +                        GValue   prop_val = { 0, };
   1220 +                        GValue  *session_val;
   1221 +
   1222 +                        g_value_init (&prop_val, G_TYPE_VALUE);
   1223 +                        res = dbus_g_type_struct_get_member (&val_struct, 1, &prop_val);
   1224 +
   1225 +                        if (! res) {
   1226 +                                g_debug ("Unable to read parameter value");
   1227 +                                continue;
   1228 +                        }
   1229 +
   1230 +                        session_val = g_value_get_boxed (&prop_val);
   1231 +
   1232 +                        return g_value_dup_string (session_val);
   1233 +                }
   1234 +        }
   1235 +
   1236 +        return NULL;
   1237 +}
   1238 +
   1239  static gboolean
   1240 -create_session_for_sender (CkManager             *manager,
   1241 -                           const char            *sender,
   1242 -                           const GPtrArray       *parameters,
   1243 -                           DBusGMethodInvocation *context)
   1244 +open_session_for_sender (CkManager             *manager,
   1245 +                         const char            *sender,
   1246 +                         const GPtrArray       *parameters,
   1247 +                         DBusGMethodInvocation *context)
   1248  {
   1249          pid_t           pid;
   1250          uid_t           uid;
   1251 @@ -1722,6 +1759,7 @@ create_session_for_sender (CkManager             *manager,
   1252          char            *cookie;
   1253          char            *ssid;
   1254          CkSessionLeader *leader;
   1255 +        CkSession       *session;
   1256  
   1257          g_debug ("CkManager: create session for sender: %s", sender);
   1258  
   1259 @@ -1740,9 +1778,21 @@ create_session_for_sender (CkManager             *manager,
   1260          }
   1261  
   1262          cookie = generate_session_cookie (manager);
   1263 -        ssid = generate_session_id (manager);
   1264  
   1265 -        g_debug ("Creating new session ssid: %s", ssid);
   1266 +        ssid = check_parameters_for_ssid (parameters);
   1267 +
   1268 +        if (IS_STR_SET (ssid)) {
   1269 +                session = g_hash_table_lookup (manager->priv->sessions, ssid);
   1270 +
   1271 +                /* FIXME: Need to verify that the session belongs to a seat
   1272 +                 * managed by the sender
   1273 +                 */
   1274 +                g_debug ("Managing existing session ssid: %s", ssid);
   1275 +        } else {
   1276 +                ssid = generate_session_id (manager);
   1277 +                session = NULL;
   1278 +                g_debug ("Creating new session ssid: %s", ssid);
   1279 +        }
   1280  
   1281          leader = ck_session_leader_new ();
   1282          ck_session_leader_set_uid (leader, uid);
   1283 @@ -1980,7 +2030,7 @@ ck_manager_open_session (CkManager             *manager,
   1284          gboolean ret;
   1285  
   1286          sender = dbus_g_method_get_sender (context);
   1287 -        ret = create_session_for_sender (manager, sender, NULL, context);
   1288 +        ret = open_session_for_sender (manager, sender, NULL, context);
   1289          g_free (sender);
   1290  
   1291          return ret;
   1292 @@ -1995,7 +2045,7 @@ ck_manager_open_session_with_parameters (CkManager             *manager,
   1293          gboolean ret;
   1294  
   1295          sender = dbus_g_method_get_sender (context);
   1296 -        ret = create_session_for_sender (manager, sender, parameters, context);
   1297 +        ret = open_session_for_sender (manager, sender, parameters, context);
   1298          g_free (sender);
   1299  
   1300          return ret;
   1301 @@ -2012,10 +2062,12 @@ remove_session_for_cookie (CkManager  *manager,
   1302          char            *sid;
   1303          gboolean         res;
   1304          gboolean         ret;
   1305 +        gboolean         should_remove_session;
   1306  
   1307          ret = FALSE;
   1308          orig_ssid = NULL;
   1309          orig_session = NULL;
   1310 +        should_remove_session = FALSE;
   1311  
   1312          g_debug ("Removing session for cookie: %s", cookie);
   1313  
   1314 @@ -2042,6 +2094,17 @@ remove_session_for_cookie (CkManager  *manager,
   1315                  goto out;
   1316          }
   1317  
   1318 +        ck_session_set_is_open (orig_session, FALSE, NULL);
   1319 +        ck_session_set_cookie (orig_session, NULL, NULL);
   1320 +        ck_session_set_active (orig_session, FALSE, NULL);
   1321 +        ck_session_set_unix_user (orig_session, 0, NULL);
   1322 +        ck_session_set_x11_display (orig_session, NULL, NULL);
   1323 +        ck_session_set_x11_display_device (orig_session, NULL, NULL);
   1324 +        ck_session_set_display_device (orig_session, NULL, NULL);
   1325 +        ck_session_set_login_session_id (orig_session, NULL, NULL);
   1326 +        ck_session_set_remote_host_name (orig_session, NULL, NULL);
   1327 +        ck_session_set_under_request (orig_session, FALSE, NULL);
   1328 +
   1329          /* Must keep a reference to the session in the manager until
   1330           * all events for seats are cleared.  So don't remove
   1331           * or steal the session from the master list until
   1332 @@ -2049,31 +2112,35 @@ remove_session_for_cookie (CkManager  *manager,
   1333           * for seat removals doesn't work.
   1334           */
   1335  
   1336 -        /* remove from seat */
   1337 -        sid = NULL;
   1338 -        ck_session_get_seat_id (orig_session, &sid, NULL);
   1339 -        if (sid != NULL) {
   1340 -                CkSeat *seat;
   1341 -                seat = g_hash_table_lookup (manager->priv->seats, sid);
   1342 -                if (seat != NULL) {
   1343 -                        CkSeatKind kind;
   1344 -
   1345 -                        ck_seat_remove_session (seat, orig_session, NULL);
   1346 -
   1347 -                        kind = CK_SEAT_KIND_STATIC;
   1348 -                        /* if dynamic seat has no sessions then remove it */
   1349 -                        ck_seat_get_kind (seat, &kind, NULL);
   1350 -                        if (kind == CK_SEAT_KIND_DYNAMIC) {
   1351 -                                remove_seat (manager, seat);
   1352 +        ck_session_get_remove_on_close (orig_session, &should_remove_session, NULL);
   1353 +
   1354 +        if (should_remove_session) {
   1355 +                /* remove from seat */
   1356 +                sid = NULL;
   1357 +                ck_session_get_seat_id (orig_session, &sid, NULL);
   1358 +                if (sid != NULL) {
   1359 +                        CkSeat *seat;
   1360 +                        seat = g_hash_table_lookup (manager->priv->seats, sid);
   1361 +                        if (seat != NULL) {
   1362 +                                CkSeatKind kind;
   1363 +
   1364 +                                ck_seat_remove_session (seat, orig_session, NULL);
   1365 +
   1366 +                                kind = CK_SEAT_KIND_STATIC;
   1367 +                                /* if dynamic seat has no sessions then remove it */
   1368 +                                ck_seat_get_kind (seat, &kind, NULL);
   1369 +                                if (kind == CK_SEAT_KIND_DYNAMIC) {
   1370 +                                        g_hash_table_remove (manager->priv->sessions, orig_ssid);
   1371 +                                }
   1372                          }
   1373                  }
   1374 -        }
   1375 -        g_free (sid);
   1376 +                g_free (sid);
   1377  
   1378 -        /* Remove the session from the list but don't call
   1379 -         * unref until we are done with it */
   1380 -        g_hash_table_steal (manager->priv->sessions,
   1381 -                            ck_session_leader_peek_session_id (leader));
   1382 +                /* Remove the session from the list but don't call
   1383 +                 * unref until we are done with it */
   1384 +                g_hash_table_steal (manager->priv->sessions,
   1385 +                                    ck_session_leader_peek_session_id (leader));
   1386 +        }
   1387  
   1388          ck_manager_dump (manager);
   1389  
   1390 @@ -2081,11 +2148,13 @@ remove_session_for_cookie (CkManager  *manager,
   1391  
   1392          ret = TRUE;
   1393   out:
   1394 -        if (orig_session != NULL) {
   1395 -                g_object_unref (orig_session);
   1396 -        }
   1397 -        g_free (orig_ssid);
   1398 +        if (should_remove_session) {
   1399 +                if (orig_session != NULL) {
   1400 +                        g_object_unref (orig_session);
   1401 +                }
   1402  
   1403 +                g_free (orig_ssid);
   1404 +        }
   1405          return ret;
   1406  }
   1407  
   1408 @@ -2303,9 +2372,11 @@ ck_manager_class_init (CkManagerClass *klass)
   1409                                G_STRUCT_OFFSET (CkManagerClass, seat_added),
   1410                                NULL,
   1411                                NULL,
   1412 -                              g_cclosure_marshal_VOID__BOXED,
   1413 +                              ck_marshal_VOID__STRING_STRING,
   1414                                G_TYPE_NONE,
   1415 -                              1, DBUS_TYPE_G_OBJECT_PATH);
   1416 +                              2,
   1417 +                              G_TYPE_STRING,
   1418 +                              G_TYPE_STRING);
   1419          signals [SEAT_REMOVED] =
   1420                  g_signal_new ("seat-removed",
   1421                                G_TYPE_FROM_CLASS (object_class),
   1422 @@ -2412,6 +2483,43 @@ ck_manager_get_seats (CkManager  *manager,
   1423  }
   1424  
   1425  static void
   1426 +listify_unmanaged_seat_ids (char       *id,
   1427 +                            CkSeat     *seat,
   1428 +                            GPtrArray **array)
   1429 +{
   1430 +        if (ck_seat_is_managed (seat)) {
   1431 +                return;
   1432 +        }
   1433 +
   1434 +        g_ptr_array_add (*array, g_strdup (id));
   1435 +}
   1436 +
   1437 +
   1438 +/*
   1439 +  Example:
   1440 +  dbus-send --system --dest=org.freedesktop.ConsoleKit \
   1441 +  --type=method_call --print-reply --reply-timeout=2000 \
   1442 +  /org/freedesktop/ConsoleKit/Manager \
   1443 +  org.freedesktop.ConsoleKit.Manager.GetUnmanagedSeats
   1444 +*/
   1445 +gboolean
   1446 +ck_manager_get_unmanaged_seats (CkManager  *manager,
   1447 +                                GPtrArray **seats,
   1448 +                                GError    **error)
   1449 +{
   1450 +        g_return_val_if_fail (CK_IS_MANAGER (manager), FALSE);
   1451 +
   1452 +        if (seats == NULL) {
   1453 +                return FALSE;
   1454 +        }
   1455 +
   1456 +        *seats = g_ptr_array_new ();
   1457 +        g_hash_table_foreach (manager->priv->seats, (GHFunc)listify_unmanaged_seat_ids, seats);
   1458 +
   1459 +        return TRUE;
   1460 +}
   1461 +
   1462 +static void
   1463  listify_session_ids (char       *id,
   1464                       CkSession  *session,
   1465                       GPtrArray **array)
   1466 @@ -2436,16 +2544,307 @@ ck_manager_get_sessions (CkManager  *manager,
   1467          return TRUE;
   1468  }
   1469  
   1470 +/*
   1471 +  Example:
   1472 +  dbus-send --system --dest=org.freedesktop.ConsoleKit \
   1473 +  --type=method_call --print-reply --reply-timeout=2000 \
   1474 +  /org/freedesktop/ConsoleKit/Manager \
   1475 +  org.freedesktop.ConsoleKit.Manager.AddSeat string:Default
   1476 +*/
   1477 +gboolean
   1478 +ck_manager_add_seat (CkManager  *manager,
   1479 +                     const char *type,
   1480 +                     char      **sid,
   1481 +                     GError    **error)
   1482 +{
   1483 +        CkSeat    *seat;
   1484 +                
   1485 +        g_return_val_if_fail (CK_IS_MANAGER (manager), FALSE);
   1486 +
   1487 +        seat = add_new_seat (manager, NULL, CK_SEAT_KIND_DYNAMIC, type);
   1488 +
   1489 +        if (!ck_seat_get_id (seat, sid, error)) {
   1490 +                return FALSE;
   1491 +        }
   1492 +
   1493 +        return TRUE;
   1494 +}
   1495 +
   1496 +/*
   1497 +  Example:
   1498 +  dbus-send --system --dest=org.freedesktop.ConsoleKit \
   1499 +  --type=method_call --print-reply --reply-timeout=2000 \
   1500 +  /org/freedesktop/ConsoleKit/Manager \
   1501 +  org.freedesktop.ConsoleKit.Manager.AddSeatById \
   1502 +  objpath:/org/freedesktop/ConsoleKit/SeatTest \
   1503 +*/
   1504 +gboolean
   1505 +ck_manager_add_seat_by_id (CkManager  *manager,
   1506 +                           const char *type,
   1507 +                           const char *sid,
   1508 +                           GError    **error) 
   1509 +{
   1510 +        CkSeat    *seat;
   1511 +
   1512 +        g_return_val_if_fail (CK_IS_MANAGER (manager), FALSE);
   1513 +
   1514 +        seat = add_new_seat (manager, sid, CK_SEAT_KIND_DYNAMIC, type);
   1515 +
   1516 +        return !(seat == NULL);
   1517 +}
   1518 +
   1519 +/*
   1520 +  Example:
   1521 +  dbus-send --system --dest=org.freedesktop.ConsoleKit \
   1522 +  --type=method_call --print-reply --reply-timeout=2000 \
   1523 +  /org/freedesktop/ConsoleKit/Manager \
   1524 +  org.freedesktop.ConsoleKit.Manager.RemoveSeat \
   1525 +  obj:/org/freedesktop/ConsoleKit/Seat2
   1526 +*/
   1527 +gboolean
   1528 +ck_manager_remove_seat (CkManager             *manager,
   1529 +                        const char            *sid,
   1530 +                        DBusGMethodInvocation *context)
   1531 +{
   1532 +        CkSeat     *seat = NULL;
   1533 +        CkSeatKind kind;
   1534 +
   1535 +        g_return_val_if_fail (CK_IS_MANAGER (manager), FALSE);
   1536 +
   1537 +        seat = g_hash_table_lookup (manager->priv->seats, sid);
   1538 +
   1539 +        if (seat == NULL) {
   1540 +                GError *error;
   1541 +
   1542 +                error = g_error_new (CK_SEAT_ERROR,
   1543 +                                     CK_SEAT_ERROR_GENERAL,
   1544 +                                     _("Seat '%s' doesn't exist"),
   1545 +                                     sid);
   1546 +
   1547 +                dbus_g_method_return_error (context, error);
   1548 +                g_error_free (error);
   1549 +
   1550 +                return FALSE;
   1551 +        }
   1552 +
   1553 +        ck_seat_get_kind (seat, &kind, NULL);
   1554 +
   1555 +        if (kind == CK_SEAT_KIND_STATIC) {
   1556 +                GError *error;
   1557 +
   1558 +                error = g_error_new (CK_SEAT_ERROR,
   1559 +                                     CK_SEAT_ERROR_GENERAL,
   1560 +                                     _("Seat '%s' is static and can't be removed"),
   1561 +                                     sid);
   1562 +
   1563 +                dbus_g_method_return_error (context, error);
   1564 +                g_error_free (error);
   1565 +
   1566 +                return FALSE;
   1567 +        }
   1568 +
   1569 +        if (ck_seat_is_managed (seat)) {
   1570 +                ck_seat_request_removal (seat);
   1571 +        } else {
   1572 +                remove_seat (manager, seat);
   1573 +        }
   1574 +
   1575 +        return TRUE;
   1576 +}
   1577 +
   1578 +/*
   1579 +  Example:
   1580 +  dbus-send --system --dest=org.freedesktop.ConsoleKit \
   1581 +  --type=method_call --print-reply --reply-timeout=2000 \
   1582 +  /org/freedesktop/ConsoleKit/Manager \
   1583 +  org.freedesktop.ConsoleKit.Manager.AddSession \
   1584 +  objpath:/org/freedesktop/ConsoleKit/Seat2 \
   1585 +  string:"LoginWindow" \
   1586 +  dict:string:string:"vt","vt9","display",":123"
   1587 +*/
   1588 +gboolean
   1589 +ck_manager_add_session (CkManager             *manager,
   1590 +                        const char            *sid,
   1591 +                        const char            *type,
   1592 +                        const char            *display_type,
   1593 +                        GHashTable            *variables,
   1594 +                        DBusGMethodInvocation *context)
   1595 +{
   1596 +        CkSeat    *seat;
   1597 +        CkSession *session;
   1598 +        char      *ssid;
   1599 +
   1600 +        seat = g_hash_table_lookup (manager->priv->seats, sid);
   1601 +
   1602 +        if (seat == NULL) {
   1603 +                GError *error;
   1604 +
   1605 +                error = g_error_new (CK_SEAT_ERROR,
   1606 +                                     CK_SEAT_ERROR_GENERAL, 
   1607 +                                     _("Seat '%s' doesn't exist"),
   1608 +                                     sid);
   1609 +
   1610 +                dbus_g_method_return_error (context, error);
   1611 +                g_error_free (error);
   1612 +
   1613 +                return FALSE;
   1614 +        }
   1615 +
   1616 +        ssid = generate_session_id (manager);
   1617 +
   1618 +        session = ck_session_new (ssid, type, display_type, variables);
   1619 +
   1620 +        if (session == NULL) {
   1621 +                GError *error;
   1622 +
   1623 +                error = g_error_new (CK_SEAT_ERROR, 
   1624 +                                     CK_SEAT_ERROR_GENERAL,
   1625 +                                     _("Session could not be added to seat '%s'"),
   1626 +                                     sid);
   1627 +
   1628 +                dbus_g_method_return_error (context, error);
   1629 +                g_error_free (error);
   1630 +
   1631 +                return FALSE;
   1632 +        }
   1633 +
   1634 +        ck_session_set_seat_id (session, sid, NULL);
   1635 +        session_set_remove_on_close (session, TRUE, NULL);
   1636 +
   1637 +        ck_seat_add_session (seat, session, NULL);
   1638 +
   1639 +        g_hash_table_insert (manager->priv->sessions,
   1640 +                             ssid,
   1641 +                             session);
   1642 +
   1643 +        dbus_g_method_return (context, ssid);
   1644 +        return TRUE;
   1645 +}
   1646 +
   1647 +/*
   1648 +  Example:
   1649 +  dbus-send --system --dest=org.freedesktop.ConsoleKit \
   1650 +  --type=method_call --print-reply --reply-timeout=2000 \
   1651 +  /org/freedesktop/ConsoleKit/Manager \
   1652 +  org.freedesktop.ConsoleKit.Manager.RemoveSession \
   1653 +  objpath:/org/freedesktop/ConsoleKit/Session2
   1654 +*/
   1655 +gboolean
   1656 +ck_manager_remove_session (CkManager             *manager,
   1657 +                           const char            *ssid,
   1658 +                           DBusGMethodInvocation *context)
   1659 +{
   1660 +        CkSession *session;
   1661 +        CkSeat *seat;
   1662 +        GError *error; 
   1663 +        char *sid;
   1664 +        gboolean is_open;
   1665 +
   1666 +        session = g_hash_table_lookup (manager->priv->sessions, ssid);
   1667 +
   1668 +        if (session == NULL) {
   1669 +                GError *error;
   1670 +
   1671 +                error = g_error_new (CK_SEAT_ERROR,
   1672 +                                     CK_SEAT_ERROR_GENERAL,
   1673 +                                     _("Session '%s' doesn't exist"),
   1674 +                                     ssid);
   1675 +
   1676 +                dbus_g_method_return_error (context, error);
   1677 +                g_error_free (error);
   1678 +
   1679 +                return FALSE;
   1680 +        }
   1681 +
   1682 +        ck_session_get_seat_id (session, &sid, NULL);
   1683 +        seat = g_hash_table_lookup (manager->priv->seats, sid);
   1684 +        g_free (sid);
   1685 +
   1686 +        if (seat == NULL) {
   1687 +                g_warning ("Session '%s' is not associated with a seat", ssid);
   1688 +                g_hash_table_remove (manager->priv->sessions, ssid);
   1689 +                return TRUE;
   1690 +        }
   1691 +
   1692 +        error = NULL;
   1693 +
   1694 +        ck_session_is_open (session, &is_open, NULL);
   1695 +        session_set_remove_on_close (session, TRUE, NULL);
   1696 +
   1697 +        /* We'll let the seat manager close us when it's ready
   1698 +         */
   1699 +        if (ck_seat_is_managed (seat) && is_open) {
   1700 +                ck_seat_request_close_session (seat, session, NULL);
   1701 +                dbus_g_method_return (context);
   1702 +
   1703 +                return TRUE;
   1704 +        }
   1705 +
   1706 +        if (!ck_seat_remove_session (seat, session, &error)) {
   1707 +                if (error == NULL) {
   1708 +                        return TRUE;
   1709 +                }
   1710 +                
   1711 +                dbus_g_method_return_error (context, error);
   1712 +                g_error_free (error);
   1713 +                return FALSE;
   1714 +        }
   1715 +        
   1716 +        g_hash_table_remove (manager->priv->sessions, ssid);
   1717 +        dbus_g_method_return (context);
   1718 +        return TRUE;
   1719 +}
   1720 + 
   1721 +static void
   1722 +add_sessions_from_seat (CkManager *manager,
   1723 +                        CkSeat    *seat)
   1724 +{
   1725 +        GPtrArray *sessions;
   1726 +        int i;
   1727 +
   1728 +        ck_seat_get_sessions (seat, &sessions, NULL);
   1729 +
   1730 +        for (i = 0; i < sessions->len; i++) {
   1731 +                char *ssid;
   1732 +                CkSession *session; 
   1733 +
   1734 +                ssid = g_ptr_array_index (sessions, i);
   1735 +                session = ck_seat_get_session (seat, ssid);
   1736 +
   1737 +                g_hash_table_insert (manager->priv->sessions,
   1738 +                                     ssid,
   1739 +                                     session);
   1740 +        }
   1741 +
   1742 +        g_ptr_array_free (sessions, TRUE);
   1743 +}
   1744 +
   1745  static void
   1746  add_seat_for_file (CkManager  *manager,
   1747                     const char *filename)
   1748  {
   1749          char   *sid;
   1750 +        char   *orig_sid;
   1751          CkSeat *seat;
   1752  
   1753          sid = generate_seat_id (manager);
   1754 +        orig_sid = g_strdup (sid);
   1755 +        seat = ck_seat_new_from_file (&sid, filename);
   1756 +
   1757 +        if (seat == NULL) {
   1758 +                /* returns null if connection to bus fails */
   1759 +                g_free (sid);
   1760 +                g_free (orig_sid);
   1761 +                manager->priv->seat_serial--;
   1762 +                return;
   1763 +        }
   1764  
   1765 -        seat = ck_seat_new_from_file (sid, filename);
   1766 +        if (!g_str_equal (orig_sid, sid)) {
   1767 +                manager->priv->seat_serial--;
   1768 +        }
   1769 +        g_free (orig_sid);
   1770 +
   1771 +        add_sessions_from_seat (manager, seat);
   1772  
   1773          connect_seat_signals (manager, seat);
   1774          if (!ck_seat_register (seat)) {
   1775 @@ -2464,7 +2863,7 @@ add_seat_for_file (CkManager  *manager,
   1776          ck_seat_run_programs (seat, NULL, NULL, "seat_added");
   1777  
   1778          g_debug ("Emitting seat-added: %s", sid);
   1779 -        g_signal_emit (manager, signals [SEAT_ADDED], 0, sid);
   1780 +        g_signal_emit (manager, signals [SEAT_ADDED], 0, sid, "Default");
   1781  
   1782          log_seat_added_event (manager, seat);
   1783  }
   1784 @@ -2475,6 +2874,7 @@ load_seats_from_dir (CkManager *manager)
   1785          GDir       *d;
   1786          GError     *error;
   1787          const char *file;
   1788 +        GQueue      seat_queue;
   1789  
   1790          error = NULL;
   1791          d = g_dir_open (CK_SEAT_DIR,
   1792 @@ -2486,15 +2886,26 @@ load_seats_from_dir (CkManager *manager)
   1793                  return FALSE;
   1794          }
   1795  
   1796 +        g_queue_init (&seat_queue);
   1797          while ((file = g_dir_read_name (d)) != NULL) {
   1798                  char *path;
   1799                  path = g_build_filename (CK_SEAT_DIR, file, NULL);
   1800 +                g_queue_push_tail (&seat_queue, path);
   1801 +        }
   1802 +        g_dir_close (d);
   1803 +
   1804 +        g_queue_sort (&seat_queue, (GCompareDataFunc) strverscmp, NULL);
   1805 +
   1806 +        while (!g_queue_is_empty (&seat_queue)) {
   1807 +                char *path;
   1808 +
   1809 +                path = g_queue_pop_head (&seat_queue);
   1810 +
   1811                  add_seat_for_file (manager, path);
   1812 +
   1813                  g_free (path);
   1814          }
   1815  
   1816 -        g_dir_close (d);
   1817 -
   1818          return TRUE;
   1819  }
   1820  
   1821 @@ -2530,8 +2941,6 @@ ck_manager_init (CkManager *manager)
   1822                                                          (GDestroyNotify) g_object_unref);
   1823  
   1824          manager->priv->logger = ck_event_logger_new (LOG_FILE);
   1825 -
   1826 -        create_seats (manager);
   1827  }
   1828  
   1829  static void
   1830 @@ -2576,6 +2985,8 @@ ck_manager_new (void)
   1831                          g_object_unref (manager_object);
   1832                          return NULL;
   1833                  }
   1834 +
   1835 +                create_seats (CK_MANAGER (manager_object));
   1836          }
   1837  
   1838          return CK_MANAGER (manager_object);
   1839 diff --git a/src/ck-manager.h b/src/ck-manager.h
   1840 index 4bd56e8..4304e71 100644
   1841 --- a/src/ck-manager.h
   1842 +++ b/src/ck-manager.h
   1843 @@ -49,7 +49,8 @@ typedef struct
   1844          GObjectClass   parent_class;
   1845  
   1846          void          (* seat_added)               (CkManager  *manager,
   1847 -                                                    const char *sid);
   1848 +                                                    const char *sid,
   1849 +                                                    const char *type);
   1850          void          (* seat_removed)             (CkManager  *manager,
   1851                                                      const char *sid);
   1852          void          (* system_idle_hint_changed) (CkManager  *manager,
   1853 @@ -96,6 +97,9 @@ gboolean            ck_manager_get_sessions                   (CkManager
   1854  gboolean            ck_manager_get_seats                      (CkManager             *manager,
   1855                                                                 GPtrArray            **seats,
   1856                                                                 GError               **error);
   1857 +gboolean            ck_manager_get_unmanaged_seats            (CkManager             *manager,
   1858 +                                                               GPtrArray            **seats,
   1859 +                                                               GError               **error);
   1860  gboolean            ck_manager_close_session                  (CkManager             *manager,
   1861                                                                 const char            *cookie,
   1862                                                                 DBusGMethodInvocation *context);
   1863 @@ -128,6 +132,28 @@ gboolean            ck_manager_open_session_with_parameters   (CkManager
   1864                                                                 const GPtrArray       *parameters,
   1865                                                                 DBusGMethodInvocation *context);
   1866  
   1867 +gboolean            ck_manager_add_seat                       (CkManager             *manager,
   1868 +                                                               const char            *type,
   1869 +                                                               char                 **sid,
   1870 +                                                               GError               **error);
   1871 +gboolean            ck_manager_add_seat_by_id                 (CkManager             *manager,
   1872 +                                                               const char            *type,
   1873 +                                                               const char            *sid,
   1874 +                                                               GError               **error);
   1875 +gboolean            ck_manager_remove_seat                    (CkManager             *manager,
   1876 +                                                               const char            *sid,
   1877 +                                                               DBusGMethodInvocation *context);
   1878 +
   1879 +gboolean            ck_manager_add_session                    (CkManager             *manager,
   1880 +                                                               const char            *sid,
   1881 +                                                               const char            *type,
   1882 +                                                               const char            *display_type,
   1883 +                                                               GHashTable            *parameters,
   1884 +                                                               DBusGMethodInvocation *context);
   1885 +gboolean            ck_manager_remove_session                  (CkManager             *manager,
   1886 +                                                                const char            *ssid,
   1887 +                                                                DBusGMethodInvocation *context);
   1888 +
   1889  G_END_DECLS
   1890  
   1891  #endif /* __CK_MANAGER_H */
   1892 diff --git a/src/ck-marshal.list b/src/ck-marshal.list
   1893 index 7f60efc..f8029a6 100644
   1894 --- a/src/ck-marshal.list
   1895 +++ b/src/ck-marshal.list
   1896 @@ -1,3 +1,5 @@
   1897  VOID:UINT,STRING
   1898  BOOLEAN:POINTER
   1899 +VOID:STRING,STRING
   1900 +VOID:STRING,BOOLEAN,STRING,POINTER,STRING,POINTER
   1901  VOID:OBJECT,OBJECT
   1902 diff --git a/src/ck-seat.c b/src/ck-seat.c
   1903 index af7db59..c7b725a 100644
   1904 --- a/src/ck-seat.c
   1905 +++ b/src/ck-seat.c
   1906 @@ -40,21 +40,30 @@
   1907  #include "ck-seat-glue.h"
   1908  #include "ck-marshal.h"
   1909  
   1910 +#include "ck-display-template.h"
   1911  #include "ck-session.h"
   1912  #include "ck-vt-monitor.h"
   1913  #include "ck-run-programs.h"
   1914  
   1915  #define CK_SEAT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CK_TYPE_SEAT, CkSeatPrivate))
   1916  
   1917 +#define CK_SESSION_DIR SYSCONFDIR "/ConsoleKit/sessions.d"
   1918 +
   1919  #define CK_DBUS_PATH "/org/freedesktop/ConsoleKit"
   1920  #define CK_DBUS_NAME "org.freedesktop.ConsoleKit"
   1921  
   1922  #define NONULL_STRING(x) ((x) != NULL ? (x) : "")
   1923 +#define N_ELEMENTS(arr)  (sizeof (arr) / sizeof ((arr)[0]))
   1924 +
   1925 +#define IS_STR_SET(x) (x != NULL && x[0] != '\0')
   1926 +
   1927 +#define CK_DBUS_TYPE_G_STRING_STRING_HASHTABLE (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_STRING))
   1928  
   1929  struct CkSeatPrivate
   1930  {
   1931          char            *id;
   1932          CkSeatKind       kind;
   1933 +        char            *type;
   1934          GHashTable      *sessions;
   1935          GPtrArray       *devices;
   1936  
   1937 @@ -63,6 +72,8 @@ struct CkSeatPrivate
   1938          CkVtMonitor     *vt_monitor;
   1939  
   1940          DBusGConnection *connection;
   1941 +
   1942 +        DBusGProxy      *manager_proxy;
   1943  };
   1944  
   1945  enum {
   1946 @@ -74,6 +85,7 @@ enum {
   1947          SESSION_REMOVED_FULL,
   1948          DEVICE_ADDED,
   1949          DEVICE_REMOVED,
   1950 +        REMOVE_REQUEST,
   1951          LAST_SIGNAL
   1952  };
   1953  
   1954 @@ -81,6 +93,7 @@ enum {
   1955          PROP_0,
   1956          PROP_ID,
   1957          PROP_KIND,
   1958 +        PROP_TYPE
   1959  };
   1960  
   1961  static guint signals [LAST_SIGNAL] = { 0, };
   1962 @@ -287,6 +300,7 @@ ck_seat_activate_session (CkSeat                *seat,
   1963  {
   1964          CkSession *session;
   1965          gboolean   ret;
   1966 +        gboolean   is_open;
   1967  
   1968          g_return_val_if_fail (CK_IS_SEAT (seat), FALSE);
   1969  
   1970 @@ -298,12 +312,387 @@ ck_seat_activate_session (CkSeat                *seat,
   1971                  session = g_hash_table_lookup (seat->priv->sessions, ssid);
   1972          }
   1973  
   1974 -        ret = _seat_activate_session (seat, session, context);
   1975 +        ck_session_is_open (session, &is_open, NULL);
   1976 +        if (!is_open) {
   1977 +                ret = ck_seat_request_open_session (seat, session, NULL);
   1978 +                dbus_g_method_return (context, NULL);
   1979 +        } else {
   1980 +                ret = _seat_activate_session (seat, session, context);
   1981 +        }
   1982  
   1983          return ret;
   1984  }
   1985  
   1986  static gboolean
   1987 +on_substitution_match (const GMatchInfo *match_info,
   1988 +                       GString          *result,
   1989 +                       GHashTable       *substitution_variables)
   1990 +{
   1991 +        char *match;
   1992 +        char *value;
   1993 +
   1994 +        match = g_match_info_fetch (match_info, 1);
   1995 +
   1996 +        value = g_hash_table_lookup (substitution_variables, match);
   1997 +
   1998 +        if (value != NULL) {
   1999 +                g_string_append (result, value);
   2000 +        } else {
   2001 +                char *original_string;
   2002 +
   2003 +                original_string = g_match_info_fetch (match_info, 0);
   2004 +                g_string_append (result, original_string);
   2005 +                g_free (original_string);
   2006 +        }
   2007 +        g_free (match);
   2008 +
   2009 +        return FALSE;
   2010 +}
   2011 +
   2012 +static char *
   2013 +apply_substitutions (const char *value,
   2014 +                     GHashTable *substitution_variables)
   2015 +{
   2016 +        GRegex *expression;
   2017 +        char *expanded_string;
   2018 +
   2019 +        expression = g_regex_new ("\\$([^[:space:]]+)", 0, 0, NULL);
   2020 +        expanded_string = g_regex_replace_eval (expression,
   2021 +                                                value,
   2022 +                                                -1, 0, 0,
   2023 +                                                (GRegexEvalCallback)
   2024 +                                                on_substitution_match,
   2025 +                                                substitution_variables,
   2026 +                                                NULL);
   2027 +
   2028 +        if (expanded_string == NULL) {
   2029 +                expanded_string = g_strdup (value);
   2030 +        }
   2031 +
   2032 +        return expanded_string;
   2033 +}
   2034 +
   2035 +static GHashTable *
   2036 +get_evaluated_parameter_map (GHashTable    *parameters,
   2037 +                             GHashTable    *substitution_variables)
   2038 +{
   2039 +        GHashTable *evaluated_parameters;
   2040 +        GHashTableIter iter;
   2041 +        gpointer key, value;
   2042 +
   2043 +        evaluated_parameters = g_hash_table_new_full (g_str_hash, g_str_equal,
   2044 +                                                      (GDestroyNotify) g_free,
   2045 +                                                      (GDestroyNotify) g_free);
   2046 +
   2047 +        g_hash_table_iter_init (&iter, parameters);
   2048 +        while (g_hash_table_iter_next (&iter, &key, &value)) {
   2049 +                char *expanded_string;
   2050 +
   2051 +                expanded_string = apply_substitutions ((char *) value,
   2052 +                                                       substitution_variables);
   2053 +
   2054 +                g_hash_table_insert (evaluated_parameters,
   2055 +                                     g_strdup ((char *) key),
   2056 +                                     expanded_string);
   2057 +        }
   2058 +
   2059 +        return evaluated_parameters;
   2060 +}
   2061 +
   2062 +static void
   2063 +request_session (gpointer key,
   2064 +                 gpointer value,
   2065 +                 gpointer user_data)
   2066 +{
   2067 +        CkSeat      *seat = CK_SEAT (user_data);
   2068 +        CkSession   *session = (CkSession *) value;
   2069 +
   2070 +        ck_session_set_ever_open (session, FALSE, NULL);
   2071 +        ck_session_set_under_request (session, FALSE, NULL);
   2072 +        ck_seat_request_open_session (seat, session, NULL);
   2073 +}
   2074 +
   2075 +static void
   2076 +append_hash_table_to_dbus_message_iter (DBusMessageIter *iter,
   2077 +                                        GHashTable      *hash_table)
   2078 +{
   2079 +        GHashTableIter hash_table_iter;
   2080 +        gpointer key, value;
   2081 +        DBusMessageIter array_iter;
   2082 +
   2083 +        dbus_message_iter_open_container (iter,
   2084 +                                          DBUS_TYPE_ARRAY,
   2085 +                                          DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
   2086 +                                          DBUS_TYPE_STRING_AS_STRING
   2087 +                                          DBUS_TYPE_STRING_AS_STRING
   2088 +                                          DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
   2089 +                                          &array_iter);
   2090 +
   2091 +
   2092 +        g_hash_table_iter_init (&hash_table_iter, hash_table);
   2093 +        while (g_hash_table_iter_next (&hash_table_iter, &key, &value)) {
   2094 +                DBusMessageIter dict_iter;
   2095 +
   2096 +                dbus_message_iter_open_container (&array_iter,
   2097 +                                                  DBUS_TYPE_DICT_ENTRY,
   2098 +                                                  NULL,
   2099 +                                                  &dict_iter);
   2100 +
   2101 +                dbus_message_iter_append_basic (&dict_iter, DBUS_TYPE_STRING, &key);
   2102 +                dbus_message_iter_append_basic (&dict_iter, DBUS_TYPE_STRING, &value);
   2103 +                dbus_message_iter_close_container (&array_iter, &dict_iter);
   2104 +        }
   2105 +        dbus_message_iter_close_container (iter, &array_iter);
   2106 +}
   2107 +
   2108 +static void
   2109 +emit_session_open_request (CkSeat     *seat,
   2110 +                          const char *ssid,
   2111 +                          const char *session_type,
   2112 +                          const char *display_template_name,
   2113 +                          GHashTable *display_variables,
   2114 +                          const char *display_type,
   2115 +                          GHashTable *evaluated_parameters)
   2116 +{
   2117 +        DBusMessage    *message;
   2118 +        DBusConnection *connection;
   2119 +        DBusMessageIter iter;
   2120 +
   2121 +        message = dbus_message_new_signal (seat->priv->id,
   2122 +                                           "org.freedesktop.ConsoleKit.Seat",
   2123 +                                           "OpenSessionRequest");
   2124 +
   2125 +        dbus_message_set_destination (message,
   2126 +                                      dbus_g_proxy_get_bus_name (seat->priv->manager_proxy));
   2127 +
   2128 +        dbus_message_iter_init_append (message, &iter);
   2129 +        dbus_message_iter_append_basic (&iter, DBUS_TYPE_OBJECT_PATH, &ssid);
   2130 +        dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &session_type);
   2131 +        dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &display_template_name);
   2132 +        append_hash_table_to_dbus_message_iter (&iter, display_variables);
   2133 +        dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &display_type);
   2134 +        append_hash_table_to_dbus_message_iter (&iter, evaluated_parameters);
   2135 +
   2136 +        connection = dbus_bus_get (DBUS_BUS_SYSTEM, NULL);
   2137 +        dbus_connection_send (connection, message, NULL);
   2138 +        dbus_connection_unref (connection);
   2139 +        dbus_message_unref (message);
   2140 +}
   2141 +
   2142 +gboolean
   2143 +ck_seat_request_open_session (CkSeat                *seat,
   2144 +                              CkSession             *session,
   2145 +                              GError               **error)
   2146 +{
   2147 +        char        *ssid;
   2148 +        char        *type;
   2149 +        CkDisplayTemplate *display_template;
   2150 +        GHashTable  *display_variables;
   2151 +        GHashTable  *display_parameters;
   2152 +        GHashTable  *evaluated_parameters;
   2153 +        gboolean    is_open;
   2154 +        gboolean    ever_open;
   2155 +        gboolean    under_request;
   2156 +
   2157 +        ck_session_is_open (session, &is_open, NULL);
   2158 +
   2159 +        if (is_open) {
   2160 +                return TRUE;
   2161 +        }
   2162 +
   2163 +        ck_session_get_under_request (session, &under_request, NULL);
   2164 +        if (under_request) {
   2165 +                return TRUE;
   2166 +        }
   2167 +
   2168 +        ck_session_set_under_request (session, TRUE, NULL);
   2169 +
   2170 +        ck_session_get_ever_open (session, &ever_open, NULL);
   2171 +
   2172 +        display_template = ck_session_get_display_template (session);
   2173 +
   2174 +        if (display_template == NULL) {
   2175 +                return TRUE;
   2176 +        }
   2177 +
   2178 +        ck_session_get_session_type (session, &type, NULL);
   2179 +
   2180 +        if (type == NULL) {
   2181 +                g_object_unref (display_template);
   2182 +                return TRUE;
   2183 +        }
   2184 +
   2185 +        /* substitute $display $vt etc */
   2186 +        display_variables = ck_session_get_display_variables (session);
   2187 +        display_parameters = ck_display_template_get_parameters (display_template);
   2188 +
   2189 +        if (display_parameters == NULL) {
   2190 +                g_free (type);
   2191 +                g_object_unref (display_template);
   2192 +                g_hash_table_unref (display_variables);
   2193 +                return TRUE;
   2194 +        }
   2195 +
   2196 +        if (!ever_open) {
   2197 +                evaluated_parameters = get_evaluated_parameter_map (display_parameters, display_variables);
   2198 +        } else {
   2199 +                evaluated_parameters = get_evaluated_parameter_map (display_parameters, NULL);
   2200 +        }
   2201 +
   2202 +        g_hash_table_unref (display_parameters);
   2203 +
   2204 +        ck_session_get_id (session, &ssid, NULL);
   2205 +
   2206 +        emit_session_open_request (seat, ssid, type,
   2207 +                                   ck_display_template_get_name (display_template),
   2208 +                                   display_variables,
   2209 +                                   ck_display_template_get_type_string (display_template),
   2210 +                                   evaluated_parameters);
   2211 +
   2212 +        g_free (ssid);
   2213 +        g_free (type);
   2214 +        g_hash_table_unref (evaluated_parameters);
   2215 +        g_hash_table_unref (display_variables);
   2216 +        g_object_unref (display_template);
   2217 +
   2218 +        return TRUE;
   2219 +}
   2220 +
   2221 +static void
   2222 +on_seat_manager_disappeared (CkSeat *seat)
   2223 +{
   2224 +        g_signal_handlers_disconnect_by_func (seat->priv->manager_proxy,
   2225 +                                              G_CALLBACK (on_seat_manager_disappeared),
   2226 +                                              seat);
   2227 +        g_object_unref (seat->priv->manager_proxy);
   2228 +        seat->priv->manager_proxy = NULL;
   2229 +
   2230 +        /* FIXME: should probably emit a signal so a new display manager
   2231 +         * knows that the seat is now unmanaged
   2232 +         *
   2233 +         * (maybe only if its kind is static?)
   2234 +         */
   2235 +}
   2236 +
   2237 +gboolean
   2238 +ck_seat_manage (CkSeat                *seat,
   2239 +                DBusGMethodInvocation *context)
   2240 +{
   2241 +        char *sender_name;
   2242 +
   2243 +        sender_name = dbus_g_method_get_sender (context);
   2244 +
   2245 +        if (seat->priv->manager_proxy != NULL) {
   2246 +                GError *error;
   2247 +                const char   *existing_manager_name;
   2248 +
   2249 +                existing_manager_name = dbus_g_proxy_get_bus_name (seat->priv->manager_proxy);
   2250 +
   2251 +                if (existing_manager_name == NULL) {
   2252 +                        g_warning ("Seat manager lacks bus unique name");
   2253 +                        existing_manager_name = "<unknown>";
   2254 +                }
   2255 +
   2256 +                error = g_error_new (CK_SEAT_ERROR,
   2257 +                                     CK_SEAT_ERROR_GENERAL,
   2258 +                                     _("Seat already managed (by '%s')"),
   2259 +                                     existing_manager_name);
   2260 +
   2261 +                dbus_g_method_return_error (context, error);
   2262 +                g_error_free (error);
   2263 +                return FALSE;
   2264 +        }
   2265 +
   2266 +        /* FIXME: We pass in a bogus object path (the path we use on this side of
   2267 +         * the pipe) and interface here.
   2268 +         *
   2269 +         * We only use the proxy to watch for when the other side disappears, not
   2270 +         * for communicating with it.  All communication is one-way using signals.
   2271 +         */
   2272 +        seat->priv->manager_proxy = dbus_g_proxy_new_for_name (seat->priv->connection,
   2273 +
   2274 +                                                               sender_name,
   2275 +                                                               seat->priv->id,
   2276 +                                                               "org.freedesktop.ConsoleKit.SeatManager");
   2277 +        g_free (sender_name);
   2278 +
   2279 +        g_signal_connect_swapped (seat->priv->manager_proxy,
   2280 +                                  "destroy",
   2281 +                                  G_CALLBACK (on_seat_manager_disappeared),
   2282 +                                  seat);
   2283 +
   2284 +        g_hash_table_foreach (seat->priv->sessions, request_session, seat);
   2285 +
   2286 +        dbus_g_method_return (context);
   2287 +        return TRUE;
   2288 +}
   2289 +
   2290 +gboolean
   2291 +ck_seat_unmanage (CkSeat                *seat,
   2292 +                  DBusGMethodInvocation *context)
   2293 +{
   2294 +        GError *error;
   2295 +        const char   *existing_manager_name;
   2296 +        char *sender_name;
   2297 +
   2298 +        if (seat->priv->manager_proxy == NULL) {
   2299 +                GError *error;
   2300 +
   2301 +                error = g_error_new (CK_SEAT_ERROR,
   2302 +                                     CK_SEAT_ERROR_GENERAL,
   2303 +                                     _("Seat not managed"));
   2304 +
   2305 +                dbus_g_method_return_error (context, error);
   2306 +                g_error_free (error);
   2307 +                return FALSE;
   2308 +        }
   2309 +
   2310 +        sender_name = dbus_g_method_get_sender (context);
   2311 +        existing_manager_name = dbus_g_proxy_get_bus_name (seat->priv->manager_proxy);
   2312 +
   2313 +        if (strcmp (sender_name, existing_manager_name) != 0) {
   2314 +
   2315 +            error = g_error_new (CK_SEAT_ERROR,
   2316 +                                 CK_SEAT_ERROR_GENERAL,
   2317 +                                 _("Seat managed by '%s' not '%s'"),
   2318 +                                 existing_manager_name,
   2319 +                                 sender_name);
   2320 +
   2321 +            dbus_g_method_return_error (context, error);
   2322 +            g_error_free (error);
   2323 +
   2324 +            return FALSE;
   2325 +        }
   2326 +
   2327 +        on_seat_manager_disappeared (seat);
   2328 +
   2329 +        dbus_g_method_return (context);
   2330 +        return TRUE;
   2331 +}
   2332 +
   2333 +void
   2334 +ck_seat_request_removal (CkSeat *seat)
   2335 +{
   2336 +        DBusMessage    *message;
   2337 +        DBusConnection *connection;
   2338 +
   2339 +        g_return_if_fail (CK_IS_SEAT (seat));
   2340 +        g_return_if_fail (ck_seat_is_managed (seat));
   2341 +
   2342 +        message = dbus_message_new_signal (seat->priv->id,
   2343 +                                           "org.freedesktop.ConsoleKit.Seat",
   2344 +                                           "RemoveRequest");
   2345 +
   2346 +        dbus_message_set_destination (message,
   2347 +                                      dbus_g_proxy_get_bus_name (seat->priv->manager_proxy));
   2348 +
   2349 +        connection = dbus_bus_get (DBUS_BUS_SYSTEM, NULL);
   2350 +        dbus_connection_send (connection, message, NULL);
   2351 +        dbus_connection_unref (connection);
   2352 +        dbus_message_unref (message);
   2353 +}
   2354 +
   2355 +static gboolean
   2356  match_session_display_device (const char *key,
   2357                                CkSession  *session,
   2358                                const char *display_device)
   2359 @@ -526,6 +915,40 @@ change_active_session (CkSeat    *seat,
   2360  }
   2361  
   2362  static void
   2363 +find_possible_session_to_activate (CkSeat *seat)
   2364 +{
   2365 +        GHashTableIter iter;
   2366 +        gpointer       key, value;
   2367 +        gboolean       is_open;
   2368 +        char          *session_type = NULL;
   2369 +        CkSession     *login_session = NULL;
   2370 +
   2371 +        g_hash_table_iter_init (&iter, seat->priv->sessions);
   2372 +        while (g_hash_table_iter_next (&iter, &key, &value)) {
   2373 +
   2374 +                ck_session_is_open (value, &is_open, NULL);
   2375 +
   2376 +                if (is_open) {
   2377 +                        change_active_session (seat, value);
   2378 +                        break;
   2379 +                }
   2380 +
   2381 +                ck_session_get_session_type (value, &session_type, NULL);
   2382 +                if (IS_STR_SET (session_type) &&
   2383 +                    g_str_equal (session_type, "LoginWindow")) {
   2384 +                        login_session = value;
   2385 +                        g_free (session_type);
   2386 +                }
   2387 +        }
   2388 +
   2389 +        if (login_session != NULL) {
   2390 +                ck_session_set_ever_open (login_session, FALSE, NULL);
   2391 +                ck_seat_request_open_session (seat, login_session, NULL);
   2392 +        }
   2393 +
   2394 +}
   2395 +
   2396 +static void
   2397  update_active_vt (CkSeat *seat,
   2398                    guint   num)
   2399  {
   2400 @@ -537,7 +960,12 @@ update_active_vt (CkSeat *seat,
   2401          g_debug ("Active device: %s", device);
   2402  
   2403          session = find_session_for_display_device (seat, device);
   2404 -        change_active_session (seat, session);
   2405 +
   2406 +        if (session == NULL) {
   2407 +                find_possible_session_to_activate (seat);
   2408 +        } else {
   2409 +                change_active_session (seat, session);
   2410 +        }
   2411  
   2412          g_free (device);
   2413  }
   2414 @@ -628,18 +1056,77 @@ ck_seat_remove_session (CkSeat         *seat,
   2415          return ret;
   2416  }
   2417  
   2418 +static void
   2419 +emit_session_close_request (CkSeat     *seat,
   2420 +                            const char *ssid)
   2421 +{
   2422 +        DBusMessage    *message;
   2423 +        DBusConnection *connection;
   2424 +        DBusMessageIter iter;
   2425 +
   2426 +        message = dbus_message_new_signal (seat->priv->id,
   2427 +                                           "org.freedesktop.ConsoleKit.Seat",
   2428 +                                           "CloseSessionRequest");
   2429 +
   2430 +        dbus_message_set_destination (message,
   2431 +                                      dbus_g_proxy_get_bus_name (seat->priv->manager_proxy));
   2432 +
   2433 +        dbus_message_iter_init_append (message, &iter);
   2434 +        dbus_message_iter_append_basic (&iter, DBUS_TYPE_OBJECT_PATH, &ssid);
   2435 +
   2436 +        connection = dbus_bus_get (DBUS_BUS_SYSTEM, NULL);
   2437 +        dbus_connection_send (connection, message, NULL);
   2438 +        dbus_connection_unref (connection);
   2439 +        dbus_message_unref (message);
   2440 +}
   2441 +
   2442 +gboolean
   2443 +ck_seat_request_close_session (CkSeat                *seat,
   2444 +                               CkSession             *session,
   2445 +                               GError               **error)
   2446 +{
   2447 +        char      *ssid;
   2448 +
   2449 +        g_return_val_if_fail (CK_IS_SEAT (seat), FALSE);
   2450 +        g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
   2451 +        g_return_val_if_fail (ck_seat_is_managed (seat), FALSE);
   2452 +
   2453 +        ck_session_get_id (session, &ssid, NULL);
   2454 +
   2455 +        emit_session_close_request (seat, ssid);
   2456 +
   2457 +        g_free (ssid);
   2458 +
   2459 +        return FALSE;
   2460 +}
   2461 +
   2462  gboolean
   2463  ck_seat_add_session (CkSeat         *seat,
   2464                       CkSession      *session,
   2465                       GError        **error)
   2466  {
   2467          char *ssid;
   2468 +        GHashTableIter iter;
   2469 +        gpointer key, value;
   2470 +        gboolean found;
   2471  
   2472          g_return_val_if_fail (CK_IS_SEAT (seat), FALSE);
   2473  
   2474          ck_session_get_id (session, &ssid, NULL);
   2475  
   2476 -        g_hash_table_insert (seat->priv->sessions, g_strdup (ssid), g_object_ref (session));
   2477 +        found = FALSE;
   2478 +        g_hash_table_iter_init (&iter, seat->priv->sessions);
   2479 +        while (g_hash_table_iter_next (&iter, &key, &value)) {
   2480 +                if (g_str_equal ((gchar *)key, ssid)) {
   2481 +                        found = TRUE;
   2482 +                        break;
   2483 +                }
   2484 +        }
   2485 +
   2486 +        if (! found)
   2487 +                g_hash_table_insert (seat->priv->sessions, g_strdup (ssid), g_object_ref (session));
   2488 +        else
   2489 +                g_object_ref (session);
   2490  
   2491          ck_session_set_seat_id (session, seat->priv->id, NULL);
   2492  
   2493 @@ -656,6 +1143,10 @@ ck_seat_add_session (CkSeat         *seat,
   2494  
   2495          maybe_update_active_session (seat);
   2496  
   2497 +        if (ck_seat_is_managed (seat)) {
   2498 +                ck_seat_request_open_session (seat, session, NULL);
   2499 +        }
   2500 +
   2501          g_free (ssid);
   2502  
   2503          return TRUE;
   2504 @@ -742,6 +1233,20 @@ ck_seat_get_kind (CkSeat        *seat,
   2505  }
   2506  
   2507  gboolean
   2508 +ck_seat_get_type_string (CkSeat                *seat,
   2509 +                         char                 **type,
   2510 +                         GError               **error)
   2511 +{
   2512 +        g_return_val_if_fail (CK_IS_SEAT (seat), FALSE);
   2513 +
   2514 +        if (type != NULL) {
   2515 +                *type = g_strdup (seat->priv->type);
   2516 +        }
   2517 +
   2518 +        return TRUE;
   2519 +}
   2520 +
   2521 +gboolean
   2522  ck_seat_get_id (CkSeat         *seat,
   2523                  char          **id,
   2524                  GError        **error)
   2525 @@ -858,6 +1363,14 @@ _ck_seat_set_kind (CkSeat    *seat,
   2526  }
   2527  
   2528  static void
   2529 +_ck_seat_set_type_string (CkSeat         *seat,
   2530 +                          const char     *type)
   2531 +{
   2532 +        g_free (seat->priv->type);
   2533 +        seat->priv->type = g_strdup (type);
   2534 +}
   2535 +
   2536 +static void
   2537  ck_seat_set_property (GObject            *object,
   2538                        guint               prop_id,
   2539                        const GValue       *value,
   2540 @@ -874,6 +1387,9 @@ ck_seat_set_property (GObject            *object,
   2541          case PROP_KIND:
   2542                  _ck_seat_set_kind (self, g_value_get_enum (value));
   2543                  break;
   2544 +        case PROP_TYPE:
   2545 +                _ck_seat_set_type_string (self, g_value_get_string (value));
   2546 +                break;
   2547          default:
   2548                  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
   2549                  break;
   2550 @@ -895,7 +1411,10 @@ ck_seat_get_property (GObject    *object,
   2551                  g_value_set_string (value, self->priv->id);
   2552                  break;
   2553          case PROP_KIND:
   2554 -                g_value_set_string (value, self->priv->id);
   2555 +                g_value_set_enum (value, self->priv->kind);
   2556 +                break;
   2557 +        case PROP_TYPE:
   2558 +                g_value_set_string (value, self->priv->type);
   2559                  break;
   2560          default:
   2561                  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
   2562 @@ -1008,6 +1527,15 @@ ck_seat_class_init (CkSeatClass *klass)
   2563                                                   G_TYPE_NONE,
   2564                                                   1, CK_TYPE_DEVICE);
   2565  
   2566 +        signals [REMOVE_REQUEST] = g_signal_new ("remove-request",
   2567 +                                                  G_TYPE_FROM_CLASS (object_class),
   2568 +                                                  G_SIGNAL_RUN_LAST,
   2569 +                                                  G_STRUCT_OFFSET (CkSeatClass, remove_request),
   2570 +                                                  NULL,
   2571 +                                                  NULL,
   2572 +                                                  g_cclosure_marshal_VOID__VOID,
   2573 +                                                  G_TYPE_NONE, 0);
   2574 +
   2575          g_object_class_install_property (object_class,
   2576                                           PROP_ID,
   2577                                           g_param_spec_string ("id",
   2578 @@ -1024,6 +1552,13 @@ ck_seat_class_init (CkSeatClass *klass)
   2579                                                              CK_SEAT_KIND_DYNAMIC,
   2580                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
   2581  
   2582 +        g_object_class_install_property (object_class,
   2583 +                                         PROP_TYPE,
   2584 +                                         g_param_spec_string ("type",
   2585 +                                                              "type",
   2586 +                                                              "type",
   2587 +                                                              NULL,
   2588 +                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
   2589          g_type_class_add_private (klass, sizeof (CkSeatPrivate));
   2590  
   2591          dbus_g_object_type_install_info (CK_TYPE_SEAT, &dbus_glib_ck_seat_object_info);
   2592 @@ -1039,6 +1574,7 @@ ck_seat_init (CkSeat *seat)
   2593                                                        g_free,
   2594                                                        (GDestroyNotify) g_object_unref);
   2595          seat->priv->devices = g_ptr_array_new ();
   2596 +        seat->priv->manager_proxy = NULL;
   2597  }
   2598  
   2599  static void
   2600 @@ -1064,28 +1600,32 @@ ck_seat_finalize (GObject *object)
   2601          g_ptr_array_free (seat->priv->devices, TRUE);
   2602          g_hash_table_destroy (seat->priv->sessions);
   2603          g_free (seat->priv->id);
   2604 +        g_free (seat->priv->type);
   2605  
   2606          G_OBJECT_CLASS (ck_seat_parent_class)->finalize (object);
   2607  }
   2608  
   2609  CkSeat *
   2610  ck_seat_new (const char *sid,
   2611 -             CkSeatKind  kind)
   2612 +             CkSeatKind  kind,
   2613 +             const char *type)
   2614  {
   2615          GObject *object;
   2616  
   2617          object = g_object_new (CK_TYPE_SEAT,
   2618                                 "id", sid,
   2619                                 "kind", kind,
   2620 +                               "type", type,
   2621                                 NULL);
   2622  
   2623          return CK_SEAT (object);
   2624  }
   2625  
   2626  CkSeat *
   2627 -ck_seat_new_with_devices (const char *sid,
   2628 -                          CkSeatKind  kind,
   2629 -                          GPtrArray  *devices)
   2630 +ck_seat_new_with_devices_and_sessions (const char *sid,
   2631 +                                       CkSeatKind  kind,
   2632 +                                       GPtrArray  *devices,
   2633 +                                       GPtrArray  *sessions)
   2634  {
   2635          GObject *object;
   2636          int      i;
   2637 @@ -1100,24 +1640,57 @@ ck_seat_new_with_devices (const char *sid,
   2638                          ck_seat_add_device (CK_SEAT (object), g_ptr_array_index (devices, i), NULL);
   2639                  }
   2640          }
   2641 +        if (sessions != NULL) {
   2642 +                for (i = 0; i < sessions->len; i++) {
   2643 +                        ck_seat_add_session (CK_SEAT (object), g_ptr_array_index (sessions, i), NULL);
   2644 +                }
   2645 +        }
   2646 +
   2647  
   2648          return CK_SEAT (object);
   2649  }
   2650  
   2651 +static char *
   2652 +generate_static_session_id (const char *sid,
   2653 +                            const char *session_name)
   2654 +{
   2655 +        const char *seat_name;
   2656 +        char *ssid;
   2657 +
   2658 +        seat_name = strrchr (sid, '/');
   2659 +
   2660 +        if (seat_name == NULL) {
   2661 +                g_warning ("Seat id '%s' lacks a /", sid);
   2662 +                seat_name = sid;
   2663 +        } else {
   2664 +                seat_name++;
   2665 +        }
   2666 +
   2667 +        ssid = g_strdup_printf ("%s/Session%s%s",
   2668 +                                CK_DBUS_PATH, seat_name,
   2669 +                                session_name);
   2670 +
   2671 +        return ssid;
   2672 +}
   2673 +
   2674  CkSeat *
   2675 -ck_seat_new_from_file (const char *sid,
   2676 +ck_seat_new_from_file (char       **sid,
   2677                         const char *path)
   2678  {
   2679 -        GKeyFile  *key_file;
   2680 -        gboolean   res;
   2681 -        GError    *error;
   2682 -        char      *group;
   2683 -        CkSeat    *seat;
   2684 -        gboolean   hidden;
   2685 -        GPtrArray *devices;
   2686 -        char     **device_list;
   2687 -        gsize      ndevices;
   2688 -        gsize      i;
   2689 +        GKeyFile      *key_file;
   2690 +        gboolean       res;
   2691 +        GError        *error;
   2692 +        char          *group;
   2693 +        CkSeat        *seat;
   2694 +        char          *read_sid;
   2695 +        gboolean       hidden;
   2696 +        GPtrArray     *sessions;
   2697 +        char         **session_list;
   2698 +        gsize          nsessions;
   2699 +        GPtrArray     *devices;
   2700 +        char         **device_list;
   2701 +        gsize          ndevices;
   2702 +        gsize          i;
   2703  
   2704          seat = NULL;
   2705  
   2706 @@ -1145,6 +1718,49 @@ ck_seat_new_from_file (const char *sid,
   2707                  goto out;
   2708          }
   2709  
   2710 +        read_sid = g_key_file_get_string (key_file, group, "ID", NULL);
   2711 +        if (IS_STR_SET (read_sid)) {
   2712 +                g_free (*sid);
   2713 +                *sid = g_strdup_printf ("%s/%s", CK_DBUS_PATH, read_sid);
   2714 +        } else {
   2715 +                g_free (read_sid);
   2716 +        }
   2717 +
   2718 +        session_list = g_key_file_get_string_list (key_file, group, "Sessions", &nsessions, NULL);
   2719 +
   2720 +        sessions = g_ptr_array_sized_new (nsessions);
   2721 +
   2722 +        for (i = 0; i < nsessions; i++) {
   2723 +                char *path;
   2724 +                char *file;
   2725 +                char *ssid;
   2726 +                CkSession *session;
   2727 +
   2728 +                file = g_strconcat (session_list[i], ".session", NULL);
   2729 +                path = g_build_filename (CK_SESSION_DIR, file, NULL);
   2730 +                g_free (file);
   2731 +
   2732 +                /* FIXME: we should probably use the same naming pool as
   2733 +                 * sessions generated from ck-manager.  We mangle the name
   2734 +                 * here so we don't clash with names from ck-manager
   2735 +                 */
   2736 +                ssid = generate_static_session_id (*sid, session_list[i]);
   2737 +
   2738 +                session = ck_session_new_from_file (ssid, path);
   2739 +
   2740 +                if (session == NULL) {
   2741 +                        g_warning ("Unable to load session from file %s", path);
   2742 +                        g_free (path);
   2743 +                        continue;
   2744 +                }
   2745 +                g_free (path);
   2746 +                ck_session_set_seat_id (session, *sid, NULL);
   2747 +
   2748 +                g_ptr_array_add (sessions, session);
   2749 +        }
   2750 +
   2751 +        g_strfreev (session_list);
   2752 +
   2753          device_list = g_key_file_get_string_list (key_file, group, "Devices", &ndevices, NULL);
   2754  
   2755          g_debug ("Creating seat %s with %zd devices", sid, ndevices);
   2756 @@ -1176,11 +1792,12 @@ ck_seat_new_from_file (const char *sid,
   2757                  g_strfreev (split);
   2758          }
   2759          g_strfreev (device_list);
   2760 -        g_free (group);
   2761  
   2762 -        seat = ck_seat_new_with_devices (sid, CK_SEAT_KIND_STATIC, devices);
   2763 +        seat = ck_seat_new_with_devices_and_sessions (*sid, CK_SEAT_KIND_STATIC, devices, sessions);
   2764          g_ptr_array_free (devices, TRUE);
   2765  
   2766 +        g_free (group);
   2767 +
   2768  out:
   2769  
   2770          g_key_file_free (key_file);
   2771 @@ -1370,3 +1987,24 @@ ck_seat_dump (CkSeat   *seat,
   2772  
   2773          g_free (group_name);
   2774  }
   2775 +
   2776 +gboolean
   2777 +ck_seat_is_managed (CkSeat *seat)
   2778 +{
   2779 +        return seat->priv->manager_proxy != NULL;
   2780 +}
   2781 +
   2782 +CkSession *
   2783 +ck_seat_get_session (CkSeat                *seat,
   2784 +                     const char            *ssid)
   2785 +{
   2786 +        CkSession *session;
   2787 +
   2788 +        session = g_hash_table_lookup (seat->priv->sessions, ssid);
   2789 +
   2790 +        if (session == NULL) {
   2791 +                return NULL;
   2792 +        }
   2793 +
   2794 +        return g_object_ref (session);
   2795 +}
   2796 diff --git a/src/ck-seat.h b/src/ck-seat.h
   2797 index fb9a955..6276021 100644
   2798 --- a/src/ck-seat.h
   2799 +++ b/src/ck-seat.h
   2800 @@ -47,6 +47,7 @@ typedef struct
   2801  {
   2802          GObjectClass   parent_class;
   2803  
   2804 +        void          (* remove_request)         (CkSeat      *seat);
   2805          void          (* active_session_changed) (CkSeat      *seat,
   2806                                                    const char  *ssid);
   2807          void          (* session_added)          (CkSeat      *seat,
   2808 @@ -57,6 +58,11 @@ typedef struct
   2809                                                    GValueArray *device);
   2810          void          (* device_removed)         (CkSeat      *seat,
   2811                                                    GValueArray *device);
   2812 +        void          (* session_to_add)         (CkSeat      *seat,
   2813 +                                                  gboolean     is_dynamic,
   2814 +                                                  const char  *command);
   2815 +        void          (* session_to_remove)      (CkSeat      *seat,
   2816 +                                                  int          display_number);
   2817  } CkSeatClass;
   2818  
   2819  typedef enum
   2820 @@ -84,12 +90,14 @@ typedef enum
   2821  GQuark              ck_seat_error_quark         (void);
   2822  GType               ck_seat_get_type            (void);
   2823  CkSeat            * ck_seat_new                 (const char            *sid,
   2824 -                                                 CkSeatKind             kind);
   2825 -CkSeat            * ck_seat_new_from_file       (const char            *sid,
   2826 -                                                 const char            *path);
   2827 -CkSeat            * ck_seat_new_with_devices    (const char            *sid,
   2828                                                   CkSeatKind             kind,
   2829 -                                                 GPtrArray             *devices);
   2830 +                                                 const char            *type);
   2831 +CkSeat            * ck_seat_new_from_file       (char                 **sid,
   2832 +                                                 const char            *path);
   2833 +CkSeat            * ck_seat_new_with_devices_and_sessions    (const char            *sid,
   2834 +                                                              CkSeatKind             kind,
   2835 +                                                              GPtrArray             *devices,
   2836 +                                                              GPtrArray             *sessions);
   2837  
   2838  gboolean            ck_seat_register            (CkSeat                *seat);
   2839  
   2840 @@ -104,18 +112,31 @@ void                ck_seat_dump                (CkSeat                *seat,
   2841  gboolean            ck_seat_get_kind            (CkSeat                *seat,
   2842                                                   CkSeatKind            *kind,
   2843                                                   GError               **error);
   2844 +gboolean            ck_seat_get_type_string     (CkSeat                *seat,
   2845 +                                                 char                 **type,
   2846 +                                                 GError               **error);
   2847  gboolean            ck_seat_add_session         (CkSeat                *seat,
   2848                                                   CkSession             *session,
   2849                                                   GError               **error);
   2850  gboolean            ck_seat_remove_session      (CkSeat                *seat,
   2851                                                   CkSession             *session,
   2852                                                   GError               **error);
   2853 +gboolean            ck_seat_request_open_session (CkSeat                *seat,
   2854 +                                                  CkSession             *session,
   2855 +                                                  GError               **error);
   2856 +gboolean            ck_seat_request_close_session (CkSeat                *seat,
   2857 +                                                   CkSession             *session,
   2858 +                                                   GError               **error);
   2859  gboolean            ck_seat_add_device          (CkSeat                *seat,
   2860                                                   GValueArray           *device,
   2861                                                   GError               **error);
   2862  gboolean            ck_seat_remove_device       (CkSeat                *seat,
   2863                                                   GValueArray           *device,
   2864                                                   GError               **error);
   2865 +gboolean            ck_seat_is_managed          (CkSeat                *seat);
   2866 +CkSession          *ck_seat_get_session         (CkSeat                *seat,
   2867 +                                                 const char            *ssid);
   2868 +void                ck_seat_request_removal     (CkSeat                *seat);
   2869  
   2870  /* exported methods */
   2871  gboolean            ck_seat_get_id                (CkSeat                *seat,
   2872 @@ -137,6 +158,10 @@ gboolean            ck_seat_can_activate_sessions (CkSeat                *seat,
   2873  gboolean            ck_seat_activate_session      (CkSeat                *seat,
   2874                                                     const char            *ssid,
   2875                                                     DBusGMethodInvocation *context);
   2876 +gboolean            ck_seat_manage                (CkSeat                *seat,
   2877 +                                                   DBusGMethodInvocation *context);
   2878 +gboolean            ck_seat_unmanage              (CkSeat                *seat,
   2879 +                                                   DBusGMethodInvocation *context);
   2880  
   2881  G_END_DECLS
   2882  
   2883 diff --git a/src/ck-session-leader.c b/src/ck-session-leader.c
   2884 index 3702602..908d2bb 100644
   2885 --- a/src/ck-session-leader.c
   2886 +++ b/src/ck-session-leader.c
   2887 @@ -238,6 +238,7 @@ static struct {
   2888          { "x11-display",        add_param_string },
   2889          { "remote-host-name",   add_param_string },
   2890          { "session-type",       add_param_string },
   2891 +        { "display-type",       add_param_string },
   2892          { "is-local",           add_param_boolean },
   2893          { "unix-user",          add_param_int },
   2894  };
   2895 diff --git a/src/ck-session.c b/src/ck-session.c
   2896 index d8db9dd..aa53bf0 100644
   2897 --- a/src/ck-session.c
   2898 +++ b/src/ck-session.c
   2899 @@ -41,6 +41,7 @@
   2900  #include "ck-session-glue.h"
   2901  #include "ck-marshal.h"
   2902  #include "ck-run-programs.h"
   2903 +#include "ck-display-template.h"
   2904  
   2905  #define CK_SESSION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CK_TYPE_SESSION, CkSessionPrivate))
   2906  
   2907 @@ -58,6 +59,7 @@ struct CkSessionPrivate
   2908          char            *seat_id;
   2909  
   2910          char            *session_type;
   2911 +        char            *display_type;
   2912          char            *login_session_id;
   2913          char            *display_device;
   2914          char            *x11_display_device;
   2915 @@ -65,8 +67,15 @@ struct CkSessionPrivate
   2916          char            *remote_host_name;
   2917          guint            uid;
   2918  
   2919 +        CkDisplayTemplate *display_template;
   2920 +        GHashTable      *display_variables;
   2921 +
   2922          gboolean         active;
   2923          gboolean         is_local;
   2924 +        gboolean         is_open;
   2925 +        gboolean         ever_open;
   2926 +        gboolean         under_request;
   2927 +        GMutex          *mutex_under_request;
   2928  
   2929          GTimeVal         creation_time;
   2930  
   2931 @@ -75,6 +84,8 @@ struct CkSessionPrivate
   2932          gboolean         idle_hint;
   2933          GTimeVal         idle_since_hint;
   2934  
   2935 +        gboolean         remove_on_close;
   2936 +
   2937          DBusGConnection *connection;
   2938          DBusGProxy      *bus_proxy;
   2939  };
   2940 @@ -92,17 +103,24 @@ enum {
   2941          PROP_0,
   2942          PROP_ID,
   2943          PROP_COOKIE,
   2944 +        PROP_SEAT_ID,
   2945          PROP_USER,
   2946          PROP_UNIX_USER,
   2947          PROP_X11_DISPLAY,
   2948          PROP_X11_DISPLAY_DEVICE,
   2949          PROP_DISPLAY_DEVICE,
   2950          PROP_SESSION_TYPE,
   2951 +        PROP_DISPLAY_TYPE,
   2952 +        PROP_DISPLAY_TEMPLATE,
   2953 +        PROP_DISPLAY_VARIABLES,
   2954          PROP_REMOTE_HOST_NAME,
   2955          PROP_LOGIN_SESSION_ID,
   2956          PROP_IS_LOCAL,
   2957 +        PROP_IS_OPEN,
   2958 +        PROP_EVER_OPEN,
   2959          PROP_ACTIVE,
   2960          PROP_IDLE_HINT,
   2961 +        PROP_REMOVE_ON_CLOSE,
   2962  };
   2963  
   2964  static guint signals [LAST_SIGNAL] = { 0, };
   2965 @@ -128,6 +146,7 @@ static gboolean
   2966  register_session (CkSession *session)
   2967  {
   2968          GError *error = NULL;
   2969 +        GObject *existing_session;
   2970  
   2971          error = NULL;
   2972          session->priv->connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
   2973 @@ -144,6 +163,15 @@ register_session (CkSession *session)
   2974                                                                DBUS_PATH_DBUS,
   2975                                                                DBUS_INTERFACE_DBUS);
   2976  
   2977 +        existing_session = dbus_g_connection_lookup_g_object (session->priv->connection,
   2978 +                                                              session->priv->id);
   2979 +
   2980 +        if (existing_session != NULL) {
   2981 +                g_warning ("Session '%s' was registered twice!",
   2982 +                           session->priv->id);
   2983 +                return FALSE;
   2984 +        }
   2985 +
   2986          dbus_g_connection_register_g_object (session->priv->connection, session->priv->id, G_OBJECT (session));
   2987  
   2988          return TRUE;
   2989 @@ -302,6 +330,35 @@ ck_session_set_idle_hint (CkSession             *session,
   2990  }
   2991  
   2992  gboolean
   2993 +session_set_remove_on_close (CkSession      *session,
   2994 +                             gboolean        remove_on_close,
   2995 +                             GError        **error)
   2996 +{
   2997 +        g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
   2998 +
   2999 +        if (session->priv->remove_on_close != remove_on_close) {
   3000 +                session->priv->remove_on_close = remove_on_close;
   3001 +        }
   3002 +
   3003 +        return TRUE;
   3004 +}
   3005 +
   3006 +/*
   3007 +  Example:
   3008 +  dbus-send --system --dest=org.freedesktop.ConsoleKit \
   3009 +  --type=method_call --print-reply --reply-timeout=2000 \
   3010 +  /org/freedesktop/ConsoleKit/Session1 \
   3011 +  org.freedesktop.ConsoleKit.Session.SetRemoveOnClose boolean:TRUE
   3012 +*/
   3013 +gboolean
   3014 +ck_session_set_remove_on_close (CkSession             *session,
   3015 +                                gboolean               remove_on_close,
   3016 +                                DBusGMethodInvocation *context)
   3017 +{
   3018 +        return session_set_remove_on_close (session, remove_on_close, NULL);
   3019 +}
   3020 +
   3021 +gboolean
   3022  ck_session_get_idle_hint (CkSession *session,
   3023                            gboolean  *idle_hint,
   3024                            GError   **error)
   3025 @@ -420,6 +477,68 @@ ck_session_set_is_local (CkSession      *session,
   3026  }
   3027  
   3028  gboolean
   3029 +ck_session_set_is_open (CkSession    *session,
   3030 +                        gboolean      is_open,
   3031 +                        GError      **error)
   3032 +{
   3033 +        g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
   3034 +
   3035 +        if (session->priv->is_open != is_open) {
   3036 +                session->priv->is_open = is_open;
   3037 +                session->priv->ever_open = TRUE;
   3038 +        }
   3039 +
   3040 +        return TRUE;
   3041 +}
   3042 +
   3043 +gboolean
   3044 +ck_session_set_ever_open (CkSession    *session,
   3045 +                          gboolean      ever_open,
   3046 +                          GError      **error)
   3047 +{
   3048 +        g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
   3049 +
   3050 +        if (session->priv->ever_open != ever_open) {
   3051 +                session->priv->ever_open = ever_open;
   3052 +        }
   3053 +
   3054 +        return TRUE;
   3055 +}
   3056 +
   3057 +static gboolean
   3058 +timeout_for_under_request (gpointer data)
   3059 +{
   3060 +        CkSession *session = CK_SESSION (data);
   3061 +        g_mutex_lock (session->priv->mutex_under_request);
   3062 +        session->priv->under_request = FALSE;
   3063 +        g_mutex_unlock (session->priv->mutex_under_request);
   3064 +
   3065 +        g_debug ("timeout for under request of session %s", session->priv->id);
   3066 +        return FALSE;
   3067 +}
   3068 +
   3069 +gboolean
   3070 +ck_session_set_under_request (CkSession    *session,
   3071 +                              gboolean      under_request,
   3072 +                              GError      **error)
   3073 +{
   3074 +        g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
   3075 +
   3076 +        g_mutex_lock (session->priv->mutex_under_request);
   3077 +        if (!under_request) {
   3078 +                session->priv->under_request = FALSE;
   3079 +        } else {
   3080 +                if (!session->priv->under_request) {
   3081 +                        session->priv->under_request = TRUE;
   3082 +                        g_timeout_add_seconds (1, timeout_for_under_request, session);
   3083 +                }
   3084 +        }
   3085 +        g_mutex_unlock (session->priv->mutex_under_request);
   3086 +
   3087 +        return TRUE;
   3088 +}
   3089 +
   3090 +gboolean
   3091  ck_session_get_id (CkSession      *session,
   3092                     char          **id,
   3093                     GError        **error)
   3094 @@ -555,6 +674,20 @@ ck_session_get_creation_time (CkSession      *session,
   3095  }
   3096  
   3097  gboolean
   3098 +ck_session_get_remove_on_close (CkSession   *session,
   3099 +                                gboolean    *remove_on_close,
   3100 +                                GError     **error)
   3101 +{
   3102 +        g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
   3103 +
   3104 +        if (remove_on_close != NULL) {
   3105 +                *remove_on_close = session->priv->remove_on_close;
   3106 +        }
   3107 +
   3108 +        return TRUE;
   3109 +}
   3110 +
   3111 +gboolean
   3112  ck_session_get_session_type (CkSession      *session,
   3113                               char          **type,
   3114                               GError        **error)
   3115 @@ -569,6 +702,20 @@ ck_session_get_session_type (CkSession      *session,
   3116  }
   3117  
   3118  gboolean
   3119 +ck_session_get_display_type (CkSession      *session,
   3120 +                             char          **type,
   3121 +                             GError        **error)
   3122 +{
   3123 +        g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
   3124 +
   3125 +        if (type != NULL) {
   3126 +                *type = g_strdup (session->priv->display_type);
   3127 +        }
   3128 +
   3129 +        return TRUE;
   3130 +}
   3131 +
   3132 +gboolean
   3133  ck_session_is_active (CkSession      *session,
   3134                        gboolean       *active,
   3135                        GError        **error)
   3136 @@ -597,6 +744,50 @@ ck_session_is_local (CkSession      *session,
   3137  }
   3138  
   3139  gboolean
   3140 +ck_session_is_open (CkSession      *session,
   3141 +                    gboolean       *open,
   3142 +                    GError        **error)
   3143 +{
   3144 +        g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
   3145 +
   3146 +        if (open != NULL) {
   3147 +                *open = session->priv->is_open;
   3148 +        }
   3149 +
   3150 +        return TRUE;
   3151 +}
   3152 +
   3153 +gboolean
   3154 +ck_session_get_ever_open (CkSession      *session,
   3155 +                          gboolean       *open,
   3156 +                          GError        **error)
   3157 +{
   3158 +        g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
   3159 +
   3160 +        if (open != NULL) {
   3161 +                *open = session->priv->ever_open;
   3162 +        }
   3163 +
   3164 +        return TRUE;
   3165 +}
   3166 +
   3167 +gboolean
   3168 +ck_session_get_under_request (CkSession      *session,
   3169 +                              gboolean       *under_request,
   3170 +                              GError        **error)
   3171 +{
   3172 +        g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
   3173 +
   3174 +        if (under_request != NULL) {
   3175 +                g_mutex_lock (session->priv->mutex_under_request);
   3176 +                *under_request = session->priv->under_request;
   3177 +                g_mutex_unlock (session->priv->mutex_under_request);
   3178 +        }
   3179 +
   3180 +        return TRUE;
   3181 +}
   3182 +
   3183 +gboolean
   3184  ck_session_set_id (CkSession      *session,
   3185                     const char     *id,
   3186                     GError        **error)
   3187 @@ -609,6 +800,21 @@ ck_session_set_id (CkSession      *session,
   3188          return TRUE;
   3189  }
   3190  
   3191 +static void
   3192 +ck_session_set_display_variables (CkSession  *session,
   3193 +                                  GHashTable *display_variables)
   3194 +{
   3195 +        if (session->priv->display_variables != NULL) {
   3196 +                g_hash_table_unref (session->priv->display_variables);
   3197 +        }
   3198 +
   3199 +        if (display_variables != NULL) {
   3200 +                session->priv->display_variables = g_hash_table_ref (display_variables);
   3201 +        } else {
   3202 +                session->priv->display_variables = NULL;
   3203 +        }
   3204 +}
   3205 +
   3206  gboolean
   3207  ck_session_set_cookie (CkSession      *session,
   3208                         const char     *cookie,
   3209 @@ -725,6 +931,54 @@ ck_session_set_session_type (CkSession      *session,
   3210          return TRUE;
   3211  }
   3212  
   3213 +gboolean
   3214 +ck_session_set_display_type (CkSession      *session,
   3215 +                             const char     *type,
   3216 +                             GError        **error)
   3217 +{
   3218 +        g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
   3219 +
   3220 +        g_free (session->priv->display_type);
   3221 +        session->priv->display_type = g_strdup (type);
   3222 +
   3223 +        return TRUE;
   3224 +}
   3225 +
   3226 +static gboolean
   3227 +ck_session_set_display_template (CkSession      *session,
   3228 +                             CkDisplayTemplate  *display_template,
   3229 +                             GError        **error)
   3230 +{
   3231 +        g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
   3232 +
   3233 +        if (session->priv->display_template != NULL) {
   3234 +                g_object_unref (session->priv->display_template);
   3235 +        }
   3236 +
   3237 +        if (display_template != NULL) {
   3238 +                session->priv->display_template = g_object_ref (display_template);
   3239 +                ck_session_set_display_type (session, ck_display_template_get_name (display_template), error);
   3240 +        } else {
   3241 +                session->priv->display_template = NULL;
   3242 +        }
   3243 +
   3244 +        return TRUE;
   3245 +}
   3246 +
   3247 +GHashTable *
   3248 +ck_session_get_display_variables (CkSession *session)
   3249 +{
   3250 +        return g_hash_table_ref (session->priv->display_variables);
   3251 +}
   3252 +
   3253 +CkDisplayTemplate *
   3254 +ck_session_get_display_template (CkSession      *session)
   3255 +{
   3256 +        g_return_val_if_fail (CK_IS_SESSION (session), FALSE);
   3257 +
   3258 +        return g_object_ref (session->priv->display_template);
   3259 +}
   3260 +
   3261  static void
   3262  ck_session_set_property (GObject            *object,
   3263                           guint               prop_id,
   3264 @@ -742,15 +996,33 @@ ck_session_set_property (GObject            *object,
   3265          case PROP_IS_LOCAL:
   3266                  ck_session_set_is_local (self, g_value_get_boolean (value), NULL);
   3267                  break;
   3268 +        case PROP_IS_OPEN:
   3269 +                ck_session_set_is_open (self, g_value_get_boolean (value), NULL);
   3270 +                break;
   3271 +        case PROP_EVER_OPEN:
   3272 +                ck_session_set_ever_open (self, g_value_get_boolean (value), NULL);
   3273 +                break;
   3274          case PROP_ID:
   3275                  ck_session_set_id (self, g_value_get_string (value), NULL);
   3276                  break;
   3277          case PROP_COOKIE:
   3278                  ck_session_set_cookie (self, g_value_get_string (value), NULL);
   3279                  break;
   3280 +        case PROP_SEAT_ID:
   3281 +                ck_session_set_seat_id (self, g_value_get_string (value), NULL);
   3282 +                break;
   3283          case PROP_SESSION_TYPE:
   3284                  ck_session_set_session_type (self, g_value_get_string (value), NULL);
   3285                  break;
   3286 +        case PROP_DISPLAY_TYPE:
   3287 +                ck_session_set_display_type (self, g_value_get_string (value), NULL);
   3288 +                break;
   3289 +        case PROP_DISPLAY_TEMPLATE:
   3290 +                ck_session_set_display_template (self, g_value_get_object (value), NULL);
   3291 +                break;
   3292 +        case PROP_DISPLAY_VARIABLES:
   3293 +                ck_session_set_display_variables (self, g_value_get_boxed (value));
   3294 +                break;
   3295          case PROP_X11_DISPLAY:
   3296                  ck_session_set_x11_display (self, g_value_get_string (value), NULL);
   3297                  break;
   3298 @@ -775,6 +1047,9 @@ ck_session_set_property (GObject            *object,
   3299          case PROP_IDLE_HINT:
   3300                  session_set_idle_hint_internal (self, g_value_get_boolean (value));
   3301                  break;
   3302 +        case PROP_REMOVE_ON_CLOSE:
   3303 +                session_set_remove_on_close (self, g_value_get_boolean (value), NULL);
   3304 +                break;
   3305          default:
   3306                  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
   3307                  break;
   3308 @@ -798,15 +1073,33 @@ ck_session_get_property (GObject    *object,
   3309          case PROP_IS_LOCAL:
   3310                  g_value_set_boolean (value, self->priv->is_local);
   3311                  break;
   3312 +        case PROP_IS_OPEN:
   3313 +                g_value_set_boolean (value, self->priv->is_open);
   3314 +                break;
   3315 +        case PROP_EVER_OPEN:
   3316 +                g_value_set_boolean (value, self->priv->ever_open);
   3317 +                break;
   3318          case PROP_ID:
   3319                  g_value_set_string (value, self->priv->id);
   3320                  break;
   3321          case PROP_COOKIE:
   3322                  g_value_set_string (value, self->priv->cookie);
   3323                  break;
   3324 +        case PROP_SEAT_ID:
   3325 +                g_value_set_string (value, self->priv->seat_id);
   3326 +                break;
   3327          case PROP_SESSION_TYPE:
   3328                  g_value_set_string (value, self->priv->session_type);
   3329                  break;
   3330 +        case PROP_DISPLAY_TYPE:
   3331 +                g_value_set_string (value, self->priv->display_type);
   3332 +                break;
   3333 +        case PROP_DISPLAY_TEMPLATE:
   3334 +                g_value_set_object (value, self->priv->display_template);
   3335 +                break;
   3336 +        case PROP_DISPLAY_VARIABLES:
   3337 +                g_value_set_boxed (value, self->priv->display_variables);
   3338 +                break;
   3339          case PROP_X11_DISPLAY:
   3340                  g_value_set_string (value, self->priv->x11_display);
   3341                  break;
   3342 @@ -831,6 +1124,9 @@ ck_session_get_property (GObject    *object,
   3343          case PROP_IDLE_HINT:
   3344                  g_value_set_boolean (value, self->priv->idle_hint);
   3345                  break;
   3346 +        case PROP_REMOVE_ON_CLOSE:
   3347 +                g_value_set_boolean (value, self->priv->remove_on_close);
   3348 +                break;
   3349          default:
   3350                  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
   3351                  break;
   3352 @@ -1000,6 +1296,13 @@ ck_session_class_init (CkSessionClass *klass)
   3353                                                                "cookie",
   3354                                                                NULL,
   3355                                                                G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
   3356 +        g_object_class_install_property (object_class,
   3357 +                                         PROP_SEAT_ID,
   3358 +                                         g_param_spec_string ("seat-id",
   3359 +                                                              "seat id",
   3360 +                                                              "seat id",
   3361 +                                                              NULL,
   3362 +                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
   3363  
   3364          g_object_class_install_property (object_class,
   3365                                           PROP_SESSION_TYPE,
   3366 @@ -1009,6 +1312,27 @@ ck_session_class_init (CkSessionClass *klass)
   3367                                                                NULL,
   3368                                                                G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
   3369          g_object_class_install_property (object_class,
   3370 +                                         PROP_DISPLAY_TYPE,
   3371 +                                         g_param_spec_string ("display-type",
   3372 +                                                              "session-type",
   3373 +                                                              "session type",
   3374 +                                                              NULL,
   3375 +                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
   3376 +        g_object_class_install_property (object_class,
   3377 +                                         PROP_DISPLAY_TEMPLATE,
   3378 +                                         g_param_spec_object ("display-template",
   3379 +                                                              "Display Template",
   3380 +                                                              "The display template",
   3381 +                                                              CK_TYPE_DISPLAY_TEMPLATE,
   3382 +                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
   3383 +        g_object_class_install_property (object_class,
   3384 +                                         PROP_DISPLAY_VARIABLES,
   3385 +                                         g_param_spec_boxed ("display-variables",
   3386 +                                                             "Display Variables",
   3387 +                                                             "Display type specific variables",
   3388 +                                                             G_TYPE_HASH_TABLE,
   3389 +                                                             G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
   3390 +        g_object_class_install_property (object_class,
   3391                                           PROP_LOGIN_SESSION_ID,
   3392                                           g_param_spec_string ("login-session-id",
   3393                                                                "login-session-id",
   3394 @@ -1070,6 +1394,13 @@ ck_session_class_init (CkSessionClass *klass)
   3395                                                                 NULL,
   3396                                                                 FALSE,
   3397                                                                 G_PARAM_READWRITE));
   3398 +        g_object_class_install_property (object_class,
   3399 +                                         PROP_REMOVE_ON_CLOSE,
   3400 +                                         g_param_spec_boolean ("remove-on-close",
   3401 +                                                               NULL,
   3402 +                                                               NULL,
   3403 +                                                               FALSE,
   3404 +                                                               G_PARAM_READWRITE));
   3405  
   3406          g_type_class_add_private (klass, sizeof (CkSessionPrivate));
   3407  
   3408 @@ -1081,8 +1412,16 @@ ck_session_init (CkSession *session)
   3409  {
   3410          session->priv = CK_SESSION_GET_PRIVATE (session);
   3411  
   3412 +        session->priv->display_variables = g_hash_table_new_full (g_str_hash,
   3413 +                                                                  g_str_equal,
   3414 +                                                                  (GDestroyNotify) g_free,
   3415 +                                                                  (GDestroyNotify) g_free);
   3416 +
   3417          /* FIXME: should we have a property for this? */
   3418          g_get_current_time (&session->priv->creation_time);
   3419 +
   3420 +        if (!session->priv->mutex_under_request)
   3421 +                session->priv->mutex_under_request = g_mutex_new ();
   3422  }
   3423  
   3424  static void
   3425 @@ -1105,6 +1444,7 @@ ck_session_finalize (GObject *object)
   3426          g_free (session->priv->cookie);
   3427          g_free (session->priv->seat_id);
   3428          g_free (session->priv->session_type);
   3429 +        g_free (session->priv->display_type);
   3430          g_free (session->priv->x11_display);
   3431          g_free (session->priv->display_device);
   3432          g_free (session->priv->x11_display_device);
   3433 @@ -1114,16 +1454,135 @@ ck_session_finalize (GObject *object)
   3434  }
   3435  
   3436  CkSession *
   3437 +ck_session_new_from_file (const char *ssid,
   3438 +                          const char *path)
   3439 +{
   3440 +        GKeyFile  *key_file;
   3441 +        gboolean   res;
   3442 +        GError    *error;
   3443 +        char      *group;
   3444 +        char      *name;
   3445 +        gboolean   hidden;
   3446 +        char      *type;
   3447 +        char      *display_template_string;
   3448 +        CkSession *session;
   3449 +        GHashTable *display_variables;
   3450 +        char     **type_keys;
   3451 +
   3452 +        key_file = g_key_file_new ();
   3453 +        error = NULL;
   3454 +        res = g_key_file_load_from_file (key_file,
   3455 +                                         path,
   3456 +                                         G_KEY_FILE_NONE,
   3457 +                                         &error);
   3458 +
   3459 +        if (! res) {
   3460 +                g_warning ("Unable to load sessions from file %s: %s",
   3461 +                           path, error->message);
   3462 +                g_error_free (error);
   3463 +                return NULL;
   3464 +        }
   3465 +
   3466 +        group = g_key_file_get_start_group (key_file);
   3467 +        if (group == NULL || strcmp (group, "Session Entry") != 0) {
   3468 +                g_warning ("Not a session file: %s", path);
   3469 +                g_key_file_free (key_file);
   3470 +                return NULL;
   3471 +        }
   3472 +
   3473 +        hidden = g_key_file_get_boolean (key_file, group, "Hidden", NULL);
   3474 +
   3475 +        if (hidden) {
   3476 +                g_debug ("Session is hidden");
   3477 +                g_free (group);
   3478 +                g_key_file_free (key_file);
   3479 +                return NULL;
   3480 +        }
   3481 +
   3482 +        name = g_key_file_get_string (key_file, group, "Name", NULL);
   3483 +
   3484 +        if (name == NULL) {
   3485 +                g_warning ("Session file %s doesn't contain a name", path);
   3486 +                g_free (group);
   3487 +                g_key_file_free (key_file);
   3488 +                return NULL;
   3489 +        }
   3490 +
   3491 +        type = g_key_file_get_string (key_file, group, "Type", NULL);
   3492 +
   3493 +        if (type == NULL) {
   3494 +                g_warning ("Session file %s doesn't contain a type", path);
   3495 +                g_free (group);
   3496 +                g_key_file_free (key_file);
   3497 +                return NULL;
   3498 +        }
   3499 +
   3500 +        display_template_string = g_key_file_get_string (key_file, group, "DisplayTemplate", NULL);
   3501 +
   3502 +        if (display_template_string == NULL) {
   3503 +                g_warning ("Session file %s doesn't contain a display type", path);
   3504 +                g_free (group);
   3505 +                g_key_file_free (key_file);
   3506 +                return NULL;
   3507 +        }
   3508 +
   3509 +        /* Find a group in the key file named after the display type and stuff
   3510 +         * all its entries into a hash table for later.
   3511 +         *
   3512 +         * Those keys are for things like the display number and the vt to
   3513 +         * run X with.
   3514 +         */
   3515 +        display_variables = g_hash_table_new_full (g_str_hash, g_str_equal,
   3516 +                                                   (GDestroyNotify) g_free,
   3517 +                                                   (GDestroyNotify) g_free);
   3518 +        type_keys = g_key_file_get_keys (key_file, display_template_string, NULL, NULL);
   3519 +
   3520 +        if (type_keys != NULL) {
   3521 +                int i;
   3522 +                for (i = 0; type_keys[i] != NULL; i++) {
   3523 +                        char    *string;
   3524 +                        string = g_key_file_get_string (key_file, display_template_string, type_keys[i], NULL);
   3525 +
   3526 +                        g_hash_table_insert (display_variables, g_strdup (type_keys[i]), string);
   3527 +                }
   3528 +                g_strfreev (type_keys);
   3529 +        }
   3530 +
   3531 +        session = ck_session_new (ssid, type, display_template_string, display_variables);
   3532 +
   3533 +        g_free (display_template_string);
   3534 +        g_free (group);
   3535 +        g_free (type);
   3536 +        g_hash_table_unref (display_variables);
   3537 +
   3538 +        return session;
   3539 +}
   3540 +
   3541 +CkSession *
   3542  ck_session_new (const char *ssid,
   3543 -                const char *cookie)
   3544 +                const char *type,
   3545 +                const char *display_template_string,
   3546 +                GHashTable *display_variables)
   3547  {
   3548 +        CkDisplayTemplate *display_template;
   3549          GObject *object;
   3550          gboolean res;
   3551  
   3552 +        display_template = ck_display_template_get_from_name (display_template_string);
   3553 +
   3554 +        if (display_template == NULL) {
   3555 +                g_warning ("Unable to load display type %s", display_template_string);
   3556 +                return NULL;
   3557 +        }
   3558 +
   3559          object = g_object_new (CK_TYPE_SESSION,
   3560                                 "id", ssid,
   3561 -                               "cookie", cookie,
   3562 +                               "session-type", type,
   3563 +                               "display-type", display_template_string,
   3564 +                               "display-template", display_template,
   3565 +                               "display-variables", display_variables,
   3566                                 NULL);
   3567 +
   3568          res = register_session (CK_SESSION (object));
   3569          if (! res) {
   3570                  g_object_unref (object);
   3571 @@ -1138,9 +1597,80 @@ ck_session_new (const char *ssid,
   3572                                                            G_TYPE_VALUE, \
   3573                                                            G_TYPE_INVALID))
   3574  
   3575 +void
   3576 +ck_session_set_parameters (CkSession       *session,
   3577 +                           const GPtrArray *parameters)
   3578 +{
   3579 +        int           i;
   3580 +        GObjectClass *class;
   3581 +        GType         object_type;
   3582 +
   3583 +        object_type = CK_TYPE_SESSION;
   3584 +        class = g_type_class_ref (object_type);
   3585 +        for (i = 0; i < parameters->len; i++) {
   3586 +                gboolean    res;
   3587 +                GValue      val_struct = { 0, };
   3588 +                GValue      value = { 0, };
   3589 +                char       *prop_name;
   3590 +                GValue     *prop_val;
   3591 +                GParamSpec *pspec;
   3592 +
   3593 +                g_value_init (&val_struct, CK_TYPE_PARAMETER_STRUCT);
   3594 +                g_value_set_static_boxed (&val_struct, g_ptr_array_index (parameters, i));
   3595 +
   3596 +                res = dbus_g_type_struct_get (&val_struct,
   3597 +                                              0, &prop_name,
   3598 +                                              1, &prop_val,
   3599 +                                              G_MAXUINT);
   3600 +                if (! res) {
   3601 +                        g_debug ("Unable to extract parameter input");
   3602 +                        goto cont;
   3603 +                }
   3604 +
   3605 +                if (prop_name == NULL) {
   3606 +                        g_debug ("Skipping NULL parameter");
   3607 +                        goto cont;
   3608 +                }
   3609 +
   3610 +                if (strcmp (prop_name, "id") == 0
   3611 +                    || strcmp (prop_name, "cookie") == 0) {
   3612 +                        g_debug ("Skipping restricted parameter: %s", prop_name);
   3613 +                        goto cont;
   3614 +                }
   3615 +
   3616 +                pspec = g_object_class_find_property (class, prop_name);
   3617 +                if (! pspec) {
   3618 +                        g_debug ("Skipping unknown parameter: %s", prop_name);
   3619 +                        goto cont;
   3620 +                }
   3621 +
   3622 +                if (!(pspec->flags & G_PARAM_WRITABLE)) {
   3623 +                        g_debug ("property '%s' is not writable", pspec->name);
   3624 +                        goto cont;
   3625 +                }
   3626 +
   3627 +                g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
   3628 +                res = g_value_transform (prop_val, &value);
   3629 +                if (! res) {
   3630 +                        g_debug ("unable to transform property value for '%s'", pspec->name);
   3631 +                        goto cont;
   3632 +                }
   3633 +
   3634 +                g_object_set_property (G_OBJECT (session), prop_name, &value);
   3635 +                g_value_unset (&value);
   3636 +        cont:
   3637 +                g_free (prop_name);
   3638 +                if (prop_val != NULL) {
   3639 +                        g_value_unset (prop_val);
   3640 +                        g_free (prop_val);
   3641 +                }
   3642 +        }
   3643 +
   3644 +        g_type_class_unref (class);
   3645 +}
   3646 +
   3647  CkSession *
   3648  ck_session_new_with_parameters (const char      *ssid,
   3649 -                                const char      *cookie,
   3650                                  const GPtrArray *parameters)
   3651  {
   3652          GObject      *object;
   3653 @@ -1169,12 +1699,6 @@ ck_session_new_with_parameters (const char      *ssid,
   3654          g_value_set_string (&params[n_params].value, ssid);
   3655          n_params++;
   3656  
   3657 -        params[n_params].name = g_strdup ("cookie");
   3658 -        params[n_params].value.g_type = 0;
   3659 -        g_value_init (&params[n_params].value, G_TYPE_STRING);
   3660 -        g_value_set_string (&params[n_params].value, cookie);
   3661 -        n_params++;
   3662 -
   3663          if (parameters != NULL) {
   3664                  for (i = 0; i < parameters->len; i++) {
   3665                          gboolean    res;
   3666 @@ -1259,7 +1783,7 @@ ck_session_run_programs (CkSession  *session,
   3667                           const char *action)
   3668  {
   3669          int   n;
   3670 -        char *extra_env[11]; /* be sure to adjust this as needed */
   3671 +        char *extra_env[12]; /* be sure to adjust this as needed */
   3672  
   3673          n = 0;
   3674  
   3675 @@ -1267,6 +1791,9 @@ ck_session_run_programs (CkSession  *session,
   3676          if (session->priv->session_type != NULL) {
   3677                  extra_env[n++] = g_strdup_printf ("CK_SESSION_TYPE=%s", session->priv->session_type);
   3678          }
   3679 +        if (session->priv->display_type != NULL) {
   3680 +                extra_env[n++] = g_strdup_printf ("CK_SESSION_DISPLAY_TYPE=%s", session->priv->display_type);
   3681 +        }
   3682          extra_env[n++] = g_strdup_printf ("CK_SESSION_SEAT_ID=%s", session->priv->seat_id);
   3683          extra_env[n++] = g_strdup_printf ("CK_SESSION_USER_UID=%d", session->priv->uid);
   3684          if (session->priv->display_device != NULL && strlen (session->priv->display_device) > 0) {
   3685 @@ -1301,6 +1828,10 @@ ck_session_dump (CkSession *session,
   3686          char *s;
   3687          char *group_name;
   3688  
   3689 +        if (!session->priv->is_open) {
   3690 +                return;
   3691 +        }
   3692 +
   3693          group_name = g_strdup_printf ("Session %s", session->priv->id);
   3694          g_key_file_set_integer (key_file, group_name, "uid", session->priv->uid);
   3695          g_key_file_set_string (key_file,
   3696 @@ -1313,6 +1844,12 @@ ck_session_dump (CkSession *session,
   3697                                         "type",
   3698                                         NONULL_STRING (session->priv->session_type));
   3699          }
   3700 +        if (session->priv->display_type != NULL) {
   3701 +                g_key_file_set_string (key_file,
   3702 +                                       group_name,
   3703 +                                       "display_type",
   3704 +                                       NONULL_STRING (session->priv->display_type));
   3705 +        }
   3706          if (session->priv->login_session_id != NULL && strlen (session->priv->login_session_id) > 0) {
   3707                  g_key_file_set_string (key_file,
   3708                                         group_name,
   3709 diff --git a/src/ck-session.h b/src/ck-session.h
   3710 index b6b565b..a24d0a8 100644
   3711 --- a/src/ck-session.h
   3712 +++ b/src/ck-session.h
   3713 @@ -25,6 +25,8 @@
   3714  #include <glib-object.h>
   3715  #include <dbus/dbus-glib.h>
   3716  
   3717 +#include "ck-display-template.h"
   3718 +
   3719  G_BEGIN_DECLS
   3720  
   3721  #define CK_TYPE_SESSION         (ck_session_get_type ())
   3722 @@ -68,10 +70,15 @@ typedef enum
   3723  
   3724  GQuark              ck_session_error_quark            (void);
   3725  GType               ck_session_get_type               (void);
   3726 +CkSession         * ck_session_new_from_file          (const char            *ssid,
   3727 +                                                       const char            *path);
   3728  CkSession         * ck_session_new                    (const char            *ssid,
   3729 -                                                       const char            *cookie);
   3730 +                                                       const char            *type,
   3731 +                                                       const char            *display_type_string,
   3732 +                                                       GHashTable            *display_variables);
   3733  CkSession         * ck_session_new_with_parameters    (const char            *ssid,
   3734 -                                                       const char            *cookie,
   3735 +                                                       const GPtrArray       *parameters);
   3736 +void                ck_session_set_parameters         (CkSession             *session,
   3737                                                         const GPtrArray       *parameters);
   3738  
   3739  void                ck_session_dump                   (CkSession             *session,
   3740 @@ -86,6 +93,15 @@ gboolean            ck_session_set_active             (CkSession             *se
   3741  gboolean            ck_session_set_is_local           (CkSession             *session,
   3742                                                         gboolean               is_local,
   3743                                                         GError               **error);
   3744 +gboolean            ck_session_set_is_open            (CkSession             *session,
   3745 +                                                       gboolean               is_open,
   3746 +                                                       GError               **error);
   3747 +gboolean            ck_session_set_ever_open          (CkSession             *session,
   3748 +                                                       gboolean               ever_open,
   3749 +                                                       GError               **error);
   3750 +gboolean            ck_session_set_under_request      (CkSession             *session,
   3751 +                                                       gboolean               under_request,
   3752 +                                                       GError               **error);
   3753  gboolean            ck_session_set_id                 (CkSession             *session,
   3754                                                         const char            *ssid,
   3755                                                         GError               **error);
   3756 @@ -116,6 +132,11 @@ gboolean            ck_session_set_remote_host_name   (CkSession             *se
   3757  gboolean            ck_session_set_session_type       (CkSession             *session,
   3758                                                         const char            *type,
   3759                                                         GError               **error);
   3760 +gboolean            ck_session_set_display_type       (CkSession             *session,
   3761 +                                                       const char            *type,
   3762 +                                                       GError               **error);
   3763 +GHashTable         *ck_session_get_display_variables  (CkSession             *session);
   3764 +CkDisplayTemplate  *ck_session_get_display_template   (CkSession             *session);
   3765  
   3766  /* Exported methods */
   3767  
   3768 @@ -132,6 +153,15 @@ gboolean            ck_session_is_active              (CkSession             *se
   3769  gboolean            ck_session_is_local               (CkSession             *session,
   3770                                                         gboolean              *local,
   3771                                                         GError               **error);
   3772 +gboolean            ck_session_is_open                (CkSession             *session,
   3773 +                                                       gboolean              *open,
   3774 +                                                       GError               **error);
   3775 +gboolean            ck_session_get_ever_open          (CkSession             *session,
   3776 +                                                       gboolean              *open,
   3777 +                                                       GError               **error);
   3778 +gboolean            ck_session_get_under_request      (CkSession             *session,
   3779 +                                                       gboolean              *under_request,
   3780 +                                                       GError               **error);
   3781  gboolean            ck_session_get_unix_user          (CkSession             *session,
   3782                                                         guint                 *uid,
   3783                                                         GError               **error);
   3784 @@ -150,12 +180,18 @@ gboolean            ck_session_get_login_session_id   (CkSession             *se
   3785  gboolean            ck_session_get_session_type       (CkSession             *session,
   3786                                                         char                 **type,
   3787                                                         GError               **error);
   3788 +gboolean            ck_session_get_display_type       (CkSession             *session,
   3789 +                                                       char                 **type,
   3790 +                                                       GError               **error);
   3791  gboolean            ck_session_get_remote_host_name   (CkSession             *session,
   3792                                                         char                 **host_name,
   3793                                                         GError               **error);
   3794  gboolean            ck_session_get_creation_time      (CkSession             *session,
   3795                                                         char                 **iso8601_datetime,
   3796                                                         GError               **error);
   3797 +gboolean            ck_session_get_remove_on_close    (CkSession             *session,
   3798 +                                                       gboolean              *remove_on_close,
   3799 +                                                       GError               **error);
   3800  /*deprecated*/
   3801  gboolean            ck_session_get_user               (CkSession             *session,
   3802                                                         guint                 *uid,
   3803 @@ -171,6 +207,12 @@ gboolean            ck_session_get_idle_since_hint    (CkSession             *se
   3804  gboolean            ck_session_set_idle_hint          (CkSession             *session,
   3805                                                         gboolean               idle_hint,
   3806                                                         DBusGMethodInvocation *context);
   3807 +gboolean            session_set_remove_on_close       (CkSession             *session,
   3808 +                                                       gboolean               remove_on_close,
   3809 +                                                       GError               **error);
   3810 +gboolean            ck_session_set_remove_on_close    (CkSession             *session,
   3811 +                                                       gboolean               remove_on_close,
   3812 +                                                       DBusGMethodInvocation *context);
   3813  
   3814  /* Privileged actions */
   3815  gboolean            ck_session_activate               (CkSession             *session,
   3816 diff --git a/src/org.freedesktop.ConsoleKit.Manager.xml b/src/org.freedesktop.ConsoleKit.Manager.xml
   3817 index f903b55..34a6d04 100644
   3818 --- a/src/org.freedesktop.ConsoleKit.Manager.xml
   3819 +++ b/src/org.freedesktop.ConsoleKit.Manager.xml
   3820 @@ -160,6 +160,23 @@
   3821        </doc:doc>
   3822      </method>
   3823  
   3824 +    <method name="GetUnmanagedSeats">
   3825 +      <arg name="seats" direction="out" type="ao">
   3826 +        <doc:doc>
   3827 +          <doc:summary>an array of unmanaged Seat IDs</doc:summary>
   3828 +        </doc:doc>
   3829 +      </arg>
   3830 +      <doc:doc>
   3831 +        <doc:description>
   3832 +          <doc:para>This gets a list of the unmanaged <doc:ref type="interface" to="Seat">Seats</doc:ref>
   3833 +          that are statically configured under /etc/ConsoleKit/seats.d</doc:para>
   3834 +          <doc:para>Each Seat ID is an D-Bus object path for the object that implements the
   3835 +          <doc:ref type="interface" to="Seat">Seat</doc:ref> interface.</doc:para>
   3836 +        </doc:description>
   3837 +        <doc:seealso><doc:ref type="interface" to="Seat">org.freedesktop.ConsoleKit.Seat</doc:ref></doc:seealso>
   3838 +      </doc:doc>
   3839 +    </method>
   3840 +
   3841      <method name="GetSessions">
   3842        <arg name="sessions" direction="out" type="ao">
   3843          <doc:doc>
   3844 @@ -310,12 +327,115 @@
   3845        </doc:doc>
   3846      </method>
   3847  
   3848 +    <method name="AddSeat">
   3849 +      <arg name="type" type="s" direction="in">
   3850 +        <doc:doc>
   3851 +          <doc:summary>The type of seat to add</doc:summary>
   3852 +        </doc:doc>
   3853 +      </arg>
   3854 +      <arg name="sid" type="o" direction="out">
   3855 +        <doc:doc>
   3856 +          <doc:summary>The Seat ID of the added seat</doc:summary>
   3857 +        </doc:doc>
   3858 +      </arg>
   3859 +      <doc:doc>
   3860 +        <doc:description>
   3861 +          <doc:para>This method is to create a new seat
   3862 +          </doc:para>
   3863 +        </doc:description>
   3864 +      </doc:doc>
   3865 +    </method>
   3866 +    <method name="AddSeatById">
   3867 +      <arg name="type" type="s" direction="in">
   3868 +        <doc:doc>
   3869 +          <doc:summary>The type of seat to add</doc:summary>
   3870 +        </doc:doc>
   3871 +      </arg>
   3872 +      <arg name="sid" type="o" direction="in">
   3873 +        <doc:doc>
   3874 +          <doc:summary>The Seat ID of to be added seat</doc:summary>
   3875 +        </doc:doc>
   3876 +      </arg>
   3877 +      <doc:doc>
   3878 +        <doc:description>
   3879 +          <doc:para>This method is to create a new seat by specify given sid
   3880 +          </doc:para>
   3881 +        </doc:description>
   3882 +      </doc:doc>
   3883 +    </method>
   3884 +    <method name="RemoveSeat">
   3885 +      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
   3886 +      <arg name="sid" type="o" direction="in">
   3887 +        <doc:doc>
   3888 +          <doc:summary>The Seat ID of the seat to remove</doc:summary>
   3889 +        </doc:doc>
   3890 +      </arg>
   3891 +      <doc:doc>
   3892 +        <doc:description>
   3893 +          <doc:para>This method is to remove a seat
   3894 +          </doc:para>
   3895 +        </doc:description>
   3896 +      </doc:doc>
   3897 +    </method>
   3898 +    <method name="AddSession">
   3899 +      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
   3900 +      <arg name="sid" type="o">
   3901 +        <doc:doc>
   3902 +          <doc:summary>The seat to add the session to</doc:summary>
   3903 +        </doc:doc>
   3904 +      </arg>
   3905 +      <arg name="type" type="s">
   3906 +        <doc:doc>
   3907 +          <doc:summary>The type of session to run (e.g. "LoginWindow", "Chooser", etc)</doc:summary>
   3908 +        </doc:doc>
   3909 +      </arg>
   3910 +      <arg name="display_type" type="s">
   3911 +        <doc:doc>
   3912 +          <doc:summary>The name of the display type to use (defined in displays.d)</doc:summary>
   3913 +        </doc:doc>
   3914 +      </arg>
   3915 +      <arg name="variables" type="a{ss}">
   3916 +        <doc:doc>
   3917 +          <doc:summary>Session type specific parameters</doc:summary>
   3918 +        </doc:doc>
   3919 +      </arg>
   3920 +      <arg name="ssid" direction="out" type="o">
   3921 +        <doc:doc>
   3922 +          <doc:summary>Session ID</doc:summary>
   3923 +        </doc:doc>
   3924 +      </arg>
   3925 +      <doc:doc>
   3926 +        <doc:description>
   3927 +          <doc:para>Request a new session gets added to seat.</doc:para>
   3928 +        </doc:description>
   3929 +      </doc:doc>
   3930 +    </method>
   3931 +    <method name="RemoveSession">
   3932 +      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
   3933 +      <arg name="ssid" type="o" direction="in">
   3934 +        <doc:doc>
   3935 +          <doc:summary>The session id of the session to remove</doc:summary>
   3936 +        </doc:doc>
   3937 +      </arg>
   3938 +      <doc:doc>
   3939 +        <doc:description>
   3940 +          <doc:para>This method is to remove a session from a seat
   3941 +          </doc:para>
   3942 +        </doc:description>
   3943 +      </doc:doc>
   3944 +    </method>
   3945 +
   3946      <signal name="SeatAdded">
   3947        <arg name="sid" type="o">
   3948          <doc:doc>
   3949            <doc:summary>The Seat ID for the added seat</doc:summary>
   3950          </doc:doc>
   3951        </arg>
   3952 +      <arg name="type" type="s">
   3953 +        <doc:doc>
   3954 +          <doc:summary>The type of seat added.</doc:summary>
   3955 +        </doc:doc>
   3956 +      </arg>
   3957        <doc:doc>
   3958          <doc:description>
   3959            <doc:para>Emitted when a Seat has been added to the system.
   3960 diff --git a/src/org.freedesktop.ConsoleKit.Seat.xml b/src/org.freedesktop.ConsoleKit.Seat.xml
   3961 index d95990b..1f6c46f 100644
   3962 --- a/src/org.freedesktop.ConsoleKit.Seat.xml
   3963 +++ b/src/org.freedesktop.ConsoleKit.Seat.xml
   3964 @@ -100,6 +100,24 @@ seat at a time.</doc:para>
   3965        </doc:doc>
   3966      </method>
   3967  
   3968 +    <method name="Manage">
   3969 +      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
   3970 +      <doc:doc>
   3971 +        <doc:description>
   3972 +          <doc:para>Attempt to create unmanaged sessions for this seat.</doc:para>
   3973 +        </doc:description>
   3974 +      </doc:doc>
   3975 +    </method>
   3976 +
   3977 +    <method name="Unmanage">
   3978 +      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
   3979 +      <doc:doc>
   3980 +        <doc:description>
   3981 +          <doc:para>Stop managing seat.</doc:para>
   3982 +        </doc:description>
   3983 +      </doc:doc>
   3984 +    </method>
   3985 +
   3986      <signal name="ActiveSessionChanged">
   3987        <arg name="ssid" type="o">
   3988          <doc:doc>
   3989 @@ -160,5 +178,61 @@ seat at a time.</doc:para>
   3990          </doc:description>
   3991        </doc:doc>
   3992      </signal>
   3993 +    <signal name="OpenSessionRequest">
   3994 +      <arg name="ssid" type="o">
   3995 +        <doc:doc>
   3996 +          <doc:summary>The session id of the session to add</doc:summary>
   3997 +        </doc:doc>
   3998 +      </arg>
   3999 +      <arg name="session_type" type="s">
   4000 +        <doc:doc>
   4001 +          <doc:summary>The type of session to run (e.g. "LoginWindow", "Chooser", etc)</doc:summary>
   4002 +        </doc:doc>
   4003 +      </arg>
   4004 +      <arg name="display_template_name" type="s">
   4005 +        <doc:doc>
   4006 +          <doc:summary>The name of display template </doc:summary>
   4007 +        </doc:doc>
   4008 +      </arg>
   4009 +      <arg name="parameters" type="a{ss}">
   4010 +        <doc:doc>
   4011 +          <doc:summary>Session type specific parameters</doc:summary>
   4012 +        </doc:doc>
   4013 +      </arg>
   4014 +      <arg name="display_type" type="s">
   4015 +        <doc:doc>
   4016 +          <doc:summary>The type of display to use (e.g. "X11", "Command", "XDMCP", etc)</doc:summary>
   4017 +        </doc:doc>
   4018 +      </arg>
   4019 +      <arg name="display_parameters" type="a{ss}">
   4020 +        <doc:doc>
   4021 +          <doc:summary>Display type specific parameters</doc:summary>
   4022 +        </doc:doc>
   4023 +      </arg>
   4024 +      <doc:doc>
   4025 +        <doc:description>
   4026 +          <doc:para>Emitted when a new session should get added to the seat.</doc:para>
   4027 +        </doc:description>
   4028 +      </doc:doc>
   4029 +    </signal>
   4030 +    <signal name="CloseSessionRequest">
   4031 +      <arg name="ssid" type="o">
   4032 +        <doc:doc>
   4033 +          <doc:summary>The session id of the session to remove</doc:summary>
   4034 +        </doc:doc>
   4035 +      </arg>
   4036 +      <doc:doc>
   4037 +        <doc:description>
   4038 +          <doc:para>Emitted when a session with given display number need to be removed.</doc:para>
   4039 +        </doc:description>
   4040 +      </doc:doc>
   4041 +    </signal>
   4042 +    <signal name="RemoveRequest">
   4043 +      <doc:doc>
   4044 +        <doc:description>
   4045 +          <doc:para>Emitted when seat needs to get removed.</doc:para>
   4046 +        </doc:description>
   4047 +      </doc:doc>
   4048 +    </signal>
   4049    </interface>
   4050  </node>
   4051 diff --git a/src/org.freedesktop.ConsoleKit.Session.xml b/src/org.freedesktop.ConsoleKit.Session.xml
   4052 index b6e1cdb..2652058 100644
   4053 --- a/src/org.freedesktop.ConsoleKit.Session.xml
   4054 +++ b/src/org.freedesktop.ConsoleKit.Session.xml
   4055 @@ -52,6 +52,19 @@
   4056          <doc:seealso><doc:ref type="property" to="Session:session-type">session-type</doc:ref></doc:seealso>
   4057        </doc:doc>
   4058      </method>
   4059 +    <method name="GetDisplayType">
   4060 +      <arg name="type" direction="out" type="s">
   4061 +        <doc:doc>
   4062 +          <doc:summary>Display type</doc:summary>
   4063 +        </doc:doc>
   4064 +      </arg>
   4065 +      <doc:doc>
   4066 +        <doc:description>
   4067 +          <doc:para>Returns the display type of the session.</doc:para>
   4068 +        </doc:description>
   4069 +        <doc:seealso><doc:ref type="property" to="Session:display-type">display-type</doc:ref></doc:seealso>
   4070 +      </doc:doc>
   4071 +    </method>
   4072      <method name="GetUser">
   4073        <arg name="uid" direction="out" type="u">
   4074          <doc:doc>
   4075 @@ -174,6 +187,18 @@
   4076          <doc:seealso><doc:ref type="property" to="Session:is-local">is-local</doc:ref></doc:seealso>
   4077        </doc:doc>
   4078      </method>
   4079 +    <method name="IsOpen">
   4080 +      <arg name="open" direction="out" type="b">
   4081 +        <doc:doc>
   4082 +          <doc:summary>TRUE if the session is open, otherwise FALSE</doc:summary>
   4083 +        </doc:doc>
   4084 +      </arg>
   4085 +      <doc:doc>
   4086 +        <doc:description><doc:para>Returns whether the session is open</doc:para>
   4087 +        </doc:description>
   4088 +        <doc:seealso><doc:ref type="property" to="Session:is-open">is-open</doc:ref></doc:seealso>
   4089 +      </doc:doc>
   4090 +    </method>
   4091      <method name="GetCreationTime">
   4092        <arg name="iso8601_datetime" type="s" direction="out">
   4093          <doc:doc>
   4094 @@ -275,6 +300,21 @@
   4095          </doc:description>
   4096        </doc:doc>
   4097      </method>
   4098 +    <method name="SetRemoveOnClose">
   4099 +      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
   4100 +      <arg name="remove_on_close" type="b" direction="in">
   4101 +        <doc:doc>
   4102 +          <doc:summary>boolean value to set the remove-on-close to</doc:summary>
   4103 +        </doc:doc>
   4104 +      </arg>
   4105 +      <doc:doc>
   4106 +        <doc:description>
   4107 +          <doc:para>This may be used by the session to indicate that
   4108 +          it should be respawn or not when it is closed.
   4109 +          </doc:para>
   4110 +        </doc:description>
   4111 +      </doc:doc>
   4112 +    </method>
   4113  
   4114      <signal name="ActiveChanged">
   4115        <arg name="is_active" type="b">
   4116 @@ -317,6 +357,19 @@
   4117        </doc:doc>
   4118      </signal>
   4119  
   4120 +    <property name="session" type="o" access="readwrite">
   4121 +      <doc:doc>
   4122 +        <doc:description>
   4123 +          <doc:para>The id of the session.</doc:para>
   4124 +          <doc:para>
   4125 +          The object path of the session.  Typically this is set by a session leader during a call to the
   4126 +          <doc:ref type="method" to="Manager.OpenSessionWithParameters">OpenSessionWithParameters</doc:ref> method, when
   4127 +          opening a session in response to the <doc:ref type="signal" to="Seat::OpenSessionRequest">OpenSessionRequest</doc:ref>
   4128 +          signal.
   4129 +          </doc:para>
   4130 +        </doc:description>
   4131 +      </doc:doc>
   4132 +    </property>
   4133      <property name="unix-user" type="u" access="readwrite">
   4134        <doc:doc>
   4135          <doc:description>
   4136 @@ -342,6 +395,16 @@
   4137          </doc:description>
   4138        </doc:doc>
   4139      </property>
   4140 +    <property name="display-type" type="s" access="readwrite">
   4141 +      <doc:doc>
   4142 +        <doc:description>
   4143 +          <doc:para>The display type of the session.</doc:para>
   4144 +          <doc:para>Indicate the display template name. All the display template configuration
   4145 +          files are under /etc/ConsoleKit/displays.d/.
   4146 +          </doc:para>
   4147 +        </doc:description>
   4148 +      </doc:doc>
   4149 +    </property>
   4150      <property name="remote-host-name" type="s" access="readwrite">
   4151        <doc:doc>
   4152          <doc:description>
   4153 @@ -396,6 +459,19 @@
   4154          </doc:description>
   4155        </doc:doc>
   4156      </property>
   4157 +    <property name="is-open" type="b" access="readwrite">
   4158 +      <doc:doc>
   4159 +        <doc:description>
   4160 +          <doc:para>
   4161 +          Whether the session is open</doc:para>
   4162 +          <doc:para>Sessions added from static configuration or in direct response to a call to
   4163 +          the <doc:ref type="method" to="Manager.AddSession">AddSession</doc:ref> method are initialally
   4164 +          closed and aren't open until a call to the <doc:ref type="method" to="Manager.OpenSessionWithParameters">OpenSessionWithParameters</doc:ref>
   4165 +          method.
   4166 +          </doc:para>
   4167 +        </doc:description>
   4168 +      </doc:doc>
   4169 +    </property>
   4170      <property name="is-local" type="b" access="readwrite">
   4171        <doc:doc>
   4172          <doc:description>
   4173 @@ -408,6 +484,14 @@
   4174          </doc:description>
   4175        </doc:doc>
   4176      </property>
   4177 +    <property name="is-dynamic" type="b" access="readwrite">
   4178 +      <doc:doc>
   4179 +        <doc:description>
   4180 +          <doc:para>
   4181 +          Whether the session is dynamic</doc:para>
   4182 +        </doc:description>
   4183 +      </doc:doc>
   4184 +    </property>
   4185      <property name="idle-hint" type="b" access="readwrite">
   4186        <doc:doc>
   4187          <doc:description>
   4188 @@ -430,6 +514,14 @@
   4189          </doc:description>
   4190        </doc:doc>
   4191      </property>
   4192 +    <property name="remove-on-close" type="b" access="readwrite">
   4193 +      <doc:doc>
   4194 +        <doc:description>
   4195 +          <doc:para>
   4196 +          Whether the session respawn when it is closed</doc:para>
   4197 +        </doc:description>
   4198 +      </doc:doc>
   4199 +    </property>
   4200  
   4201    </interface>
   4202  </node>
   4203 diff --git a/src/strverscmp.c b/src/strverscmp.c
   4204 new file mode 100644
   4205 index 0000000..f077651
   4206 --- /dev/null
   4207 +++ b/src/strverscmp.c
   4208 @@ -0,0 +1,131 @@
   4209 +/* Compare strings while treating digits characters numerically.
   4210 +   Copyright (C) 1997, 2000, 2002, 2004, 2006 Free Software Foundation, Inc.
   4211 +   This file is part of the GNU C Library.
   4212 +   Contributed by Jean-Franois Bignolles <bignolle (a] ecoledoc.ibp.fr>, 1997.
   4213 +
   4214 +   This program is free software; you can redistribute it and/or modify
   4215 +   it under the terms of the GNU General Public License as published by
   4216 +   the Free Software Foundation; either version 2, or (at your option)
   4217 +   any later version.
   4218 +
   4219 +   This program is distributed in the hope that it will be useful,
   4220 +   but WITHOUT ANY WARRANTY; without even the implied warranty of
   4221 +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   4222 +   GNU General Public License for more details.
   4223 +
   4224 +   You should have received a copy of the GNU General Public License along
   4225 +   with this program; if not, write to the Free Software Foundation,
   4226 +   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
   4227 +
   4228 +#if !_LIBC
   4229 +# include <config.h>
   4230 +#endif
   4231 +
   4232 +#include <string.h>
   4233 +#include <ctype.h>
   4234 +
   4235 +/* states: S_N: normal, S_I: comparing integral part, S_F: comparing
   4236 +           fractional parts, S_Z: idem but with leading Zeroes only */
   4237 +#define S_N    0x0
   4238 +#define S_I    0x4
   4239 +#define S_F    0x8
   4240 +#define S_Z    0xC
   4241 +
   4242 +/* result_type: CMP: return diff; LEN: compare using len_diff/diff */
   4243 +#define CMP    2
   4244 +#define LEN    3
   4245 +
   4246 +
   4247 +/* ISDIGIT differs from isdigit, as follows:
   4248 +   - Its arg may be any int or unsigned int; it need not be an unsigned char
   4249 +     or EOF.
   4250 +   - It's typically faster.
   4251 +   POSIX says that only '0' through '9' are digits.  Prefer ISDIGIT to
   4252 +   isdigit unless it's important to use the locale's definition
   4253 +   of `digit' even when the host does not conform to POSIX.  */
   4254 +#define ISDIGIT(c) ((unsigned int) (c) - '0' <= 9)
   4255 +
   4256 +#undef __strverscmp
   4257 +#undef strverscmp
   4258 +
   4259 +#ifndef weak_alias
   4260 +# define __strverscmp strverscmp
   4261 +#endif
   4262 +
   4263 +/* Compare S1 and S2 as strings holding indices/version numbers,
   4264 +   returning less than, equal to or greater than zero if S1 is less than,
   4265 +   equal to or greater than S2 (for more info, see the texinfo doc).
   4266 +*/
   4267 +
   4268 +int
   4269 +__strverscmp (const char *s1, const char *s2)
   4270 +{
   4271 +  const unsigned char *p1 = (const unsigned char *) s1;
   4272 +  const unsigned char *p2 = (const unsigned char *) s2;
   4273 +  unsigned char c1, c2;
   4274 +  int state;
   4275 +  int diff;
   4276 +
   4277 +  /* Symbol(s)    0       [1-9]   others  (padding)
   4278 +     Transition   (10) 0  (01) d  (00) x  (11) -   */
   4279 +  static const unsigned int next_state[] =
   4280 +  {
   4281 +      /* state    x    d    0    - */
   4282 +      /* S_N */  S_N, S_I, S_Z, S_N,
   4283 +      /* S_I */  S_N, S_I, S_I, S_I,
   4284 +      /* S_F */  S_N, S_F, S_F, S_F,
   4285 +      /* S_Z */  S_N, S_F, S_Z, S_Z
   4286 +  };
   4287 +
   4288 +  static const int result_type[] =
   4289 +  {
   4290 +      /* state   x/x  x/d  x/0  x/-  d/x  d/d  d/0  d/-
   4291 +                 0/x  0/d  0/0  0/-  -/x  -/d  -/0  -/- */
   4292 +
   4293 +      /* S_N */  CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP,
   4294 +                 CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP,
   4295 +      /* S_I */  CMP, -1,  -1,  CMP,  1,  LEN, LEN, CMP,
   4296 +                  1,  LEN, LEN, CMP, CMP, CMP, CMP, CMP,
   4297 +      /* S_F */  CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP,
   4298 +                 CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP,
   4299 +      /* S_Z */  CMP,  1,   1,  CMP, -1,  CMP, CMP, CMP,
   4300 +                 -1,  CMP, CMP, CMP
   4301 +  };
   4302 +
   4303 +  if (p1 == p2)
   4304 +    return 0;
   4305 +
   4306 +  c1 = *p1++;
   4307 +  c2 = *p2++;
   4308 +  /* Hint: '0' is a digit too.  */
   4309 +  state = S_N | ((c1 == '0') + (ISDIGIT (c1) != 0));
   4310 +
   4311 +  while ((diff = c1 - c2) == 0 && c1 != '\0')
   4312 +    {
   4313 +      state = next_state[state];
   4314 +      c1 = *p1++;
   4315 +      c2 = *p2++;
   4316 +      state |= (c1 == '0') + (ISDIGIT (c1) != 0);
   4317 +    }
   4318 +
   4319 +  state = result_type[state << 2 | ((c2 == '0') + (ISDIGIT (c2) != 0))];
   4320 +
   4321 +  switch (state)
   4322 +    {
   4323 +    case CMP:
   4324 +      return diff;
   4325 +
   4326 +    case LEN:
   4327 +      while (ISDIGIT (*p1++))
   4328 +	if (!ISDIGIT (*p2++))
   4329 +	  return 1;
   4330 +
   4331 +      return ISDIGIT (*p2) ? -1 : diff;
   4332 +
   4333 +    default:
   4334 +      return state;
   4335 +    }
   4336 +}
   4337 +#ifdef weak_alias
   4338 +weak_alias (__strverscmp, strverscmp)
   4339 +#endif
   4340 diff --git a/src/strverscmp.h b/src/strverscmp.h
   4341 new file mode 100644
   4342 index 0000000..48670c8
   4343 --- /dev/null
   4344 +++ b/src/strverscmp.h
   4345 @@ -0,0 +1,25 @@
   4346 +/* Compare strings while treating digits characters numerically.
   4347 +   Copyright (C) 1997, 2000, 2002, 2004, 2006 Free Software Foundation, Inc.
   4348 +   This file is part of the GNU C Library.
   4349 +   Contributed by Jean-Franois Bignolles <bignolle (a] ecoledoc.ibp.fr>, 1997.
   4350 +
   4351 +   This program is free software; you can redistribute it and/or modify
   4352 +   it under the terms of the GNU General Public License as published by
   4353 +   the Free Software Foundation; either version 2, or (at your option)
   4354 +   any later version.
   4355 +
   4356 +   This program is distributed in the hope that it will be useful,
   4357 +   but WITHOUT ANY WARRANTY; without even the implied warranty of
   4358 +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   4359 +   GNU General Public License for more details.
   4360 +
   4361 +   You should have received a copy of the GNU General Public License along
   4362 +   with this program; if not, write to the Free Software Foundation,
   4363 +   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
   4364 +
   4365 +#ifndef STRVERSCMP_H_
   4366 +# define STRVERSCMP_H_
   4367 +
   4368 +int strverscmp (const char *, const char *);
   4369 +
   4370 +#endif /* not STRVERSCMP_H_ */
   4371 diff --git a/tools/Makefile.am b/tools/Makefile.am
   4372 index 13c191f..fa16c68 100644
   4373 --- a/tools/Makefile.am
   4374 +++ b/tools/Makefile.am
   4375 @@ -54,6 +54,7 @@ sbin_PROGRAMS = \
   4376  	ck-log-system-start		\
   4377  	ck-log-system-restart		\
   4378  	ck-log-system-stop		\
   4379 +	ck-seat-tool			\
   4380  	$(NULL)
   4381  
   4382  ck_launch_session_SOURCES =		\
   4383 @@ -83,6 +84,14 @@ ck_history_LDADD =			\
   4384  	$(top_builddir)/src/libck-event-log.la	\
   4385  	$(NULL)
   4386  
   4387 +ck_seat_tool_SOURCES =			\
   4388 +	ck-seat-tool.c			\
   4389 +	$(NULL)
   4390 +
   4391 +ck_seat_tool_LDADD =			\
   4392 +	$(CONSOLE_KIT_LIBS)		\
   4393 +	$(NULL)
   4394 +
   4395  ck_log_system_start_SOURCES =		\
   4396  	ck-log-system-start.c		\
   4397  	$(NULL)
   4398 diff --git a/tools/ck-seat-tool.c b/tools/ck-seat-tool.c
   4399 new file mode 100644
   4400 index 0000000..810fe14
   4401 --- /dev/null
   4402 +++ b/tools/ck-seat-tool.c
   4403 @@ -0,0 +1,442 @@
   4404 +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
   4405 + *
   4406 + * Copyright (C) 2009 Sun Microsystems, Inc.
   4407 + *
   4408 + * This program is free software; you can redistribute it and/or
   4409 + * modify it under the terms of the GNU General Public License as
   4410 + * published by the Free Software Foundation; either version 2 of the
   4411 + * License, or (at your option) any later version.
   4412 + *
   4413 + * This program is distributed in the hope that it will be useful, but
   4414 + * WITHOUT ANY WARRANTY; without even the implied warranty of
   4415 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   4416 + * General Public License for more details.
   4417 + *
   4418 + * You should have received a copy of the GNU General Public License
   4419 + * along with this program; if not, write to the Free Software
   4420 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
   4421 + * 02111-1307, USA.
   4422 + *
   4423 + * Authors: Halton Huo <halton.huo (a] sun.com>
   4424 + *
   4425 + */
   4426 +
   4427 +#include "config.h"
   4428 +
   4429 +#include <stdlib.h>
   4430 +#include <stdio.h>
   4431 +#include <sys/types.h>
   4432 +#include <unistd.h>
   4433 +#include <strings.h>
   4434 +#include <glib/gi18n.h>
   4435 +#include <dbus/dbus-glib.h>
   4436 +#include <dbus/dbus-glib-lowlevel.h>
   4437 +
   4438 +#define CK_NAME              "org.freedesktop.ConsoleKit"
   4439 +#define CK_PATH              "/org/freedesktop/ConsoleKit"
   4440 +#define CK_INTERFACE         "org.freedesktop.ConsoleKit"
   4441 +#define CK_MANAGER_PATH      "/org/freedesktop/ConsoleKit/Manager"
   4442 +#define CK_MANAGER_INTERFACE "org.freedesktop.ConsoleKit.Manager"
   4443 +#define CK_SEAT_INTERFACE    "org.freedesktop.ConsoleKit.Seat"
   4444 +#define CK_SESSION_INTERFACE "org.freedesktop.ConsoleKit.Session"
   4445 +
   4446 +#define CK_DBUS_TYPE_G_STRING_STRING_HASHTABLE (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_STRING))
   4447 +
   4448 +#define IS_STR_SET(x) (x != NULL && x[0] != '\0')
   4449 +#define CK_PATH_PREFIX       "/org/freedesktop/ConsoleKit/"
   4450 +
   4451 +static gboolean  add = FALSE;
   4452 +static gboolean  delete = FALSE;
   4453 +static gboolean  show_version = FALSE;
   4454 +static char     *session_type = NULL;
   4455 +static char     *display_type = NULL;
   4456 +static char     *seat_id = NULL;
   4457 +static char     *session_id = NULL;
   4458 +static gchar   **remaining_args = NULL;
   4459 +
   4460 +static const GOptionEntry options [] = {
   4461 +        { "add", 'a', 0, G_OPTION_ARG_NONE, &add, N_("Add a new session"), NULL},
   4462 +        { "session-type", '\0', 0, G_OPTION_ARG_STRING, &session_type, N_("Specify session type when adding a session. Default is LoginWindow."), NULL},
   4463 +        { "display-type", '\0', 0, G_OPTION_ARG_STRING, &display_type, N_("Specify display type under <etc>/ConsoleKit/displays.d/ when adding a session."), NULL},
   4464 +        { "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},
   4465 +        { 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 },
   4466 +        { "delete", 'd', 0, G_OPTION_ARG_NONE, &delete, N_("Delete a session"), NULL},
   4467 +        { "session-id", '\0', 0, G_OPTION_ARG_STRING, &session_id, N_("Specify session id when deleting a session"), NULL},
   4468 +        { "version", 'V', 0, G_OPTION_ARG_NONE, &show_version, N_("Version of this application"), NULL },
   4469 +        { NULL }
   4470 +};
   4471 +
   4472 +static void
   4473 +add_session (DBusGConnection  *connection)
   4474 +{
   4475 +        DBusGProxy *mgr_proxy = NULL;
   4476 +        DBusGProxy *seat_proxy = NULL;
   4477 +        GError     *error = NULL;
   4478 +        gboolean    res;
   4479 +        char       *sid = NULL;
   4480 +        GPtrArray  *seats;
   4481 +        char       *ssid = NULL;
   4482 +        int         i;
   4483 +        gboolean    found;
   4484 +        char       *sstype = NULL;
   4485 +        GHashTable *variables = NULL;
   4486 +
   4487 +        if (! IS_STR_SET (session_type)) {
   4488 +                sstype = g_strdup ("LoginWindow");
   4489 +        } else {
   4490 +                sstype = g_strdup (session_type);
   4491 +        }
   4492 +
   4493 +        mgr_proxy = dbus_g_proxy_new_for_name (connection,
   4494 +                                               CK_NAME,
   4495 +                                               CK_MANAGER_PATH,
   4496 +                                               CK_MANAGER_INTERFACE);
   4497 +        if (mgr_proxy == NULL) {
   4498 +                return;
   4499 +        }
   4500 +
   4501 +        if (! IS_STR_SET(seat_id)) {
   4502 +
   4503 +                /* If seat id is not given, create a new seat */
   4504 +                error = NULL;
   4505 +                res = dbus_g_proxy_call (mgr_proxy,
   4506 +                                         "AddSeat",
   4507 +                                         &error,
   4508 +                                         G_TYPE_STRING, "Default",
   4509 +                                         G_TYPE_INVALID,
   4510 +                                         DBUS_TYPE_G_OBJECT_PATH, &sid,
   4511 +                                         G_TYPE_INVALID);
   4512 +                if (!res) {
   4513 +                        g_warning ("Unable to add seat: %s", error->message);
   4514 +                        g_error_free (error);
   4515 +                        g_object_unref (mgr_proxy);
   4516 +                        return;
   4517 +                }
   4518 +
   4519 +        } else {
   4520 +                if (!g_str_has_prefix (seat_id, CK_PATH_PREFIX)) {
   4521 +                        sid = g_strdup_printf ("%s%s", CK_PATH_PREFIX, seat_id);
   4522 +                } else {
   4523 +                        sid = g_strdup (seat_id);
   4524 +                }
   4525 +                /* Check whether seat is existing, if not, try to create it. */
   4526 +
   4527 +                error = NULL;
   4528 +                res = dbus_g_proxy_call (mgr_proxy,
   4529 +                                         "GetSeats",
   4530 +                                         &error,
   4531 +                                         G_TYPE_INVALID,
   4532 +                                         dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH),
   4533 +                                         &seats,
   4534 +                                         G_TYPE_INVALID);
   4535 +                if (!res) {
   4536 +                        g_warning ("Unable to get seat list: %s", error->message);
   4537 +                        g_error_free (error);
   4538 +                        g_object_unref (mgr_proxy);
   4539 +                        return;
   4540 +                }
   4541 +
   4542 +                found = FALSE;
   4543 +                for (i = 0; i < seats->len; i++) {
   4544 +                        char *tmp_sid;
   4545 +
   4546 +                        tmp_sid = g_ptr_array_index (seats, i);
   4547 +                        if (g_str_equal (sid, tmp_sid)) {
   4548 +                                found = TRUE;
   4549 +                                g_free (tmp_sid);
   4550 +                                break;
   4551 +                        }
   4552 +
   4553 +                        g_free (tmp_sid);
   4554 +                }
   4555 +
   4556 +                if (! found) {
   4557 +                        error = NULL;
   4558 +                        res = dbus_g_proxy_call (mgr_proxy,
   4559 +                                                 "AddSeatById",
   4560 +                                                 &error,
   4561 +                                                 G_TYPE_STRING, "Default",
   4562 +                                                 DBUS_TYPE_G_OBJECT_PATH, sid,
   4563 +                                                 G_TYPE_INVALID,
   4564 +                                                 G_TYPE_INVALID);
   4565 +                        if (!res) {
   4566 +                                g_warning ("Unable to add seat: %s", error->message);
   4567 +                                g_error_free (error);
   4568 +                                g_object_unref (mgr_proxy);
   4569 +                                return;
   4570 +                        }
   4571 +                }
   4572 +        }
   4573 +
   4574 +        seat_proxy = dbus_g_proxy_new_for_name (connection,
   4575 +                                                CK_NAME,
   4576 +                                                sid,
   4577 +                                                CK_SEAT_INTERFACE);
   4578 +
   4579 +        if (seat_proxy == NULL) {
   4580 +                g_warning ("Failed to talk to seat '%s'", sid);
   4581 +                g_object_unref (mgr_proxy);
   4582 +                return;
   4583 +        }
   4584 +
   4585 +        variables = g_hash_table_new_full (g_str_hash, g_str_equal,
   4586 +                                           (GDestroyNotify) g_free,
   4587 +                                           (GDestroyNotify) g_free);
   4588 +
   4589 +        for (i = 0; i < G_N_ELEMENTS (remaining_args); i++) {
   4590 +                char **arr;
   4591 +
   4592 +                /* split var=value */
   4593 +                arr = g_strsplit (remaining_args[i], "=", 2);
   4594 +                if (arr[0] && arr[1]) {
   4595 +                        g_hash_table_insert (variables,
   4596 +                                             g_strdup(arr[0]),
   4597 +                                             g_strdup (arr[1]));
   4598 +                }
   4599 +                g_strfreev (arr);
   4600 +
   4601 +        }
   4602 +
   4603 +        error = NULL;
   4604 +        res = dbus_g_proxy_call (mgr_proxy,
   4605 +                                 "AddSession",
   4606 +                                 &error,
   4607 +                                 DBUS_TYPE_G_OBJECT_PATH, sid,
   4608 +                                 G_TYPE_STRING, sstype,
   4609 +                                 G_TYPE_STRING, display_type,
   4610 +                                 CK_DBUS_TYPE_G_STRING_STRING_HASHTABLE, variables,
   4611 +                                 G_TYPE_INVALID,
   4612 +                                 DBUS_TYPE_G_OBJECT_PATH, &ssid,
   4613 +                                 G_TYPE_INVALID);
   4614 +
   4615 +        if (!res) {
   4616 +                g_warning ("Unable to add dynamic session: %s", error->message);
   4617 +                g_error_free (error);
   4618 +        } else {
   4619 +                dbus_g_proxy_call_no_reply (seat_proxy,
   4620 +                                            "Manage",
   4621 +                                            G_TYPE_INVALID,
   4622 +                                            G_TYPE_INVALID);
   4623 +                g_print ("Seat %s with session %s has been added\n", sid, ssid);
   4624 +        }
   4625 +
   4626 +        g_object_unref (seat_proxy);
   4627 +        g_object_unref (mgr_proxy);
   4628 +}
   4629 +
   4630 +static gboolean
   4631 +is_session_on_seat (DBusGConnection *connection,
   4632 +                    const char      *sid,
   4633 +                    const char      *ssid,
   4634 +                    gboolean        *is_last_session)
   4635 +{
   4636 +
   4637 +        DBusGProxy *seat_proxy = NULL;
   4638 +        GPtrArray  *sessions = NULL;
   4639 +        char       *ssid_tmp = NULL;
   4640 +        gboolean    res;
   4641 +        gboolean    retval = FALSE;
   4642 +        int         i;
   4643 +        GError     *error = NULL;
   4644 +
   4645 +        seat_proxy = dbus_g_proxy_new_for_name (connection,
   4646 +                                                CK_NAME,
   4647 +                                                sid,
   4648 +                                                CK_SEAT_INTERFACE);
   4649 +
   4650 +        if (seat_proxy == NULL) {
   4651 +                g_warning ("Failed to talk to seat '%s'", sid);
   4652 +                return FALSE;
   4653 +        }
   4654 +
   4655 +        error = NULL;
   4656 +        res = dbus_g_proxy_call (seat_proxy,
   4657 +                                 "GetSessions",
   4658 +                                 &error,
   4659 +                                 G_TYPE_INVALID,
   4660 +                                 dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH),
   4661 +                                 &sessions,
   4662 +                                 G_TYPE_INVALID);
   4663 +        if (! res) {
   4664 +                g_warning ("Failed to get list of sessions for %s: %s", sid, error->message);
   4665 +                g_error_free (error);
   4666 +                g_object_unref (seat_proxy);
   4667 +                return FALSE;
   4668 +        }
   4669 +
   4670 +        for (i = 0; i < sessions->len; i++) {
   4671 +
   4672 +                ssid_tmp = g_ptr_array_index (sessions, i);
   4673 +
   4674 +                if (g_str_equal (ssid, ssid_tmp)) {
   4675 +                        retval = TRUE;
   4676 +                        break;
   4677 +                }
   4678 +
   4679 +                g_free (ssid_tmp);
   4680 +                ssid_tmp = NULL;
   4681 +        }
   4682 +
   4683 +        if (is_last_session != NULL) {
   4684 +                *is_last_session = sessions->len == 1;
   4685 +        }
   4686 +
   4687 +        g_ptr_array_free (sessions, TRUE);
   4688 +        g_object_unref (seat_proxy);
   4689 +
   4690 +        return retval;
   4691 +}
   4692 +
   4693 +static char *
   4694 +find_seat_id_from_session_id (DBusGConnection *connection,
   4695 +                              DBusGProxy      *proxy,
   4696 +                              const char      *ssid,
   4697 +                              gboolean        *is_last_session)
   4698 +{
   4699 +        GError     *error;
   4700 +        GPtrArray  *seats;
   4701 +        int         i;
   4702 +        char       *sid;
   4703 +        gboolean    res;
   4704 +
   4705 +        error = NULL;
   4706 +        res = dbus_g_proxy_call (proxy,
   4707 +                                 "GetSeats",
   4708 +                                 &error,
   4709 +                                 G_TYPE_INVALID,
   4710 +                                 dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH),
   4711 +                                 &seats,
   4712 +                                 G_TYPE_INVALID);
   4713 +
   4714 +        if (! res) {
   4715 +                g_warning ("Failed to get list of seats: %s", error->message);
   4716 +                g_error_free (error);
   4717 +                return NULL;
   4718 +        }
   4719 +
   4720 +        for (i = 0; i < seats->len; i++) {
   4721 +
   4722 +                sid = g_ptr_array_index (seats, i);
   4723 +                if (is_session_on_seat (connection, sid, ssid, is_last_session)) {
   4724 +                        break;
   4725 +                }
   4726 +
   4727 +                g_free (sid);
   4728 +        }
   4729 +        g_ptr_array_free (seats, TRUE);
   4730 +
   4731 +        return sid;
   4732 +}
   4733 +
   4734 +static void
   4735 +delete_session (DBusGConnection *connection)
   4736 +{
   4737 +        DBusGProxy *proxy;
   4738 +        char       *ssid;
   4739 +        char       *sid;
   4740 +        gboolean    is_last_session;
   4741 +
   4742 +        if (!g_str_has_prefix (session_id, CK_PATH_PREFIX)) {
   4743 +                ssid = g_strdup_printf ("%s%s", CK_PATH_PREFIX, session_id);
   4744 +        } else {
   4745 +                ssid = g_strdup (session_id);
   4746 +        }
   4747 +
   4748 +        proxy = dbus_g_proxy_new_for_name (connection,
   4749 +                                           CK_NAME,
   4750 +                                           CK_MANAGER_PATH,
   4751 +                                           CK_MANAGER_INTERFACE);
   4752 +        if (proxy == NULL) {
   4753 +                return;
   4754 +        }
   4755 +
   4756 +        sid = find_seat_id_from_session_id (connection, proxy, ssid, &is_last_session);
   4757 +
   4758 +        dbus_g_proxy_call_no_reply (proxy,
   4759 +                                   "RemoveSession",
   4760 +                                   DBUS_TYPE_G_OBJECT_PATH, ssid,
   4761 +                                   G_TYPE_INVALID,
   4762 +                                   G_TYPE_INVALID);
   4763 +
   4764 +        if (is_last_session) {
   4765 +                dbus_g_proxy_call_no_reply (proxy,
   4766 +                                           "RemoveSeat",
   4767 +                                           DBUS_TYPE_G_OBJECT_PATH, sid,
   4768 +                                           G_TYPE_INVALID,
   4769 +                                           G_TYPE_INVALID);
   4770 +        }
   4771 +
   4772 +        g_object_unref (proxy);
   4773 +}
   4774 +
   4775 +int
   4776 +main (int argc, char *argv[])
   4777 +{
   4778 +        DBusGConnection *connection;
   4779 +        GOptionContext  *ctx;
   4780 +        GError          *error = NULL;
   4781 +        gboolean         res;
   4782 +
   4783 +        g_type_init ();
   4784 +
   4785 +        /* Option parsing */
   4786 +        ctx = g_option_context_new (_("- Manage dynamic sessions"));
   4787 +        g_option_context_add_main_entries (ctx, options, GETTEXT_PACKAGE);
   4788 +        res = g_option_context_parse (ctx, &argc, &argv, &error);
   4789 +
   4790 +        if (!res) {
   4791 +                if (error) {
   4792 +                        g_warning ("%s", error->message);
   4793 +                        g_error_free (error);
   4794 +                }
   4795 +                exit (1);
   4796 +        }
   4797 +
   4798 +        g_option_context_free (ctx);    
   4799 +
   4800 +        if (show_version) {
   4801 +                g_print ("%s %s\n", argv[0], VERSION);
   4802 +                exit (0);
   4803 +        }
   4804 +
   4805 +        if (add && delete) {
   4806 +                g_warning ("Can not specify -a and -d at the same time!");
   4807 +                exit (1);
   4808 +        }
   4809 +
   4810 +        if (!add && !delete) {
   4811 +                g_warning ("Must specify -a, -d!");
   4812 +                exit (1);
   4813 +        }
   4814 +
   4815 +        if (delete && (! IS_STR_SET (session_id))) {
   4816 +                g_warning ("You must specify session id for deleting a session. You can get all sessions by ck-list-sessions");
   4817 +                exit (1);
   4818 +        }
   4819 +
   4820 +        if (add && (! IS_STR_SET (display_type)) ) {
   4821 +                g_warning ("You must specify display type for adding a session. You can get all display types under <etc>/ConsoleKit/displays.d/");
   4822 +                g_warning ("Invalid display type!");
   4823 +                exit (1);
   4824 +        }
   4825 +
   4826 +        error = NULL;
   4827 +        connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
   4828 +        if (connection == NULL) {
   4829 +                g_message ("Failed to connect to the D-Bus daemon: %s", error->message);
   4830 +                g_error_free (error);
   4831 +                exit (1);
   4832 +        }
   4833 +
   4834 +
   4835 +        if (add) {
   4836 +                add_session (connection);
   4837 +        } else if (delete) {
   4838 +                delete_session (connection);
   4839 +        } else {
   4840 +                g_warning ("Invaild parameters!");
   4841 +                exit (1);
   4842 +        }
   4843 +
   4844 +        return 0;
   4845 +}
   4846 diff --git a/tools/list-sessions.c b/tools/list-sessions.c
   4847 index 3933772..cc69d57 100644
   4848 --- a/tools/list-sessions.c
   4849 +++ b/tools/list-sessions.c
   4850 @@ -46,6 +46,23 @@
   4851  #define CK_SEAT_INTERFACE    "org.freedesktop.ConsoleKit.Seat"
   4852  #define CK_SESSION_INTERFACE "org.freedesktop.ConsoleKit.Session"
   4853  
   4854 +#define IS_STR_SET(x) (x != NULL && x[0] != '\0')
   4855 +
   4856 +typedef struct CkSessionOutput {
   4857 +        char    *prop_name;
   4858 +        char    *prop_value;
   4859 +} CkSessionOutput;
   4860 +
   4861 +static gboolean do_all = FALSE;
   4862 +static gboolean do_version = FALSE;
   4863 +static char *do_format = NULL;
   4864 +static GOptionEntry entries [] = {
   4865 +        { "all", 'a', 0, G_OPTION_ARG_NONE, &do_all, N_("List all sessions. If not given, only list open sessions"), NULL },
   4866 +        { "format", 'f', 0, G_OPTION_ARG_STRING, &do_format, N_("Prints information according to the given format"), NULL },
   4867 +        { "version", 'V', 0, G_OPTION_ARG_NONE, &do_version, N_("Version of this application"), NULL },
   4868 +        { NULL }
   4869 +};
   4870 +
   4871  static gboolean
   4872  get_uint (DBusGProxy *proxy,
   4873            const char *method,
   4874 @@ -176,6 +193,7 @@ list_session (DBusGConnection *connection,
   4875          char       *sid;
   4876          char       *lsid;
   4877          char       *session_type;
   4878 +        char       *display_type;
   4879          char       *x11_display;
   4880          char       *x11_display_device;
   4881          char       *display_device;
   4882 @@ -184,8 +202,11 @@ list_session (DBusGConnection *connection,
   4883          char       *idle_since_hint;
   4884          gboolean    is_active;
   4885          gboolean    is_local;
   4886 +        gboolean    is_open;
   4887          char       *short_sid;
   4888          const char *short_ssid;
   4889 +        char      **format_arr = NULL;
   4890 +        int         i, j;
   4891  
   4892          proxy = dbus_g_proxy_new_for_name (connection,
   4893                                             CK_NAME,
   4894 @@ -198,6 +219,7 @@ list_session (DBusGConnection *connection,
   4895          sid = NULL;
   4896          lsid = NULL;
   4897          session_type = NULL;
   4898 +        display_type = NULL;
   4899          x11_display = NULL;
   4900          x11_display_device = NULL;
   4901          display_device = NULL;
   4902 @@ -209,15 +231,21 @@ list_session (DBusGConnection *connection,
   4903          get_path (proxy, "GetSeatId", &sid);
   4904          get_string (proxy, "GetLoginSessionId", &lsid);
   4905          get_string (proxy, "GetSessionType", &session_type);
   4906 +        get_string (proxy, "GetDisplayType", &display_type);
   4907          get_string (proxy, "GetX11Display", &x11_display);
   4908          get_string (proxy, "GetX11DisplayDevice", &x11_display_device);
   4909          get_string (proxy, "GetDisplayDevice", &display_device);
   4910          get_string (proxy, "GetRemoteHostName", &remote_host_name);
   4911 +        get_boolean (proxy, "IsOpen", &is_open);
   4912          get_boolean (proxy, "IsActive", &is_active);
   4913          get_boolean (proxy, "IsLocal", &is_local);
   4914          get_string (proxy, "GetCreationTime", &creation_time);
   4915          get_string (proxy, "GetIdleSinceHint", &idle_since_hint);
   4916  
   4917 +        if (!do_all && !is_open) {
   4918 +                return;
   4919 +        }
   4920 +
   4921          realname = get_real_name (uid);
   4922  
   4923          short_sid = sid;
   4924 @@ -230,24 +258,49 @@ list_session (DBusGConnection *connection,
   4925                  short_ssid = ssid + strlen (CK_PATH) + 1;
   4926          }
   4927  
   4928 -        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'",
   4929 -                short_ssid,
   4930 -                uid,
   4931 -                realname,
   4932 -                short_sid,
   4933 -                session_type,
   4934 -                is_active ? "TRUE" : "FALSE",
   4935 -                x11_display,
   4936 -                x11_display_device,
   4937 -                display_device,
   4938 -                remote_host_name,
   4939 -                is_local ? "TRUE" : "FALSE",
   4940 -                creation_time,
   4941 -                lsid);
   4942 -        if (idle_since_hint != NULL && idle_since_hint[0] != '\0') {
   4943 -                printf ("\n\tidle-since-hint = '%s'", idle_since_hint);
   4944 +        CkSessionOutput output[] = {
   4945 +                {"session-id", g_strdup (short_ssid)},
   4946 +                {"unix-user", g_strdup_printf ("%d", uid)},
   4947 +                {"realname", g_strdup (realname)},
   4948 +                {"seat", g_strdup (short_sid)},
   4949 +                {"session-type", g_strdup (session_type)},
   4950 +                {"display-type", g_strdup (display_type)},
   4951 +                {"open", is_open ? "TRUE" : "FALSE"},
   4952 +                {"active", is_active ? "TRUE" : "FALSE"},
   4953 +                {"x11-display", g_strdup (x11_display)},
   4954 +                {"x11-display-device", g_strdup (x11_display_device)},
   4955 +                {"display-device", g_strdup (display_device)},
   4956 +                {"remote-host-name", g_strdup (remote_host_name)},
   4957 +                {"is-local", is_local ? "TRUE" : "FALSE"},
   4958 +                {"on-since", g_strdup (creation_time)},
   4959 +                {"login-session-id", g_strdup (lsid)},
   4960 +                {"idle-since-hint", g_strdup (idle_since_hint)},
   4961 +        };
   4962 +
   4963 +        if (IS_STR_SET (do_format)) {
   4964 +                format_arr = g_strsplit (do_format, ",", -1);
   4965 +
   4966 +                for (i = 0; format_arr[i] != NULL; ++i) {
   4967 +                        for (j = 0; j < G_N_ELEMENTS (output); j++) {
   4968 +                                if (g_str_equal (format_arr[i], output[j].prop_name)) {
   4969 +                                        printf ("'%s'\t", output[j].prop_value);
   4970 +                                        break;
   4971 +                                }
   4972 +                        }
   4973 +                }
   4974 +                printf ("\n");
   4975 +                g_strfreev (format_arr);
   4976 +
   4977 +        } else {
   4978 +                for (j = 0; j < G_N_ELEMENTS (output); j++) {
   4979 +                        if (g_str_equal (output[j].prop_name, "session-id"))
   4980 +                                printf ("%s:\n", output[j].prop_value);
   4981 +                        else
   4982 +                                printf ("\t%s = '%s'\n",
   4983 +                                        output[j].prop_name,
   4984 +                                        output[j].prop_value);
   4985 +                }
   4986          }
   4987 -        printf ("\n");
   4988  
   4989          g_free (idle_since_hint);
   4990          g_free (creation_time);
   4991 @@ -256,9 +309,11 @@ list_session (DBusGConnection *connection,
   4992          g_free (sid);
   4993          g_free (lsid);
   4994          g_free (session_type);
   4995 +        g_free (display_type);
   4996          g_free (x11_display);
   4997          g_free (x11_display_device);
   4998          g_free (display_device);
   4999 +
   5000          g_object_unref (proxy);
   5001  }
   5002  
   5003 @@ -368,11 +423,6 @@ main (int    argc,
   5004          GOptionContext *context;
   5005          gboolean        retval;
   5006          GError         *error = NULL;
   5007 -        static gboolean do_version = FALSE;
   5008 -        static GOptionEntry entries [] = {
   5009 -                { "version", 'V', 0, G_OPTION_ARG_NONE, &do_version, N_("Version of this application"), NULL },
   5010 -                { NULL }
   5011 -        };
   5012  
   5013          g_type_init ();
   5014  
   5015