gdm r5645 - in trunk: . common daemon data gui/simple-chooser gui/simple-greeter po



Author: mccann
Date: Thu Jan 31 00:51:46 2008
New Revision: 5645
URL: http://svn.gnome.org/viewvc/gdm?rev=5645&view=rev

Log:
2008-01-30  William Jon McCann  <mccann jhu edu>

	* common/gdm-address.c: (add_local_siocgifconf),
	(add_local_addrinfo), (gdm_address_peek_local_list):
	* daemon/Makefile.am:
	* daemon/gdm-chooser-server.c: (generate_address),
	(handle_select_hostname), (handle_disconnect),
	(chooser_handle_child_message), (do_introspect),
	(chooser_server_message_handler),
	(chooser_server_unregister_handler), (connection_filter_function),
	(allow_user_function), (handle_connection),
	(gdm_chooser_server_start), (gdm_chooser_server_stop),
	(gdm_chooser_server_get_address),
	(_gdm_chooser_server_set_display_id),
	(_gdm_chooser_server_set_user_name),
	(_gdm_chooser_server_set_group_name),
	(gdm_chooser_server_set_property),
	(gdm_chooser_server_get_property),
	(gdm_chooser_server_constructor), (gdm_chooser_server_class_init),
	(gdm_chooser_server_init), (gdm_chooser_server_finalize),
	(gdm_chooser_server_new):
	* daemon/gdm-chooser-server.h:
	* daemon/gdm-chooser-session.c: (listify_hash),
	(get_chooser_environment), (chooser_session_child_watch),
	(spawn_child_setup), (spawn_command_line_sync_as_user),
	(spawn_command_line_async_as_user), (parse_value_as_integer),
	(parse_dbus_launch_output), (start_dbus_daemon),
	(stop_dbus_daemon), (gdm_chooser_session_spawn),
	(gdm_chooser_session_start), (wait_on_child),
	(chooser_session_died), (gdm_chooser_session_stop),
	(gdm_chooser_session_set_server_address),
	(_gdm_chooser_session_set_x11_display_name),
	(_gdm_chooser_session_set_x11_display_hostname),
	(_gdm_chooser_session_set_x11_display_device),
	(_gdm_chooser_session_set_x11_authority_file),
	(_gdm_chooser_session_set_user_name),
	(_gdm_chooser_session_set_group_name),
	(gdm_chooser_session_set_property),
	(gdm_chooser_session_get_property),
	(gdm_chooser_session_constructor),
	(gdm_chooser_session_class_init), (gdm_chooser_session_init),
	(gdm_chooser_session_finalize), (gdm_chooser_session_new):
	* daemon/gdm-chooser-session.h:
	* daemon/gdm-display.c: (gdm_display_real_set_slave_bus_name),
	(gdm_display_set_slave_bus_name), (gdm_display_class_init):
	* daemon/gdm-display.h:
	* daemon/gdm-display.xml:
	* daemon/gdm-factory-slave.c:
	* daemon/gdm-greeter-server.c:
	* daemon/gdm-greeter-session.c: (gdm_greeter_session_init):
	* daemon/gdm-product-slave.c:
	* daemon/gdm-simple-slave.c:
	* daemon/gdm-slave.c: (gdm_slave_set_slave_bus_name),
	(gdm_slave_real_start), (register_slave), (gdm_slave_constructor):
	* daemon/gdm-xdmcp-chooser-display.c: (on_hostname_selected),
	(gdm_xdmcp_chooser_display_set_slave_bus_name),
	(gdm_xdmcp_chooser_display_manage),
	(gdm_xdmcp_chooser_display_class_init),
	(gdm_xdmcp_chooser_display_init),
	(gdm_xdmcp_chooser_display_finalize),
	(gdm_xdmcp_chooser_display_new):
	* daemon/gdm-xdmcp-chooser-display.h:
	* daemon/gdm-xdmcp-chooser-display.xml:
	* daemon/gdm-xdmcp-chooser-slave.c: (on_chooser_session_start),
	(on_chooser_session_stop), (on_chooser_session_exited),
	(on_chooser_session_died), (on_chooser_hostname_selected),
	(on_chooser_disconnected), (on_chooser_connected), (setup_server),
	(run_chooser), (idle_connect_to_display),
	(gdm_xdmcp_chooser_slave_run), (gdm_xdmcp_chooser_slave_start),
	(gdm_xdmcp_chooser_slave_stop),
	(gdm_xdmcp_chooser_slave_set_property),
	(gdm_xdmcp_chooser_slave_get_property),
	(gdm_xdmcp_chooser_slave_constructor),
	(gdm_xdmcp_chooser_slave_class_init),
	(gdm_xdmcp_chooser_slave_init), (gdm_xdmcp_chooser_slave_finalize),
	(gdm_xdmcp_chooser_slave_new):
	* daemon/gdm-xdmcp-chooser-slave.h:
	* daemon/gdm-xdmcp-display-factory.c: (set_port_for_request),
	(gdm_xdmcp_send_forward_query), (indirect_client_create),
	(indirect_client_destroy), (indirect_client_lookup_by_chosen),
	(indirect_client_lookup), (gdm_xdmcp_handle_indirect_query),
	(forward_query_destroy), (remove_oldest_forward),
	(forward_query_create), (forward_query_lookup),
	(gdm_xdmcp_handle_forward_query), (gdm_xdmcp_send_decline),
	(on_hostname_selected), (gdm_xdmcp_display_create),
	(gdm_xdmcp_handle_request), (gdm_xdmcp_send_refuse),
	(gdm_xdmcp_handle_manage), (gdm_xdmcp_handle_managed_forward):
	* daemon/gdm-xdmcp-display.c: (gdm_xdmcp_display_class_init),
	(gdm_xdmcp_display_finalize):
	* daemon/gdm-xdmcp-display.h:
	* daemon/gdm-xdmcp-display.xml:
	* daemon/gdm-xdmcp-greeter-display.c:
	(gdm_xdmcp_greeter_display_class_init),
	(gdm_xdmcp_greeter_display_init),
	(gdm_xdmcp_greeter_display_finalize),
	(gdm_xdmcp_greeter_display_new):
	* daemon/gdm-xdmcp-greeter-display.h:
	* daemon/xdmcp-chooser-slave-main.c: (get_system_bus), (signal_cb),
	(on_slave_stopped), (main):
	* data/gdm.conf:
	* gui/simple-chooser/Makefile.am:
	* gui/simple-chooser/chooser-main.c: (assistive_registry_launch),
	(filter_watch), (filter_timeout), (assistive_registry_start),
	(at_set_gtk_modules), (load_a11y), (main):
	* gui/simple-chooser/gdm-chooser-client.c:
	(gdm_chooser_client_error_quark), (send_dbus_string_method),
	(send_dbus_void_method), (gdm_chooser_client_call_select_hostname),
	(gdm_chooser_client_call_disconnect), (client_dbus_handle_message),
	(client_dbus_filter_function), (gdm_chooser_client_start),
	(gdm_chooser_client_stop), (gdm_chooser_client_set_property),
	(gdm_chooser_client_get_property),
	(gdm_chooser_client_constructor), (gdm_chooser_client_dispose),
	(gdm_chooser_client_class_init), (gdm_chooser_client_init),
	(gdm_chooser_client_finalize), (gdm_chooser_client_new):
	* gui/simple-chooser/gdm-chooser-client.h:
	* gui/simple-chooser/gdm-chooser-session.c: (launch_compiz),
	(launch_metacity), (start_window_manager), (start_settings_daemon),
	(on_dialog_response), (gdm_chooser_session_start),
	(gdm_chooser_session_stop), (gdm_chooser_session_set_property),
	(gdm_chooser_session_get_property),
	(gdm_chooser_session_constructor), (gdm_chooser_session_dispose),
	(gdm_chooser_session_class_init), (gdm_chooser_session_init),
	(gdm_chooser_session_finalize), (gdm_chooser_session_new):
	* gui/simple-chooser/gdm-chooser-session.h:
	* gui/simple-chooser/test-host-chooser.c:
	(assistive_registry_launch), (filter_watch), (filter_timeout),
	(assistive_registry_start), (at_set_gtk_modules), (load_a11y),
	(main):
	* gui/simple-greeter/greeter-main.c: (load_a11y), (main):
	Initial support for XDMCP IndirectQuery choosers.
	Also fix broken gdm_address_is_local.



Added:
   trunk/daemon/gdm-chooser-server.c
   trunk/daemon/gdm-chooser-server.h
   trunk/daemon/gdm-chooser-session.c
   trunk/daemon/gdm-chooser-session.h
   trunk/daemon/gdm-xdmcp-chooser-display.c
   trunk/daemon/gdm-xdmcp-chooser-display.h
   trunk/daemon/gdm-xdmcp-chooser-display.xml
   trunk/daemon/gdm-xdmcp-chooser-slave.c
   trunk/daemon/gdm-xdmcp-chooser-slave.h
   trunk/daemon/gdm-xdmcp-greeter-display.c
   trunk/daemon/gdm-xdmcp-greeter-display.h
   trunk/daemon/gdm-xdmcp-greeter-display.xml
      - copied unchanged from r5644, /trunk/daemon/gdm-xdmcp-display.xml
   trunk/daemon/xdmcp-chooser-slave-main.c
   trunk/gui/simple-chooser/gdm-chooser-client.c
   trunk/gui/simple-chooser/gdm-chooser-client.h
   trunk/gui/simple-chooser/gdm-chooser-session.c
   trunk/gui/simple-chooser/gdm-chooser-session.h
   trunk/gui/simple-chooser/test-host-chooser.c
Removed:
   trunk/daemon/gdm-xdmcp-display.xml
Modified:
   trunk/ChangeLog
   trunk/common/gdm-address.c
   trunk/daemon/Makefile.am
   trunk/daemon/gdm-display.c
   trunk/daemon/gdm-display.h
   trunk/daemon/gdm-display.xml
   trunk/daemon/gdm-factory-slave.c
   trunk/daemon/gdm-greeter-server.c
   trunk/daemon/gdm-greeter-session.c
   trunk/daemon/gdm-product-slave.c
   trunk/daemon/gdm-simple-slave.c
   trunk/daemon/gdm-slave.c
   trunk/daemon/gdm-xdmcp-display-factory.c
   trunk/daemon/gdm-xdmcp-display.c
   trunk/daemon/gdm-xdmcp-display.h
   trunk/data/gdm.conf
   trunk/gui/simple-chooser/Makefile.am
   trunk/gui/simple-chooser/chooser-main.c
   trunk/gui/simple-greeter/greeter-main.c
   trunk/po/ChangeLog
   trunk/po/POTFILES.in

Modified: trunk/common/gdm-address.c
==============================================================================
--- trunk/common/gdm-address.c	(original)
+++ trunk/common/gdm-address.c	Thu Jan 31 00:51:46 2008
@@ -30,6 +30,8 @@
 #include <sys/socket.h>
 #endif
 #include <netdb.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
 
 #ifndef G_OS_WIN32
 #include <sys/socket.h>
@@ -280,25 +282,71 @@
         return FALSE;
 }
 
-const GList *
-gdm_address_peek_local_list (void)
+static void
+add_local_siocgifconf (GList **list)
 {
-        static GList *the_list = NULL;
-        static time_t last_time = 0;
-        char hostbuf[BUFSIZ];
-        struct addrinfo *result;
-        struct addrinfo *res;
+        struct ifconf ifc;
+        struct ifreq  ifreq;
+        struct ifreq *ifr;
+        struct ifreq *the_end;
+        int           sock;
+        char          buf[BUFSIZ];
+
+        if ((sock = socket (PF_INET, SOCK_DGRAM, 0)) < 0) {
+                perror ("socket");
+                return;
+        }
+
+        ifc.ifc_len = sizeof (buf);
+        ifc.ifc_buf = buf;
+        if (ioctl (sock, SIOCGIFCONF, (char *) &ifc) < 0) {
+                perror ("SIOCGIFCONF");
+                close (sock);
+                return;
+        }
+
+        /* Get IP address of each active IP network interface. */
+        the_end = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
+
+        for (ifr = ifc.ifc_req; ifr < the_end; ifr++) {
+                if (ifr->ifr_addr.sa_family == AF_INET) {
+                        /* IP net interface */
+                        ifreq = *ifr;
+
+                        if (ioctl (sock, SIOCGIFFLAGS, (char *) &ifreq) < 0) {
+                                perror("SIOCGIFFLAGS");
+                        } else if (ifreq.ifr_flags & IFF_UP) {  /* active interface */
+                                if (ioctl (sock, SIOCGIFADDR, (char *) &ifreq) < 0) {
+                                        perror("SIOCGIFADDR");
+                                } else {
+                                        GdmAddress *address;
+                                        address = gdm_address_new_from_sockaddr ((struct sockaddr *)&ifreq.ifr_addr,
+                                                                                 sizeof (struct sockaddr));
+
+                                        gdm_address_debug (address);
+
+                                        *list = g_list_append (*list, address);
+                                }
+                        }
+                }
 
-        /* Don't check more then every 5 seconds */
-        if (last_time + 5 > time (NULL)) {
-                return the_list;
+                /* Support for variable-length addresses. */
+#ifdef HAS_SA_LEN
+                ifr = (struct ifreq *) ((caddr_t) ifr
+                                        + ifr->ifr_addr.sa_len - sizeof(struct sockaddr));
+#endif
         }
 
-        g_list_foreach (the_list, (GFunc)gdm_address_free, NULL);
-        g_list_free (the_list);
-        the_list = NULL;
+        close (sock);
+}
 
-        last_time = time (NULL);
+static void
+add_local_addrinfo (GList **list)
+{
+        char             hostbuf[BUFSIZ];
+        struct addrinfo *result;
+        struct addrinfo *res;
+        struct addrinfo  hints;
 
         hostbuf[BUFSIZ-1] = '\0';
         if (gethostname (hostbuf, BUFSIZ-1) != 0) {
@@ -306,26 +354,58 @@
                 snprintf (hostbuf, BUFSIZ-1, "localhost");
         }
 
+        memset (&hints, 0, sizeof (hints));
+        hints.ai_family = AF_UNSPEC;
+        hints.ai_flags = AI_CANONNAME;
+
+        g_debug ("GdmAddress: looking up hostname: %s", hostbuf);
         result = NULL;
-        if (getaddrinfo (hostbuf, NULL, NULL, &result) != 0) {
+        if (getaddrinfo (hostbuf, NULL, &hints, &result) != 0) {
                 g_debug ("%s: Could not get address from hostname!", "gdm_peek_local_address_list");
 
-                return NULL;
+                return;
         }
 
         for (res = result; res != NULL; res = res->ai_next) {
                 GdmAddress *address;
 
+                g_debug ("family=%d sock_type=%d protocol=%d flags=0x%x canonname=%s\n",
+                         res->ai_family,
+                         res->ai_socktype,
+                         res->ai_protocol,
+                         res->ai_flags,
+                         res->ai_canonname);
                 address = gdm_address_new_from_sockaddr (res->ai_addr, res->ai_addrlen);
-                the_list = g_list_append (the_list, address);
+                *list = g_list_append (*list, address);
         }
 
         if (result != NULL) {
                 freeaddrinfo (result);
                 result = NULL;
         }
+}
+
+const GList *
+gdm_address_peek_local_list (void)
+{
+        static GList  *list = NULL;
+        static time_t  last_time = 0;
+
+        /* Don't check more then every 5 seconds */
+        if (last_time + 5 > time (NULL)) {
+                return list;
+        }
+
+        g_list_foreach (list, (GFunc)gdm_address_free, NULL);
+        g_list_free (list);
+        list = NULL;
+
+        last_time = time (NULL);
+
+        add_local_siocgifconf (&list);
+        add_local_addrinfo (&list);
 
-        return the_list;
+        return list;
 }
 
 gboolean

Modified: trunk/daemon/Makefile.am
==============================================================================
--- trunk/daemon/Makefile.am	(original)
+++ trunk/daemon/Makefile.am	Thu Jan 31 00:51:46 2008
@@ -32,9 +32,11 @@
 	gdm-simple-slave-glue.h			\
 	gdm-factory-slave-glue.h		\
 	gdm-product-slave-glue.h		\
+	gdm-xdmcp-chooser-slave-glue.h		\
 	gdm-manager-glue.h			\
 	gdm-display-glue.h			\
-	gdm-xdmcp-display-glue.h		\
+	gdm-xdmcp-greeter-display-glue.h	\
+	gdm-xdmcp-chooser-display-glue.h	\
 	gdm-static-display-glue.h		\
 	gdm-transient-display-glue.h		\
 	gdm-local-display-factory-glue.h	\
@@ -52,10 +54,14 @@
 	dbus-binding-tool --prefix=gdm_factory_slave --mode=glib-server --output=gdm-factory-slave-glue.h $(srcdir)/gdm-factory-slave.xml
 gdm-product-slave-glue.h: gdm-product-slave.xml Makefile.am
 	dbus-binding-tool --prefix=gdm_product_slave --mode=glib-server --output=gdm-product-slave-glue.h $(srcdir)/gdm-product-slave.xml
+gdm-xdmcp-chooser-slave-glue.h: gdm-xdmcp-chooser-slave.xml Makefile.am
+	dbus-binding-tool --prefix=gdm_xdmcp_chooser_slave --mode=glib-server --output=gdm-xdmcp-chooser-slave-glue.h $(srcdir)/gdm-xdmcp-chooser-slave.xml
 gdm-display-glue.h: gdm-display.xml Makefile.am
 	dbus-binding-tool --prefix=gdm_display --mode=glib-server --output=gdm-display-glue.h $(srcdir)/gdm-display.xml
-gdm-xdmcp-display-glue.h: gdm-xdmcp-display.xml Makefile.am
-	dbus-binding-tool --prefix=gdm_xdmcp_display --mode=glib-server --output=gdm-xdmcp-display-glue.h $(srcdir)/gdm-xdmcp-display.xml
+gdm-xdmcp-greeter-display-glue.h: gdm-xdmcp-greeter-display.xml Makefile.am
+	dbus-binding-tool --prefix=gdm_xdmcp_greeter_display --mode=glib-server --output=gdm-xdmcp-greeter-display-glue.h $(srcdir)/gdm-xdmcp-greeter-display.xml
+gdm-xdmcp-chooser-display-glue.h: gdm-xdmcp-chooser-display.xml Makefile.am
+	dbus-binding-tool --prefix=gdm_xdmcp_chooser_display --mode=glib-server --output=gdm-xdmcp-chooser-display-glue.h $(srcdir)/gdm-xdmcp-chooser-display.xml
 gdm-static-display-glue.h: gdm-static-display.xml Makefile.am
 	dbus-binding-tool --prefix=gdm_static_display --mode=glib-server --output=gdm-static-display-glue.h $(srcdir)/gdm-static-display.xml
 gdm-transient-display-glue.h: gdm-transient-display.xml Makefile.am
@@ -106,6 +112,7 @@
 	gdm-simple-slave		\
 	gdm-factory-slave		\
 	gdm-product-slave		\
+	gdm-xdmcp-chooser-slave		\
 	gdm-session-worker		\
 	$(NULL)
 
@@ -208,6 +215,25 @@
 	$(top_builddir)/common/libgdmcommon.la	\
 	$(NULL)
 
+gdm_xdmcp_chooser_slave_SOURCES = 		\
+	xdmcp-chooser-slave-main.c 		\
+	gdm-chooser-server.c			\
+	gdm-chooser-server.h			\
+	gdm-chooser-session.c			\
+	gdm-chooser-session.h			\
+	gdm-slave.c				\
+	gdm-slave.h				\
+	gdm-xdmcp-chooser-slave.c		\
+	gdm-xdmcp-chooser-slave.h		\
+	$(NULL)
+
+gdm_xdmcp_chooser_slave_LDADD = 		\
+	$(XLIB_LIBS)				\
+	$(DAEMON_LIBS)				\
+	$(EXTRA_DAEMON_LIBS)                    \
+	$(top_builddir)/common/libgdmcommon.la	\
+	$(NULL)
+
 gdm_session_worker_SOURCES = 			\
 	session-worker-main.c 			\
 	gdm-session-worker.h			\
@@ -241,6 +267,10 @@
 	gdm-display.h			\
 	gdm-xdmcp-display.c		\
 	gdm-xdmcp-display.h		\
+	gdm-xdmcp-greeter-display.c	\
+	gdm-xdmcp-greeter-display.h	\
+	gdm-xdmcp-chooser-display.c	\
+	gdm-xdmcp-chooser-display.h	\
 	gdm-static-display.c		\
 	gdm-static-display.h		\
 	gdm-transient-display.c		\
@@ -309,9 +339,11 @@
 	gdm-simple-slave.xml		\
 	gdm-factory-slave.xml		\
 	gdm-product-slave.xml		\
+	gdm-xdmcp-chooser-slave.xml	\
 	gdm-manager.xml			\
 	gdm-display.xml			\
-	gdm-xdmcp-display.xml		\
+	gdm-xdmcp-greeter-display.xml	\
+	gdm-xdmcp-chooser-display.xml	\
 	gdm-static-display.xml		\
 	gdm-transient-display.xml	\
 	gdm-local-display-factory.xml	\

Added: trunk/daemon/gdm-chooser-server.c
==============================================================================
--- (empty file)
+++ trunk/daemon/gdm-chooser-server.c	Thu Jan 31 00:51:46 2008
@@ -0,0 +1,628 @@
+/* -*- 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 <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <grp.h>
+
+#if defined (_POSIX_PRIORITY_SCHEDULING) && defined (HAVE_SCHED_YIELD)
+#include <sched.h>
+#endif
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+#define DBUS_API_SUBJECT_TO_CHANGE
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include "gdm-chooser-server.h"
+
+#define GDM_CHOOSER_SERVER_DBUS_PATH      "/org/gnome/DisplayManager/ChooserServer"
+#define GDM_CHOOSER_SERVER_DBUS_INTERFACE "org.gnome.DisplayManager.ChooserServer"
+
+#define GDM_CHOOSER_SERVER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_CHOOSER_SERVER, GdmChooserServerPrivate))
+
+struct GdmChooserServerPrivate
+{
+        char           *user_name;
+        char           *group_name;
+        char           *display_id;
+
+        DBusServer     *server;
+        char           *server_address;
+        DBusConnection *chooser_connection;
+};
+
+enum {
+        PROP_0,
+        PROP_USER_NAME,
+        PROP_GROUP_NAME,
+        PROP_DISPLAY_ID,
+};
+
+enum {
+        HOSTNAME_SELECTED,
+        CONNECTED,
+        DISCONNECTED,
+        LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL] = { 0, };
+
+static void     gdm_chooser_server_class_init   (GdmChooserServerClass *klass);
+static void     gdm_chooser_server_init         (GdmChooserServer      *chooser_server);
+static void     gdm_chooser_server_finalize     (GObject               *object);
+
+G_DEFINE_TYPE (GdmChooserServer, gdm_chooser_server, G_TYPE_OBJECT)
+
+/* Note: Use abstract sockets like dbus does by default on Linux. Abstract
+ * sockets are only available on Linux.
+ */
+static char *
+generate_address (void)
+{
+        char *path;
+#if defined (__linux__)
+        int   i;
+        char  tmp[9];
+
+        for (i = 0; i < 8; i++) {
+                if (g_random_int_range (0, 2) == 0) {
+                        tmp[i] = g_random_int_range ('a', 'z' + 1);
+                } else {
+                        tmp[i] = g_random_int_range ('A', 'Z' + 1);
+                }
+        }
+        tmp[8] = '\0';
+
+        path = g_strdup_printf ("unix:abstract=/tmp/gdm-chooser-%s", tmp);
+#else
+        path = g_strdup ("unix:tmpdir=/tmp");
+#endif
+
+        return path;
+}
+
+static DBusHandlerResult
+handle_select_hostname (GdmChooserServer *chooser_server,
+                        DBusConnection   *connection,
+                        DBusMessage      *message)
+{
+        DBusMessage *reply;
+        DBusError    error;
+        const char  *text;
+
+        dbus_error_init (&error);
+        if (! dbus_message_get_args (message, &error,
+                                     DBUS_TYPE_STRING, &text,
+                                     DBUS_TYPE_INVALID)) {
+                g_warning ("ERROR: %s", error.message);
+        }
+
+        g_debug ("ChooserServer: SelectHostname: %s", text);
+
+        reply = dbus_message_new_method_return (message);
+        dbus_connection_send (connection, reply, NULL);
+        dbus_message_unref (reply);
+
+        g_signal_emit (chooser_server, signals [HOSTNAME_SELECTED], 0, text);
+
+        return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult
+handle_disconnect (GdmChooserServer *chooser_server,
+                   DBusConnection   *connection,
+                   DBusMessage      *message)
+{
+        DBusMessage *reply;
+
+        reply = dbus_message_new_method_return (message);
+        dbus_connection_send (connection, reply, NULL);
+        dbus_message_unref (reply);
+
+        g_signal_emit (chooser_server, signals [DISCONNECTED], 0);
+
+        return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult
+chooser_handle_child_message (DBusConnection *connection,
+                              DBusMessage    *message,
+                              void           *user_data)
+{
+        GdmChooserServer *chooser_server = GDM_CHOOSER_SERVER (user_data);
+
+        if (dbus_message_is_method_call (message, GDM_CHOOSER_SERVER_DBUS_INTERFACE, "SelectHostname")) {
+                return handle_select_hostname (chooser_server, connection, message);
+        } else if (dbus_message_is_method_call (message, GDM_CHOOSER_SERVER_DBUS_INTERFACE, "Disconnect")) {
+                return handle_disconnect (chooser_server, connection, message);
+        }
+
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static DBusHandlerResult
+do_introspect (DBusConnection *connection,
+               DBusMessage    *message)
+{
+        DBusMessage *reply;
+        GString     *xml;
+        char        *xml_string;
+
+        g_debug ("ChooserServer: Do introspect");
+
+        /* standard header */
+        xml = g_string_new ("<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
+                            "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\";>\n"
+                            "<node>\n"
+                            "  <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
+                            "    <method name=\"Introspect\">\n"
+                            "      <arg name=\"data\" direction=\"out\" type=\"s\"/>\n"
+                            "    </method>\n"
+                            "  </interface>\n");
+
+        /* interface */
+        xml = g_string_append (xml,
+                               "  <interface name=\"org.gnome.DisplayManager.ChooserServer\">\n"
+                               "    <method name=\"SelectHostname\">\n"
+                               "      <arg name=\"text\" direction=\"in\" type=\"s\"/>\n"
+                               "    </method>\n"
+                               "    <method name=\"Disconnect\">\n"
+                               "    </method>\n"
+                               "  </interface>\n");
+
+        reply = dbus_message_new_method_return (message);
+
+        xml = g_string_append (xml, "</node>\n");
+        xml_string = g_string_free (xml, FALSE);
+
+        dbus_message_append_args (reply,
+                                  DBUS_TYPE_STRING, &xml_string,
+                                  DBUS_TYPE_INVALID);
+
+        g_free (xml_string);
+
+        if (reply == NULL) {
+                g_error ("No memory");
+        }
+
+        if (! dbus_connection_send (connection, reply, NULL)) {
+                g_error ("No memory");
+        }
+
+        dbus_message_unref (reply);
+
+        return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult
+chooser_server_message_handler (DBusConnection  *connection,
+                                DBusMessage     *message,
+                                void            *user_data)
+{
+        const char *dbus_destination = dbus_message_get_destination (message);
+        const char *dbus_path        = dbus_message_get_path (message);
+        const char *dbus_interface   = dbus_message_get_interface (message);
+        const char *dbus_member      = dbus_message_get_member (message);
+
+        g_debug ("chooser_server_message_handler: destination=%s obj_path=%s interface=%s method=%s",
+                 dbus_destination ? dbus_destination : "(null)",
+                 dbus_path        ? dbus_path        : "(null)",
+                 dbus_interface   ? dbus_interface   : "(null)",
+                 dbus_member      ? dbus_member      : "(null)");
+
+        if (dbus_message_is_method_call (message, "org.freedesktop.DBus", "AddMatch")) {
+                DBusMessage *reply;
+
+                reply = dbus_message_new_method_return (message);
+
+                if (reply == NULL) {
+                        g_error ("No memory");
+                }
+
+                if (! dbus_connection_send (connection, reply, NULL)) {
+                        g_error ("No memory");
+                }
+
+                dbus_message_unref (reply);
+
+                return DBUS_HANDLER_RESULT_HANDLED;
+        } else if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected") &&
+                   strcmp (dbus_message_get_path (message), DBUS_PATH_LOCAL) == 0) {
+
+                /*dbus_connection_unref (connection);*/
+
+                return DBUS_HANDLER_RESULT_HANDLED;
+        } else if (dbus_message_is_method_call (message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
+                return do_introspect (connection, message);
+        } else {
+                return chooser_handle_child_message (connection, message, user_data);
+        }
+
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static void
+chooser_server_unregister_handler (DBusConnection  *connection,
+                                   void            *user_data)
+{
+        g_debug ("chooser_server_unregister_handler");
+}
+
+static DBusHandlerResult
+connection_filter_function (DBusConnection *connection,
+                            DBusMessage    *message,
+                            void           *user_data)
+{
+        GdmChooserServer *chooser_server = GDM_CHOOSER_SERVER (user_data);
+        const char       *dbus_path      = dbus_message_get_path (message);
+        const char       *dbus_interface = dbus_message_get_interface (message);
+        const char       *dbus_message   = dbus_message_get_member (message);
+
+        g_debug ("ChooserServer: obj_path=%s interface=%s method=%s",
+                 dbus_path      ? dbus_path      : "(null)",
+                 dbus_interface ? dbus_interface : "(null)",
+                 dbus_message   ? dbus_message   : "(null)");
+
+        if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected")
+            && strcmp (dbus_path, DBUS_PATH_LOCAL) == 0) {
+
+                g_debug ("ChooserServer: Disconnected");
+
+                dbus_connection_unref (connection);
+                chooser_server->priv->chooser_connection = NULL;
+
+                return DBUS_HANDLER_RESULT_HANDLED;
+        }
+
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static dbus_bool_t
+allow_user_function (DBusConnection *connection,
+                     unsigned long   uid,
+                     void           *data)
+{
+        GdmChooserServer *chooser_server = GDM_CHOOSER_SERVER (data);
+        struct passwd    *pwent;
+
+        if (chooser_server->priv->user_name == NULL) {
+                return FALSE;
+        }
+
+        pwent = getpwnam (chooser_server->priv->user_name);
+        if (pwent == NULL) {
+                return FALSE;
+        }
+
+        if (pwent->pw_uid == uid) {
+                return TRUE;
+        }
+
+        return FALSE;
+}
+
+static void
+handle_connection (DBusServer      *server,
+                   DBusConnection  *new_connection,
+                   void            *user_data)
+{
+        GdmChooserServer *chooser_server = GDM_CHOOSER_SERVER (user_data);
+
+        g_debug ("ChooserServer: Handing new connection");
+
+        if (chooser_server->priv->chooser_connection == NULL) {
+                DBusObjectPathVTable vtable = { &chooser_server_unregister_handler,
+                                                &chooser_server_message_handler,
+                                                NULL, NULL, NULL, NULL
+                };
+
+                chooser_server->priv->chooser_connection = new_connection;
+                dbus_connection_ref (new_connection);
+                dbus_connection_setup_with_g_main (new_connection, NULL);
+
+                g_debug ("ChooserServer: chooser connection is %p", new_connection);
+
+                dbus_connection_add_filter (new_connection,
+                                            connection_filter_function,
+                                            chooser_server,
+                                            NULL);
+
+                dbus_connection_set_unix_user_function (new_connection,
+                                                        allow_user_function,
+                                                        chooser_server,
+                                                        NULL);
+
+                dbus_connection_register_object_path (new_connection,
+                                                      GDM_CHOOSER_SERVER_DBUS_PATH,
+                                                      &vtable,
+                                                      chooser_server);
+
+                g_signal_emit (chooser_server, signals[CONNECTED], 0);
+
+        }
+}
+
+gboolean
+gdm_chooser_server_start (GdmChooserServer *chooser_server)
+{
+        DBusError   error;
+        gboolean    ret;
+        char       *address;
+        const char *auth_mechanisms[] = {"EXTERNAL", NULL};
+
+        ret = FALSE;
+
+        g_debug ("ChooserServer: Creating D-Bus server for chooser");
+
+        address = generate_address ();
+
+        dbus_error_init (&error);
+        chooser_server->priv->server = dbus_server_listen (address, &error);
+        g_free (address);
+
+        if (chooser_server->priv->server == NULL) {
+                g_warning ("Cannot create D-BUS server for the chooser: %s", error.message);
+                /* FIXME: should probably fail if we can't create the socket */
+                goto out;
+        }
+
+        dbus_server_setup_with_g_main (chooser_server->priv->server, NULL);
+        dbus_server_set_auth_mechanisms (chooser_server->priv->server, auth_mechanisms);
+        dbus_server_set_new_connection_function (chooser_server->priv->server,
+                                                 handle_connection,
+                                                 chooser_server,
+                                                 NULL);
+        ret = TRUE;
+
+        g_free (chooser_server->priv->server_address);
+        chooser_server->priv->server_address = dbus_server_get_address (chooser_server->priv->server);
+
+        g_debug ("ChooserServer: D-Bus server listening on %s", chooser_server->priv->server_address);
+
+ out:
+
+        return ret;
+}
+
+gboolean
+gdm_chooser_server_stop (GdmChooserServer *chooser_server)
+{
+        gboolean ret;
+
+        ret = FALSE;
+
+        g_debug ("ChooserServer: Stopping chooser server...");
+
+        return ret;
+}
+
+char *
+gdm_chooser_server_get_address (GdmChooserServer *chooser_server)
+{
+        return g_strdup (chooser_server->priv->server_address);
+}
+
+static void
+_gdm_chooser_server_set_display_id (GdmChooserServer *chooser_server,
+                                    const char       *display_id)
+{
+        g_free (chooser_server->priv->display_id);
+        chooser_server->priv->display_id = g_strdup (display_id);
+}
+
+static void
+_gdm_chooser_server_set_user_name (GdmChooserServer *chooser_server,
+                                  const char *name)
+{
+        g_free (chooser_server->priv->user_name);
+        chooser_server->priv->user_name = g_strdup (name);
+}
+
+static void
+_gdm_chooser_server_set_group_name (GdmChooserServer *chooser_server,
+                                    const char *name)
+{
+        g_free (chooser_server->priv->group_name);
+        chooser_server->priv->group_name = g_strdup (name);
+}
+
+static void
+gdm_chooser_server_set_property (GObject      *object,
+                                guint         prop_id,
+                                const GValue *value,
+                                GParamSpec   *pspec)
+{
+        GdmChooserServer *self;
+
+        self = GDM_CHOOSER_SERVER (object);
+
+        switch (prop_id) {
+        case PROP_DISPLAY_ID:
+                _gdm_chooser_server_set_display_id (self, g_value_get_string (value));
+                break;
+        case PROP_USER_NAME:
+                _gdm_chooser_server_set_user_name (self, g_value_get_string (value));
+                break;
+        case PROP_GROUP_NAME:
+                _gdm_chooser_server_set_group_name (self, g_value_get_string (value));
+                break;
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+        }
+}
+
+static void
+gdm_chooser_server_get_property (GObject    *object,
+                                guint       prop_id,
+                                GValue     *value,
+                                GParamSpec *pspec)
+{
+        GdmChooserServer *self;
+
+        self = GDM_CHOOSER_SERVER (object);
+
+        switch (prop_id) {
+        case PROP_DISPLAY_ID:
+                g_value_set_string (value, self->priv->display_id);
+                break;
+        case PROP_USER_NAME:
+                g_value_set_string (value, self->priv->user_name);
+                break;
+        case PROP_GROUP_NAME:
+                g_value_set_string (value, self->priv->group_name);
+                break;
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+        }
+}
+
+static GObject *
+gdm_chooser_server_constructor (GType                  type,
+                               guint                  n_construct_properties,
+                               GObjectConstructParam *construct_properties)
+{
+        GdmChooserServer      *chooser_server;
+        GdmChooserServerClass *klass;
+
+        klass = GDM_CHOOSER_SERVER_CLASS (g_type_class_peek (GDM_TYPE_CHOOSER_SERVER));
+
+        chooser_server = GDM_CHOOSER_SERVER (G_OBJECT_CLASS (gdm_chooser_server_parent_class)->constructor (type,
+                                                                                       n_construct_properties,
+                                                                                       construct_properties));
+
+        return G_OBJECT (chooser_server);
+}
+
+static void
+gdm_chooser_server_class_init (GdmChooserServerClass *klass)
+{
+        GObjectClass    *object_class = G_OBJECT_CLASS (klass);
+
+        object_class->get_property = gdm_chooser_server_get_property;
+        object_class->set_property = gdm_chooser_server_set_property;
+        object_class->constructor = gdm_chooser_server_constructor;
+        object_class->finalize = gdm_chooser_server_finalize;
+
+        g_type_class_add_private (klass, sizeof (GdmChooserServerPrivate));
+
+        g_object_class_install_property (object_class,
+                                         PROP_DISPLAY_ID,
+                                         g_param_spec_string ("display-id",
+                                                              "display id",
+                                                              "display id",
+                                                              NULL,
+                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+         g_object_class_install_property (object_class,
+                                         PROP_USER_NAME,
+                                         g_param_spec_string ("user-name",
+                                                              "user name",
+                                                              "user name",
+                                                              "gdm",
+                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+        g_object_class_install_property (object_class,
+                                         PROP_GROUP_NAME,
+                                         g_param_spec_string ("group-name",
+                                                              "group name",
+                                                              "group name",
+                                                              "gdm",
+                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+        signals [HOSTNAME_SELECTED] =
+                g_signal_new ("hostname-selected",
+                              G_OBJECT_CLASS_TYPE (object_class),
+                              G_SIGNAL_RUN_FIRST,
+                              G_STRUCT_OFFSET (GdmChooserServerClass, hostname_selected),
+                              NULL,
+                              NULL,
+                              g_cclosure_marshal_VOID__STRING,
+                              G_TYPE_NONE,
+                              1,
+                              G_TYPE_STRING);
+        signals [CONNECTED] =
+                g_signal_new ("connected",
+                              G_OBJECT_CLASS_TYPE (object_class),
+                              G_SIGNAL_RUN_FIRST,
+                              G_STRUCT_OFFSET (GdmChooserServerClass, connected),
+                              NULL,
+                              NULL,
+                              g_cclosure_marshal_VOID__VOID,
+                              G_TYPE_NONE,
+                              0);
+        signals [DISCONNECTED] =
+                g_signal_new ("disconnected",
+                              G_OBJECT_CLASS_TYPE (object_class),
+                              G_SIGNAL_RUN_FIRST,
+                              G_STRUCT_OFFSET (GdmChooserServerClass, disconnected),
+                              NULL,
+                              NULL,
+                              g_cclosure_marshal_VOID__VOID,
+                              G_TYPE_NONE,
+                              0);
+}
+
+static void
+gdm_chooser_server_init (GdmChooserServer *chooser_server)
+{
+
+        chooser_server->priv = GDM_CHOOSER_SERVER_GET_PRIVATE (chooser_server);
+}
+
+static void
+gdm_chooser_server_finalize (GObject *object)
+{
+        GdmChooserServer *chooser_server;
+
+        g_return_if_fail (object != NULL);
+        g_return_if_fail (GDM_IS_CHOOSER_SERVER (object));
+
+        chooser_server = GDM_CHOOSER_SERVER (object);
+
+        g_return_if_fail (chooser_server->priv != NULL);
+
+        gdm_chooser_server_stop (chooser_server);
+
+        G_OBJECT_CLASS (gdm_chooser_server_parent_class)->finalize (object);
+}
+
+GdmChooserServer *
+gdm_chooser_server_new (const char *display_id)
+{
+        GObject *object;
+
+        object = g_object_new (GDM_TYPE_CHOOSER_SERVER,
+                               "display-id", display_id,
+                               NULL);
+
+        return GDM_CHOOSER_SERVER (object);
+}

Added: trunk/daemon/gdm-chooser-server.h
==============================================================================
--- (empty file)
+++ trunk/daemon/gdm-chooser-server.h	Thu Jan 31 00:51:46 2008
@@ -0,0 +1,63 @@
+/* -*- 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_CHOOSER_SERVER_H
+#define __GDM_CHOOSER_SERVER_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_CHOOSER_SERVER         (gdm_chooser_server_get_type ())
+#define GDM_CHOOSER_SERVER(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_CHOOSER_SERVER, GdmChooserServer))
+#define GDM_CHOOSER_SERVER_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_CHOOSER_SERVER, GdmChooserServerClass))
+#define GDM_IS_CHOOSER_SERVER(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_CHOOSER_SERVER))
+#define GDM_IS_CHOOSER_SERVER_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_CHOOSER_SERVER))
+#define GDM_CHOOSER_SERVER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_CHOOSER_SERVER, GdmChooserServerClass))
+
+typedef struct GdmChooserServerPrivate GdmChooserServerPrivate;
+
+typedef struct
+{
+        GObject                  parent;
+        GdmChooserServerPrivate *priv;
+} GdmChooserServer;
+
+typedef struct
+{
+        GObjectClass   parent_class;
+
+        void (* hostname_selected)          (GdmChooserServer  *chooser_server,
+                                             const char        *hostname);
+        void (* connected)                  (GdmChooserServer  *chooser_server);
+        void (* disconnected)               (GdmChooserServer  *chooser_server);
+} GdmChooserServerClass;
+
+GType               gdm_chooser_server_get_type              (void);
+GdmChooserServer *  gdm_chooser_server_new                   (const char       *display_id);
+
+gboolean            gdm_chooser_server_start                 (GdmChooserServer *chooser_server);
+gboolean            gdm_chooser_server_stop                  (GdmChooserServer *chooser_server);
+char *              gdm_chooser_server_get_address           (GdmChooserServer *chooser_server);
+
+G_END_DECLS
+
+#endif /* __GDM_CHOOSER_SERVER_H */

Added: trunk/daemon/gdm-chooser-session.c
==============================================================================
--- (empty file)
+++ trunk/daemon/gdm-chooser-session.c	Thu Jan 31 00:51:46 2008
@@ -0,0 +1,948 @@
+/* -*- 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 <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <grp.h>
+#include <signal.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+#define DBUS_API_SUBJECT_TO_CHANGE
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include "gdm-common.h"
+
+#include "gdm-chooser-session.h"
+
+#define DBUS_LAUNCH_COMMAND BINDIR "/dbus-launch --exit-with-session"
+
+#define GDM_CHOOSER_SERVER_DBUS_PATH      "/org/gnome/DisplayManager/ChooserServer"
+#define GDM_CHOOSER_SERVER_DBUS_INTERFACE "org.gnome.DisplayManager.ChooserServer"
+
+extern char **environ;
+
+#define GDM_CHOOSER_SESSION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_CHOOSER_SESSION, GdmChooserSessionPrivate))
+
+struct GdmChooserSessionPrivate
+{
+        char           *command;
+        GPid            pid;
+
+        char           *user_name;
+        char           *group_name;
+
+        char           *x11_display_name;
+        char           *x11_display_device;
+        char           *x11_display_hostname;
+        char           *x11_authority_file;
+
+        guint           child_watch_id;
+
+        GPid            dbus_pid;
+        char           *dbus_bus_address;
+
+        char           *server_address;
+};
+
+enum {
+        PROP_0,
+        PROP_X11_DISPLAY_NAME,
+        PROP_X11_DISPLAY_DEVICE,
+        PROP_X11_DISPLAY_HOSTNAME,
+        PROP_X11_AUTHORITY_FILE,
+        PROP_USER_NAME,
+        PROP_GROUP_NAME,
+        PROP_SERVER_ADDRESS,
+};
+
+enum {
+        STARTED,
+        STOPPED,
+        EXITED,
+        DIED,
+        LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL] = { 0, };
+
+static void     gdm_chooser_session_class_init    (GdmChooserSessionClass *klass);
+static void     gdm_chooser_session_init          (GdmChooserSession      *chooser_session);
+static void     gdm_chooser_session_finalize      (GObject                *object);
+
+G_DEFINE_TYPE (GdmChooserSession, gdm_chooser_session, G_TYPE_OBJECT)
+
+static void
+listify_hash (const char *key,
+              const char *value,
+              GPtrArray  *env)
+{
+        char *str;
+        str = g_strdup_printf ("%s=%s", key, value);
+        g_debug ("GdmChooserSession: chooser environment: %s", str);
+        g_ptr_array_add (env, str);
+}
+
+static GPtrArray *
+get_chooser_environment (GdmChooserSession *chooser_session)
+{
+        GPtrArray     *env;
+        GHashTable    *hash;
+        struct passwd *pwent;
+
+        env = g_ptr_array_new ();
+
+        /* create a hash table of current environment, then update keys has necessary */
+        hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+        if (chooser_session->priv->dbus_bus_address != NULL) {
+                g_hash_table_insert (hash, g_strdup ("DBUS_SESSION_BUS_ADDRESS"), g_strdup (chooser_session->priv->dbus_bus_address));
+        }
+        if (chooser_session->priv->server_address != NULL) {
+                g_hash_table_insert (hash, g_strdup ("GDM_CHOOSER_DBUS_ADDRESS"), g_strdup (chooser_session->priv->server_address));
+        }
+
+        g_hash_table_insert (hash, g_strdup ("XAUTHORITY"), g_strdup (chooser_session->priv->x11_authority_file));
+        g_hash_table_insert (hash, g_strdup ("DISPLAY"), g_strdup (chooser_session->priv->x11_display_name));
+
+#if 0
+        /* hackish ain't it */
+        set_xnest_parent_stuff ();
+#endif
+
+        g_hash_table_insert (hash, g_strdup ("LOGNAME"), g_strdup (chooser_session->priv->user_name));
+        g_hash_table_insert (hash, g_strdup ("USER"), g_strdup (chooser_session->priv->user_name));
+        g_hash_table_insert (hash, g_strdup ("USERNAME"), g_strdup (chooser_session->priv->user_name));
+
+        g_hash_table_insert (hash, g_strdup ("GDM_VERSION"), g_strdup (VERSION));
+        g_hash_table_remove (hash, "MAIL");
+
+        g_hash_table_insert (hash, g_strdup ("HOME"), g_strdup ("/"));
+        g_hash_table_insert (hash, g_strdup ("PWD"), g_strdup ("/"));
+        g_hash_table_insert (hash, g_strdup ("SHELL"), g_strdup ("/bin/sh"));
+
+        pwent = getpwnam (chooser_session->priv->user_name);
+        if (pwent != NULL) {
+                if (pwent->pw_dir != NULL && pwent->pw_dir[0] != '\0') {
+                        g_hash_table_insert (hash, g_strdup ("HOME"), g_strdup (pwent->pw_dir));
+                        g_hash_table_insert (hash, g_strdup ("PWD"), g_strdup (pwent->pw_dir));
+                }
+
+                g_hash_table_insert (hash, g_strdup ("SHELL"), g_strdup (pwent->pw_shell));
+        }
+
+
+        g_hash_table_insert (hash, g_strdup ("PATH"), g_strdup (g_getenv ("PATH")));
+
+        g_hash_table_insert (hash, g_strdup ("RUNNING_UNDER_GDM"), g_strdup ("true"));
+
+        g_hash_table_foreach (hash, (GHFunc)listify_hash, env);
+        g_hash_table_destroy (hash);
+
+        g_ptr_array_add (env, NULL);
+
+        return env;
+}
+
+static void
+chooser_session_child_watch (GPid               pid,
+                             int                status,
+                             GdmChooserSession *session)
+{
+        g_debug ("GdmChooserSession: child (pid:%d) done (%s:%d)",
+                 (int) pid,
+                 WIFEXITED (status) ? "status"
+                 : WIFSIGNALED (status) ? "signal"
+                 : "unknown",
+                 WIFEXITED (status) ? WEXITSTATUS (status)
+                 : WIFSIGNALED (status) ? WTERMSIG (status)
+                 : -1);
+
+        if (WIFEXITED (status)) {
+                int code = WEXITSTATUS (status);
+                g_signal_emit (session, signals [EXITED], 0, code);
+        } else if (WIFSIGNALED (status)) {
+                int num = WTERMSIG (status);
+                g_signal_emit (session, signals [DIED], 0, num);
+        }
+
+        g_spawn_close_pid (session->priv->pid);
+        session->priv->pid = -1;
+}
+
+typedef struct {
+        const char *user_name;
+        const char *group_name;
+} SpawnChildData;
+
+static void
+spawn_child_setup (SpawnChildData *data)
+{
+        struct passwd *pwent;
+        struct group  *grent;
+
+        if (data->user_name == NULL) {
+                return;
+        }
+
+        pwent = getpwnam (data->user_name);
+        if (pwent == NULL) {
+                g_warning (_("User %s doesn't exist"),
+                           data->user_name);
+                _exit (1);
+        }
+
+        grent = getgrnam (data->group_name);
+        if (grent == NULL) {
+                g_warning (_("Group %s doesn't exist"),
+                           data->group_name);
+                _exit (1);
+        }
+
+        g_debug ("GdmChooserSession: Changing (uid:gid) for child process to (%d:%d)",
+                 pwent->pw_uid,
+                 grent->gr_gid);
+
+        if (pwent->pw_uid != 0) {
+                if (setgid (grent->gr_gid) < 0)  {
+                        g_warning (_("Couldn't set groupid to %d"),
+                                   grent->gr_gid);
+                        _exit (1);
+                }
+
+                if (initgroups (pwent->pw_name, pwent->pw_gid) < 0) {
+                        g_warning (_("initgroups () failed for %s"),
+                                   pwent->pw_name);
+                        _exit (1);
+                }
+
+                if (setuid (pwent->pw_uid) < 0)  {
+                        g_warning (_("Couldn't set userid to %d"),
+                                   (int)pwent->pw_uid);
+                        _exit (1);
+                }
+        } else {
+                gid_t groups[1] = { 0 };
+
+                if (setgid (0) < 0)  {
+                        g_warning (_("Couldn't set groupid to 0"));
+                        /* Don't error out, it's not fatal, if it fails we'll
+                         * just still be */
+                }
+
+                /* this will get rid of any suplementary groups etc... */
+                setgroups (1, groups);
+        }
+
+        if (setsid () < 0) {
+                g_debug ("GdmChooserSession: could not set pid '%u' as leader of new session and process group - %s",
+                         (guint) getpid (), g_strerror (errno));
+                _exit (2);
+        }
+}
+
+static gboolean
+spawn_command_line_sync_as_user (const char *command_line,
+                                 const char *user_name,
+                                 const char *group_name,
+                                 char       **env,
+                                 char       **std_output,
+                                 char       **std_error,
+                                 int         *exit_status,
+                                 GError     **error)
+{
+        char           **argv;
+        GError          *local_error;
+        gboolean         ret;
+        gboolean         res;
+        SpawnChildData   data;
+
+        ret = FALSE;
+
+        argv = NULL;
+        local_error = NULL;
+        if (! g_shell_parse_argv (command_line, NULL, &argv, &local_error)) {
+                g_warning ("Could not parse command: %s", local_error->message);
+                g_propagate_error (error, local_error);
+                goto out;
+        }
+
+        data.user_name = user_name;
+        data.group_name = group_name;
+
+        local_error = NULL;
+        res = g_spawn_sync (NULL,
+                            argv,
+                            env,
+                            G_SPAWN_SEARCH_PATH,
+                            (GSpawnChildSetupFunc)spawn_child_setup,
+                            &data,
+                            std_output,
+                            std_error,
+                            exit_status,
+                            &local_error);
+
+        if (! res) {
+                g_warning ("Could not spawn command: %s", local_error->message);
+                g_propagate_error (error, local_error);
+                goto out;
+        }
+
+        ret = TRUE;
+ out:
+        g_strfreev (argv);
+
+        return ret;
+}
+
+static gboolean
+spawn_command_line_async_as_user (const char *command_line,
+                                  const char *user_name,
+                                  const char *group_name,
+                                  char      **env,
+                                  GPid       *child_pid,
+                                  GError    **error)
+{
+        char           **argv;
+        GError          *local_error;
+        gboolean         ret;
+        gboolean         res;
+        SpawnChildData   data;
+
+        ret = FALSE;
+
+        argv = NULL;
+        local_error = NULL;
+        if (! g_shell_parse_argv (command_line, NULL, &argv, &local_error)) {
+                g_warning ("Could not parse command: %s", local_error->message);
+                g_propagate_error (error, local_error);
+                goto out;
+        }
+
+        data.user_name = user_name;
+        data.group_name = group_name;
+
+        local_error = NULL;
+        res = g_spawn_async (NULL,
+                             argv,
+                             env,
+                             G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
+                             (GSpawnChildSetupFunc)spawn_child_setup,
+                             &data,
+                             child_pid,
+                             &local_error);
+        if (! res) {
+                g_warning ("Could not spawn command: %s", local_error->message);
+                g_propagate_error (error, local_error);
+                goto out;
+        }
+
+        ret = TRUE;
+ out:
+        g_strfreev (argv);
+
+        return ret;
+}
+
+static gboolean
+parse_value_as_integer (const char *value,
+                        int        *intval)
+{
+        char *end_of_valid_int;
+        glong long_value;
+        gint  int_value;
+
+        errno = 0;
+        long_value = strtol (value, &end_of_valid_int, 10);
+
+        if (*value == '\0' || *end_of_valid_int != '\0') {
+                return FALSE;
+        }
+
+        int_value = long_value;
+        if (int_value != long_value || errno == ERANGE) {
+                return FALSE;
+        }
+
+        *intval = int_value;
+
+        return TRUE;
+}
+
+static gboolean
+parse_dbus_launch_output (const char *output,
+                          char      **addressp,
+                          GPid       *pidp)
+{
+        GRegex     *re;
+        GMatchInfo *match_info;
+        gboolean    ret;
+        gboolean    res;
+        GError     *error;
+
+        ret = FALSE;
+
+        error = NULL;
+        re = g_regex_new ("DBUS_SESSION_BUS_ADDRESS=(.+)\nDBUS_SESSION_BUS_PID=([0-9]+)", 0, 0, &error);
+        if (re == NULL) {
+                g_critical (error->message);
+        }
+
+        g_regex_match (re, output, 0, &match_info);
+
+        res = g_match_info_matches (match_info);
+        if (! res) {
+                g_warning ("Unable to parse output: %s", output);
+                goto out;
+        }
+
+        if (addressp != NULL) {
+                *addressp = g_strdup (g_match_info_fetch (match_info, 1));
+        }
+
+        if (pidp != NULL) {
+                int      pid;
+                gboolean res;
+                res = parse_value_as_integer (g_match_info_fetch (match_info, 2), &pid);
+                if (res) {
+                        *pidp = pid;
+                } else {
+                        *pidp = 0;
+                }
+        }
+
+        ret = TRUE;
+
+ out:
+        g_match_info_free (match_info);
+        g_regex_unref (re);
+
+        return ret;
+}
+
+static gboolean
+start_dbus_daemon (GdmChooserSession *chooser_session)
+{
+        gboolean   res;
+        char      *std_out;
+        char      *std_err;
+        int        exit_status;
+        GError    *error;
+        GPtrArray *env;
+
+        env = get_chooser_environment (chooser_session);
+
+        error = NULL;
+        res = spawn_command_line_sync_as_user (DBUS_LAUNCH_COMMAND,
+                                               chooser_session->priv->user_name,
+                                               chooser_session->priv->group_name,
+                                               (char **)env->pdata,
+                                               &std_out,
+                                               &std_err,
+                                               &exit_status,
+                                               &error);
+        g_ptr_array_foreach (env, (GFunc)g_free, NULL);
+        g_ptr_array_free (env, TRUE);
+
+        if (! res) {
+                g_warning ("Unable to launch D-Bus daemon: %s", error->message);
+                g_error_free (error);
+                goto out;
+        }
+
+        /* pull the address and pid from the output */
+        res = parse_dbus_launch_output (std_out,
+                                        &chooser_session->priv->dbus_bus_address,
+                                        &chooser_session->priv->dbus_pid);
+        if (! res) {
+                g_warning ("Unable to parse D-Bus launch output");
+        } else {
+                g_debug ("GdmChooserSession: Started D-Bus daemon on pid %d", chooser_session->priv->dbus_pid);
+        }
+ out:
+        return res;
+}
+
+static gboolean
+stop_dbus_daemon (GdmChooserSession *chooser_session)
+{
+        if (chooser_session->priv->dbus_pid > 0) {
+                gdm_signal_pid (-1 * chooser_session->priv->dbus_pid, SIGTERM);
+                chooser_session->priv->dbus_pid = 0;
+        }
+        return TRUE;
+}
+
+static gboolean
+gdm_chooser_session_spawn (GdmChooserSession *chooser_session)
+{
+        GError          *error;
+        GPtrArray       *env;
+        gboolean         ret;
+        gboolean         res;
+
+        ret = FALSE;
+
+        g_debug ("GdmChooserSession: Running chooser_session process: %s", chooser_session->priv->command);
+
+        res = start_dbus_daemon (chooser_session);
+        if (! res) {
+                /* FIXME: */
+        }
+
+        env = get_chooser_environment (chooser_session);
+
+        error = NULL;
+
+        ret = spawn_command_line_async_as_user (chooser_session->priv->command,
+                                                chooser_session->priv->user_name,
+                                                chooser_session->priv->group_name,
+                                                (char **)env->pdata,
+                                                &chooser_session->priv->pid,
+                                                &error);
+
+        g_ptr_array_foreach (env, (GFunc)g_free, NULL);
+        g_ptr_array_free (env, TRUE);
+
+        if (! ret) {
+                g_warning ("Could not start command '%s': %s",
+                           chooser_session->priv->command,
+                           error->message);
+                g_error_free (error);
+                goto out;
+        } else {
+                g_debug ("GdmChooserSession: ChooserSession on pid %d", (int)chooser_session->priv->pid);
+        }
+
+        chooser_session->priv->child_watch_id = g_child_watch_add (chooser_session->priv->pid,
+                                                                   (GChildWatchFunc)chooser_session_child_watch,
+                                                                   chooser_session);
+
+ out:
+
+        return ret;
+}
+
+/**
+ * gdm_chooser_session_start:
+ * @disp: Pointer to a GdmDisplay structure
+ *
+ * Starts a local X chooser_session. Handles retries and fatal errors properly.
+ */
+gboolean
+gdm_chooser_session_start (GdmChooserSession *chooser_session)
+{
+        gboolean    res;
+
+        g_debug ("GdmChooserSession: Starting chooser...");
+
+        res = gdm_chooser_session_spawn (chooser_session);
+
+        if (res) {
+
+        }
+
+
+        return res;
+}
+
+static int
+wait_on_child (int pid)
+{
+        int status;
+
+ wait_again:
+        if (waitpid (pid, &status, 0) < 0) {
+                if (errno == EINTR) {
+                        goto wait_again;
+                } else if (errno == ECHILD) {
+                        ; /* do nothing, child already reaped */
+                } else {
+                        g_debug ("GdmChooserSession: waitpid () should not fail");
+                }
+        }
+
+        return status;
+}
+
+static void
+chooser_session_died (GdmChooserSession *chooser_session)
+{
+        int exit_status;
+
+        g_debug ("GdmChooserSession: Waiting on process %d", chooser_session->priv->pid);
+        exit_status = wait_on_child (chooser_session->priv->pid);
+
+        if (WIFEXITED (exit_status) && (WEXITSTATUS (exit_status) != 0)) {
+                g_debug ("GdmChooserSession: Wait on child process failed");
+        } else {
+                /* exited normally */
+        }
+
+        g_spawn_close_pid (chooser_session->priv->pid);
+        chooser_session->priv->pid = -1;
+
+        g_debug ("GdmChooserSession: ChooserSession died");
+}
+
+gboolean
+gdm_chooser_session_stop (GdmChooserSession *chooser_session)
+{
+
+        if (chooser_session->priv->pid <= 1) {
+                return TRUE;
+        }
+
+        /* remove watch source before we can wait on child */
+        if (chooser_session->priv->child_watch_id > 0) {
+                g_source_remove (chooser_session->priv->child_watch_id);
+                chooser_session->priv->child_watch_id = 0;
+        }
+
+        g_debug ("GdmChooserSession: Stopping chooser_session");
+
+        gdm_signal_pid (-1 * chooser_session->priv->pid, SIGTERM);
+        chooser_session_died (chooser_session);
+
+        stop_dbus_daemon (chooser_session);
+
+        return TRUE;
+}
+
+void
+gdm_chooser_session_set_server_address (GdmChooserSession *chooser_session,
+                                        const char        *address)
+{
+        g_return_if_fail (GDM_IS_CHOOSER_SESSION (chooser_session));
+
+        g_free (chooser_session->priv->server_address);
+        chooser_session->priv->server_address = g_strdup (address);
+}
+
+static void
+_gdm_chooser_session_set_x11_display_name (GdmChooserSession *chooser_session,
+                                           const char        *name)
+{
+        g_free (chooser_session->priv->x11_display_name);
+        chooser_session->priv->x11_display_name = g_strdup (name);
+}
+
+static void
+_gdm_chooser_session_set_x11_display_hostname (GdmChooserSession *chooser_session,
+                                               const char        *name)
+{
+        g_free (chooser_session->priv->x11_display_hostname);
+        chooser_session->priv->x11_display_hostname = g_strdup (name);
+}
+
+static void
+_gdm_chooser_session_set_x11_display_device (GdmChooserSession *chooser_session,
+                                             const char        *name)
+{
+        g_free (chooser_session->priv->x11_display_device);
+        chooser_session->priv->x11_display_device = g_strdup (name);
+}
+
+static void
+_gdm_chooser_session_set_x11_authority_file (GdmChooserSession *chooser_session,
+                                             const char        *file)
+{
+        g_free (chooser_session->priv->x11_authority_file);
+        chooser_session->priv->x11_authority_file = g_strdup (file);
+}
+
+static void
+_gdm_chooser_session_set_user_name (GdmChooserSession *chooser_session,
+                                    const char        *name)
+{
+        g_free (chooser_session->priv->user_name);
+        chooser_session->priv->user_name = g_strdup (name);
+}
+
+static void
+_gdm_chooser_session_set_group_name (GdmChooserSession *chooser_session,
+                                     const char        *name)
+{
+        g_free (chooser_session->priv->group_name);
+        chooser_session->priv->group_name = g_strdup (name);
+}
+
+static void
+gdm_chooser_session_set_property (GObject      *object,
+                                  guint         prop_id,
+                                  const GValue *value,
+                                  GParamSpec   *pspec)
+{
+        GdmChooserSession *self;
+
+        self = GDM_CHOOSER_SESSION (object);
+
+        switch (prop_id) {
+        case PROP_X11_DISPLAY_NAME:
+                _gdm_chooser_session_set_x11_display_name (self, g_value_get_string (value));
+                break;
+        case PROP_X11_DISPLAY_HOSTNAME:
+                _gdm_chooser_session_set_x11_display_hostname (self, g_value_get_string (value));
+                break;
+        case PROP_X11_DISPLAY_DEVICE:
+                _gdm_chooser_session_set_x11_display_device (self, g_value_get_string (value));
+                break;
+        case PROP_X11_AUTHORITY_FILE:
+                _gdm_chooser_session_set_x11_authority_file (self, g_value_get_string (value));
+                break;
+        case PROP_USER_NAME:
+                _gdm_chooser_session_set_user_name (self, g_value_get_string (value));
+                break;
+        case PROP_GROUP_NAME:
+                _gdm_chooser_session_set_group_name (self, g_value_get_string (value));
+                break;
+        case PROP_SERVER_ADDRESS:
+                gdm_chooser_session_set_server_address (self, g_value_get_string (value));
+                break;
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+        }
+}
+
+static void
+gdm_chooser_session_get_property (GObject    *object,
+                                  guint       prop_id,
+                                  GValue     *value,
+                                  GParamSpec *pspec)
+{
+        GdmChooserSession *self;
+
+        self = GDM_CHOOSER_SESSION (object);
+
+        switch (prop_id) {
+        case PROP_X11_DISPLAY_NAME:
+                g_value_set_string (value, self->priv->x11_display_name);
+                break;
+        case PROP_X11_DISPLAY_HOSTNAME:
+                g_value_set_string (value, self->priv->x11_display_hostname);
+                break;
+        case PROP_X11_DISPLAY_DEVICE:
+                g_value_set_string (value, self->priv->x11_display_device);
+                break;
+        case PROP_X11_AUTHORITY_FILE:
+                g_value_set_string (value, self->priv->x11_authority_file);
+                break;
+        case PROP_USER_NAME:
+                g_value_set_string (value, self->priv->user_name);
+                break;
+        case PROP_GROUP_NAME:
+                g_value_set_string (value, self->priv->group_name);
+                break;
+        case PROP_SERVER_ADDRESS:
+                g_value_set_string (value, self->priv->server_address);
+                break;
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+        }
+}
+
+static GObject *
+gdm_chooser_session_constructor (GType                  type,
+                                 guint                  n_construct_properties,
+                                 GObjectConstructParam *construct_properties)
+{
+        GdmChooserSession      *chooser_session;
+        GdmChooserSessionClass *klass;
+
+        klass = GDM_CHOOSER_SESSION_CLASS (g_type_class_peek (GDM_TYPE_CHOOSER_SESSION));
+
+        chooser_session = GDM_CHOOSER_SESSION (G_OBJECT_CLASS (gdm_chooser_session_parent_class)->constructor (type,
+                                                                                                               n_construct_properties,
+                                                                                                               construct_properties));
+
+        return G_OBJECT (chooser_session);
+}
+
+static void
+gdm_chooser_session_class_init (GdmChooserSessionClass *klass)
+{
+        GObjectClass    *object_class = G_OBJECT_CLASS (klass);
+
+        object_class->get_property = gdm_chooser_session_get_property;
+        object_class->set_property = gdm_chooser_session_set_property;
+        object_class->constructor = gdm_chooser_session_constructor;
+        object_class->finalize = gdm_chooser_session_finalize;
+
+        g_type_class_add_private (klass, sizeof (GdmChooserSessionPrivate));
+
+        g_object_class_install_property (object_class,
+                                         PROP_X11_DISPLAY_NAME,
+                                         g_param_spec_string ("x11-display-name",
+                                                              "name",
+                                                              "name",
+                                                              NULL,
+                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+        g_object_class_install_property (object_class,
+                                         PROP_X11_DISPLAY_HOSTNAME,
+                                         g_param_spec_string ("x11-display-hostname",
+                                                              "hostname",
+                                                              "hostname",
+                                                              NULL,
+                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+        g_object_class_install_property (object_class,
+                                         PROP_X11_DISPLAY_DEVICE,
+                                         g_param_spec_string ("x11-display-device",
+                                                              "device",
+                                                              "device",
+                                                              NULL,
+                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+        g_object_class_install_property (object_class,
+                                         PROP_X11_AUTHORITY_FILE,
+                                         g_param_spec_string ("x11-authority-file",
+                                                              "authority file",
+                                                              "authority file",
+                                                              NULL,
+                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+        g_object_class_install_property (object_class,
+                                         PROP_USER_NAME,
+                                         g_param_spec_string ("user-name",
+                                                              "user name",
+                                                              "user name",
+                                                              "gdm",
+                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+        g_object_class_install_property (object_class,
+                                         PROP_GROUP_NAME,
+                                         g_param_spec_string ("group-name",
+                                                              "group name",
+                                                              "group name",
+                                                              "gdm",
+                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+        g_object_class_install_property (object_class,
+                                         PROP_SERVER_ADDRESS,
+                                         g_param_spec_string ("server-address",
+                                                              "server address",
+                                                              "server address",
+                                                              NULL,
+                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+        signals [STARTED] =
+                g_signal_new ("started",
+                              G_OBJECT_CLASS_TYPE (object_class),
+                              G_SIGNAL_RUN_FIRST,
+                              G_STRUCT_OFFSET (GdmChooserSessionClass, started),
+                              NULL,
+                              NULL,
+                              g_cclosure_marshal_VOID__VOID,
+                              G_TYPE_NONE,
+                              0);
+        signals [STOPPED] =
+                g_signal_new ("stopped",
+                              G_OBJECT_CLASS_TYPE (object_class),
+                              G_SIGNAL_RUN_FIRST,
+                              G_STRUCT_OFFSET (GdmChooserSessionClass, stopped),
+                              NULL,
+                              NULL,
+                              g_cclosure_marshal_VOID__VOID,
+                              G_TYPE_NONE,
+                              0);
+        signals [EXITED] =
+                g_signal_new ("exited",
+                              G_OBJECT_CLASS_TYPE (object_class),
+                              G_SIGNAL_RUN_FIRST,
+                              G_STRUCT_OFFSET (GdmChooserSessionClass, exited),
+                              NULL,
+                              NULL,
+                              g_cclosure_marshal_VOID__INT,
+                              G_TYPE_NONE,
+                              1,
+                              G_TYPE_INT);
+        signals [DIED] =
+                g_signal_new ("died",
+                              G_OBJECT_CLASS_TYPE (object_class),
+                              G_SIGNAL_RUN_FIRST,
+                              G_STRUCT_OFFSET (GdmChooserSessionClass, died),
+                              NULL,
+                              NULL,
+                              g_cclosure_marshal_VOID__INT,
+                              G_TYPE_NONE,
+                              1,
+                              G_TYPE_INT);
+}
+
+static void
+gdm_chooser_session_init (GdmChooserSession *chooser_session)
+{
+
+        chooser_session->priv = GDM_CHOOSER_SESSION_GET_PRIVATE (chooser_session);
+
+        chooser_session->priv->pid = -1;
+
+        chooser_session->priv->command = g_strdup (LIBEXECDIR "/gdm-simple-chooser");
+}
+
+static void
+gdm_chooser_session_finalize (GObject *object)
+{
+        GdmChooserSession *chooser_session;
+
+        g_return_if_fail (object != NULL);
+        g_return_if_fail (GDM_IS_CHOOSER_SESSION (object));
+
+        chooser_session = GDM_CHOOSER_SESSION (object);
+
+        g_return_if_fail (chooser_session->priv != NULL);
+
+        gdm_chooser_session_stop (chooser_session);
+
+        g_free (chooser_session->priv->command);
+        g_free (chooser_session->priv->user_name);
+        g_free (chooser_session->priv->group_name);
+        g_free (chooser_session->priv->x11_display_name);
+        g_free (chooser_session->priv->x11_display_device);
+        g_free (chooser_session->priv->x11_display_hostname);
+        g_free (chooser_session->priv->x11_authority_file);
+        g_free (chooser_session->priv->server_address);
+
+        G_OBJECT_CLASS (gdm_chooser_session_parent_class)->finalize (object);
+}
+
+GdmChooserSession *
+gdm_chooser_session_new (const char *display_name,
+                         const char *display_device,
+                         const char *display_hostname)
+{
+        GObject *object;
+
+        object = g_object_new (GDM_TYPE_CHOOSER_SESSION,
+                               "x11-display-name", display_name,
+                               "x11-display-device", display_device,
+                               "x11-display-hostname", display_hostname,
+                               NULL);
+
+        return GDM_CHOOSER_SESSION (object);
+}

Added: trunk/daemon/gdm-chooser-session.h
==============================================================================
--- (empty file)
+++ trunk/daemon/gdm-chooser-session.h	Thu Jan 31 00:51:46 2008
@@ -0,0 +1,67 @@
+/* -*- 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_CHOOSER_SESSION_H
+#define __GDM_CHOOSER_SESSION_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_CHOOSER_SESSION         (gdm_chooser_session_get_type ())
+#define GDM_CHOOSER_SESSION(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_CHOOSER_SESSION, GdmChooserSession))
+#define GDM_CHOOSER_SESSION_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_CHOOSER_SESSION, GdmChooserSessionClass))
+#define GDM_IS_CHOOSER_SESSION(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_CHOOSER_SESSION))
+#define GDM_IS_CHOOSER_SESSION_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_CHOOSER_SESSION))
+#define GDM_CHOOSER_SESSION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_CHOOSER_SESSION, GdmChooserSessionClass))
+
+typedef struct GdmChooserSessionPrivate GdmChooserSessionPrivate;
+
+typedef struct
+{
+        GObject                   parent;
+        GdmChooserSessionPrivate *priv;
+} GdmChooserSession;
+
+typedef struct
+{
+        GObjectClass   parent_class;
+
+        void (* started)           (GdmChooserSession  *chooser_session);
+        void (* stopped)           (GdmChooserSession  *chooser_session);
+        void (* exited)            (GdmChooserSession  *chooser_session,
+                                    int                 exit_code);
+        void (* died)              (GdmChooserSession  *chooser_session,
+                                    int                 signal_number);
+} GdmChooserSessionClass;
+
+GType                 gdm_chooser_session_get_type           (void);
+GdmChooserSession *   gdm_chooser_session_new                (const char        *display_name,
+                                                              const char        *display_device,
+                                                              const char        *display_hostname);
+void                  gdm_chooser_session_set_server_address (GdmChooserSession *chooser_session,
+                                                              const char        *server_address);
+gboolean              gdm_chooser_session_start              (GdmChooserSession *chooser_session);
+gboolean              gdm_chooser_session_stop               (GdmChooserSession *chooser_session);
+
+G_END_DECLS
+
+#endif /* __GDM_CHOOSER_SESSION_H */

Modified: trunk/daemon/gdm-display.c
==============================================================================
--- trunk/daemon/gdm-display.c	(original)
+++ trunk/daemon/gdm-display.c	Thu Jan 31 00:51:46 2008
@@ -47,25 +47,25 @@
 
 struct GdmDisplayPrivate
 {
-        char            *id;
-        char            *seat_id;
+        char                 *id;
+        char                 *seat_id;
 
-        char            *remote_hostname;
-        int              x11_display_number;
-        char            *x11_display_name;
-        int              status;
-        time_t           creation_time;
-        char            *slave_command;
+        char                 *remote_hostname;
+        int                   x11_display_number;
+        char                 *x11_display_name;
+        int                   status;
+        time_t                creation_time;
+        char                 *slave_command;
 
         char                 *x11_cookie;
         gsize                 x11_cookie_size;
         GdmDisplayAccessFile *access_file;
 
-        gboolean         is_local;
-        guint            finish_idle_id;
+        gboolean              is_local;
+        guint                 finish_idle_id;
 
-        GdmSlaveProxy   *slave_proxy;
-        DBusGConnection *connection;
+        GdmSlaveProxy        *slave_proxy;
+        DBusGConnection      *connection;
         GdmDisplayAccessFile *user_access_file;
 };
 
@@ -263,6 +263,33 @@
 }
 
 static gboolean
+gdm_display_real_set_slave_bus_name (GdmDisplay *display,
+                                     const char *name,
+                                     GError    **error)
+{
+
+        return TRUE;
+}
+
+gboolean
+gdm_display_set_slave_bus_name (GdmDisplay *display,
+                                const char *name,
+                                GError    **error)
+{
+        gboolean ret;
+
+        g_return_val_if_fail (GDM_IS_DISPLAY (display), FALSE);
+
+        g_debug ("Setting slave bus name:%s on display %s", name, display->priv->x11_display_name);
+
+        g_object_ref (display);
+        ret = GDM_DISPLAY_GET_CLASS (display)->set_slave_bus_name (display, name, error);
+        g_object_unref (display);
+
+        return ret;
+}
+
+static gboolean
 gdm_display_real_remove_user_authorization (GdmDisplay *display,
                                             const char *username,
                                             GError    **error)
@@ -802,6 +829,7 @@
         klass->create_authority = gdm_display_real_create_authority;
         klass->add_user_authorization = gdm_display_real_add_user_authorization;
         klass->remove_user_authorization = gdm_display_real_remove_user_authorization;
+        klass->set_slave_bus_name = gdm_display_real_set_slave_bus_name;
         klass->manage = gdm_display_real_manage;
         klass->finish = gdm_display_real_finish;
         klass->unmanage = gdm_display_real_unmanage;

Modified: trunk/daemon/gdm-display.h
==============================================================================
--- trunk/daemon/gdm-display.h	(original)
+++ trunk/daemon/gdm-display.h	Thu Jan 31 00:51:46 2008
@@ -61,10 +61,12 @@
         gboolean (*remove_user_authorization) (GdmDisplay *display,
                                                const char *username,
                                                GError    **error);
+        gboolean (*set_slave_bus_name)        (GdmDisplay *display,
+                                               const char *name,
+                                               GError    **error);
         gboolean (*manage)                    (GdmDisplay *display);
         gboolean (*finish)                    (GdmDisplay *display);
         gboolean (*unmanage)                  (GdmDisplay *display);
-
 } GdmDisplayClass;
 
 typedef enum
@@ -123,6 +125,9 @@
 gboolean            gdm_display_remove_user_authorization      (GdmDisplay *display,
                                                                 const char *username,
                                                                 GError    **error);
+gboolean            gdm_display_set_slave_bus_name             (GdmDisplay *display,
+                                                                const char *name,
+                                                                GError    **error);
 
 
 G_END_DECLS

Modified: trunk/daemon/gdm-display.xml
==============================================================================
--- trunk/daemon/gdm-display.xml	(original)
+++ trunk/daemon/gdm-display.xml	Thu Jan 31 00:51:46 2008
@@ -32,5 +32,8 @@
     <method name="RemoveUserAuthorization">
       <arg name="username" direction="in" type="s"/>
     </method>
+    <method name="SetSlaveBusName">
+      <arg name="name" direction="in" type="s"/>
+    </method>
   </interface>
 </node>

Modified: trunk/daemon/gdm-factory-slave.c
==============================================================================
--- trunk/daemon/gdm-factory-slave.c	(original)
+++ trunk/daemon/gdm-factory-slave.c	Thu Jan 31 00:51:46 2008
@@ -67,8 +67,6 @@
 {
         char              *id;
         GPid               pid;
-        guint              output_watch_id;
-        guint              error_watch_id;
         guint              greeter_reset_id;
 
         GPid               server_pid;

Modified: trunk/daemon/gdm-greeter-server.c
==============================================================================
--- trunk/daemon/gdm-greeter-server.c	(original)
+++ trunk/daemon/gdm-greeter-server.c	Thu Jan 31 00:51:46 2008
@@ -56,9 +56,6 @@
         char           *group_name;
         char           *display_id;
 
-        gboolean        interrupted;
-        gboolean        always_restart_greeter;
-
         DBusServer     *server;
         char           *server_address;
         DBusConnection *greeter_connection;

Modified: trunk/daemon/gdm-greeter-session.c
==============================================================================
--- trunk/daemon/gdm-greeter-session.c	(original)
+++ trunk/daemon/gdm-greeter-session.c	Thu Jan 31 00:51:46 2008
@@ -71,11 +71,6 @@
 
         CkConnector    *ckc;
 
-        int             user_max_filesize;
-
-        gboolean        interrupted;
-        gboolean        always_restart_greeter;
-
         guint           child_watch_id;
 
         GPid            dbus_pid;
@@ -1030,7 +1025,6 @@
         greeter_session->priv->pid = -1;
 
         greeter_session->priv->command = g_strdup (LIBEXECDIR "/gdm-simple-greeter");
-        greeter_session->priv->user_max_filesize = 65536;
 }
 
 static void

Modified: trunk/daemon/gdm-product-slave.c
==============================================================================
--- trunk/daemon/gdm-product-slave.c	(original)
+++ trunk/daemon/gdm-product-slave.c	Thu Jan 31 00:51:46 2008
@@ -66,8 +66,6 @@
 {
         char             *id;
         GPid              pid;
-        guint             output_watch_id;
-        guint             error_watch_id;
 
         char             *relay_address;
 

Modified: trunk/daemon/gdm-simple-slave.c
==============================================================================
--- trunk/daemon/gdm-simple-slave.c	(original)
+++ trunk/daemon/gdm-simple-slave.c	Thu Jan 31 00:51:46 2008
@@ -62,8 +62,6 @@
 {
         char              *id;
         GPid               pid;
-        guint              output_watch_id;
-        guint              error_watch_id;
 
         guint              greeter_reset_id;
         guint              start_session_id;

Modified: trunk/daemon/gdm-slave.c
==============================================================================
--- trunk/daemon/gdm-slave.c	(original)
+++ trunk/daemon/gdm-slave.c	Thu Jan 31 00:51:46 2008
@@ -417,6 +417,35 @@
 }
 
 static gboolean
+gdm_slave_set_slave_bus_name (GdmSlave *slave)
+{
+        gboolean    res;
+        GError     *error;
+        const char *name;
+
+        name = dbus_bus_get_unique_name (dbus_g_connection_get_connection (slave->priv->connection));
+
+        error = NULL;
+        res = dbus_g_proxy_call (slave->priv->display_proxy,
+                                 "SetSlaveBusName",
+                                 &error,
+                                 G_TYPE_STRING, name,
+                                 G_TYPE_INVALID,
+                                 G_TYPE_INVALID);
+
+        if (! res) {
+                if (error != NULL) {
+                        g_warning ("Failed to set slave bus name on parent: %s", error->message);
+                        g_error_free (error);
+                } else {
+                        g_warning ("Failed to set slave bus name on parent");
+                }
+        }
+
+        return res;
+}
+
+static gboolean
 gdm_slave_real_start (GdmSlave *slave)
 {
         gboolean res;
@@ -475,6 +504,8 @@
                 exit (1);
         }
 
+        gdm_slave_set_slave_bus_name (slave);
+
         /* cache some values up front */
         error = NULL;
         res = dbus_g_proxy_call (slave->priv->display_proxy,
@@ -1123,7 +1154,7 @@
 static gboolean
 register_slave (GdmSlave *slave)
 {
-        GError *error = NULL;
+        GError *error;
 
         error = NULL;
         slave->priv->connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
@@ -1155,6 +1186,7 @@
         slave = GDM_SLAVE (G_OBJECT_CLASS (gdm_slave_parent_class)->constructor (type,
                                                                                  n_construct_properties,
                                                                                  construct_properties));
+        /* Always match the slave id with the master */
 
         id = NULL;
         if (g_str_has_prefix (slave->priv->display_id, "/org/gnome/DisplayManager/Display")) {

Added: trunk/daemon/gdm-xdmcp-chooser-display.c
==============================================================================
--- (empty file)
+++ trunk/daemon/gdm-xdmcp-chooser-display.c	Thu Jan 31 00:51:46 2008
@@ -0,0 +1,234 @@
+/* -*- 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 <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+
+#include "gdm-display.h"
+#include "gdm-xdmcp-chooser-display.h"
+#include "gdm-xdmcp-chooser-display-glue.h"
+
+#include "gdm-common.h"
+#include "gdm-address.h"
+
+#define DEFAULT_SLAVE_COMMAND LIBEXECDIR"/gdm-xdmcp-chooser-slave"
+
+#define GDM_DBUS_NAME                          "/org/gnome/DisplayManager"
+#define GDM_XDMCP_CHOOSER_SLAVE_DBUS_INTERFACE "org.gnome.DisplayManager.XdmcpChooserSlave"
+
+#define GDM_XDMCP_CHOOSER_DISPLAY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_XDMCP_CHOOSER_DISPLAY, GdmXdmcpChooserDisplayPrivate))
+
+struct GdmXdmcpChooserDisplayPrivate
+{
+        DBusGProxy      *slave_proxy;
+};
+
+enum {
+        PROP_0,
+};
+
+enum {
+        HOSTNAME_SELECTED,
+        LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL] = { 0, };
+
+static void     gdm_xdmcp_chooser_display_class_init    (GdmXdmcpChooserDisplayClass *klass);
+static void     gdm_xdmcp_chooser_display_init          (GdmXdmcpChooserDisplay      *xdmcp_chooser_display);
+static void     gdm_xdmcp_chooser_display_finalize      (GObject                     *object);
+
+G_DEFINE_TYPE (GdmXdmcpChooserDisplay, gdm_xdmcp_chooser_display, GDM_TYPE_XDMCP_DISPLAY)
+
+static void
+on_hostname_selected (DBusGProxy             *proxy,
+                      const char             *hostname,
+                      GdmXdmcpChooserDisplay *display)
+{
+        g_debug ("GdmXdmcpChooserDisplay: hostname selected: %s", hostname);
+        g_signal_emit (display, signals [HOSTNAME_SELECTED], 0, hostname);
+}
+
+static gboolean
+gdm_xdmcp_chooser_display_set_slave_bus_name (GdmDisplay *display,
+                                              const char *name,
+                                              GError    **error)
+{
+        char            *display_id;
+        const char      *slave_num;
+        char            *slave_id;
+        DBusGConnection *connection;
+        GError          *local_error;
+        GdmXdmcpChooserDisplay *chooser_display;
+
+        display_id = NULL;
+        slave_id = NULL;
+        slave_num = NULL;
+
+        chooser_display = GDM_XDMCP_CHOOSER_DISPLAY (display);
+        if (chooser_display->priv->slave_proxy != NULL) {
+                g_object_unref (chooser_display->priv->slave_proxy);
+        }
+
+        g_object_get (display, "id", &display_id, NULL);
+
+        if (g_str_has_prefix (display_id, "/org/gnome/DisplayManager/Display")) {
+                slave_num = display_id + strlen ("/org/gnome/DisplayManager/Display");
+        }
+
+        slave_id = g_strdup_printf ("/org/gnome/DisplayManager/Slave%s", slave_num);
+
+        local_error = NULL;
+        connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &local_error);
+        if (connection == NULL) {
+                if (local_error != NULL) {
+                        g_critical ("error getting system bus: %s", local_error->message);
+                        g_error_free (local_error);
+                }
+        }
+
+        g_debug ("GdmXdmcpChooserDisplay: creating proxy for %s on %s", slave_id, name);
+
+        chooser_display->priv->slave_proxy = dbus_g_proxy_new_for_name (connection,
+                                                                         name,
+                                                                         slave_id,
+                                                                         GDM_XDMCP_CHOOSER_SLAVE_DBUS_INTERFACE);
+        if (chooser_display->priv->slave_proxy == NULL) {
+                g_warning ("Failed to connect to the slave object");
+                goto out;
+        }
+        dbus_g_proxy_add_signal (chooser_display->priv->slave_proxy,
+                                 "HostnameSelected",
+                                 G_TYPE_STRING,
+                                 G_TYPE_INVALID);
+        dbus_g_proxy_connect_signal (chooser_display->priv->slave_proxy,
+                                     "HostnameSelected",
+                                     G_CALLBACK (on_hostname_selected),
+                                     display,
+                                     NULL);
+ out:
+
+        g_free (display_id);
+        g_free (slave_id);
+
+        return GDM_DISPLAY_CLASS (gdm_xdmcp_chooser_display_parent_class)->set_slave_bus_name (display, name, error);
+}
+
+static gboolean
+gdm_xdmcp_chooser_display_manage (GdmDisplay *display)
+{
+        g_return_val_if_fail (GDM_IS_DISPLAY (display), FALSE);
+
+        GDM_DISPLAY_CLASS (gdm_xdmcp_chooser_display_parent_class)->manage (display);
+
+        return TRUE;
+}
+
+static void
+gdm_xdmcp_chooser_display_class_init (GdmXdmcpChooserDisplayClass *klass)
+{
+        GObjectClass    *object_class = G_OBJECT_CLASS (klass);
+        GdmDisplayClass *display_class = GDM_DISPLAY_CLASS (klass);
+
+        object_class->finalize = gdm_xdmcp_chooser_display_finalize;
+
+        display_class->manage = gdm_xdmcp_chooser_display_manage;
+        display_class->set_slave_bus_name = gdm_xdmcp_chooser_display_set_slave_bus_name;
+
+        signals [HOSTNAME_SELECTED] =
+                g_signal_new ("hostname-selected",
+                              G_OBJECT_CLASS_TYPE (object_class),
+                              G_SIGNAL_RUN_FIRST,
+                              G_STRUCT_OFFSET (GdmXdmcpChooserDisplayClass, hostname_selected),
+                              NULL,
+                              NULL,
+                              g_cclosure_marshal_VOID__STRING,
+                              G_TYPE_NONE,
+                              1,
+                              G_TYPE_STRING);
+
+        g_type_class_add_private (klass, sizeof (GdmXdmcpChooserDisplayPrivate));
+
+        dbus_g_object_type_install_info (GDM_TYPE_XDMCP_CHOOSER_DISPLAY, &dbus_glib_gdm_xdmcp_chooser_display_object_info);
+}
+
+static void
+gdm_xdmcp_chooser_display_init (GdmXdmcpChooserDisplay *xdmcp_chooser_display)
+{
+
+        xdmcp_chooser_display->priv = GDM_XDMCP_CHOOSER_DISPLAY_GET_PRIVATE (xdmcp_chooser_display);
+}
+
+static void
+gdm_xdmcp_chooser_display_finalize (GObject *object)
+{
+        GdmXdmcpChooserDisplay *chooser_display;
+
+        g_return_if_fail (object != NULL);
+        g_return_if_fail (GDM_IS_XDMCP_CHOOSER_DISPLAY (object));
+
+        chooser_display = GDM_XDMCP_CHOOSER_DISPLAY (object);
+
+        g_return_if_fail (chooser_display->priv != NULL);
+
+        if (chooser_display->priv->slave_proxy != NULL) {
+                g_object_unref (chooser_display->priv->slave_proxy);
+        }
+
+        G_OBJECT_CLASS (gdm_xdmcp_chooser_display_parent_class)->finalize (object);
+}
+
+GdmDisplay *
+gdm_xdmcp_chooser_display_new (const char              *hostname,
+                               int                      number,
+                               GdmAddress              *address,
+                               gint32                   session_number)
+{
+        GObject *object;
+        char    *x11_display;
+
+        x11_display = g_strdup_printf ("%s:%d", hostname, number);
+        object = g_object_new (GDM_TYPE_XDMCP_CHOOSER_DISPLAY,
+                               "slave-command", DEFAULT_SLAVE_COMMAND,
+                               "remote-hostname", hostname,
+                               "x11-display-number", number,
+                               "x11-display-name", x11_display,
+                               "is-local", FALSE,
+                               "remote-address", address,
+                               "session-number", session_number,
+                               NULL);
+        g_free (x11_display);
+
+        return GDM_DISPLAY (object);
+}

Added: trunk/daemon/gdm-xdmcp-chooser-display.h
==============================================================================
--- (empty file)
+++ trunk/daemon/gdm-xdmcp-chooser-display.h	Thu Jan 31 00:51:46 2008
@@ -0,0 +1,68 @@
+/* -*- 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_XDMCP_CHOOSER_DISPLAY_H
+#define __GDM_XDMCP_CHOOSER_DISPLAY_H
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <glib-object.h>
+#include <dbus/dbus-glib.h>
+
+#include "gdm-xdmcp-display.h"
+#include "gdm-address.h"
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_XDMCP_CHOOSER_DISPLAY         (gdm_xdmcp_chooser_display_get_type ())
+#define GDM_XDMCP_CHOOSER_DISPLAY(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_XDMCP_CHOOSER_DISPLAY, GdmXdmcpChooserDisplay))
+#define GDM_XDMCP_CHOOSER_DISPLAY_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_XDMCP_CHOOSER_DISPLAY, GdmXdmcpChooserDisplayClass))
+#define GDM_IS_XDMCP_CHOOSER_DISPLAY(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_XDMCP_CHOOSER_DISPLAY))
+#define GDM_IS_XDMCP_CHOOSER_DISPLAY_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_XDMCP_CHOOSER_DISPLAY))
+#define GDM_XDMCP_CHOOSER_DISPLAY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_XDMCP_CHOOSER_DISPLAY, GdmXdmcpChooserDisplayClass))
+
+typedef struct GdmXdmcpChooserDisplayPrivate GdmXdmcpChooserDisplayPrivate;
+
+typedef struct
+{
+        GdmXdmcpDisplay                parent;
+        GdmXdmcpChooserDisplayPrivate *priv;
+} GdmXdmcpChooserDisplay;
+
+typedef struct
+{
+        GdmXdmcpDisplayClass   parent_class;
+
+        void (* hostname_selected)          (GdmXdmcpChooserDisplay *display,
+                                             const char             *hostname);
+} GdmXdmcpChooserDisplayClass;
+
+GType                     gdm_xdmcp_chooser_display_get_type                 (void);
+
+
+GdmDisplay *              gdm_xdmcp_chooser_display_new                      (const char              *hostname,
+                                                                              int                      number,
+                                                                              GdmAddress              *addr,
+                                                                              gint32                   serial_number);
+
+G_END_DECLS
+
+#endif /* __GDM_XDMCP_CHOOSER_DISPLAY_H */

Added: trunk/daemon/gdm-xdmcp-chooser-display.xml
==============================================================================
--- (empty file)
+++ trunk/daemon/gdm-xdmcp-chooser-display.xml	Thu Jan 31 00:51:46 2008
@@ -0,0 +1,5 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd";>
+<node>
+  <interface name="org.gnome.DisplayManager.XdmcpChooserDisplay">
+  </interface>
+</node>

Added: trunk/daemon/gdm-xdmcp-chooser-slave.c
==============================================================================
--- (empty file)
+++ trunk/daemon/gdm-xdmcp-chooser-slave.c	Thu Jan 31 00:51:46 2008
@@ -0,0 +1,432 @@
+/* -*- 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 <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+#include <glib-object.h>
+
+#define DBUS_API_SUBJECT_TO_CHANGE
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include <X11/Xlib.h> /* for Display */
+
+#include "gdm-common.h"
+
+#include "gdm-xdmcp-chooser-slave.h"
+#include "gdm-xdmcp-chooser-slave-glue.h"
+
+#include "gdm-server.h"
+#include "gdm-chooser-server.h"
+#include "gdm-chooser-session.h"
+
+#define GDM_XDMCP_CHOOSER_SLAVE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_XDMCP_CHOOSER_SLAVE, GdmXdmcpChooserSlavePrivate))
+
+#define GDM_DBUS_NAME              "org.gnome.DisplayManager"
+#define GDM_DBUS_DISPLAY_INTERFACE "org.gnome.DisplayManager.Display"
+
+#define MAX_CONNECT_ATTEMPTS 10
+
+struct GdmXdmcpChooserSlavePrivate
+{
+        char              *id;
+        GPid               pid;
+
+        int                ping_interval;
+
+        guint              connection_attempts;
+
+        GdmChooserServer  *chooser_server;
+        GdmChooserSession *chooser;
+};
+
+enum {
+        PROP_0,
+};
+
+enum {
+        HOSTNAME_SELECTED,
+        LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL] = { 0, };
+
+static void     gdm_xdmcp_chooser_slave_class_init     (GdmXdmcpChooserSlaveClass *klass);
+static void     gdm_xdmcp_chooser_slave_init           (GdmXdmcpChooserSlave      *xdmcp_chooser_slave);
+static void     gdm_xdmcp_chooser_slave_finalize       (GObject                   *object);
+
+G_DEFINE_TYPE (GdmXdmcpChooserSlave, gdm_xdmcp_chooser_slave, GDM_TYPE_SLAVE)
+
+
+static void
+on_chooser_session_start (GdmChooserSession    *chooser,
+                          GdmXdmcpChooserSlave *slave)
+{
+        g_debug ("GdmXdmcpChooserSlave: Chooser started");
+}
+
+static void
+on_chooser_session_stop (GdmChooserSession    *chooser,
+                         GdmXdmcpChooserSlave *slave)
+{
+        g_debug ("GdmXdmcpChooserSlave: Chooser stopped");
+        gdm_slave_stopped (GDM_SLAVE (slave));
+}
+
+static void
+on_chooser_session_exited (GdmChooserSession    *chooser,
+                           int                   code,
+                           GdmXdmcpChooserSlave *slave)
+{
+        g_debug ("GdmXdmcpChooserSlave: Chooser exited: %d", code);
+        gdm_slave_stopped (GDM_SLAVE (slave));
+}
+
+static void
+on_chooser_session_died (GdmChooserSession    *chooser,
+                         int                   signal,
+                         GdmXdmcpChooserSlave *slave)
+{
+        g_debug ("GdmXdmcpChooserSlave: Chooser died: %d", signal);
+        gdm_slave_stopped (GDM_SLAVE (slave));
+}
+
+static void
+on_chooser_hostname_selected (GdmChooserServer     *chooser_server,
+                              const char           *name,
+                              GdmXdmcpChooserSlave *slave)
+{
+        g_debug ("GdmXdmcpChooserSlave: emitting hostname selected: %s", name);
+        g_signal_emit (slave, signals [HOSTNAME_SELECTED], 0, name);
+}
+
+static void
+on_chooser_disconnected (GdmChooserServer     *chooser_server,
+                         GdmXdmcpChooserSlave *slave)
+{
+        g_debug ("GdmXdmcpChooserSlave: Chooser disconnected");
+
+        /* stop pinging */
+        alarm (0);
+
+        gdm_slave_stopped (GDM_SLAVE (slave));
+}
+
+static void
+on_chooser_connected (GdmChooserServer     *chooser_server,
+                      GdmXdmcpChooserSlave *slave)
+{
+        g_debug ("GdmXdmcpChooserSlave: Chooser connected");
+}
+
+static void
+setup_server (GdmXdmcpChooserSlave *slave)
+{
+        /* Set the busy cursor */
+        gdm_slave_set_busy_cursor (GDM_SLAVE (slave));
+}
+
+static void
+run_chooser (GdmXdmcpChooserSlave *slave)
+{
+        char          *display_id;
+        char          *display_name;
+        char          *display_device;
+        char          *display_hostname;
+        char          *auth_file;
+        char          *address;
+
+        g_debug ("GdmXdmcpChooserSlave: Running chooser");
+
+        display_id = NULL;
+        display_name = NULL;
+        auth_file = NULL;
+        display_device = NULL;
+        display_hostname = NULL;
+
+        g_object_get (slave,
+                      "display-id", &display_id,
+                      "display-name", &display_name,
+                      "display-hostname", &display_hostname,
+                      "display-x11-authority-file", &auth_file,
+                      NULL);
+
+        g_debug ("GdmXdmcpChooserSlave: Creating chooser for %s %s", display_name, display_hostname);
+
+        /* FIXME: send a signal back to the master */
+
+        /* If XDMCP setup pinging */
+        if (slave->priv->ping_interval > 0) {
+                alarm (slave->priv->ping_interval);
+        }
+
+        /* Run the init script. gdmslave suspends until script has terminated */
+        gdm_slave_run_script (GDM_SLAVE (slave), GDMCONFDIR "/Init", "gdm");
+
+        slave->priv->chooser_server = gdm_chooser_server_new (display_id);
+        g_signal_connect (slave->priv->chooser_server,
+                          "hostname-selected",
+                          G_CALLBACK (on_chooser_hostname_selected),
+                          slave);
+        g_signal_connect (slave->priv->chooser_server,
+                          "disconnected",
+                          G_CALLBACK (on_chooser_disconnected),
+                          slave);
+        g_signal_connect (slave->priv->chooser_server,
+                          "connected",
+                          G_CALLBACK (on_chooser_connected),
+                          slave);
+        gdm_chooser_server_start (slave->priv->chooser_server);
+
+        address = gdm_chooser_server_get_address (slave->priv->chooser_server);
+
+        g_debug ("GdmXdmcpChooserSlave: Creating chooser on %s %s %s", display_name, display_device, display_hostname);
+        slave->priv->chooser = gdm_chooser_session_new (display_name,
+                                                        display_device,
+                                                        display_hostname);
+        g_signal_connect (slave->priv->chooser,
+                          "started",
+                          G_CALLBACK (on_chooser_session_start),
+                          slave);
+        g_signal_connect (slave->priv->chooser,
+                          "stopped",
+                          G_CALLBACK (on_chooser_session_stop),
+                          slave);
+        g_signal_connect (slave->priv->chooser,
+                          "exited",
+                          G_CALLBACK (on_chooser_session_exited),
+                          slave);
+        g_signal_connect (slave->priv->chooser,
+                          "died",
+                          G_CALLBACK (on_chooser_session_died),
+                          slave);
+        g_object_set (slave->priv->chooser,
+                      "x11-authority-file", auth_file,
+                      NULL);
+        gdm_chooser_session_set_server_address (slave->priv->chooser, address);
+        gdm_chooser_session_start (slave->priv->chooser);
+
+        g_free (display_id);
+        g_free (display_name);
+        g_free (display_device);
+        g_free (display_hostname);
+        g_free (auth_file);
+}
+
+static gboolean
+idle_connect_to_display (GdmXdmcpChooserSlave *slave)
+{
+        gboolean res;
+
+        slave->priv->connection_attempts++;
+
+        res = gdm_slave_connect_to_x11_display (GDM_SLAVE (slave));
+        if (res) {
+                /* FIXME: handle wait-for-go */
+
+                setup_server (slave);
+                run_chooser (slave);
+        } else {
+                if (slave->priv->connection_attempts >= MAX_CONNECT_ATTEMPTS) {
+                        g_warning ("Unable to connect to display after %d tries - bailing out", slave->priv->connection_attempts);
+                        exit (1);
+                }
+        }
+
+        return FALSE;
+}
+
+static gboolean
+gdm_xdmcp_chooser_slave_run (GdmXdmcpChooserSlave *slave)
+{
+        char    *display_name;
+        char    *auth_file;
+
+        g_object_get (slave,
+                      "display-name", &display_name,
+                      "display-x11-authority-file", &auth_file,
+                      NULL);
+
+        g_timeout_add (500, (GSourceFunc)idle_connect_to_display, slave);
+
+        g_free (display_name);
+        g_free (auth_file);
+
+        return TRUE;
+}
+
+static gboolean
+gdm_xdmcp_chooser_slave_start (GdmSlave *slave)
+{
+        gboolean res;
+
+        res = GDM_SLAVE_CLASS (gdm_xdmcp_chooser_slave_parent_class)->start (slave);
+
+        gdm_xdmcp_chooser_slave_run (GDM_XDMCP_CHOOSER_SLAVE (slave));
+
+        return TRUE;
+}
+
+static gboolean
+gdm_xdmcp_chooser_slave_stop (GdmSlave *slave)
+{
+        gboolean res;
+
+        g_debug ("GdmXdmcpChooserSlave: Stopping xdmcp_chooser_slave");
+
+        res = GDM_SLAVE_CLASS (gdm_xdmcp_chooser_slave_parent_class)->stop (slave);
+
+        if (GDM_XDMCP_CHOOSER_SLAVE (slave)->priv->chooser != NULL) {
+                gdm_chooser_session_stop (GDM_XDMCP_CHOOSER_SLAVE (slave)->priv->chooser);
+                g_object_unref (GDM_XDMCP_CHOOSER_SLAVE (slave)->priv->chooser);
+                GDM_XDMCP_CHOOSER_SLAVE (slave)->priv->chooser = NULL;
+        }
+
+        return TRUE;
+}
+
+static void
+gdm_xdmcp_chooser_slave_set_property (GObject      *object,
+                                      guint         prop_id,
+                                      const GValue *value,
+                                      GParamSpec   *pspec)
+{
+        GdmXdmcpChooserSlave *self;
+
+        self = GDM_XDMCP_CHOOSER_SLAVE (object);
+
+        switch (prop_id) {
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+        }
+}
+
+static void
+gdm_xdmcp_chooser_slave_get_property (GObject    *object,
+                                      guint       prop_id,
+                                      GValue     *value,
+                                      GParamSpec *pspec)
+{
+        GdmXdmcpChooserSlave *self;
+
+        self = GDM_XDMCP_CHOOSER_SLAVE (object);
+
+        switch (prop_id) {
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+        }
+}
+
+static GObject *
+gdm_xdmcp_chooser_slave_constructor (GType                  type,
+                                     guint                  n_construct_properties,
+                                     GObjectConstructParam *construct_properties)
+{
+        GdmXdmcpChooserSlave      *xdmcp_chooser_slave;
+        GdmXdmcpChooserSlaveClass *klass;
+
+        klass = GDM_XDMCP_CHOOSER_SLAVE_CLASS (g_type_class_peek (GDM_TYPE_XDMCP_CHOOSER_SLAVE));
+
+        xdmcp_chooser_slave = GDM_XDMCP_CHOOSER_SLAVE (G_OBJECT_CLASS (gdm_xdmcp_chooser_slave_parent_class)->constructor (type,
+                                                                                                                           n_construct_properties,
+                                                                                                                           construct_properties));
+
+        return G_OBJECT (xdmcp_chooser_slave);
+}
+
+static void
+gdm_xdmcp_chooser_slave_class_init (GdmXdmcpChooserSlaveClass *klass)
+{
+        GObjectClass  *object_class = G_OBJECT_CLASS (klass);
+        GdmSlaveClass *slave_class = GDM_SLAVE_CLASS (klass);
+
+        object_class->get_property = gdm_xdmcp_chooser_slave_get_property;
+        object_class->set_property = gdm_xdmcp_chooser_slave_set_property;
+        object_class->constructor = gdm_xdmcp_chooser_slave_constructor;
+        object_class->finalize = gdm_xdmcp_chooser_slave_finalize;
+
+        slave_class->start = gdm_xdmcp_chooser_slave_start;
+        slave_class->stop = gdm_xdmcp_chooser_slave_stop;
+
+        signals [HOSTNAME_SELECTED] =
+                g_signal_new ("hostname-selected",
+                              G_OBJECT_CLASS_TYPE (object_class),
+                              G_SIGNAL_RUN_FIRST,
+                              G_STRUCT_OFFSET (GdmXdmcpChooserSlaveClass, hostname_selected),
+                              NULL,
+                              NULL,
+                              g_cclosure_marshal_VOID__STRING,
+                              G_TYPE_NONE,
+                              1,
+                              G_TYPE_STRING);
+
+        g_type_class_add_private (klass, sizeof (GdmXdmcpChooserSlavePrivate));
+
+        dbus_g_object_type_install_info (GDM_TYPE_XDMCP_CHOOSER_SLAVE, &dbus_glib_gdm_xdmcp_chooser_slave_object_info);
+}
+
+static void
+gdm_xdmcp_chooser_slave_init (GdmXdmcpChooserSlave *slave)
+{
+        slave->priv = GDM_XDMCP_CHOOSER_SLAVE_GET_PRIVATE (slave);
+}
+
+static void
+gdm_xdmcp_chooser_slave_finalize (GObject *object)
+{
+        GdmXdmcpChooserSlave *xdmcp_chooser_slave;
+
+        g_return_if_fail (object != NULL);
+        g_return_if_fail (GDM_IS_XDMCP_CHOOSER_SLAVE (object));
+
+        xdmcp_chooser_slave = GDM_XDMCP_CHOOSER_SLAVE (object);
+
+        g_return_if_fail (xdmcp_chooser_slave->priv != NULL);
+
+        gdm_xdmcp_chooser_slave_stop (GDM_SLAVE (xdmcp_chooser_slave));
+
+        G_OBJECT_CLASS (gdm_xdmcp_chooser_slave_parent_class)->finalize (object);
+}
+
+GdmSlave *
+gdm_xdmcp_chooser_slave_new (const char *id)
+{
+        GObject *object;
+
+        object = g_object_new (GDM_TYPE_XDMCP_CHOOSER_SLAVE,
+                               "display-id", id,
+                               NULL);
+
+        return GDM_SLAVE (object);
+}

Added: trunk/daemon/gdm-xdmcp-chooser-slave.h
==============================================================================
--- (empty file)
+++ trunk/daemon/gdm-xdmcp-chooser-slave.h	Thu Jan 31 00:51:46 2008
@@ -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_XDMCP_CHOOSER_SLAVE_H
+#define __GDM_XDMCP_CHOOSER_SLAVE_H
+
+#include <glib-object.h>
+#include "gdm-slave.h"
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_XDMCP_CHOOSER_SLAVE         (gdm_xdmcp_chooser_slave_get_type ())
+#define GDM_XDMCP_CHOOSER_SLAVE(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_XDMCP_CHOOSER_SLAVE, GdmXdmcpChooserSlave))
+#define GDM_XDMCP_CHOOSER_SLAVE_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_XDMCP_CHOOSER_SLAVE, GdmXdmcpChooserSlaveClass))
+#define GDM_IS_XDMCP_CHOOSER_SLAVE(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_XDMCP_CHOOSER_SLAVE))
+#define GDM_IS_XDMCP_CHOOSER_SLAVE_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_XDMCP_CHOOSER_SLAVE))
+#define GDM_XDMCP_CHOOSER_SLAVE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_XDMCP_CHOOSER_SLAVE, GdmXdmcpChooserSlaveClass))
+
+typedef struct GdmXdmcpChooserSlavePrivate GdmXdmcpChooserSlavePrivate;
+
+typedef struct
+{
+        GdmSlave                     parent;
+        GdmXdmcpChooserSlavePrivate *priv;
+} GdmXdmcpChooserSlave;
+
+typedef struct
+{
+        GdmSlaveClass   parent_class;
+
+        void (* hostname_selected)          (GdmXdmcpChooserSlave  *slave,
+                                             const char            *hostname);
+} GdmXdmcpChooserSlaveClass;
+
+GType               gdm_xdmcp_chooser_slave_get_type   (void);
+GdmSlave *          gdm_xdmcp_chooser_slave_new        (const char       *id);
+
+G_END_DECLS
+
+#endif /* __GDM_XDMCP_CHOOSER_SLAVE_H */

Modified: trunk/daemon/gdm-xdmcp-display-factory.c
==============================================================================
--- trunk/daemon/gdm-xdmcp-display-factory.c	(original)
+++ trunk/daemon/gdm-xdmcp-display-factory.c	Thu Jan 31 00:51:46 2008
@@ -52,7 +52,8 @@
 #include <X11/Xdmcp.h>
 
 #include "gdm-common.h"
-#include "gdm-xdmcp-display.h"
+#include "gdm-xdmcp-greeter-display.h"
+#include "gdm-xdmcp-chooser-display.h"
 #include "gdm-display-factory.h"
 #include "gdm-xdmcp-display-factory.h"
 #include "gdm-display-store.h"
@@ -136,17 +137,24 @@
 };
 
 /* NOTE: Timeout and max are hardcoded */
-typedef struct _GdmForwardQuery {
+typedef struct _ForwardQuery {
         time_t      acctime;
         GdmAddress *dsp_address;
         GdmAddress *from_address;
-} GdmForwardQuery;
+} ForwardQuery;
+
+typedef struct _IndirectClient {
+        int         id;
+        GdmAddress *dsp_address;
+        GdmAddress *chosen_address;
+        time_t      acctime;
+} IndirectClient;
 
 typedef struct {
-        int              times;
-        guint            handler;
-        GdmAddress      *manager;
-        GdmAddress      *origin;
+        int                     times;
+        guint                   handler;
+        GdmAddress             *manager;
+        GdmAddress             *origin;
         GdmXdmcpDisplayFactory *xdmcp_display_factory;
 } ManagedForward;
 
@@ -154,6 +162,7 @@
 {
         GSList          *forward_queries;
         GSList          *managed_forwards;
+        GSList          *indirect_clients;
 
         int              socket_fd;
         gint32           session_serial;
@@ -873,8 +882,6 @@
 #define SIN(__s)   ((struct sockaddr_in *) __s)
 #define SIN6(__s)  ((struct sockaddr_in6 *) __s)
 
-#if 0
-/* FIXME: Add chooser support */
 static void
 set_port_for_request (GdmAddress *address,
                       ARRAY8     *port)
@@ -898,7 +905,6 @@
                 break;
         }
 }
-#endif
 
 static void
 set_address_for_request (GdmAddress *address,
@@ -925,11 +931,9 @@
 
 }
 
-#if 0
-/* FIXME: Add chooser support */
 static void
 gdm_xdmcp_send_forward_query (GdmXdmcpDisplayFactory  *factory,
-                              GdmIndirectDisplay      *id,
+                              IndirectClient          *ic,
                               GdmAddress              *address,
                               GdmAddress              *display_address,
                               ARRAYofARRAY8Ptr         authlist)
@@ -941,11 +945,11 @@
         char                    *host;
         char                    *serv;
 
-        g_assert (id != NULL);
-        g_assert (id->chosen_host != NULL);
+        g_assert (ic != NULL);
+        g_assert (ic->chosen_address != NULL);
 
         host = NULL;
-        gdm_address_get_numeric_info (id->chosen_host, &host, NULL);
+        gdm_address_get_numeric_info (ic->chosen_address, &host, NULL);
         g_debug ("GdmXdmcpDisplayFactory: Sending forward query to %s",
                    host);
         g_free (host);
@@ -978,13 +982,12 @@
 
         XdmcpFlush (factory->priv->socket_fd,
                     &factory->priv->buf,
-                    (XdmcpNetaddr)gdm_address_peek_sockaddr_storage (id->chosen_host),
+                    (XdmcpNetaddr)gdm_address_peek_sockaddr_storage (ic->chosen_address),
                     (int)sizeof (struct sockaddr_storage));
 
         g_free (port.data);
         g_free (addr.data);
 }
-#endif
 
 static void
 handle_any_query (GdmXdmcpDisplayFactory  *factory,
@@ -1051,15 +1054,167 @@
         }
 }
 
+static IndirectClient *
+indirect_client_create (GdmXdmcpDisplayFactory *factory,
+                        GdmAddress             *dsp_address)
+{
+        IndirectClient *ic;
+        int             count;
+
+        count = g_slist_length (factory->priv->indirect_clients);
+
+        ic = g_new0 (IndirectClient, 1);
+        ic->dsp_address = gdm_address_copy (dsp_address);
+
+        factory->priv->indirect_clients = g_slist_prepend (factory->priv->indirect_clients, ic);
+
+        return ic;
+}
+
+static void
+indirect_client_destroy (GdmXdmcpDisplayFactory *factory,
+                         IndirectClient         *ic)
+{
+        if (ic == NULL) {
+                return;
+        }
+
+        factory->priv->indirect_clients = g_slist_remove (factory->priv->indirect_clients, ic);
+
+        ic->acctime = 0;
+
+        {
+                char *host;
+
+                host = NULL;
+                gdm_address_get_numeric_info (ic->dsp_address, &host, NULL);
+                g_debug ("GdmXdmcpDisplayFactory: Disposing IndirectClient for %s", host);
+                g_free (host);
+        }
+
+        g_free (ic->dsp_address);
+        ic->dsp_address = NULL;
+        g_free (ic->chosen_address);
+        ic->chosen_address = NULL;
+
+        g_free (ic);
+}
+
+static IndirectClient *
+indirect_client_lookup_by_chosen (GdmXdmcpDisplayFactory *factory,
+                                  GdmAddress             *chosen_address,
+                                  GdmAddress             *origin_address)
+{
+        GSList         *li;
+        char           *host;
+        IndirectClient *ret;
+
+        g_assert (chosen_address != NULL);
+        g_assert (origin_address != NULL);
+
+        ret = NULL;
+
+        for (li = factory->priv->indirect_clients; li != NULL; li = li->next) {
+                IndirectClient *ic = li->data;
+
+                if (ic != NULL
+                    && ic->chosen_address != NULL
+                    && gdm_address_equal (ic->chosen_address, chosen_address)) {
+                        if (gdm_address_equal (ic->dsp_address, origin_address)) {
+                                ret = ic;
+                                goto out;
+                        } else if (gdm_address_is_loopback (ic->dsp_address)
+                                   && gdm_address_is_local (origin_address)) {
+                                ret = ic;
+                                goto out;
+                        }
+                }
+        }
+
+        gdm_address_get_numeric_info (chosen_address, &host, NULL);
+
+        g_debug ("GdmXdmcpDisplayFactory: Chosen %s host not found", host);
+        g_free (host);
+ out:
+        return ret;
+}
+
+/* lookup by origin */
+static IndirectClient *
+indirect_client_lookup (GdmXdmcpDisplayFactory *factory,
+                        GdmAddress             *address)
+{
+        GSList         *li;
+        GSList         *qlist;
+        IndirectClient *ret;
+        time_t          curtime;
+
+        g_assert (address != NULL);
+
+        curtime = time (NULL);
+        ret = NULL;
+
+        qlist = g_slist_copy (factory->priv->indirect_clients);
+
+        for (li = qlist; li != NULL; li = li->next) {
+                IndirectClient *ic;
+                char           *host;
+                char           *serv;
+
+                ic = (IndirectClient *) li->data;
+
+                if (ic == NULL) {
+                        continue;
+                }
+
+                host = NULL;
+                serv = NULL;
+                gdm_address_get_numeric_info (ic->dsp_address, &host, &serv);
+
+                g_debug ("GdmXdmcpDisplayFactory: comparing %s:%s", host, serv);
+                if (gdm_address_equal (ic->dsp_address, address)) {
+                        ret = ic;
+                        g_free (host);
+                        g_free (serv);
+                        break;
+                }
+
+                if (ic->acctime > 0 && curtime > ic->acctime + factory->priv->max_wait) {
+                        g_debug ("GdmXdmcpDisplayFactory: Disposing stale forward query from %s:%s",
+                                 host, serv);
+
+                        indirect_client_destroy (factory, ic);
+                }
+
+                g_free (host);
+                g_free (serv);
+        }
+
+        g_slist_free (qlist);
+
+        if (ret == NULL) {
+                char *host;
+
+                host = NULL;
+                gdm_address_get_numeric_info (address, &host, NULL);
+                g_debug ("GdmXdmcpDisplayFactory: Host %s not found",
+                         host);
+                g_free (host);
+        }
+
+        return ret;
+}
+
 static void
 gdm_xdmcp_handle_indirect_query (GdmXdmcpDisplayFactory *factory,
                                  GdmAddress             *address,
                                  int                     len)
 {
-        ARRAYofARRAY8       clnt_authlist;
-        int                 expected_len;
-        int                 i;
-        int                 res;
+        ARRAYofARRAY8    clnt_authlist;
+        int              expected_len;
+        int              i;
+        int              res;
+        IndirectClient  *ic;
 
         if (! gdm_xdmcp_host_allow (address)) {
                 /* ignore the request */
@@ -1071,6 +1226,13 @@
                 return;
         }
 
+        if (factory->priv->num_sessions > factory->priv->max_displays ||
+            (!gdm_address_is_local (address) &&
+             gdm_xdmcp_num_displays_from_host (factory, address) > factory->priv->max_displays_per_host)) {
+                g_debug ("GdmXdmcpDisplayFactory: reached maximum number of clients - ignoring indirect query");
+                return;
+        }
+
         res = XdmcpReadARRAYofARRAY8 (&factory->priv->buf, &clnt_authlist);
         if G_UNLIKELY (! res) {
                 g_warning (_("Could not extract authlist from packet"));
@@ -1085,7 +1247,7 @@
 
         /* Try to look up the display in
          * the pending list. If found send a FORWARD_QUERY to the
-         * chosen factory. Otherwise alloc a new indirect display. */
+         * chosen manager. Otherwise alloc a new indirect display. */
 
         if (len != expected_len) {
                 g_warning (_("Error in checksum"));
@@ -1093,18 +1255,16 @@
         }
 
 
-#if 0
-        GdmIndirectDisplay *id;
-        /* FIXME: Add chooser support */
+        ic = indirect_client_lookup (factory, address);
 
-        id = gdm_choose_indirect_lookup (address);
-
-        if (id != NULL && id->chosen_host != NULL) {
+        if (ic != NULL && ic->chosen_address != NULL) {
                 /* if user chose us, then just send willing */
-                if (gdm_address_is_local (id->chosen_host)) {
+                if (gdm_address_is_local (ic->chosen_address)) {
+                        g_debug ("GdmXdmcpDisplayFactory: the chosen address is local - dropping indirect");
+
                         /* get rid of indirect, so that we don't get
                          * the chooser */
-                        gdm_choose_indirect_dispose (id);
+                        indirect_client_destroy (factory, ic);
                         gdm_xdmcp_send_willing (factory, address);
                 } else if (gdm_address_is_loopback (address)) {
                         /* woohoo! fun, I have no clue how to get
@@ -1112,13 +1272,15 @@
                          * queries with all the different IPs */
                         const GList *list = gdm_address_peek_local_list ();
 
+                        g_debug ("GdmXdmcpDisplayFactory: the chosen address is a loopback");
+
                         while (list != NULL) {
                                 GdmAddress *saddr = list->data;
 
                                 if (! gdm_address_is_loopback (saddr)) {
                                         /* forward query to * chosen host */
                                         gdm_xdmcp_send_forward_query (factory,
-                                                                      id,
+                                                                      ic,
                                                                       address,
                                                                       saddr,
                                                                       &clnt_authlist);
@@ -1129,28 +1291,27 @@
                 } else {
                         /* or send forward query to chosen host */
                         gdm_xdmcp_send_forward_query (factory,
-                                                      id,
+                                                      ic,
                                                       address,
                                                       address,
                                                       &clnt_authlist);
                 }
-        } else if (id == NULL) {
-                id = gdm_choose_indirect_alloc (address);
-                if (id != NULL) {
+        } else if (ic == NULL) {
+                ic = indirect_client_create (factory, address);
+                if (ic != NULL) {
                         gdm_xdmcp_send_willing (factory, address);
                 }
         } else  {
                 gdm_xdmcp_send_willing (factory, address);
         }
-#endif
 
 out:
         XdmcpDisposeARRAYofARRAY8 (&clnt_authlist);
 }
 
 static void
-gdm_forward_query_dispose (GdmXdmcpDisplayFactory *factory,
-                           GdmForwardQuery        *q)
+forward_query_destroy (GdmXdmcpDisplayFactory *factory,
+                       ForwardQuery           *q)
 {
         if (q == NULL) {
                 return;
@@ -1180,11 +1341,11 @@
 static gboolean
 remove_oldest_forward (GdmXdmcpDisplayFactory *factory)
 {
-        GSList          *li;
-        GdmForwardQuery *oldest = NULL;
+        GSList       *li;
+        ForwardQuery *oldest = NULL;
 
         for (li = factory->priv->forward_queries; li != NULL; li = li->next) {
-                GdmForwardQuery *query = li->data;
+                ForwardQuery *query = li->data;
 
                 if (oldest == NULL || query->acctime < oldest->acctime) {
                         oldest = query;
@@ -1192,20 +1353,20 @@
         }
 
         if (oldest != NULL) {
-                gdm_forward_query_dispose (factory, oldest);
+                forward_query_destroy (factory, oldest);
                 return TRUE;
         } else {
                 return FALSE;
         }
 }
 
-static GdmForwardQuery *
-gdm_forward_query_alloc (GdmXdmcpDisplayFactory *factory,
+static ForwardQuery *
+forward_query_create (GdmXdmcpDisplayFactory *factory,
                          GdmAddress             *mgr_address,
                          GdmAddress             *dsp_address)
 {
-        GdmForwardQuery *q;
-        int              count;
+        ForwardQuery *q;
+        int           count;
 
         count = g_slist_length (factory->priv->forward_queries);
 
@@ -1213,7 +1374,7 @@
                 count--;
         }
 
-        q = g_new0 (GdmForwardQuery, 1);
+        q = g_new0 (ForwardQuery, 1);
         q->dsp_address = gdm_address_copy (dsp_address);
         q->from_address = gdm_address_copy (mgr_address);
 
@@ -1222,14 +1383,14 @@
         return q;
 }
 
-static GdmForwardQuery *
-gdm_forward_query_lookup (GdmXdmcpDisplayFactory *factory,
+static ForwardQuery *
+forward_query_lookup (GdmXdmcpDisplayFactory *factory,
                           GdmAddress             *address)
 {
-        GSList          *li;
-        GSList          *qlist;
-        GdmForwardQuery *ret;
-        time_t           curtime;
+        GSList       *li;
+        GSList       *qlist;
+        ForwardQuery *ret;
+        time_t        curtime;
 
         curtime = time (NULL);
         ret = NULL;
@@ -1237,11 +1398,11 @@
         qlist = g_slist_copy (factory->priv->forward_queries);
 
         for (li = qlist; li != NULL; li = li->next) {
-                GdmForwardQuery *q;
-                char            *host;
-                char            *serv;
+                ForwardQuery *q;
+                char         *host;
+                char         *serv;
 
-                q = (GdmForwardQuery *) li->data;
+                q = (ForwardQuery *) li->data;
 
                 if (q == NULL) {
                         continue;
@@ -1263,7 +1424,7 @@
                         g_debug ("GdmXdmcpDisplayFactory: Disposing stale forward query from %s:%s",
                                  host, serv);
 
-                        gdm_forward_query_dispose (factory, q);
+                        forward_query_destroy (factory, q);
                 }
 
                 g_free (host);
@@ -1482,14 +1643,14 @@
 
         /* Check with tcp_wrappers if display is allowed to access */
         if (gdm_xdmcp_host_allow (disp_address)) {
-                GdmForwardQuery *q;
+                ForwardQuery *q;
 
-                q = gdm_forward_query_lookup (factory, disp_address);
+                q = forward_query_lookup (factory, disp_address);
                 if (q != NULL) {
-                        gdm_forward_query_dispose (factory, q);
+                        forward_query_destroy (factory, q);
                 }
 
-                gdm_forward_query_alloc (factory, address, disp_address);
+                forward_query_create (factory, address, disp_address);
 
                 gdm_xdmcp_send_willing (factory, disp_address);
         }
@@ -1751,7 +1912,7 @@
         ARRAY8           authentype;
         ARRAY8           authendata;
         ARRAY8           status;
-        GdmForwardQuery *fq;
+        ForwardQuery    *fq;
         char            *host;
 
         host = NULL;
@@ -1786,28 +1947,100 @@
 
         /* Send MANAGED_FORWARD to indicate that the connection
          * reached some sort of resolution */
-        fq = gdm_forward_query_lookup (factory, address);
+        fq = forward_query_lookup (factory, address);
         if (fq != NULL) {
                 gdm_xdmcp_send_managed_forward (factory, fq->from_address, address);
-                gdm_forward_query_dispose (factory, fq);
+                forward_query_destroy (factory, fq);
         }
 }
 
+static void
+on_hostname_selected (GdmXdmcpChooserDisplay *display,
+                      const char             *hostname,
+                      GdmXdmcpDisplayFactory *factory)
+{
+        struct addrinfo  hints;
+        struct addrinfo *ai_list;
+        struct addrinfo *ai;
+        int              gaierr;
+        GdmAddress      *address;
+        IndirectClient  *ic;
+
+        g_debug ("GdmXdmcpDisplayFactory: hostname selected: %s", hostname);
+
+        address = gdm_xdmcp_display_get_remote_address (GDM_XDMCP_DISPLAY (display));
+
+        g_assert (address != NULL);
+
+        ic = indirect_client_lookup (factory, address);
+
+        if (ic->chosen_address != NULL) {
+                gdm_address_free (ic->chosen_address);
+                ic->chosen_address = NULL;
+        }
+
+        memset (&hints, 0, sizeof (hints));
+        hints.ai_family = gdm_address_get_family_type (address);
+        hints.ai_flags = AI_V4MAPPED; /* this should convert IPv4 address to IPv6 if needed */
+        if ((gaierr = getaddrinfo (hostname, NULL, &hints, &ai_list)) != 0) {
+                g_warning ("Unable get address: %s", gai_strerror (gaierr));
+                return;
+        }
+
+        /* just take the first one */
+        ai = ai_list;
+
+        if (ai != NULL) {
+                char *ip;
+                ic->chosen_address = gdm_address_new_from_sockaddr (ai->ai_addr, ai->ai_addrlen);
+
+                ip = NULL;
+                gdm_address_get_numeric_info (ic->chosen_address, &ip, NULL);
+                g_debug ("GdmXdmcpDisplayFactory: hostname resolves to %s", ip);
+                g_free (ip);
+        }
+
+        freeaddrinfo (ai_list);
+}
+
 static GdmDisplay *
-gdm_xdmcp_display_alloc (GdmXdmcpDisplayFactory *factory,
-                         const char             *hostname,
-                         GdmAddress             *address,
-                         int                     displaynum)
+gdm_xdmcp_display_create (GdmXdmcpDisplayFactory *factory,
+                          const char             *hostname,
+                          GdmAddress             *address,
+                          int                     displaynum)
 {
         GdmDisplay      *display;
         GdmDisplayStore *store;
+        gboolean         use_chooser;
 
         g_debug ("GdmXdmcpDisplayFactory: Creating xdmcp display for %s:%d", hostname, displaynum);
 
-        display = gdm_xdmcp_display_new (hostname,
-                                         displaynum,
-                                         address,
-                                         get_next_session_serial (factory));
+        use_chooser = FALSE;
+        if (factory->priv->honor_indirect) {
+                IndirectClient *ic;
+
+                ic = indirect_client_lookup (factory, address);
+
+                /* This was an indirect thingie and nothing was yet chosen,
+                 * use a chooser */
+                if (ic != NULL && ic->chosen_address == NULL) {
+                        use_chooser = TRUE;
+                }
+        }
+
+        if (use_chooser) {
+                display = gdm_xdmcp_chooser_display_new (hostname,
+                                                         displaynum,
+                                                         address,
+                                                         get_next_session_serial (factory));
+                g_signal_connect (display, "hostname-selected", G_CALLBACK (on_hostname_selected), factory);
+        } else {
+                display = gdm_xdmcp_greeter_display_new (hostname,
+                                                         displaynum,
+                                                         address,
+                                                         get_next_session_serial (factory));
+        }
+
         if (display == NULL) {
                 goto out;
         }
@@ -2036,10 +2269,10 @@
                 } else {
                         GdmDisplay *display;
 
-                        display = gdm_xdmcp_display_alloc (factory,
-                                                           hostname,
-                                                           address,
-                                                           clnt_dspnum);
+                        display = gdm_xdmcp_display_create (factory,
+                                                            hostname,
+                                                            address,
+                                                            clnt_dspnum);
 
                         if (display != NULL) {
                                 ARRAY8  authentication_name;
@@ -2196,8 +2429,8 @@
                        GdmAddress             *address,
                        CARD32                  sessid)
 {
-        XdmcpHeader      header;
-        GdmForwardQuery *fq;
+        XdmcpHeader   header;
+        ForwardQuery *fq;
 
         g_debug ("GdmXdmcpDisplayFactory: Sending REFUSE to %ld",
                  (long)sessid);
@@ -2218,10 +2451,10 @@
          * This was from a forwarded query quite apparently so
          * send MANAGED_FORWARD
          */
-        fq = gdm_forward_query_lookup (factory, address);
+        fq = forward_query_lookup (factory, address);
         if (fq != NULL) {
                 gdm_xdmcp_send_managed_forward (factory, fq->from_address, address);
-                gdm_forward_query_dispose (factory, fq);
+                forward_query_destroy (factory, fq);
         }
 }
 
@@ -2234,7 +2467,7 @@
         CARD16              clnt_dspnum;
         ARRAY8              clnt_dspclass;
         GdmDisplay         *display;
-        GdmForwardQuery    *fq;
+        ForwardQuery       *fq;
         char               *host;
 
         host = NULL;
@@ -2292,36 +2525,34 @@
                 g_debug ("GdmXdmcpDisplayFactory: Looked up %s", name);
                 g_free (name);
 
-#if 0
-                /* FIXME: Add chooser support */
                 if (factory->priv->honor_indirect) {
-                        GdmIndirectDisplay *id;
+                        IndirectClient *ic;
 
-                        id = gdm_choose_indirect_lookup (address);
+                        ic = indirect_client_lookup (factory, address);
 
                         /* This was an indirect thingie and nothing was yet chosen,
                          * use a chooser */
-                        if (id != NULL &&
-                            id->chosen_host == NULL) {
-                                d->use_chooser = TRUE;
-                                d->indirect_id = id->id;
+                        if (ic != NULL && ic->chosen_address == NULL) {
+                                g_debug ("GdmXdmcpDisplayFactory: use chooser");
+                                /*d->use_chooser = TRUE;
+                                  d->indirect_id = ic->id;*/
                         } else {
-                                d->indirect_id = 0;
-                                d->use_chooser = FALSE;
-                                if (id != NULL) {
-                                        gdm_choose_indirect_dispose (id);
+                                /*d->indirect_id = 0;
+                                  d->use_chooser = FALSE;*/
+                                if (ic != NULL) {
+                                        indirect_client_destroy (factory, ic);
                                 }
                         }
                 } else {
 
                 }
-#endif
+
                 /* this was from a forwarded query quite apparently so
                  * send MANAGED_FORWARD */
-                fq = gdm_forward_query_lookup (factory, address);
+                fq = forward_query_lookup (factory, address);
                 if (fq != NULL) {
                         gdm_xdmcp_send_managed_forward (factory, fq->from_address, address);
-                        gdm_forward_query_dispose (factory, fq);
+                        forward_query_destroy (factory, fq);
                 }
 
                 factory->priv->num_sessions++;
@@ -2355,6 +2586,7 @@
         ARRAY8              clnt_address;
         char               *host;
         GdmAddress         *disp_address;
+        IndirectClient     *ic;
 
         host = NULL;
         gdm_address_get_numeric_info (address, &host, NULL);
@@ -2384,14 +2616,10 @@
                 return;
         }
 
-#if 0
-        GdmIndirectDisplay *id;
-        /* FIXME: Add chooser support */
-        id = gdm_choose_indirect_lookup_by_chosen (address, disp_address);
-        if (id != NULL) {
-                gdm_choose_indirect_dispose (id);
+        ic = indirect_client_lookup_by_chosen (factory, address, disp_address);
+        if (ic != NULL) {
+                indirect_client_destroy (factory, ic);
         }
-#endif
 
         /* Note: we send GOT even on not found, just in case our previous
          * didn't get through and this was a second managed forward */

Modified: trunk/daemon/gdm-xdmcp-display.c
==============================================================================
--- trunk/daemon/gdm-xdmcp-display.c	(original)
+++ trunk/daemon/gdm-xdmcp-display.c	Thu Jan 31 00:51:46 2008
@@ -37,7 +37,6 @@
 
 #include "gdm-display.h"
 #include "gdm-xdmcp-display.h"
-#include "gdm-xdmcp-display-glue.h"
 
 #include "gdm-common.h"
 #include "gdm-address.h"
@@ -60,7 +59,7 @@
 static void     gdm_xdmcp_display_init          (GdmXdmcpDisplay      *xdmcp_display);
 static void     gdm_xdmcp_display_finalize      (GObject              *object);
 
-G_DEFINE_TYPE (GdmXdmcpDisplay, gdm_xdmcp_display, GDM_TYPE_DISPLAY)
+G_DEFINE_ABSTRACT_TYPE (GdmXdmcpDisplay, gdm_xdmcp_display, GDM_TYPE_DISPLAY)
 
 gint32
 gdm_xdmcp_display_get_session_number (GdmXdmcpDisplay *display)
@@ -218,7 +217,6 @@
                                                            0,
                                                            G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
-        dbus_g_object_type_install_info (GDM_TYPE_XDMCP_DISPLAY, &dbus_glib_gdm_xdmcp_display_object_info);
 }
 
 static void
@@ -242,26 +240,3 @@
 
         G_OBJECT_CLASS (gdm_xdmcp_display_parent_class)->finalize (object);
 }
-
-GdmDisplay *
-gdm_xdmcp_display_new (const char              *hostname,
-                       int                      number,
-                       GdmAddress              *address,
-                       gint32                   session_number)
-{
-        GObject *object;
-        char    *x11_display;
-
-        x11_display = g_strdup_printf ("%s:%d", hostname, number);
-        object = g_object_new (GDM_TYPE_XDMCP_DISPLAY,
-                               "remote-hostname", hostname,
-                               "x11-display-number", number,
-                               "x11-display-name", x11_display,
-                               "is-local", FALSE,
-                               "remote-address", address,
-                               "session-number", session_number,
-                               NULL);
-        g_free (x11_display);
-
-        return GDM_DISPLAY (object);
-}

Modified: trunk/daemon/gdm-xdmcp-display.h
==============================================================================
--- trunk/daemon/gdm-xdmcp-display.h	(original)
+++ trunk/daemon/gdm-xdmcp-display.h	Thu Jan 31 00:51:46 2008
@@ -55,12 +55,6 @@
 
 GType                     gdm_xdmcp_display_get_type                 (void);
 
-
-GdmDisplay *              gdm_xdmcp_display_new                      (const char              *hostname,
-                                                                      int                      number,
-                                                                      GdmAddress              *addr,
-                                                                      gint32                   serial_number);
-
 gint32                    gdm_xdmcp_display_get_session_number       (GdmXdmcpDisplay         *display);
 GdmAddress              * gdm_xdmcp_display_get_remote_address       (GdmXdmcpDisplay         *display);
 

Added: trunk/daemon/gdm-xdmcp-greeter-display.c
==============================================================================
--- (empty file)
+++ trunk/daemon/gdm-xdmcp-greeter-display.c	Thu Jan 31 00:51:46 2008
@@ -0,0 +1,120 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann jhu edu>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+
+#include "gdm-xdmcp-display.h"
+#include "gdm-xdmcp-greeter-display.h"
+#include "gdm-xdmcp-greeter-display-glue.h"
+
+#include "gdm-common.h"
+#include "gdm-address.h"
+
+#define GDM_XDMCP_GREETER_DISPLAY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_XDMCP_GREETER_DISPLAY, GdmXdmcpGreeterDisplayPrivate))
+
+struct GdmXdmcpGreeterDisplayPrivate
+{
+        GdmAddress             *remote_address;
+        gint32                  session_number;
+};
+
+enum {
+        PROP_0,
+        PROP_REMOTE_ADDRESS,
+        PROP_SESSION_NUMBER,
+};
+
+static void     gdm_xdmcp_greeter_display_class_init    (GdmXdmcpGreeterDisplayClass *klass);
+static void     gdm_xdmcp_greeter_display_init          (GdmXdmcpGreeterDisplay      *xdmcp_greeter_display);
+static void     gdm_xdmcp_greeter_display_finalize      (GObject                     *object);
+
+G_DEFINE_TYPE (GdmXdmcpGreeterDisplay, gdm_xdmcp_greeter_display, GDM_TYPE_XDMCP_DISPLAY)
+
+static void
+gdm_xdmcp_greeter_display_class_init (GdmXdmcpGreeterDisplayClass *klass)
+{
+        GObjectClass    *object_class = G_OBJECT_CLASS (klass);
+
+        object_class->finalize = gdm_xdmcp_greeter_display_finalize;
+
+        g_type_class_add_private (klass, sizeof (GdmXdmcpGreeterDisplayPrivate));
+
+        dbus_g_object_type_install_info (GDM_TYPE_XDMCP_GREETER_DISPLAY, &dbus_glib_gdm_xdmcp_greeter_display_object_info);
+}
+
+static void
+gdm_xdmcp_greeter_display_init (GdmXdmcpGreeterDisplay *xdmcp_greeter_display)
+{
+
+        xdmcp_greeter_display->priv = GDM_XDMCP_GREETER_DISPLAY_GET_PRIVATE (xdmcp_greeter_display);
+}
+
+static void
+gdm_xdmcp_greeter_display_finalize (GObject *object)
+{
+        GdmXdmcpGreeterDisplay *xdmcp_greeter_display;
+
+        g_return_if_fail (object != NULL);
+        g_return_if_fail (GDM_IS_XDMCP_GREETER_DISPLAY (object));
+
+        xdmcp_greeter_display = GDM_XDMCP_GREETER_DISPLAY (object);
+
+        g_return_if_fail (xdmcp_greeter_display->priv != NULL);
+
+        G_OBJECT_CLASS (gdm_xdmcp_greeter_display_parent_class)->finalize (object);
+}
+
+GdmDisplay *
+gdm_xdmcp_greeter_display_new (const char              *hostname,
+                               int                      number,
+                               GdmAddress              *address,
+                               gint32                   session_number)
+{
+        GObject *object;
+        char    *x11_display;
+
+        x11_display = g_strdup_printf ("%s:%d", hostname, number);
+        object = g_object_new (GDM_TYPE_XDMCP_GREETER_DISPLAY,
+                               "remote-hostname", hostname,
+                               "x11-display-number", number,
+                               "x11-display-name", x11_display,
+                               "is-local", FALSE,
+                               "remote-address", address,
+                               "session-number", session_number,
+                               NULL);
+        g_free (x11_display);
+
+        return GDM_DISPLAY (object);
+}

Added: trunk/daemon/gdm-xdmcp-greeter-display.h
==============================================================================
--- (empty file)
+++ trunk/daemon/gdm-xdmcp-greeter-display.h	Thu Jan 31 00:51:46 2008
@@ -0,0 +1,65 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann jhu edu>
+ *
+ * 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_XDMCP_GREETER_DISPLAY_H
+#define __GDM_XDMCP_GREETER_DISPLAY_H
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <glib-object.h>
+#include <dbus/dbus-glib.h>
+
+#include "gdm-xdmcp-display.h"
+#include "gdm-address.h"
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_XDMCP_GREETER_DISPLAY         (gdm_xdmcp_greeter_display_get_type ())
+#define GDM_XDMCP_GREETER_DISPLAY(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_XDMCP_GREETER_DISPLAY, GdmXdmcpGreeterDisplay))
+#define GDM_XDMCP_GREETER_DISPLAY_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_XDMCP_GREETER_DISPLAY, GdmXdmcpGreeterDisplayClass))
+#define GDM_IS_XDMCP_GREETER_DISPLAY(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_XDMCP_GREETER_DISPLAY))
+#define GDM_IS_XDMCP_GREETER_DISPLAY_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_XDMCP_GREETER_DISPLAY))
+#define GDM_XDMCP_GREETER_DISPLAY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_XDMCP_GREETER_DISPLAY, GdmXdmcpGreeterDisplayClass))
+
+typedef struct GdmXdmcpGreeterDisplayPrivate GdmXdmcpGreeterDisplayPrivate;
+
+typedef struct
+{
+        GdmXdmcpDisplay                parent;
+        GdmXdmcpGreeterDisplayPrivate *priv;
+} GdmXdmcpGreeterDisplay;
+
+typedef struct
+{
+        GdmXdmcpDisplayClass           parent_class;
+
+} GdmXdmcpGreeterDisplayClass;
+
+GType                     gdm_xdmcp_greeter_display_get_type         (void);
+
+
+GdmDisplay *              gdm_xdmcp_greeter_display_new              (const char              *hostname,
+                                                                      int                      number,
+                                                                      GdmAddress              *addr,
+                                                                      gint32                   serial_number);
+
+G_END_DECLS
+
+#endif /* __GDM_XDMCP_GREETER_DISPLAY_H */

Added: trunk/daemon/xdmcp-chooser-slave-main.c
==============================================================================
--- (empty file)
+++ trunk/daemon/xdmcp-chooser-slave-main.c	Thu Jan 31 00:51:46 2008
@@ -0,0 +1,229 @@
+/* -*- 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 <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <locale.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+
+#define DBUS_API_SUBJECT_TO_CHANGE
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include "gdm-signal-handler.h"
+#include "gdm-log.h"
+#include "gdm-common.h"
+#include "gdm-xdmcp-chooser-slave.h"
+
+static int gdm_return_code = 0;
+
+static DBusGConnection *
+get_system_bus (void)
+{
+        GError          *error;
+        DBusGConnection *bus;
+        DBusConnection  *connection;
+
+        error = NULL;
+        bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
+        if (bus == NULL) {
+                g_warning ("Couldn't connect to system bus: %s",
+                           error->message);
+                g_error_free (error);
+                goto out;
+        }
+
+        connection = dbus_g_connection_get_connection (bus);
+        dbus_connection_set_exit_on_disconnect (connection, FALSE);
+
+ out:
+        return bus;
+}
+
+static gboolean
+signal_cb (int      signo,
+           gpointer data)
+{
+        int ret;
+
+        g_debug ("Got callback for signal %d", signo);
+
+        ret = TRUE;
+
+        switch (signo) {
+        case SIGSEGV:
+        case SIGBUS:
+        case SIGILL:
+        case SIGABRT:
+                g_debug ("Caught signal %d.", signo);
+
+                ret = FALSE;
+                break;
+
+        case SIGFPE:
+        case SIGPIPE:
+                /* let the fatal signals interrupt us */
+                g_debug ("Caught signal %d, shutting down abnormally.", signo);
+                ret = FALSE;
+
+                break;
+
+        case SIGINT:
+        case SIGTERM:
+                /* let the fatal signals interrupt us */
+                g_debug ("Caught signal %d, shutting down normally.", signo);
+                ret = FALSE;
+
+                break;
+
+        case SIGHUP:
+                g_debug ("Got HUP signal");
+                /* FIXME:
+                 * Reread config stuff like system config files, VPN service files, etc
+                 */
+                ret = TRUE;
+
+                break;
+
+        case SIGUSR1:
+                g_debug ("Got USR1 signal");
+                /* FIXME:
+                 * Play with log levels or something
+                 */
+                ret = TRUE;
+
+                break;
+
+        default:
+                g_debug ("Caught unhandled signal %d", signo);
+                ret = TRUE;
+
+                break;
+        }
+
+        return ret;
+}
+
+static void
+on_slave_stopped (GdmSlave   *slave,
+                  GMainLoop  *main_loop)
+{
+        g_debug ("slave finished");
+        gdm_return_code = 0;
+        g_main_loop_quit (main_loop);
+}
+
+int
+main (int    argc,
+      char **argv)
+{
+        GMainLoop        *main_loop;
+        GOptionContext   *context;
+        DBusGConnection  *connection;
+        GdmSlave         *slave;
+        static char      *display_id = NULL;
+        GdmSignalHandler *signal_handler;
+        static GOptionEntry entries []   = {
+                { "display-id", 0, 0, G_OPTION_ARG_STRING, &display_id, N_("Display ID"), N_("id") },
+                { NULL }
+        };
+
+        bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
+        textdomain (GETTEXT_PACKAGE);
+        setlocale (LC_ALL, "");
+
+        gdm_set_fatal_warnings_if_unstable ();
+
+        g_type_init ();
+
+        context = g_option_context_new (_("GNOME Display Manager Slave"));
+        g_option_context_add_main_entries (context, entries, NULL);
+
+        g_option_context_parse (context, &argc, &argv, NULL);
+        g_option_context_free (context);
+
+        connection = get_system_bus ();
+        if (connection == NULL) {
+                goto out;
+        }
+
+        gdm_log_init ();
+
+        gdm_log_set_debug (TRUE);
+
+        if (display_id == NULL) {
+                g_critical ("No display ID set");
+                exit (1);
+        }
+
+        main_loop = g_main_loop_new (NULL, FALSE);
+
+        signal_handler = gdm_signal_handler_new ();
+        gdm_signal_handler_set_main_loop (signal_handler, main_loop);
+        gdm_signal_handler_add (signal_handler, SIGTERM, signal_cb, NULL);
+        gdm_signal_handler_add (signal_handler, SIGINT, signal_cb, NULL);
+        gdm_signal_handler_add (signal_handler, SIGILL, signal_cb, NULL);
+        gdm_signal_handler_add (signal_handler, SIGBUS, signal_cb, NULL);
+        gdm_signal_handler_add (signal_handler, SIGFPE, signal_cb, NULL);
+        gdm_signal_handler_add (signal_handler, SIGHUP, signal_cb, NULL);
+        gdm_signal_handler_add (signal_handler, SIGSEGV, signal_cb, NULL);
+        gdm_signal_handler_add (signal_handler, SIGABRT, signal_cb, NULL);
+        gdm_signal_handler_add (signal_handler, SIGUSR1, signal_cb, NULL);
+
+        slave = gdm_xdmcp_chooser_slave_new (display_id);
+        if (slave == NULL) {
+                goto out;
+        }
+        g_signal_connect (slave,
+                          "stopped",
+                          G_CALLBACK (on_slave_stopped),
+                          main_loop);
+        gdm_slave_start (slave);
+
+        g_main_loop_run (main_loop);
+
+        if (slave != NULL) {
+                g_object_unref (slave);
+        }
+
+        if (signal_handler != NULL) {
+                g_object_unref (signal_handler);
+        }
+
+        g_main_loop_unref (main_loop);
+
+ out:
+
+        g_debug ("Slave finished");
+
+        return gdm_return_code;
+}

Modified: trunk/data/gdm.conf
==============================================================================
--- trunk/data/gdm.conf	(original)
+++ trunk/data/gdm.conf	Thu Jan 31 00:51:46 2008
@@ -27,6 +27,8 @@
           send_member="AddUserAuthoritization"/>
     <deny send_interface="org.gnome.DisplayManager.Display"
           send_member="RemoveUserAuthoritization"/>
+    <deny send_interface="org.gnome.DisplayManager.Display"
+          send_member="SetSlaveBusName"/>
     <deny send_interface="org.gnome.DisplayManager.Settings"
           send_member="SetValue"/>
   </policy>

Modified: trunk/gui/simple-chooser/Makefile.am
==============================================================================
--- trunk/gui/simple-chooser/Makefile.am	(original)
+++ trunk/gui/simple-chooser/Makefile.am	Thu Jan 31 00:51:46 2008
@@ -11,6 +11,10 @@
 	-DLIBEXECDIR=\""$(libexecdir)"\" 		\
 	-DSBINDIR=\""$(sbindir)"\"		 	\
 	-DPIXMAPDIR=\""$(pixmapdir)"\"		 	\
+	-DAT_SPI_REGISTRYD_DIR="\"$(AT_SPI_REGISTRYD_DIR)\""	\
+	$(GTK_CFLAGS)					\
+	$(XDMCP_CFLAGS)					\
+	$(EXTRA_CHOOSER_CFLAGS)				\
 	$(SIMPLE_CHOOSER_CFLAGS)			\
 	$(NULL)
 
@@ -18,15 +22,40 @@
 	gdm-simple-chooser		\
 	$(NULL)
 
+noinst_PROGRAMS = 			\
+	test-host-chooser		\
+	$(NULL)
+
 gdm_simple_chooser_SOURCES =  		\
 	chooser-main.c 			\
 	gdm-host-chooser-widget.c	\
 	gdm-host-chooser-widget.h	\
 	gdm-host-chooser-dialog.c	\
 	gdm-host-chooser-dialog.h	\
+	gdm-chooser-client.c		\
+	gdm-chooser-client.h		\
+	gdm-chooser-session.c		\
+	gdm-chooser-session.h		\
 	$(NULL)
 
 gdm_simple_chooser_LDADD = 		\
+	$(GTK_LIBS)			\
+	$(EXTRA_CHOOSER_LIBS)   	\
+	$(SIMPLE_CHOOSER_LIBS)		\
+	$(XDMCP_LIBS)			\
+	$(top_builddir)/common/libgdmcommon.la	\
+	$(NULL)
+
+test_host_chooser_SOURCES = 		\
+	test-host-chooser.c 		\
+	gdm-host-chooser-widget.c	\
+	gdm-host-chooser-widget.h	\
+	gdm-host-chooser-dialog.c	\
+	gdm-host-chooser-dialog.h	\
+	$(NULL)
+
+test_host_chooser_LDADD =		\
+	$(GTK_LIBS)			\
 	$(EXTRA_CHOOSER_LIBS)   	\
 	$(SIMPLE_CHOOSER_LIBS)		\
 	$(XDMCP_LIBS)			\

Modified: trunk/gui/simple-chooser/chooser-main.c
==============================================================================
--- trunk/gui/simple-chooser/chooser-main.c	(original)
+++ trunk/gui/simple-chooser/chooser-main.c	Thu Jan 31 00:51:46 2008
@@ -28,22 +28,204 @@
 #include <errno.h>
 
 #include <glib/gi18n.h>
+#include <gdk/gdkx.h>
 #include <gtk/gtk.h>
-#define DBUS_API_SUBJECT_TO_CHANGE
-#include <dbus/dbus-glib.h>
-#include <dbus/dbus-glib-lowlevel.h>
+#include <gconf/gconf-client.h>
 
 #include "gdm-common.h"
 #include "gdm-log.h"
 #include "gdm-settings-client.h"
 #include "gdm-settings-keys.h"
 
-#include "gdm-host-chooser-dialog.h"
+#include "gdm-chooser-session.h"
+
+#define ACCESSIBILITY_KEY         "/desktop/gnome/interface/accessibility"
+
+static Atom AT_SPI_IOR;
+
+
+static gboolean
+assistive_registry_launch (void)
+{
+        GPid        pid;
+        GError     *error;
+        const char *command;
+        char      **argv;
+        gboolean    res;
+
+        command = AT_SPI_REGISTRYD_DIR "/at-spi-registryd";
+
+        argv = NULL;
+        error = NULL;
+        res = g_shell_parse_argv (command, NULL, &argv, &error);
+        if (! res) {
+                g_warning ("Unable to parse command: %s", error->message);
+                return FALSE;
+        }
+
+        error = NULL;
+        res = g_spawn_async (NULL,
+                             argv,
+                             NULL,
+                             G_SPAWN_SEARCH_PATH
+                             | G_SPAWN_STDOUT_TO_DEV_NULL
+                             | G_SPAWN_STDERR_TO_DEV_NULL,
+                             NULL,
+                             NULL,
+                             &pid,
+                             &error);
+        g_strfreev (argv);
+
+        if (! res) {
+                g_warning ("Unable to run command %s: %s", command, error->message);
+                return FALSE;
+        }
+
+        if (kill (pid, 0) < 0) {
+                g_warning ("at-spi-registryd not running");
+                return FALSE;
+        }
+
+        return TRUE;
+}
+
+static GdkFilterReturn
+filter_watch (GdkXEvent *xevent,
+              GdkEvent  *event,
+              gpointer   data)
+{
+        XEvent *xev = (XEvent *)xevent;
+
+        if (xev->xany.type == PropertyNotify
+            && xev->xproperty.atom == AT_SPI_IOR) {
+                gtk_main_quit ();
+
+                return GDK_FILTER_REMOVE;
+        }
+
+        return GDK_FILTER_CONTINUE;
+}
+
+static gboolean
+filter_timeout (gpointer data)
+{
+        g_warning ("The accessibility registry was not found.");
+
+        gtk_main_quit ();
+
+        return FALSE;
+}
+
+static void
+assistive_registry_start (void)
+{
+        GdkWindow *root;
+        guint      tid;
+
+        root = gdk_get_default_root_window ();
+
+        if ( ! AT_SPI_IOR) {
+                AT_SPI_IOR = XInternAtom (GDK_DISPLAY (), "AT_SPI_IOR", False);
+        }
+
+        gdk_window_set_events (root,  GDK_PROPERTY_CHANGE_MASK);
+
+        if ( ! assistive_registry_launch ()) {
+                g_warning ("The accessibility registry could not be started.");
+                return;
+        }
+
+        gdk_window_add_filter (root, filter_watch, NULL);
+        tid = g_timeout_add_seconds (5, filter_timeout, NULL);
+
+        gtk_main ();
+
+        gdk_window_remove_filter (root, filter_watch, NULL);
+        g_source_remove (tid);
+}
+
+static void
+at_set_gtk_modules (void)
+{
+        GSList     *modules_list;
+        GSList     *l;
+        const char *old;
+        char      **modules;
+        gboolean    found_gail;
+        gboolean    found_atk_bridge;
+        int         n;
+
+        n = 0;
+        modules_list = NULL;
+        found_gail = FALSE;
+        found_atk_bridge = FALSE;
+
+        if ((old = g_getenv ("GTK_MODULES")) != NULL) {
+                modules = g_strsplit (old, ":", -1);
+                for (n = 0; modules[n]; n++) {
+                        if (!strcmp (modules[n], "gail")) {
+                                found_gail = TRUE;
+                        } else if (!strcmp (modules[n], "atk-bridge")) {
+                                found_atk_bridge = TRUE;
+                        }
+
+                        modules_list = g_slist_prepend (modules_list, modules[n]);
+                        modules[n] = NULL;
+                }
+                g_free (modules);
+        }
+
+        if (!found_gail) {
+                modules_list = g_slist_prepend (modules_list, "gail");
+                ++n;
+        }
+
+        if (!found_atk_bridge) {
+                modules_list = g_slist_prepend (modules_list, "atk-bridge");
+                ++n;
+        }
+
+        modules = g_new (char *, n + 1);
+        modules[n--] = NULL;
+        for (l = modules_list; l; l = l->next) {
+                modules[n--] = g_strdup (l->data);
+        }
+
+        g_setenv ("GTK_MODULES", g_strjoinv (":", modules), TRUE);
+        g_strfreev (modules);
+        g_slist_free (modules_list);
+}
+
+static void
+load_a11y (void)
+{
+        const char        *env_a_t_support;
+        gboolean           a_t_support;
+        GConfClient       *gconf_client;
+
+        gconf_client = gconf_client_get_default ();
+
+        env_a_t_support = g_getenv ("GNOME_ACCESSIBILITY");
+        if (env_a_t_support) {
+                a_t_support = atoi (env_a_t_support);
+        } else {
+                a_t_support = gconf_client_get_bool (gconf_client, ACCESSIBILITY_KEY, NULL);
+        }
+
+        if (a_t_support) {
+                assistive_registry_start ();
+                at_set_gtk_modules ();
+        }
+
+        g_object_unref (gconf_client);
+}
 
 int
 main (int argc, char *argv[])
 {
-        GtkWidget        *chooser;
+        GdmChooserSession *session;
+        gboolean           res;
+        GError            *error;
 
         bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
         bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
@@ -51,29 +233,42 @@
 
         setlocale (LC_ALL, "");
 
+        gdm_set_fatal_warnings_if_unstable ();
+
         g_type_init ();
 
-        g_debug ("Chooser for display %s xauthority:%s", g_getenv ("DISPLAY"), g_getenv ("XAUTHORITY"));
+        gdm_log_init ();
+        gdm_log_set_debug (TRUE);
+
+        g_debug ("Chooser for display %s xauthority:%s",
+                 g_getenv ("DISPLAY"),
+                 g_getenv ("XAUTHORITY"));
 
-        /*
-         * gdm_common_atspi_launch () needs gdk initialized.
-         * We cannot start gtk before the registry is running
-         * because the atk-bridge will crash.
-         */
         gdk_init (&argc, &argv);
-        /*gdm_common_atspi_launch ();*/
+
+        load_a11y ();
+
         gtk_init (&argc, &argv);
 
-        chooser = gdm_host_chooser_dialog_new ();
-        if (gtk_dialog_run (GTK_DIALOG (chooser)) == GTK_RESPONSE_OK) {
-                char *hostname;
+        session = gdm_chooser_session_new ();
+        if (session == NULL) {
+                g_critical ("Unable to create chooser session");
+                exit (1);
+        }
 
-                hostname = gdm_host_chooser_dialog_get_current_hostname (GDM_HOST_CHOOSER_DIALOG (chooser));
-                g_print ("hostname: %s\n", hostname);
-                g_free (hostname);
+        error = NULL;
+        res = gdm_chooser_session_start (session, &error);
+        if (! res) {
+                g_warning ("Unable to start chooser session: %s", error->message);
+                g_error_free (error);
+                exit (1);
         }
 
-        gtk_widget_destroy (chooser);
+        gtk_main ();
+
+        if (session != NULL) {
+                g_object_unref (session);
+        }
 
         return 0;
 }

Added: trunk/gui/simple-chooser/gdm-chooser-client.c
==============================================================================
--- (empty file)
+++ trunk/gui/simple-chooser/gdm-chooser-client.c	Thu Jan 31 00:51:46 2008
@@ -0,0 +1,414 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann jhu edu>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+#define DBUS_API_SUBJECT_TO_CHANGE
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include "gdm-chooser-client.h"
+
+#define GDM_CHOOSER_CLIENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_CHOOSER_CLIENT, GdmChooserClientPrivate))
+
+#define CHOOSER_SERVER_DBUS_PATH      "/org/gnome/DisplayManager/ChooserServer"
+#define CHOOSER_SERVER_DBUS_INTERFACE "org.gnome.DisplayManager.ChooserServer"
+
+#define GDM_DBUS_NAME              "org.gnome.DisplayManager"
+#define GDM_DBUS_DISPLAY_INTERFACE "org.gnome.DisplayManager.Display"
+
+struct GdmChooserClientPrivate
+{
+        DBusConnection   *connection;
+        char             *address;
+};
+
+enum {
+        PROP_0,
+};
+
+static void     gdm_chooser_client_class_init  (GdmChooserClientClass *klass);
+static void     gdm_chooser_client_init        (GdmChooserClient      *chooser_client);
+static void     gdm_chooser_client_finalize    (GObject               *object);
+
+G_DEFINE_TYPE (GdmChooserClient, gdm_chooser_client, G_TYPE_OBJECT)
+
+static gpointer client_object = NULL;
+
+GQuark
+gdm_chooser_client_error_quark (void)
+{
+        static GQuark error_quark = 0;
+
+        if (error_quark == 0)
+                error_quark = g_quark_from_static_string ("gdm-chooser-client");
+
+        return error_quark;
+}
+
+static gboolean
+send_dbus_string_method (DBusConnection *connection,
+                         const char     *method,
+                         const char     *payload)
+{
+        DBusError       error;
+        DBusMessage    *message;
+        DBusMessage    *reply;
+        DBusMessageIter iter;
+        const char     *str;
+
+        if (payload != NULL) {
+                str = payload;
+        } else {
+                str = "";
+        }
+
+        g_debug ("GdmChooserClient: Calling %s", method);
+        message = dbus_message_new_method_call (NULL,
+                                                CHOOSER_SERVER_DBUS_PATH,
+                                                CHOOSER_SERVER_DBUS_INTERFACE,
+                                                method);
+        if (message == NULL) {
+                g_warning ("Couldn't allocate the D-Bus message");
+                return FALSE;
+        }
+
+        dbus_message_iter_init_append (message, &iter);
+        dbus_message_iter_append_basic (&iter,
+                                        DBUS_TYPE_STRING,
+                                        &str);
+
+        dbus_error_init (&error);
+        reply = dbus_connection_send_with_reply_and_block (connection,
+                                                           message,
+                                                           -1,
+                                                           &error);
+
+        dbus_message_unref (message);
+
+        if (dbus_error_is_set (&error)) {
+                g_warning ("%s %s raised: %s\n",
+                           method,
+                           error.name,
+                           error.message);
+                return FALSE;
+        }
+        dbus_message_unref (reply);
+        dbus_connection_flush (connection);
+
+        return TRUE;
+}
+
+
+static gboolean
+send_dbus_void_method (DBusConnection *connection,
+                       const char     *method)
+{
+        DBusError       error;
+        DBusMessage    *message;
+        DBusMessage    *reply;
+
+        g_debug ("GdmChooserClient: Calling %s", method);
+        message = dbus_message_new_method_call (NULL,
+                                                CHOOSER_SERVER_DBUS_PATH,
+                                                CHOOSER_SERVER_DBUS_INTERFACE,
+                                                method);
+        if (message == NULL) {
+                g_warning ("Couldn't allocate the D-Bus message");
+                return FALSE;
+        }
+
+        dbus_error_init (&error);
+        reply = dbus_connection_send_with_reply_and_block (connection,
+                                                           message,
+                                                           -1,
+                                                           &error);
+
+        dbus_message_unref (message);
+
+        if (dbus_error_is_set (&error)) {
+                g_warning ("%s %s raised: %s\n",
+                           method,
+                           error.name,
+                           error.message);
+                return FALSE;
+        }
+        dbus_message_unref (reply);
+        dbus_connection_flush (connection);
+
+        return TRUE;
+}
+
+void
+gdm_chooser_client_call_select_hostname (GdmChooserClient *client,
+                                         const char       *text)
+{
+        send_dbus_string_method (client->priv->connection,
+                                 "SelectHostname",
+                                 text);
+}
+
+void
+gdm_chooser_client_call_disconnect (GdmChooserClient *client)
+{
+        send_dbus_void_method (client->priv->connection,
+                               "Disconnect");
+}
+
+static DBusHandlerResult
+client_dbus_handle_message (DBusConnection *connection,
+                            DBusMessage    *message,
+                            void           *user_data,
+                            dbus_bool_t     local_interface)
+{
+
+#if 0
+        g_message ("obj_path=%s interface=%s method=%s destination=%s",
+                   dbus_message_get_path (message),
+                   dbus_message_get_interface (message),
+                   dbus_message_get_member (message),
+                   dbus_message_get_destination (message));
+#endif
+
+        g_return_val_if_fail (connection != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
+        g_return_val_if_fail (message != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
+
+
+        return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult
+client_dbus_filter_function (DBusConnection *connection,
+                             DBusMessage    *message,
+                             void           *user_data)
+{
+        GdmChooserClient *client = GDM_CHOOSER_CLIENT (user_data);
+        const char       *path;
+
+        path = dbus_message_get_path (message);
+
+        g_debug ("GdmChooserClient: obj_path=%s interface=%s method=%s",
+                 dbus_message_get_path (message),
+                 dbus_message_get_interface (message),
+                 dbus_message_get_member (message));
+
+        if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected")
+            && strcmp (path, DBUS_PATH_LOCAL) == 0) {
+
+                g_message ("Got disconnected from the session message bus");
+
+                dbus_connection_unref (connection);
+                client->priv->connection = NULL;
+
+        } else if (dbus_message_is_signal (message,
+                                           DBUS_INTERFACE_DBUS,
+                                           "NameOwnerChanged")) {
+                g_debug ("GdmChooserClient: Name owner changed?");
+        } else {
+                return client_dbus_handle_message (connection, message, user_data, FALSE);
+        }
+
+        return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+gboolean
+gdm_chooser_client_start (GdmChooserClient *client,
+                          GError          **error)
+{
+        gboolean  ret;
+        DBusError local_error;
+
+        g_return_val_if_fail (GDM_IS_CHOOSER_CLIENT (client), FALSE);
+
+        ret = FALSE;
+
+        if (client->priv->address == NULL) {
+                g_warning ("GDM_CHOOSER_DBUS_ADDRESS not set");
+                g_set_error (error,
+                             GDM_CHOOSER_CLIENT_ERROR,
+                             GDM_CHOOSER_CLIENT_ERROR_GENERIC,
+                             "GDM_CHOOSER_DBUS_ADDRESS not set");
+                goto out;
+        }
+
+        g_debug ("GdmChooserClient: connecting to address: %s", client->priv->address);
+
+        dbus_error_init (&local_error);
+        client->priv->connection = dbus_connection_open (client->priv->address, &local_error);
+        if (client->priv->connection == NULL) {
+                if (dbus_error_is_set (&local_error)) {
+                        g_warning ("error opening connection: %s", local_error.message);
+                        g_set_error (error,
+                                     GDM_CHOOSER_CLIENT_ERROR,
+                                     GDM_CHOOSER_CLIENT_ERROR_GENERIC,
+                                     local_error.message);
+                        dbus_error_free (&local_error);
+                } else {
+                        g_warning ("Unable to open connection");
+                }
+                goto out;
+        }
+
+        dbus_connection_setup_with_g_main (client->priv->connection, NULL);
+        dbus_connection_set_exit_on_disconnect (client->priv->connection, TRUE);
+
+        dbus_connection_add_filter (client->priv->connection,
+                                    client_dbus_filter_function,
+                                    client,
+                                    NULL);
+
+        ret = TRUE;
+
+ out:
+        return ret;
+}
+
+void
+gdm_chooser_client_stop (GdmChooserClient *client)
+{
+        g_return_if_fail (GDM_IS_CHOOSER_CLIENT (client));
+
+}
+
+static void
+gdm_chooser_client_set_property (GObject        *object,
+                                 guint           prop_id,
+                                 const GValue   *value,
+                                 GParamSpec     *pspec)
+{
+        GdmChooserClient *self;
+
+        self = GDM_CHOOSER_CLIENT (object);
+
+        switch (prop_id) {
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+        }
+}
+
+static void
+gdm_chooser_client_get_property (GObject        *object,
+                                 guint           prop_id,
+                                 GValue         *value,
+                                 GParamSpec     *pspec)
+{
+        GdmChooserClient *self;
+
+        self = GDM_CHOOSER_CLIENT (object);
+
+        switch (prop_id) {
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+        }
+}
+
+static GObject *
+gdm_chooser_client_constructor (GType                  type,
+                                 guint                  n_construct_properties,
+                                 GObjectConstructParam *construct_properties)
+{
+        GdmChooserClient      *chooser_client;
+        GdmChooserClientClass *klass;
+
+        klass = GDM_CHOOSER_CLIENT_CLASS (g_type_class_peek (GDM_TYPE_CHOOSER_CLIENT));
+
+        chooser_client = GDM_CHOOSER_CLIENT (G_OBJECT_CLASS (gdm_chooser_client_parent_class)->constructor (type,
+                                                                                                            n_construct_properties,
+                                                                                                            construct_properties));
+
+        return G_OBJECT (chooser_client);
+}
+
+static void
+gdm_chooser_client_dispose (GObject *object)
+{
+        GdmChooserClient *chooser_client;
+
+        chooser_client = GDM_CHOOSER_CLIENT (object);
+
+        g_debug ("GdmChooserClient: Disposing chooser_client");
+
+        G_OBJECT_CLASS (gdm_chooser_client_parent_class)->dispose (object);
+}
+
+static void
+gdm_chooser_client_class_init (GdmChooserClientClass *klass)
+{
+        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
+
+        object_class->get_property = gdm_chooser_client_get_property;
+        object_class->set_property = gdm_chooser_client_set_property;
+        object_class->constructor = gdm_chooser_client_constructor;
+        object_class->dispose = gdm_chooser_client_dispose;
+        object_class->finalize = gdm_chooser_client_finalize;
+
+        g_type_class_add_private (klass, sizeof (GdmChooserClientPrivate));
+}
+
+static void
+gdm_chooser_client_init (GdmChooserClient *client)
+{
+
+        client->priv = GDM_CHOOSER_CLIENT_GET_PRIVATE (client);
+
+        client->priv->address = g_strdup (g_getenv ("GDM_CHOOSER_DBUS_ADDRESS"));
+}
+
+static void
+gdm_chooser_client_finalize (GObject *object)
+{
+        GdmChooserClient *client;
+
+        g_return_if_fail (object != NULL);
+        g_return_if_fail (GDM_IS_CHOOSER_CLIENT (object));
+
+        client = GDM_CHOOSER_CLIENT (object);
+
+        g_return_if_fail (client->priv != NULL);
+
+        g_free (client->priv->address);
+
+        G_OBJECT_CLASS (gdm_chooser_client_parent_class)->finalize (object);
+}
+
+GdmChooserClient *
+gdm_chooser_client_new (void)
+{
+        if (client_object != NULL) {
+                g_object_ref (client_object);
+        } else {
+                client_object = g_object_new (GDM_TYPE_CHOOSER_CLIENT, NULL);
+                g_object_add_weak_pointer (client_object,
+                                           (gpointer *) &client_object);
+        }
+
+        return GDM_CHOOSER_CLIENT (client_object);
+}

Added: trunk/gui/simple-chooser/gdm-chooser-client.h
==============================================================================
--- (empty file)
+++ trunk/gui/simple-chooser/gdm-chooser-client.h	Thu Jan 31 00:51:46 2008
@@ -0,0 +1,69 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann jhu edu>
+ *
+ * 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_CHOOSER_CLIENT_H
+#define __GDM_CHOOSER_CLIENT_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_CHOOSER_CLIENT         (gdm_chooser_client_get_type ())
+#define GDM_CHOOSER_CLIENT(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_CHOOSER_CLIENT, GdmChooserClient))
+#define GDM_CHOOSER_CLIENT_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_CHOOSER_CLIENT, GdmChooserClientClass))
+#define GDM_IS_CHOOSER_CLIENT(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_CHOOSER_CLIENT))
+#define GDM_IS_CHOOSER_CLIENT_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_CHOOSER_CLIENT))
+#define GDM_CHOOSER_CLIENT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_CHOOSER_CLIENT, GdmChooserClientClass))
+
+typedef struct GdmChooserClientPrivate GdmChooserClientPrivate;
+
+typedef struct
+{
+        GObject                  parent;
+        GdmChooserClientPrivate *priv;
+} GdmChooserClient;
+
+typedef struct
+{
+        GObjectClass   parent_class;
+} GdmChooserClientClass;
+
+#define GDM_CHOOSER_CLIENT_ERROR (gdm_chooser_client_error_quark ())
+
+typedef enum _GdmChooserClientError {
+        GDM_CHOOSER_CLIENT_ERROR_GENERIC = 0,
+} GdmChooserClientError;
+
+GType              gdm_chooser_client_get_type                       (void);
+GQuark             gdm_chooser_client_error_quark                    (void);
+
+GdmChooserClient * gdm_chooser_client_new                            (void);
+
+gboolean           gdm_chooser_client_start                          (GdmChooserClient *client,
+                                                                         GError          **error);
+void               gdm_chooser_client_stop                           (GdmChooserClient *client);
+
+void               gdm_chooser_client_call_disconnect                (GdmChooserClient *client);
+void               gdm_chooser_client_call_select_hostname           (GdmChooserClient *client,
+                                                                      const char       *text);
+
+G_END_DECLS
+
+#endif /* __GDM_CHOOSER_CLIENT_H */

Added: trunk/gui/simple-chooser/gdm-chooser-session.c
==============================================================================
--- (empty file)
+++ trunk/gui/simple-chooser/gdm-chooser-session.c	Thu Jan 31 00:51:46 2008
@@ -0,0 +1,318 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann jhu edu>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+
+#include "gdm-chooser-session.h"
+#include "gdm-chooser-client.h"
+
+#include "gdm-host-chooser-dialog.h"
+
+#define GDM_CHOOSER_SESSION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_CHOOSER_SESSION, GdmChooserSessionPrivate))
+
+struct GdmChooserSessionPrivate
+{
+        GdmChooserClient      *client;
+        GtkWidget             *chooser_dialog;
+};
+
+enum {
+        PROP_0,
+};
+
+static void     gdm_chooser_session_class_init  (GdmChooserSessionClass *klass);
+static void     gdm_chooser_session_init        (GdmChooserSession      *chooser_session);
+static void     gdm_chooser_session_finalize    (GObject                *object);
+
+G_DEFINE_TYPE (GdmChooserSession, gdm_chooser_session, G_TYPE_OBJECT)
+
+static gpointer session_object = NULL;
+
+static gboolean
+launch_compiz (GdmChooserSession *session)
+{
+        GError  *error;
+        gboolean ret;
+
+        g_debug ("GdmChooserSession: Launching compiz");
+
+        ret = FALSE;
+
+        error = NULL;
+        g_spawn_command_line_async ("gtk-window-decorator --replace", &error);
+        if (error != NULL) {
+                g_warning ("Error starting WM: %s", error->message);
+                g_error_free (error);
+                goto out;
+        }
+
+        error = NULL;
+        g_spawn_command_line_async ("compiz --replace", &error);
+        if (error != NULL) {
+                g_warning ("Error starting WM: %s", error->message);
+                g_error_free (error);
+                goto out;
+        }
+
+        ret = TRUE;
+
+        /* FIXME: should try to detect if it actually works */
+
+ out:
+        return ret;
+}
+
+static gboolean
+launch_metacity (GdmChooserSession *session)
+{
+        GError  *error;
+        gboolean ret;
+
+        g_debug ("GdmChooserSession: Launching metacity");
+
+        ret = FALSE;
+
+        error = NULL;
+        g_spawn_command_line_async ("metacity --replace", &error);
+        if (error != NULL) {
+                g_warning ("Error starting WM: %s", error->message);
+                g_error_free (error);
+                goto out;
+        }
+
+        ret = TRUE;
+
+ out:
+        return ret;
+}
+
+static void
+start_window_manager (GdmChooserSession *session)
+{
+        if (! launch_metacity (session)) {
+                launch_compiz (session);
+        }
+}
+
+static gboolean
+start_settings_daemon (GdmChooserSession *session)
+{
+        GError  *error;
+        gboolean ret;
+
+        g_debug ("GdmChooserSession: Launching settings daemon");
+
+        ret = FALSE;
+
+        error = NULL;
+        g_spawn_command_line_async (LIBEXECDIR "/gnome-settings-daemon --gconf-prefix=/apps/gdm/simple-chooser/settings-manager-plugins", &error);
+        if (error != NULL) {
+                g_warning ("Error starting settings daemon: %s", error->message);
+                g_error_free (error);
+                goto out;
+        }
+
+        ret = TRUE;
+
+ out:
+        return ret;
+}
+
+static void
+on_dialog_response (GtkDialog         *dialog,
+                    int                response_id,
+                    GdmChooserSession *session)
+{
+        char *hostname;
+
+        hostname = NULL;
+        switch (response_id) {
+        case GTK_RESPONSE_OK:
+                hostname = gdm_host_chooser_dialog_get_current_hostname (GDM_HOST_CHOOSER_DIALOG (dialog));
+        case GTK_RESPONSE_NONE:
+                /* delete event */
+        default:
+                break;
+        }
+
+        if (hostname != NULL) {
+                g_debug ("GdmChooserSession: Selected hostname '%s'", hostname);
+                gdm_chooser_client_call_select_hostname (session->priv->client, hostname);
+                g_free (hostname);
+        }
+
+        gdm_chooser_client_call_disconnect (session->priv->client);
+}
+
+gboolean
+gdm_chooser_session_start (GdmChooserSession *session,
+                           GError           **error)
+{
+        gboolean res;
+
+        g_return_val_if_fail (GDM_IS_CHOOSER_SESSION (session), FALSE);
+
+        res = gdm_chooser_client_start (session->priv->client, error);
+
+        if (res) {
+                start_settings_daemon (session);
+                start_window_manager (session);
+
+                session->priv->chooser_dialog = gdm_host_chooser_dialog_new ();
+                g_signal_connect (session->priv->chooser_dialog,
+                                  "response",
+                                  G_CALLBACK (on_dialog_response),
+                                  session);
+                gtk_widget_show (session->priv->chooser_dialog);
+        }
+
+        return res;
+}
+
+void
+gdm_chooser_session_stop (GdmChooserSession *session)
+{
+        g_return_if_fail (GDM_IS_CHOOSER_SESSION (session));
+
+}
+
+static void
+gdm_chooser_session_set_property (GObject        *object,
+                                  guint           prop_id,
+                                  const GValue   *value,
+                                  GParamSpec     *pspec)
+{
+        GdmChooserSession *self;
+
+        self = GDM_CHOOSER_SESSION (object);
+
+        switch (prop_id) {
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+        }
+}
+
+static void
+gdm_chooser_session_get_property (GObject        *object,
+                                  guint           prop_id,
+                                  GValue         *value,
+                                  GParamSpec     *pspec)
+{
+        GdmChooserSession *self;
+
+        self = GDM_CHOOSER_SESSION (object);
+
+        switch (prop_id) {
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+        }
+}
+
+static GObject *
+gdm_chooser_session_constructor (GType                  type,
+                                 guint                  n_construct_properties,
+                                 GObjectConstructParam *construct_properties)
+{
+        GdmChooserSession      *chooser_session;
+        GdmChooserSessionClass *klass;
+
+        klass = GDM_CHOOSER_SESSION_CLASS (g_type_class_peek (GDM_TYPE_CHOOSER_SESSION));
+
+        chooser_session = GDM_CHOOSER_SESSION (G_OBJECT_CLASS (gdm_chooser_session_parent_class)->constructor (type,
+                                                                                                               n_construct_properties,
+                                                                                                               construct_properties));
+
+        return G_OBJECT (chooser_session);
+}
+
+static void
+gdm_chooser_session_dispose (GObject *object)
+{
+        GdmChooserSession *chooser_session;
+
+        chooser_session = GDM_CHOOSER_SESSION (object);
+
+        g_debug ("GdmChooserSession: Disposing chooser_session");
+
+        G_OBJECT_CLASS (gdm_chooser_session_parent_class)->dispose (object);
+}
+
+static void
+gdm_chooser_session_class_init (GdmChooserSessionClass *klass)
+{
+        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
+
+        object_class->get_property = gdm_chooser_session_get_property;
+        object_class->set_property = gdm_chooser_session_set_property;
+        object_class->constructor = gdm_chooser_session_constructor;
+        object_class->dispose = gdm_chooser_session_dispose;
+        object_class->finalize = gdm_chooser_session_finalize;
+
+        g_type_class_add_private (klass, sizeof (GdmChooserSessionPrivate));
+}
+
+static void
+gdm_chooser_session_init (GdmChooserSession *session)
+{
+
+        session->priv = GDM_CHOOSER_SESSION_GET_PRIVATE (session);
+
+        session->priv->client = gdm_chooser_client_new ();
+}
+
+static void
+gdm_chooser_session_finalize (GObject *object)
+{
+        GdmChooserSession *chooser_session;
+
+        g_return_if_fail (object != NULL);
+        g_return_if_fail (GDM_IS_CHOOSER_SESSION (object));
+
+        chooser_session = GDM_CHOOSER_SESSION (object);
+
+        g_return_if_fail (chooser_session->priv != NULL);
+
+        G_OBJECT_CLASS (gdm_chooser_session_parent_class)->finalize (object);
+}
+
+GdmChooserSession *
+gdm_chooser_session_new (void)
+{
+        if (session_object != NULL) {
+                g_object_ref (session_object);
+        } else {
+                session_object = g_object_new (GDM_TYPE_CHOOSER_SESSION, NULL);
+                g_object_add_weak_pointer (session_object,
+                                           (gpointer *) &session_object);
+        }
+
+        return GDM_CHOOSER_SESSION (session_object);
+}

Added: trunk/gui/simple-chooser/gdm-chooser-session.h
==============================================================================
--- (empty file)
+++ trunk/gui/simple-chooser/gdm-chooser-session.h	Thu Jan 31 00:51:46 2008
@@ -0,0 +1,58 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann jhu edu>
+ *
+ * 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_CHOOSER_SESSION_H
+#define __GDM_CHOOSER_SESSION_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_CHOOSER_SESSION         (gdm_chooser_session_get_type ())
+#define GDM_CHOOSER_SESSION(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_CHOOSER_SESSION, GdmChooserSession))
+#define GDM_CHOOSER_SESSION_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_CHOOSER_SESSION, GdmChooserSessionClass))
+#define GDM_IS_CHOOSER_SESSION(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_CHOOSER_SESSION))
+#define GDM_IS_CHOOSER_SESSION_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_CHOOSER_SESSION))
+#define GDM_CHOOSER_SESSION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_CHOOSER_SESSION, GdmChooserSessionClass))
+
+typedef struct GdmChooserSessionPrivate GdmChooserSessionPrivate;
+
+typedef struct
+{
+        GObject                   parent;
+        GdmChooserSessionPrivate *priv;
+} GdmChooserSession;
+
+typedef struct
+{
+        GObjectClass   parent_class;
+} GdmChooserSessionClass;
+
+GType                  gdm_chooser_session_get_type                       (void);
+
+GdmChooserSession    * gdm_chooser_session_new                            (void);
+
+gboolean               gdm_chooser_session_start                          (GdmChooserSession *session,
+                                                                           GError           **error);
+void                   gdm_chooser_session_stop                           (GdmChooserSession *session);
+
+G_END_DECLS
+
+#endif /* __GDM_CHOOSER_SESSION_H */

Added: trunk/gui/simple-chooser/test-host-chooser.c
==============================================================================
--- (empty file)
+++ trunk/gui/simple-chooser/test-host-chooser.c	Thu Jan 31 00:51:46 2008
@@ -0,0 +1,263 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann jhu edu>
+ *
+ * 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 <stdlib.h>
+#include <libintl.h>
+#include <locale.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+
+#include <glib/gi18n.h>
+#include <gdk/gdkx.h>
+#include <gtk/gtk.h>
+#include <gconf/gconf-client.h>
+
+#include "gdm-common.h"
+#include "gdm-log.h"
+#include "gdm-settings-client.h"
+#include "gdm-settings-keys.h"
+
+#include "gdm-host-chooser-dialog.h"
+
+#define ACCESSIBILITY_KEY         "/desktop/gnome/interface/accessibility"
+
+static Atom AT_SPI_IOR;
+
+
+static gboolean
+assistive_registry_launch (void)
+{
+        GPid        pid;
+        GError     *error;
+        const char *command;
+        char      **argv;
+        gboolean    res;
+
+        command = AT_SPI_REGISTRYD_DIR "/at-spi-registryd";
+
+        argv = NULL;
+        error = NULL;
+        res = g_shell_parse_argv (command, NULL, &argv, &error);
+        if (! res) {
+                g_warning ("Unable to parse command: %s", error->message);
+                return FALSE;
+        }
+
+        error = NULL;
+        res = g_spawn_async (NULL,
+                             argv,
+                             NULL,
+                             G_SPAWN_SEARCH_PATH
+                             | G_SPAWN_STDOUT_TO_DEV_NULL
+                             | G_SPAWN_STDERR_TO_DEV_NULL,
+                             NULL,
+                             NULL,
+                             &pid,
+                             &error);
+        g_strfreev (argv);
+
+        if (! res) {
+                g_warning ("Unable to run command %s: %s", command, error->message);
+                return FALSE;
+        }
+
+        if (kill (pid, 0) < 0) {
+                g_warning ("at-spi-registryd not running");
+                return FALSE;
+        }
+
+        return TRUE;
+}
+
+static GdkFilterReturn
+filter_watch (GdkXEvent *xevent,
+              GdkEvent  *event,
+              gpointer   data)
+{
+        XEvent *xev = (XEvent *)xevent;
+
+        if (xev->xany.type == PropertyNotify
+            && xev->xproperty.atom == AT_SPI_IOR) {
+                gtk_main_quit ();
+
+                return GDK_FILTER_REMOVE;
+        }
+
+        return GDK_FILTER_CONTINUE;
+}
+
+static gboolean
+filter_timeout (gpointer data)
+{
+        g_warning ("The accessibility registry was not found.");
+
+        gtk_main_quit ();
+
+        return FALSE;
+}
+
+static void
+assistive_registry_start (void)
+{
+        GdkWindow *root;
+        guint      tid;
+
+        root = gdk_get_default_root_window ();
+
+        if ( ! AT_SPI_IOR) {
+                AT_SPI_IOR = XInternAtom (GDK_DISPLAY (), "AT_SPI_IOR", False);
+        }
+
+        gdk_window_set_events (root,  GDK_PROPERTY_CHANGE_MASK);
+
+        if ( ! assistive_registry_launch ()) {
+                g_warning ("The accessibility registry could not be started.");
+                return;
+        }
+
+        gdk_window_add_filter (root, filter_watch, NULL);
+        tid = g_timeout_add_seconds (5, filter_timeout, NULL);
+
+        gtk_main ();
+
+        gdk_window_remove_filter (root, filter_watch, NULL);
+        g_source_remove (tid);
+}
+
+static void
+at_set_gtk_modules (void)
+{
+        GSList     *modules_list;
+        GSList     *l;
+        const char *old;
+        char      **modules;
+        gboolean    found_gail;
+        gboolean    found_atk_bridge;
+        int         n;
+
+        n = 0;
+        modules_list = NULL;
+        found_gail = FALSE;
+        found_atk_bridge = FALSE;
+
+        if ((old = g_getenv ("GTK_MODULES")) != NULL) {
+                modules = g_strsplit (old, ":", -1);
+                for (n = 0; modules[n]; n++) {
+                        if (!strcmp (modules[n], "gail")) {
+                                found_gail = TRUE;
+                        } else if (!strcmp (modules[n], "atk-bridge")) {
+                                found_atk_bridge = TRUE;
+                        }
+
+                        modules_list = g_slist_prepend (modules_list, modules[n]);
+                        modules[n] = NULL;
+                }
+                g_free (modules);
+        }
+
+        if (!found_gail) {
+                modules_list = g_slist_prepend (modules_list, "gail");
+                ++n;
+        }
+
+        if (!found_atk_bridge) {
+                modules_list = g_slist_prepend (modules_list, "atk-bridge");
+                ++n;
+        }
+
+        modules = g_new (char *, n + 1);
+        modules[n--] = NULL;
+        for (l = modules_list; l; l = l->next) {
+                modules[n--] = g_strdup (l->data);
+        }
+
+        g_setenv ("GTK_MODULES", g_strjoinv (":", modules), TRUE);
+        g_strfreev (modules);
+        g_slist_free (modules_list);
+}
+
+static void
+load_a11y (void)
+{
+        const char        *env_a_t_support;
+        gboolean           a_t_support;
+        GConfClient       *gconf_client;
+
+        gconf_client = gconf_client_get_default ();
+
+        env_a_t_support = g_getenv ("GNOME_ACCESSIBILITY");
+        if (env_a_t_support) {
+                a_t_support = atoi (env_a_t_support);
+        } else {
+                a_t_support = gconf_client_get_bool (gconf_client, ACCESSIBILITY_KEY, NULL);
+        }
+
+        if (a_t_support) {
+                assistive_registry_start ();
+                at_set_gtk_modules ();
+        }
+
+        g_object_unref (gconf_client);
+}
+
+int
+main (int argc, char *argv[])
+{
+        GtkWidget        *chooser;
+
+        bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
+        bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+        textdomain (GETTEXT_PACKAGE);
+
+        setlocale (LC_ALL, "");
+
+        gdm_set_fatal_warnings_if_unstable ();
+
+        g_type_init ();
+
+        gdm_log_init ();
+        gdm_log_set_debug (TRUE);
+
+        g_debug ("Chooser for display %s xauthority:%s",
+                 g_getenv ("DISPLAY"),
+                 g_getenv ("XAUTHORITY"));
+
+        gdk_init (&argc, &argv);
+
+        load_a11y ();
+
+        gtk_init (&argc, &argv);
+
+        chooser = gdm_host_chooser_dialog_new ();
+        if (gtk_dialog_run (GTK_DIALOG (chooser)) == GTK_RESPONSE_OK) {
+                char *hostname;
+
+                hostname = gdm_host_chooser_dialog_get_current_hostname (GDM_HOST_CHOOSER_DIALOG (chooser));
+                g_print ("hostname: %s\n", hostname);
+                g_free (hostname);
+        }
+
+        gtk_widget_destroy (chooser);
+
+        return 0;
+}

Modified: trunk/gui/simple-greeter/greeter-main.c
==============================================================================
--- trunk/gui/simple-greeter/greeter-main.c	(original)
+++ trunk/gui/simple-greeter/greeter-main.c	Thu Jan 31 00:51:46 2008
@@ -194,15 +194,36 @@
         g_slist_free (modules_list);
 }
 
+static void
+load_a11y (void)
+{
+        const char        *env_a_t_support;
+        gboolean           a_t_support;
+        GConfClient       *gconf_client;
+
+        gconf_client = gconf_client_get_default ();
+
+        env_a_t_support = g_getenv ("GNOME_ACCESSIBILITY");
+        if (env_a_t_support) {
+                a_t_support = atoi (env_a_t_support);
+        } else {
+                a_t_support = gconf_client_get_bool (gconf_client, ACCESSIBILITY_KEY, NULL);
+        }
+
+        if (a_t_support) {
+                assistive_registry_start ();
+                at_set_gtk_modules ();
+        }
+
+        g_object_unref (gconf_client);
+}
+
 int
 main (int argc, char *argv[])
 {
         GError            *error;
         GdmGreeterSession *session;
         gboolean           res;
-        const char        *env_a_t_support;
-        gboolean           a_t_support;
-        GConfClient       *gconf_client;
 
         bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
         bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
@@ -231,19 +252,7 @@
 
         gdk_init (&argc, &argv);
 
-        gconf_client = gconf_client_get_default ();
-
-        env_a_t_support = g_getenv ("GNOME_ACCESSIBILITY");
-        if (env_a_t_support) {
-                a_t_support = atoi (env_a_t_support);
-        } else {
-                a_t_support = gconf_client_get_bool (gconf_client, ACCESSIBILITY_KEY, NULL);
-        }
-
-        if (a_t_support) {
-                assistive_registry_start ();
-                at_set_gtk_modules ();
-        }
+        load_a11y ();
 
         gtk_init (&argc, &argv);
 
@@ -253,6 +262,7 @@
                 exit (1);
         }
 
+        error = NULL;
         res = gdm_greeter_session_start (session, &error);
         if (! res) {
                 g_warning ("Unable to start greeter session: %s", error->message);

Modified: trunk/po/POTFILES.in
==============================================================================
--- trunk/po/POTFILES.in	(original)
+++ trunk/po/POTFILES.in	Thu Jan 31 00:51:46 2008
@@ -15,6 +15,7 @@
 common/test-settings-client.c
 common/test-settings-server.c
 daemon/factory-slave-main.c
+daemon/gdm-chooser-session.c
 daemon/gdm-display.c
 daemon/gdm-display-access-file.c
 daemon/gdm-display-store.c
@@ -43,6 +44,7 @@
 daemon/session-worker-main.c
 daemon/simple-slave-main.c
 daemon/test-session.c
+daemon/xdmcp-chooser-slave-main.c
 data/gdm.schemas.in.in
 gui/simple-chooser/gdm-host-chooser-widget.c
 gui/simple-greeter/gdm-chooser-widget.c



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