[gdm-list] GDM manages displays on the fly



Hi Joh and Ray,

Before version 2.21, GDM is capable of managing displays dynamically.
It's originally motivated by Sun Ray which works well on various Linux
platform. Sun Ray uses this feature to add/remove Sun Ray clients
when they are added/removed for the network. Beside Sun Ray, there
are other potential use cases, for example, launching GDM with Xvm,
or any terminal server environment might be want to start/stop display
without reconfiguration and restarting GDM daemon.

In order to fit with new GDM 2.21 framework, I try to rewrite
gdmdynamic. Please see attached patch. Could you have a look and give
some idea? Hopefully this functionality will be kept in upstream.

This patch adds a kind of display called dynamic display, which has
below features.

	- Can be Added, removed and listed dynamically without
         restarting gdm-binary
- Like static display, can be restarted by gdm-binary if it died exceptionally
	- Allow to specify custom Xserver when adding.
	- Support adding/removing multiple displays simultaneously,
         possibly hundreds of requests at the same time.
As well as static display and product display, currently I put dynamic
display under local display directory. And let gdm-simple-slave manage
it.
Apart from dyanmic management, another big difference from other display
types, we allow to specifiy custom Xserver when starting. Actually this
functionality is also needed for nest transient display, which requires
to run Xnest rather than a standard Xserver. In GDM 2.20, nest transient
display is running by "#gdmflexiserver -n".

Like transient display, property "seat-id" of dynamic displays are set
as "Seat1" in hard-code. Perhaps this needs enhancement. As my
understanding, dynamic display can be regarded as a typical multi-seat
case. But I'm not sure how this can work together with ConsoleKit?

For multi-seat, I'm a little confused. Looking into ConsoleKit code, it
seems to only support 2 seats, local and remote seats. But when I try
gdmdynamic, I find each login screen will add a new seat. Here's a
result of adding 5 displays at the same time.

----------------------------
# ck-list-sessions Session3:
       uid = '50'
       realname = 'GDM Reserved UID'
       seat = 'Seat4'
       session-type = 'LoginWindow'
       active = FALSE
       x11-display = ':102'
       x11-display-device = ''
       display-device = ''
       remote-host-name = ''
       is-local = TRUE
       on-since = '2008-04-17T08:24:26Z'
Session4:
       uid = '50'
       realname = 'GDM Reserved UID'
       seat = 'Seat5'
       session-type = 'LoginWindow'
       active = FALSE
       x11-display = ':103'
       x11-display-device = ''
       display-device = ''
       remote-host-name = ''
       is-local = TRUE
       on-since = '2008-04-17T08:24:26Z'
Session5:
       uid = '50'
       realname = 'GDM Reserved UID'
       seat = 'Seat6'
       session-type = 'LoginWindow'
       active = FALSE
       x11-display = ':100'
       x11-display-device = ''
       display-device = ''
       remote-host-name = ''
       is-local = TRUE
       on-since = '2008-04-17T08:24:26Z'
Session6:
       uid = '50'
       realname = 'GDM Reserved UID'
       seat = 'Seat7'
       session-type = 'LoginWindow'
       active = FALSE
       x11-display = ':104'
       x11-display-device = ''
       display-device = ''
       remote-host-name = ''
       is-local = TRUE
       on-since = '2008-04-17T08:24:28Z'
Session1:
       uid = '50'
       realname = 'GDM Reserved UID'
       seat = 'Seat2'
       session-type = 'LoginWindow'
       active = FALSE
       x11-display = ':0'
       x11-display-device = ''
       display-device = ''
       remote-host-name = ''
       is-local = TRUE
       on-since = '2008-04-17T08:19:53Z'
Session2:
       uid = '50'
       realname = 'GDM Reserved UID'
       seat = 'Seat3'
       session-type = 'LoginWindow'
       active = FALSE
       x11-display = ':101'
       x11-display-device = ''
       display-device = ''
       remote-host-name = ''
------------------------------------------------

Thanks,
-Simon

Index: utils/Makefile.am
===================================================================
--- utils/Makefile.am	(revision 6155)
+++ utils/Makefile.am	(working copy)
@@ -3,6 +3,7 @@ NULL =
 INCLUDES = \
 	-I.						\
 	-I..						\
+	-I$(top_srcdir)/common				\
 	-DGNOMELOCALEDIR=\""$(datadir)/locale"\" 	\
 	$(UTILS_CFLAGS)					\
 	$(GTK_CFLAGS)					\
@@ -25,6 +26,7 @@ gdm-safe-restart: gdm-safe-restart.in Ma
 bin_PROGRAMS = \
 	gdmflexiserver		\
 	gdm-screenshot		\
+	gdmdynamic		\
 	$(NULL)
 
 sbin_SCRIPTS = 			\
@@ -51,6 +53,16 @@ gdm_screenshot_LDADD =		\
 	$(COMMON_LIBS)		\
 	$(NULL)
 
+gdmdynamic_SOURCES =        	\
+        gdmdynamic.c        	\
+        $(NULL)
+
+gdmdynamic_LDADD =          	\
+        $(top_builddir)/common/libgdmcommon.la  \
+        $(GTK_LIBS)             \
+        $(COMMON_LIBS)          \
+        $(NULL)
+
 EXTRA_DIST = 			\
 	gdm-stop.in		\
 	gdm-restart.in		\
Index: utils/gdmdynamic.c
===================================================================
--- utils/gdmdynamic.c	(revision 0)
+++ utils/gdmdynamic.c	(revision 0)
@@ -0,0 +1,272 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ *    Authors: simon zheng sun com
+ *    Copyright (C) 2008 Sun Microsystems, Inc.
+ *    
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *   
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *   
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * 
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <strings.h>
+#include <glib/gi18n.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include "gdm-log.h"
+
+#define GDM_DBUS_NAME                            "org.gnome.DisplayManager"
+#define GDM_DBUS_LOCAL_DISPLAY_FACTORY_PATH      "/org/gnome/DisplayManager/LocalDisplayFactory"
+#define GDM_DBUS_LOCAL_DISPLAY_FACTORY_INTERFACE "org.gnome.DisplayManager.LocalDisplayFactory"
+
+static void
+run_in_background (gboolean background)
+{
+        /* handle background option by forking and exiting the parent */
+        if (background) {
+                switch(fork ())  {
+                        case -1:
+                                exit (1);
+                        case 0:
+                                break;
+                        default:
+                                exit (0);
+                }
+        }
+}
+
+static gboolean
+add_dynamic_display (const char *key)
+{
+        gint disp_num;
+        char *p;
+        char *xcommand;
+        char *id = NULL;
+        DBusGConnection *connection;
+        DBusGProxy *proxy;
+        GError *error = NULL;
+        gboolean ret;
+
+        if (! g_ascii_isdigit (*key)) {
+                g_warning ("Invalid display number!");
+                return FALSE;
+        }
+        disp_num = atoi (key);
+
+        p = strchr (key, '=');
+        if (p == NULL || *(p + 1) == 0) {
+                g_warning  ("No server string\n");
+                return FALSE;
+        }
+        xcommand = p + 1;
+
+        connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
+        if (connection == NULL) {
+                g_warning ("Failed to connect to the D-Bus daemon: %s",
+                       error->message);
+                g_error_free (error);
+                return FALSE;
+        }
+        proxy = dbus_g_proxy_new_for_name_owner (connection,
+                                      GDM_DBUS_NAME,
+                                      GDM_DBUS_LOCAL_DISPLAY_FACTORY_PATH,
+                                      GDM_DBUS_LOCAL_DISPLAY_FACTORY_INTERFACE,
+                                      &error);
+        if (proxy == NULL) {
+                g_warning ("Failed to create a new proxy, %s", error->message);
+                g_error_free (error);
+                return FALSE;
+        }
+        ret = dbus_g_proxy_call (proxy, 
+                                "CreateDynamicDisplay", 
+                                &error,
+                                G_TYPE_INT, disp_num,
+                                G_TYPE_STRING, xcommand,
+                                G_TYPE_INVALID,
+                                G_TYPE_STRING, &id,
+                                G_TYPE_INVALID);
+        if (ret == FALSE) {
+                if (error) {
+                         g_warning ("Unable to add dynamic display: %s", error->message);
+                         g_error_free (error);
+                }
+                return FALSE;
+        }
+        g_object_unref (proxy);
+
+        return ret;
+}
+
+static gboolean
+remove_dynamic_display (const char *key)
+{
+        gint disp_num;
+        DBusGConnection *connection;
+        DBusGProxy *proxy;
+        GError *error = NULL;
+        gboolean ret;
+
+        if (!g_ascii_isdigit (*key)) {
+                g_warning ("Invalid display number!");
+                return FALSE;
+        }
+        disp_num = atoi (key);
+
+        connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
+        if (connection == NULL) {
+                g_warning ("Failed to connect to the D-Bus daemon: %s",
+                       error->message);
+                g_error_free (error);
+                return FALSE;
+        }
+        proxy = dbus_g_proxy_new_for_name_owner (connection,
+                                      GDM_DBUS_NAME,
+                                      GDM_DBUS_LOCAL_DISPLAY_FACTORY_PATH,
+                                      GDM_DBUS_LOCAL_DISPLAY_FACTORY_INTERFACE,
+                                      &error);
+        if (proxy == NULL) {
+                g_warning ("Failed to create a new proxy, %s", error->message);
+                g_error_free (error);
+                return FALSE;
+        }
+        ret = dbus_g_proxy_call (proxy, 
+                                "RemoveDynamicDisplay", 
+                                &error,
+                                G_TYPE_INT, disp_num,
+                                G_TYPE_INVALID,
+                                G_TYPE_INVALID);
+        if (ret == FALSE) {
+                if (error) {
+                         g_warning ("Unable to remove dynamic display: %s", error->message);
+                         g_error_free (error);
+                }
+                return FALSE;
+        }
+        g_object_unref (proxy);
+
+        return ret;
+}
+
+
+static gboolean
+list_attached_displays (const char *pattern)
+{
+        DBusGConnection *connection;
+        DBusGProxy *proxy;
+        char *display_list = NULL;
+        GError *error = NULL;
+        gboolean ret;
+
+        connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
+        if (connection == NULL) {
+                g_warning ("Failed to connect to the D-Bus daemon: %s",
+                       error->message);
+                g_error_free (error);
+                return FALSE;
+        }
+        proxy = dbus_g_proxy_new_for_name_owner (connection,
+                                      GDM_DBUS_NAME,
+                                      GDM_DBUS_LOCAL_DISPLAY_FACTORY_PATH,
+                                      GDM_DBUS_LOCAL_DISPLAY_FACTORY_INTERFACE,
+                                      &error);
+        if (proxy == NULL) {
+                g_warning ("Failed to create a new proxy, %s", error->message);
+                g_error_free (error);
+                return FALSE;
+        }
+        ret = dbus_g_proxy_call (proxy, 
+                                "ListDisplays", 
+                                &error,
+                                G_TYPE_STRING, pattern,
+                                G_TYPE_INVALID,
+                                G_TYPE_STRING, &display_list,
+                                G_TYPE_INVALID);
+        if (ret == FALSE) {
+                if (error) {
+                         g_warning ("Unable to list attached display: %s", error->message);
+                         g_error_free (error);
+                }
+                return FALSE;
+        } else {
+                g_printf ("%s\n", display_list);
+        }
+        
+        g_object_unref (proxy);
+
+        return ret;
+}        
+
+int
+main (int argc, char *argv[])
+{
+        GOptionContext *ctx;
+        gboolean        res;
+        GError         *error;
+
+        char *add_params = NULL;
+        char *delete_params = NULL;
+        char *pattern = NULL;
+        gboolean verbose = FALSE;
+        gboolean background = FALSE;
+
+        /*FIXME: Do we need try sleep and background option? */
+        GOptionEntry options [] = {
+                { "add", 'a', 0, G_OPTION_ARG_STRING, &add_params, N_("Add a new display"), N_("display") },
+                { "delete", 'd', 0, G_OPTION_ARG_STRING, &delete_params, N_("Delete a display"), N_("display") },
+                { "list", 'l', 0, G_OPTION_ARG_STRING, &pattern, N_("List attached displays that match a pattern"), N_("pattern") },
+                { "background", 'b', 0, G_OPTION_ARG_NONE, &background, N_("Run in background"), NULL },
+                { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, N_("Show extra debugging information"), NULL },
+                { NULL }
+        };   
+
+        bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
+        bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+        textdomain (GETTEXT_PACKAGE);
+
+        /* Option parsing */
+        ctx = g_option_context_new ("- Manage dynamic displays");
+        g_option_context_add_main_entries (ctx, options, _("Main Options"));
+        g_option_context_parse (ctx, &argc, &argv, NULL);
+        g_option_context_free (ctx);    
+
+        g_type_init();
+
+        gdm_log_init ();
+        gdm_log_set_debug (verbose);
+
+        /*
+         * Must contain one of -a, -d, or -l.
+         */
+        if (add_params) {
+                run_in_background (background);
+                add_dynamic_display (add_params);
+        } else if (delete_params) {
+                run_in_background (background);
+                remove_dynamic_display (delete_params);
+        } else if (pattern) {
+                run_in_background (background);
+                list_attached_displays (pattern);
+        } else {
+                g_warning ("Invaild parameters!");
+                exit (1);
+        }
+
+        return 0;
+}
Index: daemon/gdm-local-display-factory.c
===================================================================
--- daemon/gdm-local-display-factory.c	(revision 6155)
+++ daemon/gdm-local-display-factory.c	(working copy)
@@ -34,6 +34,7 @@
 #include "gdm-display-store.h"
 #include "gdm-static-display.h"
 #include "gdm-transient-display.h"
+#include "gdm-dynamic-display.h"
 #include "gdm-static-factory-display.h"
 #include "gdm-product-display.h"
 
@@ -118,7 +119,7 @@ sort_nums (gpointer a,
 static guint32
 take_next_display_number (GdmLocalDisplayFactory *factory)
 {
-        GList  *list;
+        GList  *list = NULL;
         GList  *l;
         guint32 ret;
 
@@ -185,6 +186,62 @@ store_display (GdmLocalDisplayFactory *f
         g_hash_table_insert (factory->priv->displays, GUINT_TO_POINTER (num), NULL);
 }
 
+static void
+store_remove_display (GdmLocalDisplayFactory *factory,
+                      guint32                 num,
+                      GdmDisplay             *display)
+{
+        GdmDisplayStore *store;
+
+        store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
+        gdm_display_store_remove (store, display);
+
+        /* remove from our reserved spot */
+        g_hash_table_remove (factory->priv->displays, GUINT_TO_POINTER (num));
+}
+
+static gboolean
+lookup_by_display_number (const char *id,
+                          GdmDisplay *display,
+                          gpointer    data)
+{
+        gint32 number;
+        gint32 display_number = -1;
+
+        number = GPOINTER_TO_INT (data);
+
+        if (! GDM_IS_DISPLAY (display)) {
+                return FALSE;
+        }
+
+        gdm_display_get_x11_display_number (display, &display_number, NULL);
+
+        if (display_number == number) {
+                return TRUE;
+        }
+
+        return FALSE;
+}
+
+static GdmDisplay *
+gdm_local_display_lookup_by_number (GdmLocalDisplayFactory *factory,
+                          gint32                  number)
+{
+        GdmDisplay      *display;
+        GdmDisplayStore *store;
+
+        if (number < 0)
+                return NULL;
+		
+        store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
+        display = gdm_display_store_find (store,
+                                          (GdmDisplayStoreFunc)lookup_by_display_number,
+                                          GINT_TO_POINTER (number));
+
+        return display;
+}
+
+
 /*
   Example:
   dbus-send --system --dest=org.gnome.DisplayManager \
@@ -281,6 +338,151 @@ gdm_local_display_factory_create_product
         return ret;
 }
 
+gboolean
+gdm_local_display_factory_create_dynamic_display (GdmLocalDisplayFactory *factory,
+                                                  gint32          display_number,
+                                                  char           *xserver_command,
+                                                  char          **id,                                                    
+                                                  GError        **error)
+{
+        gboolean         ret;
+        GdmDisplay     *display;
+
+        g_return_val_if_fail (GDM_IS_LOCAL_DISPLAY_FACTORY (factory), FALSE);
+
+        ret = FALSE;
+
+        /* Make sure number doesn't exist */
+        if (g_hash_table_lookup_extended (factory->priv->displays,
+                                        GINT_TO_POINTER (display_number),
+                                        NULL,
+                                        NULL)) {
+                g_debug ("GdmLocalDisplayFactory: display number already exists");
+                goto out;
+        }
+
+        g_debug ("GdmLocalDisplayFactory: Creating dynamic display %d", display_number);
+
+        display = gdm_dynamic_display_new (display_number, xserver_command);
+
+        /* FIXME: don't hardcode seat1? */
+        g_object_set (display, "seat-id", CK_SEAT1_PATH, NULL);
+
+        store_display (factory, display_number, display);
+
+        if (! gdm_display_manage (display)) {
+                display = NULL;
+                goto out;
+        }
+
+        if (! gdm_display_get_id (display, id, NULL)) {
+                display = NULL;
+                goto out;
+        }
+
+        ret = TRUE;
+ out:
+        g_object_unref (display);
+
+        return ret;
+}
+
+gboolean
+gdm_local_display_factory_remove_dynamic_display (GdmLocalDisplayFactory *factory,
+                                                  gint32                  display_number,
+                                                  GError                **error)
+{
+        gboolean         ret;
+        GdmDisplay      *display;
+
+        g_return_val_if_fail (GDM_IS_LOCAL_DISPLAY_FACTORY (factory), FALSE);
+
+        ret = FALSE;
+
+        /* Make sure number already exist */
+        if (! g_hash_table_lookup_extended (factory->priv->displays,
+                                        GINT_TO_POINTER (display_number),
+                                        NULL,
+                                        NULL)) {
+                g_debug ("GdmLocalDisplayFactory: display number doesn't exists");
+                goto out;
+        }
+
+        g_debug ("GdmLocalDisplayFactory: Removing dynamic display %d", display_number);
+
+        display = gdm_local_display_lookup_by_number (factory, display_number);
+
+        if (! gdm_display_unmanage (display)) {
+                display = NULL;
+                goto out;
+        }
+
+        store_remove_display (factory, display_number, display);
+
+        ret = TRUE;
+ out:
+        return ret;
+}
+
+
+gboolean
+gdm_local_display_factory_list_displays (GdmLocalDisplayFactory *factory,
+                                         char                   *pattern,
+                                         char                  **display_list,
+                                         GError                **error)
+{
+        gboolean        ret;
+        GdmDisplay     *display;
+        GList          *list = NULL;
+        GList          *l;
+        GString        *ret_msg;
+
+        g_return_val_if_fail (GDM_IS_LOCAL_DISPLAY_FACTORY (factory), FALSE);
+
+        ret = FALSE;
+
+        /* Get display number list from our reserved spot */
+        g_hash_table_foreach (factory->priv->displays, (GHFunc)listify_hash, &list);
+        if (list == NULL) {
+                goto out;
+        }
+        /* sort low to high */
+        list = g_list_sort (list, (GCompareFunc)sort_nums);
+
+        g_debug ("GdmLocalDisplayFactory: Listing X displays");
+
+        ret_msg = g_string_new ("");
+
+        for (l = list; l != NULL; l = l->next) {
+                gint32 number = GPOINTER_TO_INT (l->data);
+                GdmDisplay *display = NULL;
+                char *xserver_cmd = NULL;
+                char *name = NULL;
+			
+                g_debug ("GdmLocalDisplayFactory: %d", number);
+                display = gdm_local_display_lookup_by_number (factory, number);
+                g_object_get (display, "xserver-command", &xserver_cmd, NULL);
+
+                if (xserver_cmd && g_pattern_match_simple (pattern, xserver_cmd)) {
+                        /* FIXME: need to show login user name as well as display name */
+                        gdm_display_get_x11_display_name (display, &name, NULL);
+                        g_string_append_printf (ret_msg, "%s, ", name?name:"None");
+                        g_free (name);
+                	g_free (xserver_cmd);
+                }
+        }
+
+        if (ret_msg->str[0])
+                *display_list = g_strdup (ret_msg->str);
+        else
+                *display_list = g_strdup ("No matching display!");
+        g_string_free (ret_msg, TRUE);
+	
+        ret = TRUE;
+ out:
+        return ret;
+}
+
 static void
 on_static_display_status_changed (GdmDisplay             *display,
                                   GParamSpec             *arg1,
Index: daemon/gdm-server.c
===================================================================
--- daemon/gdm-server.c	(revision 6155)
+++ daemon/gdm-server.c	(working copy)
@@ -730,6 +730,13 @@ gdm_server_stop (GdmServer *server)
         return TRUE;
 }
 
+static void
+_gdm_server_set_command (GdmServer  *server,
+                         const char *command)
+{
+        g_free (server->priv->command);
+        server->priv->command = g_strdup (command);
+}
 
 static void
 _gdm_server_set_display_name (GdmServer  *server,
@@ -773,6 +780,9 @@ gdm_server_set_property (GObject      *o
         self = GDM_SERVER (object);
 
         switch (prop_id) {
+        case PROP_COMMAND:
+                _gdm_server_set_command (self, g_value_get_string (value));
+                break;
         case PROP_DISPLAY_NAME:
                 _gdm_server_set_display_name (self, g_value_get_string (value));
                 break;
@@ -802,6 +812,9 @@ gdm_server_get_property (GObject    *obj
         self = GDM_SERVER (object);
 
         switch (prop_id) {
+        case PROP_COMMAND:
+                g_value_set_string (value, self->priv->command);
+                break;
         case PROP_DISPLAY_NAME:
                 g_value_set_string (value, self->priv->display_name);
                 break;
Index: daemon/gdm-local-display-factory.h
===================================================================
--- daemon/gdm-local-display-factory.h	(revision 6155)
+++ daemon/gdm-local-display-factory.h	(working copy)
@@ -71,6 +71,21 @@ gboolean                   gdm_local_dis
                                                                                char                  **id,
                                                                                GError                **error);
 
+gboolean                  gdm_local_display_factory_create_dynamic_display (GdmLocalDisplayFactory *factory,
+                                                                            gint32                  display_number,
+                                                                            char                   *xserver_command,
+                                                                            char                  **id,
+                                                                            GError                **error);
+
+gboolean                  gdm_local_display_factory_remove_dynamic_display (GdmLocalDisplayFactory *factory,
+                                                                            gint32                  display_number,
+                                                                            GError                **error);
+
+gboolean                  gdm_local_display_factory_list_displays (GdmLocalDisplayFactory *factory,
+                                                                   char                   *pattern,
+                                                                   char                  **display_list,
+                                                                   GError                **error);
+
 G_END_DECLS
 
 #endif /* __GDM_LOCAL_DISPLAY_FACTORY_H */
Index: daemon/gdm-local-display-factory.xml
===================================================================
--- daemon/gdm-local-display-factory.xml	(revision 6155)
+++ daemon/gdm-local-display-factory.xml	(working copy)
@@ -9,5 +9,17 @@
     <method name="CreateTransientDisplay">
       <arg name="id" direction="out" type="o"/>
     </method>
+    <method name="CreateDynamicDisplay">
+      <arg name="display_number" direction="in" type="i"/>
+      <arg name="xserver_command" direction="in" type="s"/>
+      <arg name="id" direction="out" type="o"/>
+    </method>
+    <method name="RemoveDynamicDisplay">
+      <arg name="display_number" direction="in" type="i"/>
+    </method>
+    <method name="ListDisplays">
+      <arg name="pattern" direction="in" type="s"/>
+      <arg name="display_list" direction="out" type="s"/>
+    </method>
   </interface>
 </node>
Index: daemon/gdm-dynamic-display.c
===================================================================
--- daemon/gdm-dynamic-display.c	(revision 0)
+++ daemon/gdm-dynamic-display.c	(revision 0)
@@ -0,0 +1,208 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 William Jon McCann <jmccann redhat com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+
+#include "gdm-common.h"
+#include "gdm-display.h"
+#include "gdm-dynamic-display.h"
+
+#define GDM_DYNAMIC_DISPLAY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_DYNAMIC_DISPLAY, GdmDynamicDisplayPrivate))
+
+struct _GdmDynamicDisplayPrivate
+{
+        gpointer dummy;
+};
+
+enum {
+        PROP_0,
+};
+
+static void     gdm_dynamic_display_class_init   (GdmDynamicDisplayClass *klass);
+static void     gdm_dynamic_display_init         (GdmDynamicDisplay      *display);
+static void     gdm_dynamic_display_finalize     (GObject                  *object);
+
+G_DEFINE_TYPE (GdmDynamicDisplay, gdm_dynamic_display, GDM_TYPE_DISPLAY)
+
+static gboolean
+gdm_dynamic_display_create_authority (GdmDisplay *display)
+{
+        g_return_val_if_fail (GDM_IS_DISPLAY (display), FALSE);
+
+        GDM_DISPLAY_CLASS (gdm_dynamic_display_parent_class)->create_authority (display);
+
+        return TRUE;
+}
+
+static gboolean
+gdm_dynamic_display_add_user_authorization (GdmDisplay *display,
+                                            const char *username,
+                                            char      **filename,
+                                            GError    **error)
+{
+        return GDM_DISPLAY_CLASS (gdm_dynamic_display_parent_class)->add_user_authorization (display, username, filename, error);
+}
+
+static gboolean
+gdm_dynamic_display_remove_user_authorization (GdmDisplay *display,
+                                               const char *username,
+                                               GError    **error)
+{
+        return GDM_DISPLAY_CLASS (gdm_dynamic_display_parent_class)->remove_user_authorization (display, username, error);
+}
+
+static gboolean
+gdm_dynamic_display_manage (GdmDisplay *display)
+{
+        g_return_val_if_fail (GDM_IS_DISPLAY (display), FALSE);
+	
+        GDM_DISPLAY_CLASS (gdm_dynamic_display_parent_class)->manage (display);
+	
+        return TRUE;
+}
+
+static gboolean
+gdm_dynamic_display_finish (GdmDisplay *display)
+{
+        int status;
+
+        g_return_val_if_fail (GDM_IS_DISPLAY (display), FALSE);
+
+        /* restart dynamic display */
+        gdm_display_unmanage (display);

+
+        status = gdm_display_get_status (display);
+        if (status != GDM_DISPLAY_FAILED) {
+                gdm_display_manage (display);
+        }
+
+        return TRUE;
+}
+
+static gboolean
+gdm_dynamic_display_unmanage (GdmDisplay *display)
+{
+        g_return_val_if_fail (GDM_IS_DISPLAY (display), FALSE);
+
+        GDM_DISPLAY_CLASS (gdm_dynamic_display_parent_class)->unmanage (display);
+
+        return TRUE;
+}
+
+static void
+gdm_dynamic_display_set_property (GObject      *object,
+                                  guint         prop_id,
+                                  const GValue *value,
+                                  GParamSpec   *pspec)
+{
+        switch (prop_id) {
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+        }
+}
+
+static void
+gdm_dynamic_display_get_property (GObject    *object,
+                                  guint       prop_id,
+                                  GValue     *value,
+                                  GParamSpec *pspec)
+{
+        switch (prop_id) {
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+        }
+}
+
+static void
+gdm_dynamic_display_class_init (GdmDynamicDisplayClass *klass)
+{
+        GObjectClass    *object_class = G_OBJECT_CLASS (klass);
+        GdmDisplayClass *display_class = GDM_DISPLAY_CLASS (klass);
+
+        object_class->get_property = gdm_dynamic_display_get_property;
+        object_class->set_property = gdm_dynamic_display_set_property;
+        object_class->finalize = gdm_dynamic_display_finalize;
+
+        display_class->create_authority = gdm_dynamic_display_create_authority;
+        display_class->add_user_authorization = gdm_dynamic_display_add_user_authorization;
+        display_class->remove_user_authorization = gdm_dynamic_display_remove_user_authorization;
+        display_class->manage = gdm_dynamic_display_manage;
+        display_class->finish = gdm_dynamic_display_finish;
+        display_class->unmanage = gdm_dynamic_display_unmanage;
+
+        g_type_class_add_private (klass, sizeof (GdmDynamicDisplayPrivate));
+}
+
+static void
+gdm_dynamic_display_init (GdmDynamicDisplay *display)
+{
+
+        display->priv = GDM_DYNAMIC_DISPLAY_GET_PRIVATE (display);
+}
+
+static void
+gdm_dynamic_display_finalize (GObject *object)
+{
+        GdmDynamicDisplay *display;
+
+        g_return_if_fail (object != NULL);
+        g_return_if_fail (GDM_IS_DYNAMIC_DISPLAY (object));
+
+        display = GDM_DYNAMIC_DISPLAY (object);
+
+        g_return_if_fail (display->priv != NULL);
+
+        G_OBJECT_CLASS (gdm_dynamic_display_parent_class)->finalize (object);
+}
+
+GdmDisplay *
+gdm_dynamic_display_new (int display_number, char* xserver_command)
+{
+        GObject *object;
+        char    *x11_display;
+
+        x11_display = g_strdup_printf (":%d", display_number);
+        object = g_object_new (GDM_TYPE_DYNAMIC_DISPLAY,
+                               "x11-display-number", display_number,
+                               "x11-display-name", x11_display,
+                               "xserver-command", xserver_command,
+                               NULL);
+        g_free (x11_display);
+
+        return GDM_DISPLAY (object);
+}
Index: daemon/gdm-dynamic-display.h
===================================================================
--- daemon/gdm-dynamic-display.h	(revision 0)
+++ daemon/gdm-dynamic-display.h	(revision 0)
@@ -0,0 +1,58 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 William Jon McCann <jmccann redhat com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+
+#ifndef __GDM_DYNAMIC_DISPLAY_H
+#define __GDM_DYNAMIC_DISPLAY_H
+
+#include <glib-object.h>
+#include <dbus/dbus-glib.h>
+#include "gdm-display.h"
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_DYNAMIC_DISPLAY         (gdm_dynamic_display_get_type ())
+#define GDM_DYNAMIC_DISPLAY(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_DYNAMIC_DISPLAY, GdmDynamicDisplay))
+#define GDM_DYNAMIC_DISPLAY_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_DYNAMIC_DISPLAY, GdmDynamicDisplayClass))
+#define GDM_IS_DYNAMIC_DISPLAY(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_DYNAMIC_DISPLAY))
+#define GDM_IS_DYNAMIC_DISPLAY_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_DYNAMIC_DISPLAY))
+#define GDM_DYNAMIC_DISPLAY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_DYNAMIC_DISPLAY, GdmDynamicDisplayClass))
+
+typedef struct _GdmDynamicDisplayPrivate GdmDynamicDisplayPrivate;
+
+typedef struct
+{
+        GdmDisplay                parent;
+        GdmDynamicDisplayPrivate *priv;
+} GdmDynamicDisplay;
+
+typedef struct
+{
+        GdmDisplayClass   parent_class;
+
+} GdmDynamicDisplayClass;
+
+GType               gdm_dynamic_display_get_type                (void);
+GdmDisplay *        gdm_dynamic_display_new                     (int display_number, char* xserver_command);
+
+
+G_END_DECLS
+
+#endif /* __GDM_DYNAMIC_DISPLAY_H */
Index: daemon/gdm-display.c
===================================================================
--- daemon/gdm-display.c	(revision 6155)
+++ daemon/gdm-display.c	(working copy)
@@ -58,6 +58,8 @@ struct GdmDisplayPrivate
         GTimer               *slave_timer;
         char                 *slave_command;
 
+        char                 *xserver_command;
+
         char                 *x11_cookie;
         gsize                 x11_cookie_size;
         GdmDisplayAccessFile *access_file;
@@ -82,6 +84,7 @@ enum {
         PROP_X11_AUTHORITY_FILE,
         PROP_IS_LOCAL,
         PROP_SLAVE_COMMAND,
+        PROP_XSERVER_COMMAND,
 };
 
 static void     gdm_display_class_init  (GdmDisplayClass *klass);
@@ -483,7 +486,13 @@ gdm_display_real_manage (GdmDisplay *dis
                           G_CALLBACK (slave_died),
                           display);
 
-        command = g_strdup_printf ("%s --display-id %s",
+        if (display->priv->xserver_command)
+                command = g_strdup_printf ("%s --display-id %s --xserver-command %s",
+                                   display->priv->slave_command,
+                                   display->priv->id,
+                                   display->priv->xserver_command);
+        else
+                command = g_strdup_printf ("%s --display-id %s",
                                    display->priv->slave_command,
                                    display->priv->id);
 
@@ -703,6 +712,14 @@ _gdm_display_set_slave_command (GdmDispl
 }
 
 static void
+_gdm_display_set_xserver_command (GdmDisplay     *display,
+                                const char     *command)
+{
+        g_free (display->priv->xserver_command);
+        display->priv->xserver_command = g_strdup (command);
+}
+
+static void
 gdm_display_set_property (GObject        *object,
                           guint           prop_id,
                           const GValue   *value,
@@ -740,6 +757,9 @@ gdm_display_set_property (GObject       
         case PROP_SLAVE_COMMAND:
                 _gdm_display_set_slave_command (self, g_value_get_string (value));
                 break;
+        case PROP_XSERVER_COMMAND:
+                _gdm_display_set_xserver_command (self, g_value_get_string (value));
+                break;
         default:
                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                 break;
@@ -788,6 +808,9 @@ gdm_display_get_property (GObject       
         case PROP_SLAVE_COMMAND:
                 g_value_set_string (value, self->priv->slave_command);
                 break;
+        case PROP_XSERVER_COMMAND:
+                g_value_set_string (value, self->priv->xserver_command);
+                break;
         default:
                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                 break;
@@ -970,6 +993,14 @@ gdm_display_class_init (GdmDisplayClass 
                                                            G_MAXINT,
                                                            GDM_DISPLAY_UNMANAGED,
                                                            G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+		
+        g_object_class_install_property (object_class,
+                                         PROP_XSERVER_COMMAND,
+                                         g_param_spec_string ("xserver-command",
+                                                              "xserver command",
+                                                              "xserver command",
+                                                              NULL,
+                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
         g_type_class_add_private (klass, sizeof (GdmDisplayPrivate));
 
Index: daemon/simple-slave-main.c
===================================================================
--- daemon/simple-slave-main.c	(revision 6155)
+++ daemon/simple-slave-main.c	(working copy)
@@ -153,9 +153,11 @@ main (int    argc,
         DBusGConnection  *connection;
         GdmSlave         *slave;
         static char      *display_id = NULL;
+        static char      *xserver_command = NULL;
         GdmSignalHandler *signal_handler;
         static GOptionEntry entries []   = {
                 { "display-id", 0, 0, G_OPTION_ARG_STRING, &display_id, N_("Display ID"), N_("id") },
+                { "xserver-command", 0, 0, G_OPTION_ARG_STRING, &xserver_command, N_("Xserver Command"), N_("xserver") },
                 { NULL }
         };
 
@@ -213,6 +215,11 @@ main (int    argc,
         if (slave == NULL) {
                 goto out;
         }
+        /* Use custom xserver */
+        if (xserver_command)
+                g_object_set (G_OBJECT (slave),
+                                    "xserver-command", xserver_command,
+                                    NULL);
         g_signal_connect (slave,
                           "stopped",
                           G_CALLBACK (on_slave_stopped),
Index: daemon/gdm-simple-slave.c
===================================================================
--- daemon/gdm-simple-slave.c	(revision 6155)
+++ daemon/gdm-simple-slave.c	(working copy)
@@ -73,6 +73,8 @@ struct GdmSimpleSlavePrivate
         GPid               server_pid;
         guint              connection_attempts;
 
+        char              *xserver_command;
+
         GdmServer         *server;
         GdmGreeterServer  *greeter_server;
         GdmGreeterSession *greeter;
@@ -84,6 +86,7 @@ struct GdmSimpleSlavePrivate
 
 enum {
         PROP_0,
+        PROP_XSERVER_COMMAND,
 };
 
 static void     gdm_simple_slave_class_init     (GdmSimpleSlaveClass *klass);
@@ -966,6 +969,11 @@ gdm_simple_slave_run (GdmSimpleSlave *sl
                 gboolean res;
 
                 slave->priv->server = gdm_server_new (display_name, auth_file);
+                /* pass in custom xserver command */
+                if (slave->priv->xserver_command)
+                        g_object_set (G_OBJECT (slave->priv->server),
+                                            "command", slave->priv->xserver_command,
+                                            NULL);
                 g_signal_connect (slave->priv->server,
                                   "exited",
                                   G_CALLBACK (on_server_exited),
@@ -1047,7 +1055,14 @@ gdm_simple_slave_set_property (GObject  
                                const GValue *value,
                                GParamSpec   *pspec)
 {
+        GdmSimpleSlave *self;
+
+        self = GDM_SIMPLE_SLAVE (object);
+
         switch (prop_id) {
+        case PROP_XSERVER_COMMAND:
+                g_free (self->priv->xserver_command);
+                self->priv->xserver_command = g_strdup (g_value_get_string (value));
         default:
                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                 break;
@@ -1060,7 +1075,14 @@ gdm_simple_slave_get_property (GObject  
                                GValue      *value,
                                GParamSpec *pspec)
 {
+        GdmSimpleSlave *self;
+	
+        self = GDM_SIMPLE_SLAVE (object);
+
         switch (prop_id) {
+        case PROP_XSERVER_COMMAND:
+                g_value_set_string (value, self->priv->xserver_command);
+                break;
         default:
                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                 break;
@@ -1097,6 +1119,15 @@ gdm_simple_slave_class_init (GdmSimpleSl
 
         g_type_class_add_private (klass, sizeof (GdmSimpleSlavePrivate));
 
+        g_object_class_install_property (object_class,
+                                         PROP_XSERVER_COMMAND,
+                                         g_param_spec_string ("xserver-command",
+                                                              "xserver command",
+                                                              "xserver command",
+                                                              NULL,
+                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+
         dbus_g_object_type_install_info (GDM_TYPE_SIMPLE_SLAVE, &dbus_glib_gdm_simple_slave_object_info);
 }
 
Index: daemon/Makefile.am
===================================================================
--- daemon/Makefile.am	(revision 6155)
+++ daemon/Makefile.am	(working copy)
@@ -301,6 +301,8 @@ gdm_binary_SOURCES = 			\
 	gdm-static-display.h		\
 	gdm-transient-display.c		\
 	gdm-transient-display.h		\
+	gdm-dynamic-display.c		\
+	gdm-dynamic-display.h		\
 	gdm-static-factory-display.c	\
 	gdm-static-factory-display.h	\
 	gdm-product-display.c		\


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