Back to index

lightdm  1.3.2
display.c
Go to the documentation of this file.
00001 /* -*- Mode: C; indent-tabs-mode: nil; tab-width: 4 -*-
00002  *
00003  * Copyright (C) 2010-2011 Robert Ancell.
00004  * Author: Robert Ancell <robert.ancell@canonical.com>
00005  *
00006  * This program is free software: you can redistribute it and/or modify it under
00007  * the terms of the GNU General Public License as published by the Free Software
00008  * Foundation, either version 3 of the License, or (at your option) any later
00009  * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
00010  * license.
00011  */
00012 
00013 #include <config.h>
00014 #include <stdlib.h>
00015 #include <string.h>
00016 #include <gio/gdesktopappinfo.h>
00017 
00018 #include "display.h"
00019 #include "configuration.h"
00020 #include "ldm-marshal.h"
00021 #include "greeter.h"
00022 
00023 enum
00024 {
00025     CREATE_SESSION,
00026     READY,
00027     SWITCH_TO_USER,
00028     SWITCH_TO_GUEST,
00029     GET_GUEST_USERNAME,
00030     DISPLAY_SERVER_READY,
00031     START_GREETER,
00032     START_SESSION,
00033     STOPPED,
00034     LAST_SIGNAL
00035 };
00036 static guint signals[LAST_SIGNAL] = { 0 };
00037 
00038 typedef enum
00039 {
00040     SESSION_NONE = 0,
00041     SESSION_GREETER_PRE_CONNECT,
00042     SESSION_GREETER,
00043     SESSION_GREETER_AUTHENTICATED,
00044     SESSION_USER
00045 } SessionType;
00046 
00047 struct DisplayPrivate
00048 {
00049     /* Display server */
00050     DisplayServer *display_server;
00051 
00052     /* Greeter session */
00053     gchar *greeter_session;
00054 
00055     /* TRUE if the user list should be shown */
00056     gboolean greeter_hide_users;
00057 
00058     /* TRUE if a manual login option should be shown */
00059     gboolean greeter_show_manual_login;
00060 
00061     /* TRUE if the greeter is a lock screen */
00062     gboolean greeter_is_lock;
00063 
00064     /* Session requested to log into */
00065     gchar *user_session;
00066 
00067     /* Program to run sessions through */
00068     gchar *session_wrapper;
00069 
00070     /* TRUE if in a user session */
00071     gboolean in_user_session;
00072 
00073     /* TRUE if have got an X server / started a greeter */
00074     gboolean is_ready;
00075 
00076     /* Session process */
00077     Session *session;
00078 
00079     /* Communication link to greeter */
00080     Greeter *greeter;
00081 
00082     /* User that should be automatically logged in */
00083     gchar *autologin_user;
00084     gboolean autologin_guest;
00085     gint autologin_timeout;
00086 
00087     /* TRUE if start greeter if fail to login */
00088     gboolean start_greeter_if_fail;
00089 
00090     /* Hint to select user in greeter */
00091     gchar *select_user_hint;
00092     gboolean select_guest_hint;
00093 
00094     /* TRUE if allowed to log into guest account */
00095     gboolean allow_guest;
00096 
00097     /* TRUE if greeter is to show the guest account */
00098     gboolean greeter_allow_guest;
00099 
00100     /* TRUE if stopping the display (waiting for dispaly server, greeter and session to stop) */
00101     gboolean stopping;
00102 
00103     /* TRUE if stopped */
00104     gboolean stopped;
00105 };
00106 
00107 /* PAM services to use */
00108 #define GREETER_SERVICE   "lightdm-greeter"
00109 #define USER_SERVICE      "lightdm"
00110 #define AUTOLOGIN_SERVICE "lightdm-autologin"
00111 
00112 G_DEFINE_TYPE (Display, display, G_TYPE_OBJECT);
00113 
00114 static void greeter_session_stopped_cb (Session *session, Display *display);
00115 static void user_session_stopped_cb (Session *session, Display *display);
00116 
00117 Display *
00118 display_new (DisplayServer *display_server)
00119 {
00120     Display *display = g_object_new (DISPLAY_TYPE, NULL);
00121 
00122     display->priv->display_server = g_object_ref (display_server);
00123 
00124     return display;
00125 }
00126 
00127 DisplayServer *
00128 display_get_display_server (Display *display)
00129 {
00130     g_return_val_if_fail (display != NULL, NULL);
00131     return display->priv->display_server;
00132 }
00133 
00134 const gchar *
00135 display_get_username (Display *display)
00136 {
00137     g_return_val_if_fail (display != NULL, NULL);
00138 
00139     if (!display->priv->session || !display->priv->in_user_session)
00140         return NULL;
00141 
00142     return session_get_username (display->priv->session);
00143 }
00144 
00145 Session *
00146 display_get_session (Display *display)
00147 {
00148     g_return_val_if_fail (display != NULL, NULL);
00149     return display->priv->session;
00150 }
00151 
00152 void
00153 display_set_greeter_session (Display *display, const gchar *greeter_session)
00154 {
00155     g_return_if_fail (display != NULL);
00156     g_free (display->priv->greeter_session);
00157     display->priv->greeter_session = g_strdup (greeter_session);
00158 }
00159 
00160 void
00161 display_set_session_wrapper (Display *display, const gchar *session_wrapper)
00162 {
00163     g_return_if_fail (display != NULL);
00164     g_free (display->priv->session_wrapper);
00165     display->priv->session_wrapper = g_strdup (session_wrapper);
00166 }
00167 
00168 void
00169 display_set_allow_guest (Display *display, gboolean allow_guest)
00170 {
00171     g_return_if_fail (display != NULL);
00172     display->priv->allow_guest = allow_guest;
00173 }
00174 
00175 void
00176 display_set_greeter_allow_guest (Display *display, gboolean greeter_allow_guest)
00177 {
00178     g_return_if_fail (display != NULL);
00179     display->priv->greeter_allow_guest = greeter_allow_guest;
00180 }
00181 
00182 void
00183 display_set_autologin_user (Display *display, const gchar *username, gboolean is_guest, gint timeout)
00184 {
00185     g_return_if_fail (display != NULL);
00186     g_free (display->priv->autologin_user);
00187     display->priv->autologin_user = g_strdup (username);
00188     display->priv->autologin_guest = is_guest;
00189     display->priv->autologin_timeout = timeout;
00190 }
00191 
00192 void
00193 display_set_select_user_hint (Display *display, const gchar *username, gboolean is_guest)
00194 {
00195     g_return_if_fail (display != NULL);
00196     g_free (display->priv->select_user_hint);
00197     display->priv->select_user_hint = g_strdup (username);
00198     display->priv->select_guest_hint = is_guest;
00199 }
00200 
00201 void
00202 display_set_hide_users_hint (Display *display, gboolean hide_users)
00203 {
00204     g_return_if_fail (display != NULL);
00205     display->priv->greeter_hide_users = hide_users;
00206 }
00207 
00208 void
00209 display_set_show_manual_login_hint (Display *display, gboolean show_manual_login)
00210 {
00211     g_return_if_fail (display != NULL);
00212     display->priv->greeter_show_manual_login = show_manual_login;
00213 }
00214 
00215 void
00216 display_set_lock_hint (Display *display, gboolean is_lock)
00217 {
00218     g_return_if_fail (display != NULL);
00219     display->priv->greeter_is_lock = is_lock;
00220 }
00221 
00222 void
00223 display_set_user_session (Display *display, const gchar *session_name)
00224 {
00225     g_return_if_fail (display != NULL);
00226     g_free (display->priv->user_session);
00227     display->priv->user_session = g_strdup (session_name);
00228 }
00229 
00230 static void
00231 display_set_is_ready (Display *display)
00232 {
00233     if (display->priv->is_ready)
00234         return;
00235 
00236     display->priv->is_ready = TRUE;
00237     g_signal_emit (display, signals[READY], 0);
00238 }
00239 
00240 static gboolean
00241 switch_to_user (Display *display, User *user)
00242 {
00243     gboolean result;
00244     g_signal_emit (display, signals[SWITCH_TO_USER], 0, user, &result);
00245     return result;
00246 }
00247 
00248 static gboolean
00249 switch_to_guest (Display *display)
00250 {
00251     gboolean result;
00252     g_signal_emit (display, signals[SWITCH_TO_GUEST], 0, &result);
00253     return result;
00254 }
00255 
00256 static gchar *
00257 get_guest_username (Display *display)
00258 {
00259     gchar *username;
00260     g_signal_emit (display, signals[GET_GUEST_USERNAME], 0, &username);
00261     return username;
00262 }
00263 
00264 static Session *
00265 create_session (Display *display)
00266 {
00267     Session *session;
00268 
00269     g_signal_emit (display, signals[CREATE_SESSION], 0, &session);
00270     if (!session)
00271         return NULL;
00272 
00273     /* Connect using the session bus */
00274     if (getuid () != 0)
00275     {
00276         if (g_getenv ("DBUS_SESSION_BUS_ADDRESS"))
00277             session_set_env (session, "DBUS_SESSION_BUS_ADDRESS", g_getenv ("DBUS_SESSION_BUS_ADDRESS"));
00278         session_set_env (session, "LDM_BUS", "SESSION");
00279         if (g_getenv ("LD_PRELOAD"))
00280             session_set_env (session, "LD_PRELOAD", g_getenv ("LD_PRELOAD"));
00281         if (g_getenv ("LD_LIBRARY_PATH"))
00282             session_set_env (session, "LD_LIBRARY_PATH", g_getenv ("LD_LIBRARY_PATH"));
00283         if (g_getenv ("PATH"))
00284             session_set_env (session, "PATH", g_getenv ("PATH"));
00285     }
00286 
00287     /* Variables required for regression tests */
00288     if (g_getenv ("LIGHTDM_TEST_ROOT"))
00289     {
00290         session_set_env (session, "LIGHTDM_TEST_ROOT", g_getenv ("LIGHTDM_TEST_ROOT"));
00291         session_set_env (session, "DBUS_SYSTEM_BUS_ADDRESS", g_getenv ("DBUS_SYSTEM_BUS_ADDRESS"));
00292         session_set_env (session, "DBUS_SESSION_BUS_ADDRESS", g_getenv ("DBUS_SESSION_BUS_ADDRESS"));
00293         session_set_env (session, "LD_PRELOAD", g_getenv ("LD_PRELOAD"));
00294         session_set_env (session, "LD_LIBRARY_PATH", g_getenv ("LD_LIBRARY_PATH"));
00295         session_set_env (session, "GI_TYPELIB_PATH", g_getenv ("GI_TYPELIB_PATH"));
00296     }
00297 
00298     return session;
00299 }
00300 
00301 static void
00302 destroy_session (Display *display)
00303 {
00304     if (!display->priv->session)
00305         return;
00306 
00307     g_signal_handlers_disconnect_matched (display->priv->session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, display);
00308     session_stop (display->priv->session);
00309     g_object_unref (display->priv->session);
00310     display->priv->session = NULL;
00311 }
00312 
00313 static void
00314 greeter_authentication_complete_cb (Session *session, Display *display)
00315 {
00316     gboolean result = FALSE;
00317 
00318     if (display->priv->stopping)
00319         return;
00320 
00321     if (session_get_is_authenticated (session))
00322     {
00323         g_debug ("Greeter authorized");
00324         g_signal_emit (display, signals[START_GREETER], 0, &result);
00325         result = !result;
00326     }
00327     else
00328         g_debug ("Greeter failed authentication");
00329 
00330     if (!result)
00331     {
00332         g_debug ("Greeter failed to start");
00333         display_stop (display);
00334     }
00335 }
00336 
00337 static void
00338 greeter_connected_cb (Greeter *greeter, Display *display)
00339 {
00340     // FIXME: Should wait for greeter to signal completely ready if it supports it
00341     g_debug ("Greeter connected, display is ready");
00342     display_set_is_ready (display);
00343 }
00344 
00345 static Session *
00346 greeter_start_authentication_cb (Greeter *greeter, const gchar *username, Display *display)
00347 {
00348     return create_session (display);
00349 }
00350 
00351 static gboolean
00352 greeter_start_session_cb (Greeter *greeter, const gchar *session_name, Display *display)
00353 {
00354     /* If no session requested, use the previous one */
00355     if (!session_name && !greeter_get_guest_authenticated (greeter))
00356     {
00357         User *user;
00358 
00359         user = session_get_user (greeter_get_authentication_session (greeter));
00360         session_name = user_get_xsession (user);
00361     }
00362 
00363     /* If a session was requested, override the default */
00364     if (session_name)
00365     {
00366         g_debug ("Using session %s", session_name);
00367         display_set_user_session (display, session_name);
00368     }
00369 
00370     /* Stop this display if that session already exists and can switch to it */
00371     if (greeter_get_guest_authenticated (greeter))
00372     {
00373         if (switch_to_guest (display))
00374             return TRUE;
00375 
00376         /* Set to login as guest */
00377         display_set_autologin_user (display, NULL, TRUE, 0);
00378     }
00379     else
00380     {
00381         if (switch_to_user (display, session_get_user (greeter_get_authentication_session (display->priv->greeter))))
00382             return TRUE;
00383     }
00384 
00385     /* Stop the greeter, the session will start when the greeter has quit */
00386     g_debug ("Stopping greeter");
00387     session_stop (display->priv->session);
00388 
00389     return TRUE;
00390 }
00391 
00392 static gboolean
00393 start_greeter (Display *display)
00394 {
00395     gchar *greeter_user;
00396     gboolean result;
00397 
00398     destroy_session (display);
00399     display->priv->session = create_session (display);
00400     session_set_class (display->priv->session, XDG_SESSION_CLASS_GREETER);
00401     g_signal_connect (display->priv->session, "authentication-complete", G_CALLBACK (greeter_authentication_complete_cb), display);
00402 
00403     /* Make communication link to greeter that will run on this session */
00404     display->priv->greeter = greeter_new (display->priv->session, USER_SERVICE);
00405     g_signal_connect (G_OBJECT (display->priv->greeter), "connected", G_CALLBACK (greeter_connected_cb), display);
00406     g_signal_connect (G_OBJECT (display->priv->greeter), "start-authentication", G_CALLBACK (greeter_start_authentication_cb), display);
00407     g_signal_connect (G_OBJECT (display->priv->greeter), "start-session", G_CALLBACK (greeter_start_session_cb), display);
00408     if (display->priv->autologin_timeout)
00409     {
00410         gchar *value = g_strdup_printf ("%d", display->priv->autologin_timeout);
00411         greeter_set_hint (display->priv->greeter, "autologin-timeout", value);
00412         g_free (value);
00413         if (display->priv->autologin_user)
00414             greeter_set_hint (display->priv->greeter, "autologin-user", display->priv->autologin_user);
00415         else if (display->priv->autologin_guest)
00416             greeter_set_hint (display->priv->greeter, "autologin-guest", "true");
00417     }
00418     if (display->priv->select_user_hint)
00419         greeter_set_hint (display->priv->greeter, "select-user", display->priv->select_user_hint);
00420     else if (display->priv->select_guest_hint)
00421         greeter_set_hint (display->priv->greeter, "select-guest", "true");
00422     greeter_set_hint (display->priv->greeter, "default-session", display->priv->user_session);
00423     greeter_set_allow_guest (display->priv->greeter, display->priv->allow_guest);
00424     greeter_set_hint (display->priv->greeter, "has-guest-account", (display->priv->allow_guest && display->priv->greeter_allow_guest) ? "true" : "false");
00425     greeter_set_hint (display->priv->greeter, "hide-users", display->priv->greeter_hide_users ? "true" : "false");
00426     greeter_set_hint (display->priv->greeter, "show-manual-login", display->priv->greeter_show_manual_login ? "true" : "false");
00427     if (display->priv->greeter_is_lock)
00428         greeter_set_hint (display->priv->greeter, "lock-screen", "true");
00429 
00430     /* Run greeter as unprivileged user */
00431     if (getuid () != 0)
00432     {
00433         User *user;
00434         user = accounts_get_current_user ();
00435         greeter_user = g_strdup (user_get_name (user));
00436         g_object_unref (user);
00437     }
00438     else
00439     {
00440         greeter_user = config_get_string (config_get_instance (), "LightDM", "greeter-user");
00441         if (!greeter_user)
00442         {
00443             g_warning ("Greeter must not be run as root");
00444             display_stop (display);
00445             return FALSE;
00446         }
00447     }
00448 
00449     g_signal_connect_after (display->priv->session, "stopped", G_CALLBACK (greeter_session_stopped_cb), display);
00450     result = greeter_start (display->priv->greeter, GREETER_SERVICE, greeter_user);
00451     g_free (greeter_user);
00452 
00453     if (!result)
00454         display_stop (display);
00455 
00456     return result;
00457 }
00458 
00459 static void
00460 autologin_authentication_complete_cb (Session *session, Display *display)
00461 {
00462     gboolean result = FALSE;
00463 
00464     if (display->priv->stopping)
00465         return;
00466 
00467     if (session_get_is_authenticated (session))
00468     {
00469         const gchar *session_name;
00470 
00471         g_debug ("Autologin user %s authorized", session_get_username (session));
00472 
00473         session_name = user_get_xsession (session_get_user (session));
00474         if (session_name)
00475         {
00476             g_debug ("Autologin using session %s", session_name);
00477             display_set_user_session (display, session_name);
00478         }
00479 
00480         g_signal_emit (display, signals[START_SESSION], 0, &result);
00481         result = !result;
00482     }
00483     else
00484         g_debug ("Autologin failed authentication");
00485 
00486     if (!result)
00487     {
00488         if (display->priv->start_greeter_if_fail)
00489             start_greeter (display);
00490         else
00491             display_stop (display);
00492     }
00493 }
00494 
00495 static gboolean
00496 autologin (Display *display, const gchar *username, const gchar *service, gboolean start_greeter_if_fail)
00497 {
00498     display->priv->start_greeter_if_fail = start_greeter_if_fail;
00499 
00500     display->priv->in_user_session = TRUE;
00501     destroy_session (display);
00502     display->priv->session = create_session (display);
00503     g_signal_connect (display->priv->session, "authentication-complete", G_CALLBACK (autologin_authentication_complete_cb), display);
00504     g_signal_connect_after (display->priv->session, "stopped", G_CALLBACK (user_session_stopped_cb), display);
00505     return session_start (display->priv->session, service, username, TRUE, FALSE);
00506 }
00507 
00508 static gboolean
00509 autologin_guest (Display *display, const gchar *service, gboolean start_greeter_if_fail)
00510 {
00511     gchar *username;
00512     gboolean result;
00513 
00514     username = get_guest_username (display);
00515     if (!username)
00516     {
00517         g_debug ("Can't autologin guest, no guest account");
00518         return FALSE;
00519     }
00520 
00521     result = autologin (display, username, service, start_greeter_if_fail);
00522     g_free (username);
00523 
00524     return result;
00525 }
00526 
00527 static gchar **
00528 get_session_command (const gchar *filename, const gchar *session_wrapper)
00529 {
00530     GKeyFile *session_desktop_file;
00531     gboolean result;
00532     int argc;
00533     gchar *command = NULL, **argv, *path;
00534     GError *error = NULL;
00535 
00536     /* Read the command from the .desktop file */
00537     session_desktop_file = g_key_file_new ();
00538     result = g_key_file_load_from_file (session_desktop_file, filename, G_KEY_FILE_NONE, &error);
00539     if (error)
00540         g_debug ("Failed to load session file %s: %s", filename, error->message);
00541     g_clear_error (&error);
00542     if (result)
00543     {
00544         command = g_key_file_get_string (session_desktop_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_EXEC, NULL);
00545         if (!command)
00546             g_debug ("No command in session file %s", filename);
00547     }
00548     g_key_file_free (session_desktop_file);
00549 
00550     if (!command)
00551         return NULL;
00552 
00553     /* If configured, run sessions through a wrapper */
00554     if (session_wrapper)
00555     {
00556         argv = g_malloc (sizeof (gchar *) * 3);
00557         path = g_find_program_in_path (session_wrapper);
00558         argv[0] = path ? path : g_strdup (session_wrapper);
00559         argv[1] = command;
00560         argv[2] = NULL;
00561         return argv;
00562     }
00563 
00564     /* Split command into an array listing and make command absolute */
00565     result = g_shell_parse_argv (command, &argc, &argv, &error);
00566     if (error)
00567         g_debug ("Invalid session command '%s': %s", command, error->message);
00568     g_clear_error (&error);
00569     g_free (command);
00570     if (!result)
00571         return NULL;
00572     path = g_find_program_in_path (argv[0]);
00573     if (path)
00574     {
00575         g_free (argv[0]);
00576         argv[0] = path;
00577     }
00578   
00579     return argv;
00580 }
00581 
00582 static void
00583 greeter_session_stopped_cb (Session *session, Display *display)
00584 {
00585     gboolean result = FALSE;
00586 
00587     g_debug ("Greeter quit");
00588 
00589     g_signal_handlers_disconnect_matched (display->priv->session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, display);
00590     g_object_unref (display->priv->session);
00591     display->priv->session = NULL;
00592 
00593     if (display->priv->stopping)
00594     {
00595         display_stop (display);
00596         return;
00597     }
00598 
00599     if (!display->priv->display_server)
00600         return;
00601 
00602     /* Start the session for the authenticated user */
00603     if (greeter_get_start_session (display->priv->greeter))
00604     {
00605         /* If guest, then start a new autologin guest session (so can setup account) */
00606         if (greeter_get_guest_authenticated (display->priv->greeter))
00607             result = autologin_guest (display, AUTOLOGIN_SERVICE, FALSE);
00608         /* Otherwise, use the session the greeter has authenticated */
00609         else
00610         {
00611             destroy_session (display);
00612             display->priv->session = g_object_ref (greeter_get_authentication_session (display->priv->greeter));
00613             g_signal_connect_after (display->priv->session, "stopped", G_CALLBACK (user_session_stopped_cb), display);
00614             display->priv->in_user_session = TRUE;
00615             g_signal_emit (display, signals[START_SESSION], 0, &result);
00616             result = !result;
00617         }
00618     }
00619 
00620     /* Destroy the greeter */
00621     g_signal_handlers_disconnect_matched (display->priv->greeter, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, display);
00622     g_object_unref (display->priv->greeter);
00623     display->priv->greeter = NULL;
00624 
00625     if (!result)
00626     {
00627         g_debug ("Failed to start greeter");
00628         display_stop (display);
00629     }
00630 }
00631 
00632 static gboolean
00633 display_start_greeter (Display *display)
00634 {
00635     gchar *log_dir, *filename, *log_filename, *sessions_dir, *path;
00636     gchar **argv;
00637 
00638     /* Log the output of the greeter to a system location */
00639     log_dir = config_get_string (config_get_instance (), "LightDM", "log-directory");
00640     filename = g_strdup_printf ("%s-greeter.log", display_server_get_name (display->priv->display_server));
00641     log_filename = g_build_filename (log_dir, filename, NULL);
00642     g_free (log_dir);
00643     g_free (filename);
00644     g_debug ("Logging to %s", log_filename);
00645     session_set_log_file (display->priv->session, log_filename);
00646     g_free (log_filename);
00647 
00648     /* Load the greeter session information */
00649     sessions_dir = config_get_string (config_get_instance (), "LightDM", "xgreeters-directory");
00650     filename = g_strdup_printf ("%s.desktop", display->priv->greeter_session);
00651     path = g_build_filename (sessions_dir, filename, NULL);
00652     g_free (sessions_dir);
00653     g_free (filename);
00654     argv = get_session_command (path, NULL);
00655     g_free (path);
00656     if (!argv)
00657         return TRUE;
00658 
00659     session_run (display->priv->session, argv);
00660 
00661     return FALSE;
00662 }
00663 
00664 static void
00665 user_session_stopped_cb (Session *session, Display *display)
00666 {
00667     g_debug ("User session quit");
00668 
00669     g_signal_handlers_disconnect_matched (display->priv->session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, display);
00670     g_object_unref (display->priv->session);
00671     display->priv->session = NULL;
00672 
00673     /* This display has ended */
00674     display_stop (display);
00675 }
00676 
00677 static void
00678 prepend_argv (gchar ***argv, const gchar *value)
00679 {
00680     gchar **old_argv, **new_argv;
00681     gint i;
00682 
00683     old_argv = *argv;
00684     new_argv = g_malloc (sizeof (gchar *) * (g_strv_length (*argv) + 2));
00685     new_argv[0] = g_strdup (value);
00686     for (i = 0; old_argv[i]; i++)
00687         new_argv[i + 1] = old_argv[i];
00688     new_argv[i + 1] = NULL;
00689 
00690     g_free (*argv);
00691     *argv = new_argv;
00692 }
00693 
00694 static gboolean
00695 display_start_session (Display *display)
00696 {
00697     User *user;
00698     gchar *filename, *sessions_dir, *path;
00699     gchar **argv;
00700 
00701     user = session_get_user (display->priv->session);
00702 
00703     /* Store this session name so we automatically use it next time */
00704     user_set_xsession (user, display->priv->user_session);
00705 
00706     /* Find the command to run for the selected session */
00707     // FIXME: This is X specific, move into xsession.c
00708     sessions_dir = config_get_string (config_get_instance (), "LightDM", "xsessions-directory");
00709     filename = g_strdup_printf ("%s.desktop", display->priv->user_session);
00710     path = g_build_filename (sessions_dir, filename, NULL);
00711     g_free (sessions_dir);
00712     g_free (filename);
00713     argv = get_session_command (path, display->priv->session_wrapper);
00714     g_free (path);
00715     if (!argv)
00716         return TRUE;
00717   
00718     session_set_env (display->priv->session, "DESKTOP_SESSION", display->priv->user_session); // FIXME: Apparently deprecated?
00719     session_set_env (display->priv->session, "GDMSESSION", display->priv->user_session); // FIXME: Not cross-desktop
00720 
00721     /* Run a guest session through the wrapper covered by MAC */
00722     if (display->priv->autologin_guest)
00723     {
00724         gchar *wrapper = g_build_filename (PKGLIBEXEC_DIR, "lightdm-guest-session-wrapper", NULL);
00725         g_debug ("Running guest session through wrapper: %s", wrapper);
00726         prepend_argv (&argv, wrapper);
00727         g_free (wrapper);
00728     }
00729 
00730     g_debug ("Starting session %s as user %s", display->priv->user_session, session_get_username (display->priv->session));
00731 
00732     session_run (display->priv->session, argv);
00733     g_strfreev (argv);
00734 
00735     // FIXME: Wait for session to indicate it is ready (maybe)
00736     display_set_is_ready (display);
00737 
00738     return FALSE;
00739 }
00740 
00741 static void
00742 display_server_stopped_cb (DisplayServer *server, Display *display)
00743 {
00744     g_debug ("Display server stopped");
00745 
00746     g_signal_handlers_disconnect_matched (display->priv->display_server, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, display);
00747     g_object_unref (display->priv->display_server);
00748     display->priv->display_server = NULL;
00749 
00750     /* Stop this display, it will be restarted by the seat if necessary */
00751     display_stop (display);
00752 }
00753 
00754 static void
00755 display_server_ready_cb (DisplayServer *display_server, Display *display)
00756 {
00757     gboolean result = FALSE;
00758 
00759     g_signal_emit (display, signals[DISPLAY_SERVER_READY], 0, &result);
00760     if (!result)
00761     {
00762         display_stop (display);
00763         return;
00764     }
00765 
00766     /* Don't run any sessions on local terminals */
00767     if (!display_server_get_start_local_sessions (display_server))
00768         return;
00769 
00770     /* Automatically start requested user session */
00771     result = FALSE;
00772     if (display->priv->autologin_guest)
00773     {
00774         g_debug ("Automatically logging in as guest");
00775         result = autologin_guest (display, AUTOLOGIN_SERVICE, TRUE);
00776     }
00777     else if (display->priv->autologin_user)
00778     {
00779         g_debug ("Automatically logging in user %s", display->priv->autologin_user);
00780         result = autologin (display, display->priv->autologin_user, AUTOLOGIN_SERVICE, TRUE);
00781     }
00782     else if (display->priv->select_user_hint)
00783     {
00784         g_debug ("Logging in user %s", display->priv->select_user_hint);
00785         result = autologin (display, display->priv->select_user_hint, USER_SERVICE, TRUE);
00786     }
00787 
00788     /* If no session started, start a greeter */
00789     if (!result)
00790     {
00791         g_debug ("Starting greeter");      
00792         result = start_greeter (display);
00793     }
00794 
00795     /* If nothing started, then the display can't work */
00796     if (!result)
00797         display_stop (display);
00798 }
00799 
00800 gboolean
00801 display_start (Display *display)
00802 {
00803     g_return_val_if_fail (display != NULL, FALSE);
00804 
00805     g_signal_connect (G_OBJECT (display->priv->display_server), "ready", G_CALLBACK (display_server_ready_cb), display);
00806     g_signal_connect (G_OBJECT (display->priv->display_server), "stopped", G_CALLBACK (display_server_stopped_cb), display);
00807 
00808     if (!display_server_start (display->priv->display_server))
00809         return FALSE;
00810 
00811     return TRUE;
00812 }
00813 
00814 void
00815 display_stop (Display *display)
00816 {
00817     g_return_if_fail (display != NULL);
00818 
00819     if (display->priv->stopped)
00820         return;
00821 
00822     if (!display->priv->stopping)
00823     {
00824         g_debug ("Stopping display");
00825         display->priv->stopping = TRUE;
00826     }
00827 
00828     /* Stop the session first */
00829     if (display->priv->session)
00830     {
00831         session_stop (display->priv->session);
00832         if (display->priv->session && !session_get_is_stopped (display->priv->session))
00833             return;
00834         g_signal_handlers_disconnect_matched (display->priv->session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, display);
00835         g_object_unref (display->priv->session);
00836         display->priv->session = NULL;
00837     }
00838 
00839     /* Stop the display server after that */
00840     if (display->priv->display_server)
00841     {
00842         display_server_stop (display->priv->display_server);
00843         if (display->priv->display_server && !display_server_get_is_stopped (display->priv->display_server))
00844             return;
00845         g_signal_handlers_disconnect_matched (display->priv->display_server, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, display);
00846         g_object_unref (display->priv->display_server);
00847         display->priv->display_server = NULL;
00848     }
00849 
00850     display->priv->stopped = TRUE;
00851     g_debug ("Display stopped");
00852     g_signal_emit (display, signals[STOPPED], 0);
00853 }
00854 
00855 gboolean
00856 display_get_is_ready (Display *display)
00857 {
00858     g_return_val_if_fail (display != NULL, FALSE);
00859 
00860     return display->priv->is_ready;
00861 }
00862 
00863 void
00864 display_lock (Display *display)
00865 {
00866     g_return_if_fail (display != NULL);
00867 
00868     if (!display->priv->session)
00869         return;
00870 
00871     g_debug ("Locking display");
00872 
00873     session_lock (display->priv->session);
00874 }
00875 
00876 void
00877 display_unlock (Display *display)
00878 {
00879     g_return_if_fail (display != NULL);
00880 
00881     if (!display->priv->session)
00882         return;
00883 
00884     g_debug ("Unlocking display");
00885 
00886     session_unlock (display->priv->session);
00887 }
00888 
00889 static gboolean
00890 display_real_switch_to_user (Display *display, User *user)
00891 {
00892     return FALSE;
00893 }
00894 
00895 static gboolean
00896 display_real_switch_to_guest (Display *display)
00897 {
00898     return FALSE;
00899 }
00900 
00901 static gchar *
00902 display_real_get_guest_username (Display *display)
00903 {
00904     return NULL;
00905 }
00906 
00907 static void
00908 display_init (Display *display)
00909 {
00910     display->priv = G_TYPE_INSTANCE_GET_PRIVATE (display, DISPLAY_TYPE, DisplayPrivate);
00911 }
00912 
00913 static void
00914 display_finalize (GObject *object)
00915 {
00916     Display *self;
00917 
00918     self = DISPLAY (object);
00919 
00920     if (self->priv->display_server)
00921     {
00922         g_signal_handlers_disconnect_matched (self->priv->display_server, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);
00923         g_object_unref (self->priv->display_server);
00924     }
00925     g_free (self->priv->greeter_session);
00926     if (self->priv->greeter)
00927     {
00928         g_signal_handlers_disconnect_matched (self->priv->greeter, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);
00929         g_object_unref (self->priv->greeter);
00930     }
00931     g_free (self->priv->session_wrapper);
00932     if (self->priv->session)
00933     {
00934         g_signal_handlers_disconnect_matched (self->priv->session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);      
00935         g_object_unref (self->priv->session);
00936     }
00937     g_free (self->priv->autologin_user);
00938     g_free (self->priv->select_user_hint);
00939     g_free (self->priv->user_session);
00940 
00941     G_OBJECT_CLASS (display_parent_class)->finalize (object);
00942 }
00943 
00944 static void
00945 display_class_init (DisplayClass *klass)
00946 {
00947     GObjectClass *object_class = G_OBJECT_CLASS (klass);
00948 
00949     klass->switch_to_user = display_real_switch_to_user;
00950     klass->switch_to_guest = display_real_switch_to_guest;
00951     klass->get_guest_username = display_real_get_guest_username;
00952     klass->start_greeter = display_start_greeter;
00953     klass->start_session = display_start_session;
00954     object_class->finalize = display_finalize;
00955 
00956     g_type_class_add_private (klass, sizeof (DisplayPrivate));
00957 
00958     signals[CREATE_SESSION] =
00959         g_signal_new ("create-session",
00960                       G_TYPE_FROM_CLASS (klass),
00961                       G_SIGNAL_RUN_LAST,
00962                       G_STRUCT_OFFSET (DisplayClass, create_session),
00963                       NULL, NULL,
00964                       ldm_marshal_OBJECT__VOID,
00965                       SESSION_TYPE, 0);
00966     signals[READY] =
00967         g_signal_new ("ready",
00968                       G_TYPE_FROM_CLASS (klass),
00969                       G_SIGNAL_RUN_LAST,
00970                       G_STRUCT_OFFSET (DisplayClass, ready),
00971                       NULL, NULL,
00972                       g_cclosure_marshal_VOID__VOID,
00973                       G_TYPE_NONE, 0);
00974     signals[SWITCH_TO_USER] =
00975         g_signal_new ("switch-to-user",
00976                       G_TYPE_FROM_CLASS (klass),
00977                       G_SIGNAL_RUN_LAST,
00978                       G_STRUCT_OFFSET (DisplayClass, switch_to_user),
00979                       g_signal_accumulator_true_handled,
00980                       NULL,
00981                       ldm_marshal_BOOLEAN__OBJECT,
00982                       G_TYPE_BOOLEAN, 1, USER_TYPE);
00983     signals[SWITCH_TO_GUEST] =
00984         g_signal_new ("switch-to-guest",
00985                       G_TYPE_FROM_CLASS (klass),
00986                       G_SIGNAL_RUN_LAST,
00987                       G_STRUCT_OFFSET (DisplayClass, switch_to_guest),
00988                       g_signal_accumulator_true_handled,
00989                       NULL,
00990                       ldm_marshal_BOOLEAN__VOID,
00991                       G_TYPE_BOOLEAN, 0);
00992     signals[GET_GUEST_USERNAME] =
00993         g_signal_new ("get-guest-username",
00994                       G_TYPE_FROM_CLASS (klass),
00995                       G_SIGNAL_RUN_LAST,
00996                       G_STRUCT_OFFSET (DisplayClass, get_guest_username),
00997                       g_signal_accumulator_first_wins,
00998                       NULL,
00999                       ldm_marshal_STRING__VOID,
01000                       G_TYPE_STRING, 0);
01001     signals[DISPLAY_SERVER_READY] =
01002         g_signal_new ("display-server-ready",
01003                       G_TYPE_FROM_CLASS (klass),
01004                       G_SIGNAL_RUN_LAST,
01005                       G_STRUCT_OFFSET (DisplayClass, display_server_ready),
01006                       NULL, NULL,
01007                       ldm_marshal_BOOLEAN__VOID,
01008                       G_TYPE_BOOLEAN, 0);
01009     signals[START_GREETER] =
01010         g_signal_new ("start-greeter",
01011                       G_TYPE_FROM_CLASS (klass),
01012                       G_SIGNAL_RUN_LAST,
01013                       G_STRUCT_OFFSET (DisplayClass, start_greeter),
01014                       g_signal_accumulator_true_handled, NULL,
01015                       ldm_marshal_BOOLEAN__VOID,
01016                       G_TYPE_BOOLEAN, 0);
01017     signals[START_SESSION] =
01018         g_signal_new ("start-session",
01019                       G_TYPE_FROM_CLASS (klass),
01020                       G_SIGNAL_RUN_LAST,
01021                       G_STRUCT_OFFSET (DisplayClass, start_session),
01022                       g_signal_accumulator_true_handled, NULL,
01023                       ldm_marshal_BOOLEAN__VOID,
01024                       G_TYPE_BOOLEAN, 0);
01025     signals[STOPPED] =
01026         g_signal_new ("stopped",
01027                       G_TYPE_FROM_CLASS (klass),
01028                       G_SIGNAL_RUN_LAST,
01029                       G_STRUCT_OFFSET (DisplayClass, stopped),
01030                       NULL, NULL,
01031                       g_cclosure_marshal_VOID__VOID,
01032                       G_TYPE_NONE, 0);
01033 }