2 * Copyright (C) 2010-2011 Robert Ancell.
3 * Author: Robert Ancell <robert.ancell@canonical.com>
5 * This program is free software: you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option) any later
8 * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
15 #include "configuration.h"
18 #include "guest-account.h"
27 static guint signals[LAST_SIGNAL] = { 0 };
31 /* Configuration for this seat */
32 gchar *config_section;
34 /* TRUE if able to switch users */
37 /* TRUE if allowed to log into guest account */
40 /* Name of guest account */
41 gchar *guest_username;
43 /* User to automatically log in as */
44 gchar *autologin_username;
45 gboolean autologin_guest;
46 guint autologin_timeout;
48 /* The displays for this seat */
51 /* The active display */
52 Display *active_display;
54 /* TRUE if stopping this seat (waiting for displays to stop) */
58 G_DEFINE_TYPE (Seat, seat, G_TYPE_OBJECT);
65 static GHashTable *seat_modules = NULL;
68 seat_register_module (const gchar *name, GType type)
73 seat_modules = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
75 g_debug ("Registered seat module %s", name);
77 module = g_malloc0 (sizeof (SeatModule));
78 module->name = g_strdup (name);
80 g_hash_table_insert (seat_modules, g_strdup (name), module);
84 seat_new (const gchar *module, const gchar *config_section)
90 m = g_hash_table_lookup (seat_modules, module);
94 seat = g_object_new (m->type, NULL);
95 seat->priv->config_section = g_strdup (config_section);
101 seat_get_config_section (Seat *seat)
103 g_return_val_if_fail (seat != NULL, NULL);
104 return seat->priv->config_section;
108 seat_set_can_switch (Seat *seat, gboolean can_switch)
110 g_return_if_fail (seat != NULL);
112 seat->priv->can_switch = can_switch;
116 seat_start (Seat *seat)
118 g_return_val_if_fail (seat != NULL, FALSE);
120 SEAT_GET_CLASS (seat)->setup (seat);
121 return SEAT_GET_CLASS (seat)->start (seat);
125 seat_get_displays (Seat *seat)
127 g_return_val_if_fail (seat != NULL, NULL);
128 return seat->priv->displays;
132 seat_set_active_display (Seat *seat, Display *display)
134 g_return_if_fail (seat != NULL);
135 display_unlock (display);
136 SEAT_GET_CLASS (seat)->set_active_display (seat, display);
140 seat_get_active_display (Seat *seat)
142 g_return_val_if_fail (seat != NULL, NULL);
143 return seat->priv->active_display;
147 seat_get_can_switch (Seat *seat)
149 g_return_val_if_fail (seat != NULL, FALSE);
150 return seat->priv->can_switch;
154 seat_get_allow_guest (Seat *seat)
156 g_return_val_if_fail (seat != NULL, FALSE);
157 return seat->priv->allow_guest && guest_account_is_installed ();
161 switch_to_user (Seat *seat, const gchar *username)
165 /* Switch to active display if it exists */
166 for (link = seat->priv->displays; link; link = link->next)
168 Display *display = link->data;
170 /* If already logged in, then switch to that display */
171 if (g_strcmp0 (display_get_username (display), username) == 0)
173 // FIXME: Use display_get_name
174 g_debug ("Switching to user %s session on display %s", username, xserver_get_address (XSERVER (display_get_display_server (display))));
175 seat_set_active_display (seat, display);
184 display_switch_to_user_cb (Display *display, User *user, Seat *seat)
186 return switch_to_user (seat, user_get_name (user));
190 display_switch_to_guest_cb (Display *display, Seat *seat)
192 /* No guest account */
193 if (!seat->priv->guest_username)
196 return switch_to_user (seat, seat->priv->guest_username);
200 display_get_guest_username_cb (Display *display, Seat *seat)
202 if (seat->priv->guest_username)
203 return seat->priv->guest_username;
205 seat->priv->guest_username = guest_account_setup ();
206 return g_strdup (seat->priv->guest_username);
210 display_ready_cb (Display *display, Seat *seat)
212 /* Switch to this new display */
213 SEAT_GET_CLASS (seat)->set_active_display (seat, display);
217 display_session_stopped_cb (Display *display, Seat *seat)
221 session = display_get_session (display);
222 if (seat->priv->guest_username && strcmp (user_get_name (session_get_user (session)), seat->priv->guest_username) == 0)
224 guest_account_cleanup (seat->priv->guest_username);
225 g_free (seat->priv->guest_username);
226 seat->priv->guest_username = NULL;
231 check_stopped (Seat *seat)
233 if (g_list_length (seat->priv->displays) == 0)
235 g_debug ("Seat stopped");
236 g_signal_emit (seat, signals[STOPPED], 0);
243 display_stopped_cb (Display *display, Seat *seat)
245 seat->priv->displays = g_list_remove (seat->priv->displays, display);
246 g_signal_handlers_disconnect_matched (display, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, seat);
247 g_signal_emit (seat, signals[DISPLAY_REMOVED], 0, display);
248 g_object_unref (display);
250 if (seat->priv->stopping)
251 check_stopped (seat);
255 switch_to_user_or_start_greeter (Seat *seat, const gchar *username, gboolean is_guest, const gchar *session_name, gboolean autologin)
258 Display *new_display = NULL;
260 /* Switch to active display if it exists */
261 for (link = seat->priv->displays; link; link = link->next)
263 Display *display = link->data;
265 /* If already logged in, then switch to that display and stop the greeter display */
266 if (g_strcmp0 (display_get_username (display), username) == 0)
268 // FIXME: Use display_get_name
270 g_debug ("Switching to user %s session on display %s", username, xserver_get_address (XSERVER (display_get_display_server (display))));
272 g_debug ("Switching to greeter on display %s", xserver_get_address (XSERVER (display_get_display_server (display))));
273 seat_set_active_display (seat, display);
278 /* They don't exist, so start a greeter */
282 g_debug ("Starting new display for automatic guest login");
284 g_debug ("Starting new display for automatic login as user %s", username);
286 g_debug ("Starting new display for greeter");
291 g_debug ("Starting new display for greeter with guest selected");
293 g_debug ("Starting new display for greeter with user %s selected", username);
295 g_debug ("Starting new display for greeter");
298 new_display = SEAT_GET_CLASS (seat)->add_display (seat);
299 display_load_config (DISPLAY (new_display), seat->priv->config_section);
300 g_signal_connect (new_display, "switch-to-user", G_CALLBACK (display_switch_to_user_cb), seat);
301 g_signal_connect (new_display, "switch-to-guest", G_CALLBACK (display_switch_to_guest_cb), seat);
302 g_signal_connect (new_display, "get-guest-username", G_CALLBACK (display_get_guest_username_cb), seat);
303 g_signal_connect (new_display, "ready", G_CALLBACK (display_ready_cb), seat);
304 g_signal_connect (new_display, "session-stopped", G_CALLBACK (display_session_stopped_cb), seat);
305 g_signal_connect (new_display, "stopped", G_CALLBACK (display_stopped_cb), seat);
306 display_set_allow_guest (new_display, seat_get_allow_guest (seat));
308 display_set_autologin_user (new_display, username, is_guest, 0);
310 display_set_select_user_hint (new_display, username, is_guest);
311 display_set_user_session (new_display, session_name);
313 seat->priv->displays = g_list_append (seat->priv->displays, new_display);
314 g_signal_emit (seat, signals[DISPLAY_ADDED], 0, new_display);
316 /* Switch to this new display */
317 if (!seat->priv->active_display)
318 seat_set_active_display (seat, new_display);
320 return display_start (new_display);
324 seat_switch_to_greeter (Seat *seat)
326 g_return_val_if_fail (seat != NULL, FALSE);
328 if (!seat->priv->can_switch)
331 g_debug ("Switching to greeter");
332 return switch_to_user_or_start_greeter (seat, NULL, FALSE, NULL, FALSE);
336 seat_switch_to_user (Seat *seat, const gchar *username, const gchar *session_name)
338 g_return_val_if_fail (seat != NULL, FALSE);
339 g_return_val_if_fail (username != NULL, FALSE);
341 if (!seat->priv->can_switch)
344 g_debug ("Switching to user %s", username);
345 return switch_to_user_or_start_greeter (seat, username, FALSE, session_name, FALSE);
349 seat_switch_to_guest (Seat *seat, const gchar *session_name)
351 g_return_val_if_fail (seat != NULL, FALSE);
353 if (!seat->priv->can_switch || !seat_get_allow_guest (seat))
356 if (seat->priv->guest_username)
357 g_debug ("Switching to existing guest account %s", seat->priv->guest_username);
359 g_debug ("Switching to new guest account");
360 return switch_to_user_or_start_greeter (seat, seat->priv->guest_username, TRUE, session_name, TRUE);
364 seat_stop (Seat *seat)
366 g_return_if_fail (seat != NULL);
368 if (seat->priv->stopping)
371 g_debug ("Stopping seat");
372 seat->priv->stopping = TRUE;
373 SEAT_GET_CLASS (seat)->stop (seat);
377 seat_real_setup (Seat *seat)
379 if (seat->priv->config_section && config_has_key (config_get_instance (), seat->priv->config_section, "allow-guest"))
380 seat->priv->allow_guest = config_get_boolean (config_get_instance (), seat->priv->config_section, "allow-guest");
381 else if (config_has_key (config_get_instance (), "SeatDefaults", "allow-guest"))
382 seat->priv->allow_guest = config_get_boolean (config_get_instance (), "SeatDefaults", "allow-guest");
383 if (seat->priv->config_section && config_has_key (config_get_instance (), seat->priv->config_section, "autologin-guest"))
384 seat->priv->autologin_guest = config_get_boolean (config_get_instance (), seat->priv->config_section, "autologin-guest");
385 else if (config_has_key (config_get_instance (), "SeatDefaults", "autologin-guest"))
386 seat->priv->autologin_guest = config_get_boolean (config_get_instance (), "SeatDefaults", "autologin-guest");
387 if (seat->priv->config_section)
388 seat->priv->autologin_username = config_get_string (config_get_instance (), seat->priv->config_section, "autologin-user");
389 if (!seat->priv->autologin_username)
390 seat->priv->autologin_username = config_get_string (config_get_instance (), "SeatDefaults", "autologin-user");
391 if (seat->priv->config_section && config_has_key (config_get_instance (), seat->priv->config_section, "autologin-user-timeout"))
392 seat->priv->autologin_timeout = config_get_integer (config_get_instance (), seat->priv->config_section, "autologin-user-timeout");
394 seat->priv->autologin_timeout = config_get_integer (config_get_instance (), "SeatDefaults", "autologin-user-timeout");
395 if (seat->priv->autologin_timeout < 0)
396 seat->priv->autologin_timeout = 0;
400 seat_real_start (Seat *seat)
402 g_debug ("Starting seat");
404 /* Start showing a greeter */
405 if (seat->priv->autologin_username)
406 return switch_to_user_or_start_greeter (seat, seat->priv->autologin_username, FALSE, NULL, TRUE);
407 else if (seat->priv->autologin_guest)
408 return switch_to_user_or_start_greeter (seat, NULL, TRUE, NULL, TRUE);
410 return switch_to_user_or_start_greeter (seat, NULL, FALSE, NULL, FALSE);
414 seat_real_add_display (Seat *seat)
420 seat_real_set_active_display (Seat *seat, Display *display)
422 if (display == seat->priv->active_display)
425 if (seat->priv->active_display)
427 /* Stop the existing display if it is a greeter */
428 if (!display_get_username (seat->priv->active_display))
430 g_debug ("Stopping greeter display being switched from");
431 display_stop (seat->priv->active_display);
433 g_object_unref (seat->priv->active_display);
435 seat->priv->active_display = g_object_ref (display);
439 seat_real_stop (Seat *seat)
443 if (check_stopped (seat))
446 for (link = seat->priv->displays; link; link = link->next)
448 Display *display = link->data;
449 display_stop (display);
454 seat_init (Seat *seat)
456 seat->priv = G_TYPE_INSTANCE_GET_PRIVATE (seat, SEAT_TYPE, SeatPrivate);
460 seat_finalize (GObject *object)
464 self = SEAT (object);
466 g_free (self->priv->config_section);
467 g_list_free_full (self->priv->displays, g_object_unref);
468 if (self->priv->active_display)
469 g_object_unref (self->priv->active_display);
471 G_OBJECT_CLASS (seat_parent_class)->finalize (object);
475 seat_class_init (SeatClass *klass)
477 GObjectClass *object_class = G_OBJECT_CLASS (klass);
479 klass->setup = seat_real_setup;
480 klass->start = seat_real_start;
481 klass->add_display = seat_real_add_display;
482 klass->set_active_display = seat_real_set_active_display;
483 klass->stop = seat_real_stop;
485 object_class->finalize = seat_finalize;
487 g_type_class_add_private (klass, sizeof (SeatPrivate));
490 g_signal_new ("started",
491 G_TYPE_FROM_CLASS (klass),
493 G_STRUCT_OFFSET (SeatClass, started),
495 g_cclosure_marshal_VOID__VOID,
497 signals[DISPLAY_ADDED] =
498 g_signal_new ("display-added",
499 G_TYPE_FROM_CLASS (klass),
501 G_STRUCT_OFFSET (SeatClass, display_added),
503 g_cclosure_marshal_VOID__OBJECT,
504 G_TYPE_NONE, 1, DISPLAY_TYPE);
505 signals[DISPLAY_REMOVED] =
506 g_signal_new ("display-removed",
507 G_TYPE_FROM_CLASS (klass),
509 G_STRUCT_OFFSET (SeatClass, display_removed),
511 g_cclosure_marshal_VOID__OBJECT,
512 G_TYPE_NONE, 1, DISPLAY_TYPE);
514 g_signal_new ("stopped",
515 G_TYPE_FROM_CLASS (klass),
517 G_STRUCT_OFFSET (SeatClass, stopped),
519 g_cclosure_marshal_VOID__VOID,