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
18 #include "guest-account.h"
27 static guint signals[LAST_SIGNAL] = { 0 };
31 /* Configuration for this seat */
32 GHashTable *properties;
34 /* TRUE if able to switch users */
37 /* Name of guest account */
38 gchar *guest_username;
40 /* The displays for this seat */
43 /* The active display */
44 Display *active_display;
46 /* TRUE if stopping this seat (waiting for displays to stop) */
53 G_DEFINE_TYPE (Seat, seat, G_TYPE_OBJECT);
60 static GHashTable *seat_modules = NULL;
63 seat_register_module (const gchar *name, GType type)
68 seat_modules = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
70 g_debug ("Registered seat module %s", name);
72 module = g_malloc0 (sizeof (SeatModule));
73 module->name = g_strdup (name);
75 g_hash_table_insert (seat_modules, g_strdup (name), module);
79 seat_new (const gchar *module_name)
84 g_return_val_if_fail (module_name != NULL, NULL);
87 m = g_hash_table_lookup (seat_modules, module_name);
91 seat = g_object_new (m->type, NULL);
97 seat_set_property (Seat *seat, const gchar *name, const gchar *value)
99 g_return_if_fail (seat != NULL);
100 g_hash_table_insert (seat->priv->properties, g_strdup (name), g_strdup (value));
104 seat_has_property (Seat *seat, const gchar *name)
106 g_return_val_if_fail (seat != NULL, FALSE);
107 return g_hash_table_lookup (seat->priv->properties, name) != NULL;
111 seat_get_string_property (Seat *seat, const gchar *name)
113 g_return_val_if_fail (seat != NULL, NULL);
114 return g_hash_table_lookup (seat->priv->properties, name);
118 seat_get_boolean_property (Seat *seat, const gchar *name)
120 return g_strcmp0 (seat_get_string_property (seat, name), "true") == 0;
124 seat_get_integer_property (Seat *seat, const gchar *name)
128 value = seat_get_string_property (seat, name);
129 return value ? atoi (value) : 0;
133 seat_set_can_switch (Seat *seat, gboolean can_switch)
135 g_return_if_fail (seat != NULL);
137 seat->priv->can_switch = can_switch;
141 seat_start (Seat *seat)
143 g_return_val_if_fail (seat != NULL, FALSE);
145 SEAT_GET_CLASS (seat)->setup (seat);
146 return SEAT_GET_CLASS (seat)->start (seat);
150 seat_get_displays (Seat *seat)
152 g_return_val_if_fail (seat != NULL, NULL);
153 return seat->priv->displays;
157 seat_set_active_display (Seat *seat, Display *display)
159 g_return_if_fail (seat != NULL);
160 display_unlock (display);
161 SEAT_GET_CLASS (seat)->set_active_display (seat, display);
165 seat_get_active_display (Seat *seat)
167 g_return_val_if_fail (seat != NULL, NULL);
168 return seat->priv->active_display;
172 seat_get_can_switch (Seat *seat)
174 g_return_val_if_fail (seat != NULL, FALSE);
175 return seat->priv->can_switch;
179 seat_get_allow_guest (Seat *seat)
181 g_return_val_if_fail (seat != NULL, FALSE);
182 return seat_get_boolean_property (seat, "allow-guest") && guest_account_is_installed ();
186 switch_to_user (Seat *seat, const gchar *username)
190 /* Switch to active display if it exists */
191 for (link = seat->priv->displays; link; link = link->next)
193 Display *display = link->data;
195 /* If already logged in, then switch to that display */
196 if (g_strcmp0 (display_get_username (display), username) == 0)
198 // FIXME: Use display_get_name
199 g_debug ("Switching to user %s session on display %s", username, xserver_get_address (XSERVER (display_get_display_server (display))));
200 seat_set_active_display (seat, display);
209 display_switch_to_user_cb (Display *display, User *user, Seat *seat)
211 return switch_to_user (seat, user_get_name (user));
215 display_switch_to_guest_cb (Display *display, Seat *seat)
217 /* No guest account */
218 if (!seat->priv->guest_username)
221 return switch_to_user (seat, seat->priv->guest_username);
225 display_get_guest_username_cb (Display *display, Seat *seat)
227 if (seat->priv->guest_username)
228 return seat->priv->guest_username;
230 seat->priv->guest_username = guest_account_setup ();
231 return g_strdup (seat->priv->guest_username);
235 display_ready_cb (Display *display, Seat *seat)
237 /* Switch to this new display */
238 SEAT_GET_CLASS (seat)->set_active_display (seat, display);
242 display_session_stopped_cb (Display *display, Seat *seat)
246 session = display_get_session (display);
247 if (seat->priv->guest_username && strcmp (user_get_name (session_get_user (session)), seat->priv->guest_username) == 0)
249 guest_account_cleanup (seat->priv->guest_username);
250 g_free (seat->priv->guest_username);
251 seat->priv->guest_username = NULL;
256 check_stopped (Seat *seat)
258 if (seat->priv->stopping &&
259 !seat->priv->stopped &&
260 g_list_length (seat->priv->displays) == 0)
262 seat->priv->stopped = TRUE;
263 g_debug ("Seat stopped");
264 g_signal_emit (seat, signals[STOPPED], 0);
269 display_stopped_cb (Display *display, Seat *seat)
271 seat->priv->displays = g_list_remove (seat->priv->displays, display);
272 g_signal_handlers_disconnect_matched (display, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, seat);
273 g_signal_emit (seat, signals[DISPLAY_REMOVED], 0, display);
274 g_object_unref (display);
276 check_stopped (seat);
280 switch_to_user_or_start_greeter (Seat *seat, const gchar *username, gboolean is_guest, const gchar *session_name, gboolean autologin)
283 Display *new_display = NULL;
285 /* Switch to active display if it exists */
286 for (link = seat->priv->displays; link; link = link->next)
288 Display *display = link->data;
290 /* If already logged in, then switch to that display and stop the greeter display */
291 if (g_strcmp0 (display_get_username (display), username) == 0)
293 // FIXME: Use display_get_name
295 g_debug ("Switching to user %s session on display %s", username, xserver_get_address (XSERVER (display_get_display_server (display))));
297 g_debug ("Switching to greeter on display %s", xserver_get_address (XSERVER (display_get_display_server (display))));
298 seat_set_active_display (seat, display);
303 /* They don't exist, so start a greeter */
307 g_debug ("Starting new display for automatic guest login");
309 g_debug ("Starting new display for automatic login as user %s", username);
311 g_debug ("Starting new display for greeter");
316 g_debug ("Starting new display for greeter with guest selected");
318 g_debug ("Starting new display for greeter with user %s selected", username);
320 g_debug ("Starting new display for greeter");
323 new_display = SEAT_GET_CLASS (seat)->add_display (seat);
324 g_signal_connect (new_display, "switch-to-user", G_CALLBACK (display_switch_to_user_cb), seat);
325 g_signal_connect (new_display, "switch-to-guest", G_CALLBACK (display_switch_to_guest_cb), seat);
326 g_signal_connect (new_display, "get-guest-username", G_CALLBACK (display_get_guest_username_cb), seat);
327 g_signal_connect (new_display, "ready", G_CALLBACK (display_ready_cb), seat);
328 g_signal_connect (new_display, "session-stopped", G_CALLBACK (display_session_stopped_cb), seat);
329 g_signal_connect (new_display, "stopped", G_CALLBACK (display_stopped_cb), seat);
330 display_set_greeter_session (new_display, seat_get_string_property (seat, "greeter-session"));
331 display_set_session_wrapper (new_display, seat_get_string_property (seat, "session-wrapper"));
332 display_set_hide_users_hint (new_display, seat_get_boolean_property (seat, "greeter-hide-users"));
333 display_set_allow_guest (new_display, seat_get_allow_guest (seat));
335 display_set_autologin_user (new_display, username, is_guest, 0);
337 display_set_select_user_hint (new_display, username, is_guest);
339 session_name = seat_get_string_property (seat, "user-session");
340 display_set_user_session (new_display, session_name);
342 seat->priv->displays = g_list_append (seat->priv->displays, new_display);
343 g_signal_emit (seat, signals[DISPLAY_ADDED], 0, new_display);
345 /* Switch to this new display */
346 if (!seat->priv->active_display)
347 seat_set_active_display (seat, new_display);
349 return display_start (new_display);
353 seat_switch_to_greeter (Seat *seat)
355 g_return_val_if_fail (seat != NULL, FALSE);
357 if (!seat->priv->can_switch)
360 g_debug ("Switching to greeter");
361 return switch_to_user_or_start_greeter (seat, NULL, FALSE, NULL, FALSE);
365 seat_switch_to_user (Seat *seat, const gchar *username, const gchar *session_name)
367 g_return_val_if_fail (seat != NULL, FALSE);
368 g_return_val_if_fail (username != NULL, FALSE);
370 if (!seat->priv->can_switch)
373 g_debug ("Switching to user %s", username);
374 return switch_to_user_or_start_greeter (seat, username, FALSE, session_name, FALSE);
378 seat_switch_to_guest (Seat *seat, const gchar *session_name)
380 g_return_val_if_fail (seat != NULL, FALSE);
382 if (!seat->priv->can_switch || !seat_get_allow_guest (seat))
385 if (seat->priv->guest_username)
386 g_debug ("Switching to existing guest account %s", seat->priv->guest_username);
388 g_debug ("Switching to new guest account");
389 return switch_to_user_or_start_greeter (seat, seat->priv->guest_username, TRUE, session_name, TRUE);
393 seat_stop (Seat *seat)
395 g_return_if_fail (seat != NULL);
397 if (seat->priv->stopping)
400 g_debug ("Stopping seat");
401 seat->priv->stopping = TRUE;
402 SEAT_GET_CLASS (seat)->stop (seat);
406 seat_get_is_stopping (Seat *seat)
408 g_return_val_if_fail (seat != NULL, FALSE);
409 return seat->priv->stopping;
413 seat_real_setup (Seat *seat)
418 seat_real_start (Seat *seat)
420 const gchar *autologin_username;
422 g_debug ("Starting seat");
424 /* Start showing a greeter */
425 autologin_username = seat_get_string_property (seat, "autologin-user");
426 if (autologin_username)
427 return switch_to_user_or_start_greeter (seat, autologin_username, FALSE, NULL, TRUE);
428 else if (seat_get_boolean_property (seat, "autologin-guest"))
429 return switch_to_user_or_start_greeter (seat, NULL, TRUE, NULL, TRUE);
431 return switch_to_user_or_start_greeter (seat, NULL, FALSE, NULL, FALSE);
435 seat_real_add_display (Seat *seat)
441 seat_real_set_active_display (Seat *seat, Display *display)
443 if (display == seat->priv->active_display)
446 if (seat->priv->active_display)
448 /* Stop the existing display if it is a greeter */
449 if (!display_get_username (seat->priv->active_display))
451 g_debug ("Stopping greeter display being switched from");
452 display_stop (seat->priv->active_display);
454 g_object_unref (seat->priv->active_display);
456 seat->priv->active_display = g_object_ref (display);
460 seat_real_stop (Seat *seat)
464 check_stopped (seat);
465 if (seat->priv->stopped)
468 for (link = seat->priv->displays; link; link = link->next)
470 Display *display = link->data;
471 display_stop (display);
476 seat_init (Seat *seat)
478 seat->priv = G_TYPE_INSTANCE_GET_PRIVATE (seat, SEAT_TYPE, SeatPrivate);
479 seat->priv->properties = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
483 seat_finalize (GObject *object)
487 self = SEAT (object);
489 g_hash_table_unref (self->priv->properties);
490 g_free (self->priv->guest_username);
491 g_list_free_full (self->priv->displays, g_object_unref);
492 if (self->priv->active_display)
493 g_object_unref (self->priv->active_display);
495 G_OBJECT_CLASS (seat_parent_class)->finalize (object);
499 seat_class_init (SeatClass *klass)
501 GObjectClass *object_class = G_OBJECT_CLASS (klass);
503 klass->setup = seat_real_setup;
504 klass->start = seat_real_start;
505 klass->add_display = seat_real_add_display;
506 klass->set_active_display = seat_real_set_active_display;
507 klass->stop = seat_real_stop;
509 object_class->finalize = seat_finalize;
511 g_type_class_add_private (klass, sizeof (SeatPrivate));
514 g_signal_new ("started",
515 G_TYPE_FROM_CLASS (klass),
517 G_STRUCT_OFFSET (SeatClass, started),
519 g_cclosure_marshal_VOID__VOID,
521 signals[DISPLAY_ADDED] =
522 g_signal_new ("display-added",
523 G_TYPE_FROM_CLASS (klass),
525 G_STRUCT_OFFSET (SeatClass, display_added),
527 g_cclosure_marshal_VOID__OBJECT,
528 G_TYPE_NONE, 1, DISPLAY_TYPE);
529 signals[DISPLAY_REMOVED] =
530 g_signal_new ("display-removed",
531 G_TYPE_FROM_CLASS (klass),
533 G_STRUCT_OFFSET (SeatClass, display_removed),
535 g_cclosure_marshal_VOID__OBJECT,
536 G_TYPE_NONE, 1, DISPLAY_TYPE);
538 g_signal_new ("stopped",
539 G_TYPE_FROM_CLASS (klass),
541 G_STRUCT_OFFSET (SeatClass, stopped),
543 g_cclosure_marshal_VOID__VOID,