gdm r5639 - in trunk: . daemon



Author: mccann
Date: Mon Jan 28 21:28:43 2008
New Revision: 5639
URL: http://svn.gnome.org/viewvc/gdm?rev=5639&view=rev

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

	* daemon/gdm-display.c: (gdm_display_get_seat_id),
	(gdm_display_class_init):
	* daemon/gdm-display.h:
	* daemon/gdm-display.xml:
	* daemon/gdm-local-display-factory.c:
	(gdm_local_display_factory_create_transient_display),
	(gdm_local_display_factory_create_product_display),
	(create_display):
	* daemon/gdm-simple-slave.c: (on_session_authorized),
	(try_migrate_session), (start_session_timeout),
	(queue_start_session), (on_session_accredited),
	(on_session_accreditation_failed):
	* daemon/gdm-slave.c: (gdm_slave_real_start),
	(_get_uid_and_gid_for_user), (x11_session_is_on_seat),
	(_get_primary_user_session_id), (activate_session_id),
	(gdm_slave_switch_to_user_session),
	(_gdm_slave_set_display_seat_id), (gdm_slave_set_property),
	(gdm_slave_get_property), (gdm_slave_class_init):
	* daemon/gdm-slave.h:
	Initial session migration support.  We still need to
	make the slave die after if it is a transient display.



Modified:
   trunk/ChangeLog
   trunk/daemon/gdm-display.c
   trunk/daemon/gdm-display.h
   trunk/daemon/gdm-display.xml
   trunk/daemon/gdm-local-display-factory.c
   trunk/daemon/gdm-simple-slave.c
   trunk/daemon/gdm-slave.c
   trunk/daemon/gdm-slave.h

Modified: trunk/daemon/gdm-display.c
==============================================================================
--- trunk/daemon/gdm-display.c	(original)
+++ trunk/daemon/gdm-display.c	Mon Jan 28 21:28:43 2008
@@ -355,6 +355,20 @@
        return TRUE;
 }
 
+gboolean
+gdm_display_get_seat_id (GdmDisplay *display,
+                         char      **seat_id,
+                         GError    **error)
+{
+       g_return_val_if_fail (GDM_IS_DISPLAY (display), FALSE);
+
+       if (seat_id != NULL) {
+               *seat_id = g_strdup (display->priv->seat_id);
+       }
+
+       return TRUE;
+}
+
 static gboolean
 finish_idle (GdmDisplay *display)
 {
@@ -800,13 +814,6 @@
                                                               NULL,
                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
         g_object_class_install_property (object_class,
-                                         PROP_SEAT_ID,
-                                         g_param_spec_string ("seat-id",
-                                                              "seat id",
-                                                              "seat id",
-                                                              NULL,
-                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-        g_object_class_install_property (object_class,
                                          PROP_REMOTE_HOSTNAME,
                                          g_param_spec_string ("remote-hostname",
                                                               "remote-hostname",
@@ -830,6 +837,13 @@
                                                               NULL,
                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
         g_object_class_install_property (object_class,
+                                         PROP_SEAT_ID,
+                                         g_param_spec_string ("seat-id",
+                                                              "seat id",
+                                                              "seat id",
+                                                              NULL,
+                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+        g_object_class_install_property (object_class,
                                          PROP_X11_COOKIE,
                                          g_param_spec_string ("x11-cookie",
                                                               "cookie",

Modified: trunk/daemon/gdm-display.h
==============================================================================
--- trunk/daemon/gdm-display.h	(original)
+++ trunk/daemon/gdm-display.h	Mon Jan 28 21:28:43 2008
@@ -101,6 +101,9 @@
 gboolean            gdm_display_get_x11_display_name           (GdmDisplay *display,
                                                                 char      **x11_display,
                                                                 GError    **error);
+gboolean            gdm_display_get_seat_id                    (GdmDisplay *display,
+                                                                char      **seat_id,
+                                                                GError    **error);
 gboolean            gdm_display_is_local                       (GdmDisplay *display,
                                                                 gboolean   *local,
                                                                 GError    **error);

Modified: trunk/daemon/gdm-display.xml
==============================================================================
--- trunk/daemon/gdm-display.xml	(original)
+++ trunk/daemon/gdm-display.xml	Mon Jan 28 21:28:43 2008
@@ -16,6 +16,9 @@
     <method name="GetX11AuthorityFile">
       <arg name="filename" direction="out" type="s"/>
     </method>
+    <method name="GetSeatId">
+      <arg name="filename" direction="out" type="s"/>
+    </method>
     <method name="GetRemoteHostname">
       <arg name="hostname" direction="out" type="s"/>
     </method>

Modified: trunk/daemon/gdm-local-display-factory.c
==============================================================================
--- trunk/daemon/gdm-local-display-factory.c	(original)
+++ trunk/daemon/gdm-local-display-factory.c	Mon Jan 28 21:28:43 2008
@@ -39,6 +39,8 @@
 
 #define GDM_LOCAL_DISPLAY_FACTORY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_LOCAL_DISPLAY_FACTORY, GdmLocalDisplayFactoryPrivate))
 
+#define CK_SEAT1_PATH                       "/org/freedesktop/ConsoleKit/Seat1"
+
 #define GDM_DBUS_PATH                       "/org/gnome/DisplayManager"
 #define GDM_LOCAL_DISPLAY_FACTORY_DBUS_PATH GDM_DBUS_PATH "/LocalDisplayFactory"
 #define GDM_MANAGER_DBUS_NAME               "org.gnome.DisplayManager.LocalDisplayFactory"
@@ -209,7 +211,7 @@
         }
 
         /* FIXME: don't hardcode seat1? */
-        g_object_set (display, "seat-id", "org.freedesktop.ConsoleKit.Seat1", NULL);
+        g_object_set (display, "seat-id", CK_SEAT1_PATH, NULL);
 
         store_display (factory, num, display);
 
@@ -261,7 +263,7 @@
         }
 
         /* FIXME: don't hardcode seat1? */
-        g_object_set (display, "seat-id", "org.freedesktop.ConsoleKit.Seat1", NULL);
+        g_object_set (display, "seat-id", CK_SEAT1_PATH, NULL);
 
         store_display (factory, num, display);
 
@@ -309,7 +311,7 @@
         }
 
         /* FIXME: don't hardcode seat1? */
-        g_object_set (display, "seat-id", "org.freedesktop.ConsoleKit.Seat1", NULL);
+        g_object_set (display, "seat-id", CK_SEAT1_PATH, NULL);
 
         store_display (factory, num, display);
 

Modified: trunk/daemon/gdm-simple-slave.c
==============================================================================
--- trunk/daemon/gdm-simple-slave.c	(original)
+++ trunk/daemon/gdm-simple-slave.c	Mon Jan 28 21:28:43 2008
@@ -66,6 +66,7 @@
         guint              error_watch_id;
 
         guint              greeter_reset_id;
+        guint              start_session_id;
 
         int                ping_interval;
 
@@ -76,7 +77,6 @@
         GdmGreeterServer  *greeter_server;
         GdmGreeterSession *greeter;
         GdmSessionDirect  *session;
-        DBusGConnection   *connection;
 };
 
 enum {
@@ -209,7 +209,6 @@
 {
         int flag;
 
-        /* FIXME: check for migration? */
         flag = GDM_SESSION_CRED_ESTABLISH;
 
         gdm_session_accredit (session, flag);
@@ -225,11 +224,39 @@
         queue_greeter_reset (slave);
 }
 
-static void
-on_session_accredited (GdmSession     *session,
-                       GdmSimpleSlave *slave)
+static gboolean
+try_migrate_session (GdmSimpleSlave *slave)
+{
+        char    *username;
+        gboolean res;
+
+        g_debug ("GdmSimpleSlave: trying to migrate session");
+
+        username = gdm_session_direct_get_username (slave->priv->session);
+
+        /* try to switch to an existing session */
+        res = gdm_slave_switch_to_user_session (GDM_SLAVE (slave), username);
+        g_free (username);
+
+        return res;
+}
+
+
+static gboolean
+start_session_timeout (GdmSimpleSlave *slave)
 {
-        char *auth_file;
+
+        char    *auth_file;
+        gboolean migrated;
+
+        g_debug ("GdmSimpleSlave: accredited");
+
+        migrated = try_migrate_session (slave);
+        g_debug ("GdmSimpleSlave: migrated: %d", migrated);
+        if (migrated) {
+                queue_greeter_reset (slave);
+                goto out;
+        }
 
         gdm_greeter_session_stop (slave->priv->greeter);
         gdm_greeter_server_stop (slave->priv->greeter_server);
@@ -239,13 +266,33 @@
 
         g_assert (auth_file != NULL);
 
-        g_object_set (session,
+        g_object_set (slave->priv->session,
                       "user-x11-authority-file", auth_file,
                       NULL);
 
         g_free (auth_file);
 
-        gdm_session_start_session (session);
+        gdm_session_start_session (GDM_SESSION (slave->priv->session));
+ out:
+        slave->priv->start_session_id = 0;
+        return FALSE;
+}
+
+static void
+queue_start_session (GdmSimpleSlave *slave)
+{
+        if (slave->priv->start_session_id > 0) {
+                return;
+        }
+
+        slave->priv->start_session_id = g_idle_add ((GSourceFunc)start_session_timeout, slave);
+}
+
+static void
+on_session_accredited (GdmSession     *session,
+                       GdmSimpleSlave *slave)
+{
+        queue_start_session (slave);
 }
 
 static void
@@ -253,7 +300,17 @@
                                  const char     *message,
                                  GdmSimpleSlave *slave)
 {
-        gdm_greeter_server_problem (slave->priv->greeter_server, _("Unable establish credentials"));
+        gboolean migrated;
+
+        g_debug ("GdmSimpleSlave: accreditation failed");
+
+        migrated = try_migrate_session (slave);
+
+        /* If we switched to another session we don't care if
+           accreditation fails */
+        if (! migrated) {
+                gdm_greeter_server_problem (slave->priv->greeter_server, _("Unable establish credentials"));
+        }
 
         queue_greeter_reset (slave);
 }

Modified: trunk/daemon/gdm-slave.c
==============================================================================
--- trunk/daemon/gdm-slave.c	(original)
+++ trunk/daemon/gdm-slave.c	Mon Jan 28 21:28:43 2008
@@ -53,6 +53,15 @@
 
 #define GDM_SLAVE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_SLAVE, GdmSlavePrivate))
 
+#define CK_NAME      "org.freedesktop.ConsoleKit"
+#define CK_PATH      "/org/freedesktop/ConsoleKit"
+#define CK_INTERFACE "org.freedesktop.ConsoleKit"
+
+#define CK_MANAGER_PATH      "/org/freedesktop/ConsoleKit/Manager"
+#define CK_MANAGER_INTERFACE "org.freedesktop.ConsoleKit.Manager"
+#define CK_SEAT_INTERFACE    "org.freedesktop.ConsoleKit.Seat"
+#define CK_SESSION_INTERFACE "org.freedesktop.ConsoleKit.Session"
+
 #define GDM_DBUS_NAME              "org.gnome.DisplayManager"
 #define GDM_DBUS_DISPLAY_INTERFACE "org.gnome.DisplayManager.Display"
 
@@ -74,6 +83,7 @@
         char            *display_hostname;
         gboolean         display_is_local;
         gboolean         display_is_parented;
+        char            *display_seat_id;
         char            *display_x11_authority_file;
         char            *parent_display_name;
         char            *parent_display_x11_authority_file;
@@ -93,6 +103,7 @@
         PROP_DISPLAY_NUMBER,
         PROP_DISPLAY_HOSTNAME,
         PROP_DISPLAY_IS_LOCAL,
+        PROP_DISPLAY_SEAT_ID,
         PROP_DISPLAY_X11_AUTHORITY_FILE
 };
 
@@ -555,6 +566,24 @@
                 return FALSE;
         }
 
+        error = NULL;
+        res = dbus_g_proxy_call (slave->priv->display_proxy,
+                                 "GetSeatId",
+                                 &error,
+                                 G_TYPE_INVALID,
+                                 G_TYPE_STRING, &slave->priv->display_seat_id,
+                                 G_TYPE_INVALID);
+        if (! res) {
+                if (error != NULL) {
+                        g_warning ("Failed to get value: %s", error->message);
+                        g_error_free (error);
+                } else {
+                        g_warning ("Failed to get value");
+                }
+
+                return FALSE;
+        }
+
         return TRUE;
 }
 
@@ -650,6 +679,317 @@
         return res;
 }
 
+static gboolean
+_get_uid_and_gid_for_user (const char *username,
+                           uid_t      *uid,
+                           gid_t      *gid)
+{
+        struct passwd *passwd_entry;
+
+        g_assert (username != NULL);
+
+        errno = 0;
+        passwd_entry = getpwnam (username);
+
+        if (passwd_entry == NULL) {
+                return FALSE;
+        }
+
+        if (uid != NULL) {
+                *uid = passwd_entry->pw_uid;
+        }
+
+        if (gid != NULL) {
+                *gid = passwd_entry->pw_gid;
+        }
+
+        return TRUE;
+}
+
+static gboolean
+x11_session_is_on_seat (GdmSlave        *slave,
+                        const char      *session_id,
+                        const char      *seat_id)
+{
+        DBusGProxy      *proxy;
+        GError          *error;
+        char            *sid;
+        gboolean         res;
+        gboolean         ret;
+        char            *x11_display_device;
+        char            *x11_display;
+
+        ret = FALSE;
+
+        if (seat_id == NULL || seat_id[0] == '\0' || session_id == NULL || session_id[0] == '\0') {
+                return FALSE;
+        }
+
+        proxy = dbus_g_proxy_new_for_name (slave->priv->connection,
+                                           CK_NAME,
+                                           session_id,
+                                           CK_SESSION_INTERFACE);
+        if (proxy == NULL) {
+                g_warning ("Failed to connect to the ConsoleKit seat object");
+                goto out;
+        }
+
+        sid = NULL;
+        error = NULL;
+        res = dbus_g_proxy_call (proxy,
+                                 "GetSeatId",
+                                 &error,
+                                 G_TYPE_INVALID,
+                                 DBUS_TYPE_G_OBJECT_PATH, &sid,
+                                 G_TYPE_INVALID);
+        if (! res) {
+                g_debug ("Failed to identify the current seat: %s", error->message);
+                g_error_free (error);
+                goto out;
+        }
+
+        if (sid == NULL || sid[0] == '\0' || strcmp (sid, seat_id) != 0) {
+                g_debug ("GdmSlave: session not on current seat: %s", seat_id);
+                goto out;
+        }
+
+        x11_display = NULL;
+        error = NULL;
+        res = dbus_g_proxy_call (proxy,
+                                 "GetX11Display",
+                                 &error,
+                                 G_TYPE_INVALID,
+                                 G_TYPE_STRING, &x11_display,
+                                 G_TYPE_INVALID);
+        if (! res) {
+                g_error_free (error);
+                goto out;
+        }
+
+        /* don't try to switch to our own session */
+        if (x11_display == NULL || x11_display[0] == '\0'
+            || strcmp (slave->priv->display_name, x11_display) == 0) {
+                g_free (x11_display);
+                goto out;
+        }
+        g_free (x11_display);
+
+        x11_display_device = NULL;
+        error = NULL;
+        res = dbus_g_proxy_call (proxy,
+                                 "GetX11DisplayDevice",
+                                 &error,
+                                 G_TYPE_INVALID,
+                                 G_TYPE_STRING, &x11_display_device,
+                                 G_TYPE_INVALID);
+        if (! res) {
+                g_error_free (error);
+                goto out;
+        }
+
+        if (x11_display_device == NULL || x11_display_device[0] == '\0') {
+                g_free (x11_display_device);
+                goto out;
+        }
+        g_free (x11_display_device);
+
+        ret = TRUE;
+
+ out:
+        if (proxy != NULL) {
+                g_object_unref (proxy);
+        }
+
+        return ret;
+}
+
+static char *
+_get_primary_user_session_id (GdmSlave   *slave,
+                              const char *username)
+{
+        gboolean    res;
+        gboolean    ret;
+        gboolean    can_activate_sessions;
+        GError     *error;
+        DBusGProxy *manager_proxy;
+        DBusGProxy *seat_proxy;
+        GPtrArray  *sessions;
+        char       *primary_ssid;
+        int         i;
+        uid_t       uid;
+
+        if (slave->priv->display_seat_id == NULL || slave->priv->display_seat_id[0] == '\0') {
+                g_debug ("GdmSlave: display seat id is not set; can't switch sessions");
+                return FALSE;
+        }
+
+        ret = FALSE;
+        manager_proxy = NULL;
+        primary_ssid = NULL;
+        sessions = NULL;
+
+        g_debug ("GdmSlave: getting proxy for seat: %s", slave->priv->display_seat_id);
+
+        seat_proxy = dbus_g_proxy_new_for_name (slave->priv->connection,
+                                                CK_NAME,
+                                                slave->priv->display_seat_id,
+                                                CK_SEAT_INTERFACE);
+
+        g_debug ("GdmSlave: checking if seat can activate sessions");
+
+        error = NULL;
+        res = dbus_g_proxy_call (seat_proxy,
+                                 "CanActivateSessions",
+                                 &error,
+                                 G_TYPE_INVALID,
+                                 G_TYPE_BOOLEAN, &can_activate_sessions,
+                                 G_TYPE_INVALID);
+        if (! res) {
+                g_warning ("unable to determine if seat can activate sessions: %s",
+                           error->message);
+                g_error_free (error);
+                goto out;
+        }
+
+        if (! can_activate_sessions) {
+                g_debug ("GdmSlave: seat is unable to activate sessions");
+                goto out;
+        }
+
+        manager_proxy = dbus_g_proxy_new_for_name (slave->priv->connection,
+                                                   CK_NAME,
+                                                   CK_MANAGER_PATH,
+                                                   CK_MANAGER_INTERFACE);
+
+        if (! _get_uid_and_gid_for_user (username, &uid, NULL)) {
+                g_debug ("GdmSlave: unable to determine uid for user: %s", username);
+                goto out;
+        }
+
+        error = NULL;
+        res = dbus_g_proxy_call (manager_proxy,
+                                 "GetSessionsForUnixUser",
+                                 &error,
+                                 G_TYPE_UINT, uid,
+                                 G_TYPE_INVALID,
+                                 dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH), &sessions,
+                                 G_TYPE_INVALID);
+        if (! res) {
+                g_warning ("unable to determine sessions for user: %s",
+                           error->message);
+                g_error_free (error);
+                goto out;
+        }
+
+        for (i = 0; i < sessions->len; i++) {
+                char *ssid;
+
+                ssid = g_ptr_array_index (sessions, i);
+
+                if (! x11_session_is_on_seat (slave, ssid, slave->priv->display_seat_id)) {
+                        goto next;
+                }
+
+                /* FIXME: better way to choose? */
+                if (primary_ssid == NULL) {
+                        primary_ssid = g_strdup (ssid);
+                }
+
+        next:
+                g_free (ssid);
+        }
+        g_ptr_array_free (sessions, TRUE);
+
+ out:
+
+        if (seat_proxy != NULL) {
+                g_object_unref (seat_proxy);
+        }
+        if (manager_proxy != NULL) {
+                g_object_unref (manager_proxy);
+        }
+
+        return primary_ssid;
+}
+
+static gboolean
+activate_session_id (GdmSlave   *slave,
+                     const char *seat_id,
+                     const char *session_id)
+{
+        DBusError    local_error;
+        DBusMessage *message;
+        DBusMessage *reply;
+        gboolean     ret;
+
+        ret = FALSE;
+
+        dbus_error_init (&local_error);
+        message = dbus_message_new_method_call ("org.freedesktop.ConsoleKit",
+                                                seat_id,
+                                                "org.freedesktop.ConsoleKit.Seat",
+                                                "ActivateSession");
+        if (message == NULL) {
+                goto out;
+        }
+
+        if (! dbus_message_append_args (message,
+                                        DBUS_TYPE_OBJECT_PATH, &session_id,
+                                        DBUS_TYPE_INVALID)) {
+                goto out;
+        }
+
+
+        dbus_error_init (&local_error);
+        reply = dbus_connection_send_with_reply_and_block (dbus_g_connection_get_connection (slave->priv->connection),
+                                                           message,
+                                                           -1,
+                                                           &local_error);
+        if (reply == NULL) {
+                if (dbus_error_is_set (&local_error)) {
+                        g_warning ("Unable to activate session: %s", local_error.message);
+                        dbus_error_free (&local_error);
+                        goto out;
+                }
+        }
+
+        ret = TRUE;
+ out:
+        return ret;
+}
+
+gboolean
+gdm_slave_switch_to_user_session (GdmSlave   *slave,
+                                  const char *username)
+{
+        gboolean    res;
+        gboolean    ret;
+        char       *ssid_to_activate;
+
+        ret = FALSE;
+
+        ssid_to_activate = _get_primary_user_session_id (slave, username);
+        if (ssid_to_activate == NULL) {
+                g_debug ("GdmSlave: unable to determine session to activate");
+                goto out;
+        }
+
+        g_debug ("GdmSlave: Activating session: '%s'", ssid_to_activate);
+
+        res = activate_session_id (slave, slave->priv->display_seat_id, ssid_to_activate);
+        if (! res) {
+                g_debug ("GdmSlave: unable to activate session: %s", ssid_to_activate);
+                goto out;
+        }
+
+        ret = TRUE;
+
+ out:
+        g_free (ssid_to_activate);
+
+        return ret;
+}
+
 static void
 _gdm_slave_set_display_id (GdmSlave   *slave,
                            const char *id)
@@ -690,6 +1030,14 @@
 }
 
 static void
+_gdm_slave_set_display_seat_id (GdmSlave   *slave,
+                                const char *id)
+{
+        g_free (slave->priv->display_seat_id);
+        slave->priv->display_seat_id = g_strdup (id);
+}
+
+static void
 _gdm_slave_set_display_is_local (GdmSlave   *slave,
                                  gboolean    is)
 {
@@ -719,6 +1067,9 @@
         case PROP_DISPLAY_HOSTNAME:
                 _gdm_slave_set_display_hostname (self, g_value_get_string (value));
                 break;
+        case PROP_DISPLAY_SEAT_ID:
+                _gdm_slave_set_display_seat_id (self, g_value_get_string (value));
+                break;
         case PROP_DISPLAY_X11_AUTHORITY_FILE:
                 _gdm_slave_set_display_x11_authority_file (self, g_value_get_string (value));
                 break;
@@ -754,6 +1105,9 @@
         case PROP_DISPLAY_HOSTNAME:
                 g_value_set_string (value, self->priv->display_hostname);
                 break;
+        case PROP_DISPLAY_SEAT_ID:
+                g_value_set_string (value, self->priv->display_seat_id);
+                break;
         case PROP_DISPLAY_X11_AUTHORITY_FILE:
                 g_value_set_string (value, self->priv->display_x11_authority_file);
                 break;
@@ -864,6 +1218,13 @@
                                                               NULL,
                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
         g_object_class_install_property (object_class,
+                                         PROP_DISPLAY_SEAT_ID,
+                                         g_param_spec_string ("display-seat-id",
+                                                              "",
+                                                              "",
+                                                              NULL,
+                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+        g_object_class_install_property (object_class,
                                          PROP_DISPLAY_X11_AUTHORITY_FILE,
                                          g_param_spec_string ("display-x11-authority-file",
                                                               "",

Modified: trunk/daemon/gdm-slave.h
==============================================================================
--- trunk/daemon/gdm-slave.h	(original)
+++ trunk/daemon/gdm-slave.h	Mon Jan 28 21:28:43 2008
@@ -60,6 +60,10 @@
 gboolean            gdm_slave_add_user_authorization (GdmSlave   *slave,
                                                       const char *username,
                                                       char      **filename);
+
+gboolean            gdm_slave_switch_to_user_session (GdmSlave   *slave,
+                                                      const char *username);
+
 gboolean            gdm_slave_connect_to_x11_display (GdmSlave   *slave);
 void                gdm_slave_set_busy_cursor        (GdmSlave   *slave);
 gboolean            gdm_slave_run_script             (GdmSlave   *slave,



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