]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - src/seat.c
Merge with trunk
[sojka/lightdm.git] / src / seat.c
1 /*
2  * Copyright (C) 2010-2011 Robert Ancell.
3  * Author: Robert Ancell <robert.ancell@canonical.com>
4  * 
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
9  * license.
10  */
11
12 #include <stdlib.h>
13 #include <string.h>
14 #include <sys/wait.h>
15
16 #include "seat.h"
17 #include "guest-account.h"
18
19 enum {
20     DISPLAY_ADDED,
21     DISPLAY_REMOVED,
22     STOPPED,
23     LAST_SIGNAL
24 };
25 static guint signals[LAST_SIGNAL] = { 0 };
26
27 struct SeatPrivate
28 {
29     /* Configuration for this seat */
30     GHashTable *properties;
31
32     /* TRUE if able to switch users */
33     gboolean can_switch;
34
35     /* TRUE if display server can be shared for sessions */
36     gboolean share_display_server;
37
38     /* Name of guest account */
39     gchar *guest_username;
40
41     /* The displays for this seat */
42     GList *displays;
43
44     /* TRUE if stopping this seat (waiting for displays to stop) */
45     gboolean stopping;
46
47     /* TRUE if stopped */
48     gboolean stopped;
49 };
50
51 G_DEFINE_TYPE (Seat, seat, G_TYPE_OBJECT);
52
53 typedef struct
54 {
55     const gchar *name;
56     GType type;
57 } SeatModule;
58 static GHashTable *seat_modules = NULL;
59
60 static Display *create_display (Seat *seat);
61
62 void
63 seat_register_module (const gchar *name, GType type)
64 {
65     SeatModule *module;
66
67     if (!seat_modules)
68         seat_modules = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
69
70     g_debug ("Registered seat module %s", name);
71
72     module = g_malloc0 (sizeof (SeatModule));
73     module->name = g_strdup (name);
74     module->type = type;
75     g_hash_table_insert (seat_modules, g_strdup (name), module);
76 }
77
78 Seat *
79 seat_new (const gchar *module_name)
80 {
81     Seat *seat;
82     SeatModule *m = NULL;
83   
84     g_return_val_if_fail (module_name != NULL, NULL);
85
86     if (seat_modules)
87         m = g_hash_table_lookup (seat_modules, module_name);
88     if (!m)
89         return NULL;
90
91     seat = g_object_new (m->type, NULL);
92
93     return seat;
94 }
95
96 void
97 seat_set_property (Seat *seat, const gchar *name, const gchar *value)
98 {
99     g_return_if_fail (seat != NULL);
100     g_hash_table_insert (seat->priv->properties, g_strdup (name), g_strdup (value));
101 }
102
103 gboolean
104 seat_has_property (Seat *seat, const gchar *name)
105 {
106     g_return_val_if_fail (seat != NULL, FALSE);
107     return g_hash_table_lookup (seat->priv->properties, name) != NULL;
108 }
109
110 const gchar *
111 seat_get_string_property (Seat *seat, const gchar *name)
112 {
113     g_return_val_if_fail (seat != NULL, NULL);
114     return g_hash_table_lookup (seat->priv->properties, name);
115 }
116
117 gboolean
118 seat_get_boolean_property (Seat *seat, const gchar *name)
119 {
120     return g_strcmp0 (seat_get_string_property (seat, name), "true") == 0;
121 }
122
123 gint
124 seat_get_integer_property (Seat *seat, const gchar *name)
125 {
126     const gchar *value;
127
128     value = seat_get_string_property (seat, name);
129     return value ? atoi (value) : 0;
130 }
131
132 void
133 seat_set_can_switch (Seat *seat, gboolean can_switch)
134 {
135     g_return_if_fail (seat != NULL);
136
137     seat->priv->can_switch = can_switch;
138 }
139
140 void
141 seat_set_share_display_server (Seat *seat, gboolean share_display_server)
142 {
143     g_return_if_fail (seat != NULL);
144
145     seat->priv->share_display_server = share_display_server;
146 }
147
148 gboolean
149 seat_start (Seat *seat)
150 {
151     g_return_val_if_fail (seat != NULL, FALSE);
152   
153     SEAT_GET_CLASS (seat)->setup (seat);
154     return SEAT_GET_CLASS (seat)->start (seat);
155 }
156
157 GList *
158 seat_get_displays (Seat *seat)
159 {
160     g_return_val_if_fail (seat != NULL, NULL);
161     return seat->priv->displays;
162 }
163
164 void
165 seat_set_active_display (Seat *seat, Display *display)
166 {
167     g_return_if_fail (seat != NULL);
168     SEAT_GET_CLASS (seat)->set_active_display (seat, display);
169 }
170
171 Display *
172 seat_get_active_display (Seat *seat)
173 {
174     g_return_val_if_fail (seat != NULL, NULL);
175     return SEAT_GET_CLASS (seat)->get_active_display (seat);
176 }
177
178 gboolean
179 seat_get_can_switch (Seat *seat)
180 {
181     g_return_val_if_fail (seat != NULL, FALSE);
182     return seat->priv->can_switch;
183 }
184
185 gboolean
186 seat_get_allow_guest (Seat *seat)
187 {
188     g_return_val_if_fail (seat != NULL, FALSE);  
189     return seat_get_boolean_property (seat, "allow-guest") && guest_account_is_installed ();
190 }
191
192 gboolean
193 seat_get_greeter_allow_guest (Seat *seat)
194 {
195     g_return_val_if_fail (seat != NULL, FALSE);  
196     return seat_get_allow_guest (seat) && seat_get_boolean_property (seat, "greeter-allow-guest");
197 }
198
199 static gboolean
200 switch_to_user (Seat *seat, const gchar *username, gboolean unlock)
201 {
202     GList *link;
203
204     /* Switch to active display if it exists */
205     for (link = seat->priv->displays; link; link = link->next)
206     {
207         Display *display = link->data;
208
209         if (display_get_is_stopped (display))
210             continue;
211
212         /* If already logged in, then switch to that display */
213         if (g_strcmp0 (display_get_username (display), username) == 0)        
214         {
215             if (username)
216                 g_debug ("Switching to existing session for user %s", username);
217             else
218                 g_debug ("Switching to existing greeter");
219             if (unlock)
220                 display_unlock (display);
221             seat_set_active_display (seat, display);
222             return TRUE;
223         }
224     }
225
226     return FALSE;
227 }
228
229 static gboolean
230 display_switch_to_user_cb (Display *display, User *user, Seat *seat)
231 {
232     return switch_to_user (seat, user_get_name (user), TRUE);
233 }
234
235 static gboolean
236 display_switch_to_guest_cb (Display *display, Seat *seat)
237 {
238     /* No guest account */
239     if (!seat->priv->guest_username)
240         return FALSE;
241
242     return switch_to_user (seat, seat->priv->guest_username, TRUE);
243 }
244
245 static const gchar *
246 display_get_guest_username_cb (Display *display, Seat *seat)
247 {
248     if (seat->priv->guest_username)
249         return seat->priv->guest_username;
250
251     seat->priv->guest_username = guest_account_setup ();
252     return g_strdup (seat->priv->guest_username);
253 }
254
255 static gboolean
256 run_script (Seat *seat, Display *display, const gchar *script_name, User *user)
257 {
258     Process *script;
259     gboolean result = FALSE;
260   
261     script = process_new ();
262
263     process_set_command (script, script_name);
264
265     /* Set POSIX variables */
266     process_set_clear_environment (script, TRUE);
267     process_set_env (script, "SHELL", "/bin/sh");
268
269     /* Variables required for regression tests */
270     if (g_getenv ("LIGHTDM_TEST_ROOT"))
271     {
272         process_set_env (script, "LIGHTDM_TEST_ROOT", g_getenv ("LIGHTDM_TEST_ROOT"));
273         process_set_env (script, "LD_PRELOAD", g_getenv ("LD_PRELOAD"));
274         process_set_env (script, "LD_LIBRARY_PATH", g_getenv ("LD_LIBRARY_PATH"));
275         process_set_env (script, "PATH", g_getenv ("PATH"));
276     }
277     else
278         process_set_env (script, "PATH", "/usr/local/bin:/usr/bin:/bin");
279
280     if (user)
281     {
282         process_set_env (script, "USER", user_get_name (user));
283         process_set_env (script, "LOGNAME", user_get_name (user));
284         process_set_env (script, "HOME", user_get_home_directory (user));
285     }
286     else
287         process_set_env (script, "HOME", "/");
288
289     SEAT_GET_CLASS (seat)->run_script (seat, display, script);
290
291     if (process_start (script, TRUE))
292     {
293         int exit_status;
294
295         exit_status = process_get_exit_status (script);
296         if (WIFEXITED (exit_status))
297         {
298             g_debug ("Exit status of %s: %d", script_name, WEXITSTATUS (exit_status));
299             result = WEXITSTATUS (exit_status) == EXIT_SUCCESS;
300         }
301     }
302
303     g_object_unref (script);
304
305     return result;
306 }
307
308 static void
309 seat_real_run_script (Seat *seat, Display *display, Process *process)
310 {  
311 }
312
313 static void
314 emit_upstart_signal (const gchar *signal)
315 {
316     g_return_if_fail (signal != NULL);
317     g_return_if_fail (signal[0] != 0);
318
319     if (getuid () != 0)
320         return;
321
322     gchar *cmd = g_strdup_printf ("initctl -q emit %s DISPLAY_MANAGER=lightdm", signal);
323     g_spawn_command_line_async (cmd, NULL); /* OK if it fails, probably not installed */
324     g_free (cmd);
325 }
326
327 static gboolean
328 display_display_server_ready_cb (Display *display, Seat *seat)
329 {
330     const gchar *script;
331
332     /* Run setup script */
333     script = seat_get_string_property (seat, "display-setup-script");
334     if (script && !run_script (seat, display, script, NULL))
335         return FALSE;
336
337     emit_upstart_signal ("login-session-start");
338
339     return TRUE;
340 }
341
342 static Session *
343 display_create_session_cb (Display *display, Seat *seat)
344 {
345     return SEAT_GET_CLASS (seat)->create_session (seat, display);
346 }
347
348 static gboolean
349 display_start_greeter_cb (Display *display, Seat *seat)
350 {
351     Session *session;
352     const gchar *script;
353
354     session = display_get_session (display);
355
356     script = seat_get_string_property (seat, "greeter-setup-script");
357     if (script)
358         return !run_script (seat, display, script, session_get_user (session));
359     else
360         return FALSE;
361 }
362
363 static gboolean
364 display_start_session_cb (Display *display, Seat *seat)
365 {
366     Session *session;
367     const gchar *script;
368
369     session = display_get_session (display);
370
371     script = seat_get_string_property (seat, "session-setup-script");
372     if (script)
373         return !run_script (seat, display, script, session_get_user (session));
374     else
375         return FALSE;
376 }
377
378 static void
379 session_stopped_cb (Session *session, Seat *seat)
380 {
381     Display *display = NULL;
382     GList *link;
383     const gchar *script;
384   
385     /* Work out what display this session is on, it's a bit hacky because we really should know already... */
386     for (link = seat->priv->displays; link; link = link->next)
387     {
388         Display *d = link->data;
389         if (display_get_session (d) == session)
390         {
391             display = d;
392             break;
393         }
394     }
395     g_return_if_fail (display != NULL);
396
397     /* Cleanup */
398     script = seat_get_string_property (seat, "session-cleanup-script");
399     if (script)
400         run_script (seat, display, script, session_get_user (session));
401
402     if (seat->priv->guest_username && strcmp (session_get_username (session), seat->priv->guest_username) == 0)
403     {
404         g_free (seat->priv->guest_username);
405         seat->priv->guest_username = NULL;
406     }
407 }
408
409 static gboolean
410 display_session_started_cb (Display *display, Seat *seat)
411 {
412     g_signal_connect (display_get_session (display), "stopped", G_CALLBACK (session_stopped_cb), seat);
413     emit_upstart_signal ("desktop-session-start");
414     return FALSE;
415 }
416
417 static void
418 display_ready_cb (Display *display, Seat *seat)
419 {
420     /* Switch to this new display */
421     g_debug ("New display ready, switching to it");
422     SEAT_GET_CLASS (seat)->set_active_display (seat, display);
423 }
424
425 static Display *
426 display_create_display_cb (Display *display, Session *session, Seat *seat)
427 {
428     Display *d;
429
430     d = create_display (seat);
431     g_signal_connect (d, "ready", G_CALLBACK (display_ready_cb), seat);
432     g_signal_emit (seat, signals[DISPLAY_ADDED], 0, d);
433
434     display_start_with_session (d, session);
435
436     return g_object_ref (d);
437 }
438
439 static void
440 check_stopped (Seat *seat)
441 {
442     if (seat->priv->stopping &&
443         !seat->priv->stopped &&
444         g_list_length (seat->priv->displays) == 0)
445     {
446         seat->priv->stopped = TRUE;
447         g_debug ("Seat stopped");
448         g_signal_emit (seat, signals[STOPPED], 0);
449     }
450 }
451
452 static void
453 display_stopped_cb (Display *display, Seat *seat)
454 {
455     gboolean is_active;
456
457     is_active = display == seat_get_active_display (seat);
458
459     g_signal_handlers_disconnect_matched (display, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, seat);
460     seat->priv->displays = g_list_remove (seat->priv->displays, display);
461
462     g_signal_emit (seat, signals[DISPLAY_REMOVED], 0, display);
463
464     /* If no more displays running either start a greeter or stop the seat */
465     if (!seat->priv->stopping)
466     {
467         if (g_list_length (seat->priv->displays) == 0)
468         {
469             /* If failed to start then stop this seat */
470             if (!display_get_is_ready (display))
471             {
472                 g_debug ("Stopping seat, failed to start a display");
473                 seat_stop (seat);
474             }
475             /* Attempt to start a greeter */
476             else if (!seat->priv->can_switch)
477             {
478                 g_debug ("Stopping seat, display stopped");
479                 seat_stop (seat);             
480             }
481             
482             else if (!seat_switch_to_greeter (seat))
483             {
484                 g_debug ("Stopping seat, unable to start greeter");
485                 seat_stop (seat);
486             }        
487         }
488         else if (is_active)
489         {
490             g_debug ("Active display stopped, switching to greeter");
491             if (!seat_switch_to_greeter (seat))
492             {
493                 g_debug ("Stopping seat, unable to start greeter");
494                 seat_stop (seat);              
495             }
496         }
497     }
498
499     g_object_unref (display);
500
501     check_stopped (seat);
502 }
503
504 static Display *
505 create_display (Seat *seat)
506 {
507     Display *display;
508     DisplayServer *display_server;
509
510     display_server = SEAT_GET_CLASS (seat)->create_display_server (seat);
511     display = display_new (display_server);
512     g_object_unref (display_server);
513
514     g_signal_connect (display, "display-server-ready", G_CALLBACK (display_display_server_ready_cb), seat);  
515     g_signal_connect (display, "switch-to-user", G_CALLBACK (display_switch_to_user_cb), seat);
516     g_signal_connect (display, "switch-to-guest", G_CALLBACK (display_switch_to_guest_cb), seat);
517     g_signal_connect (display, "get-guest-username", G_CALLBACK (display_get_guest_username_cb), seat);
518     g_signal_connect (display, "create-session", G_CALLBACK (display_create_session_cb), seat);
519     g_signal_connect (display, "start-greeter", G_CALLBACK (display_start_greeter_cb), seat);
520     g_signal_connect (display, "start-session", G_CALLBACK (display_start_session_cb), seat);
521     g_signal_connect_after (display, "start-session", G_CALLBACK (display_session_started_cb), seat);
522     g_signal_connect (display, "create-display", G_CALLBACK (display_create_display_cb), seat);
523     g_signal_connect (display, "stopped", G_CALLBACK (display_stopped_cb), seat);
524     display_set_greeter_session (display, seat_get_string_property (seat, "greeter-session"));
525     display_set_session_wrapper (display, seat_get_string_property (seat, "session-wrapper"));
526     display_set_greeter_wrapper (display, seat_get_string_property (seat, "greeter-wrapper"));
527     display_set_hide_users_hint (display, seat_get_boolean_property (seat, "greeter-hide-users"));
528     display_set_show_manual_login_hint (display, seat_get_boolean_property (seat, "greeter-show-manual-login"));
529     display_set_show_remote_login_hint (display, seat_get_boolean_property (seat, "greeter-show-remote-login"));
530     display_set_allow_guest (display, seat_get_allow_guest (seat));
531     display_set_greeter_allow_guest (display, seat_get_greeter_allow_guest (seat));
532     display_set_user_session (display, SESSION_TYPE_LOCAL, seat_get_string_property (seat, "user-session"));
533     display_set_share_display_server (display, seat->priv->share_display_server);
534
535     seat->priv->displays = g_list_append (seat->priv->displays, display);
536
537     return display;
538 }
539
540 static gboolean
541 start_display (Seat *seat, Display *display)
542 {
543     g_signal_emit (seat, signals[DISPLAY_ADDED], 0, display);
544
545     /* Switch to this display if currently not looking at anything */
546     if (seat_get_active_display (seat) == NULL)
547         seat_set_active_display (seat, display);
548
549     return display_start (display);
550 }
551
552 gboolean
553 seat_switch_to_greeter (Seat *seat)
554 {
555     Display *display;
556
557     g_return_val_if_fail (seat != NULL, FALSE);
558
559     if (!seat->priv->can_switch)
560         return FALSE;
561
562     g_debug ("Switching to greeter");
563
564     /* Switch to greeter if one open (shouldn't be though) */
565     if (switch_to_user (seat, NULL, FALSE))
566         return TRUE;
567
568     g_debug ("Starting new display for greeter");
569
570     display = create_display (seat);
571     g_signal_connect (display, "ready", G_CALLBACK (display_ready_cb), seat);
572
573     return start_display (seat, display);
574 }
575
576 gboolean
577 seat_switch_to_user (Seat *seat, const gchar *username, const gchar *session_name)
578 {
579     Display *display;
580
581     g_return_val_if_fail (seat != NULL, FALSE);
582     g_return_val_if_fail (username != NULL, FALSE);
583
584     if (!seat->priv->can_switch)
585         return FALSE;
586
587     g_debug ("Switching to user %s", username);
588
589     /* Switch to session if one open */
590     if (switch_to_user (seat, username, FALSE))
591         return TRUE;
592
593     if (username)
594         g_debug ("Starting new display for greeter with user %s selected", username);
595     else
596         g_debug ("Starting new display for greeter");
597
598     display = create_display (seat);
599     g_signal_connect (display, "ready", G_CALLBACK (display_ready_cb), seat);
600     display_set_select_user_hint (display, username, FALSE, TRUE);
601     if (session_name != NULL)
602         display_set_user_session (display, SESSION_TYPE_LOCAL, session_name);
603
604     return start_display (seat, display);
605 }
606
607 gboolean
608 seat_switch_to_guest (Seat *seat, const gchar *session_name)
609 {
610     Display *display;
611
612     g_return_val_if_fail (seat != NULL, FALSE);
613
614     if (!seat->priv->can_switch || !seat_get_allow_guest (seat))
615         return FALSE;
616
617     /* Switch to session if one open */
618     if (seat->priv->guest_username)
619     {
620         g_debug ("Switching to existing guest account %s", seat->priv->guest_username);
621         return switch_to_user (seat, seat->priv->guest_username, FALSE);
622     }
623
624     g_debug ("Starting new display for automatic guest login");
625
626     display = create_display (seat);
627     g_signal_connect (display, "ready", G_CALLBACK (display_ready_cb), seat);
628     display_set_autologin_user (display, NULL, TRUE, 0);
629     if (session_name != NULL)
630         display_set_user_session (display, SESSION_TYPE_LOCAL, session_name);
631
632     return start_display (seat, display);
633 }
634
635 gboolean
636 seat_lock (Seat *seat, const gchar *username)
637 {
638     Display *display;
639
640     g_return_val_if_fail (seat != NULL, FALSE);
641
642     if (!seat->priv->can_switch)
643         return FALSE;
644
645     g_debug ("Locking seat");
646
647     /* Switch to greeter if one open (shouldn't be though) */
648     if (switch_to_user (seat, NULL, FALSE))
649         return TRUE;
650
651     g_debug ("Starting new display for greeter (lock screen)");
652
653     display = create_display (seat);
654     g_signal_connect (display, "ready", G_CALLBACK (display_ready_cb), seat);
655     display_set_lock_hint (display, TRUE);
656     display_set_select_user_hint (display, username, FALSE, FALSE);
657
658     return start_display (seat, display);
659 }
660
661 void
662 seat_stop (Seat *seat)
663 {
664     g_return_if_fail (seat != NULL);
665
666     if (seat->priv->stopping)
667         return;
668
669     g_debug ("Stopping seat");
670     seat->priv->stopping = TRUE;
671     SEAT_GET_CLASS (seat)->stop (seat);
672 }
673
674 gboolean
675 seat_get_is_stopping (Seat *seat)
676 {
677     g_return_val_if_fail (seat != NULL, FALSE);
678     return seat->priv->stopping;
679 }
680
681 static void
682 seat_real_setup (Seat *seat)
683 {
684 }
685
686 static void
687 autologin_greeter_ready_cb (Display *display, Seat *seat)
688 {
689     const gchar *autologin_username;
690     gboolean autologin_guest;
691     Display *autologin_display;
692
693     g_debug ("Greeter ready, starting autologin session");
694
695     /* Get autologin settings */
696     autologin_username = seat_get_string_property (seat, "autologin-user");
697     if (g_strcmp0 (autologin_username, "") == 0)
698         autologin_username = NULL;
699     autologin_guest = seat_get_boolean_property (seat, "autologin-guest");
700
701     if (autologin_guest)
702         g_debug ("Starting new display for automatic guest login");
703     else if (autologin_username)
704         g_debug ("Starting new display for automatic login as user %s", autologin_username);
705
706     autologin_display = create_display (seat);
707     display_set_autologin_user (autologin_display, autologin_username, autologin_guest, 0);
708
709     start_display (seat, autologin_display);
710 }
711
712 static gboolean
713 seat_real_start (Seat *seat)
714 {
715     const gchar *autologin_username;
716     int autologin_timeout;
717     gboolean autologin_guest;
718     gboolean do_autologin;
719     gboolean autologin_in_background;
720     Display *display;
721
722     g_debug ("Starting seat");
723
724     /* Get autologin settings */
725     autologin_username = seat_get_string_property (seat, "autologin-user");
726     if (g_strcmp0 (autologin_username, "") == 0)
727         autologin_username = NULL;
728     autologin_timeout = seat_get_integer_property (seat, "autologin-user-timeout");
729     autologin_guest = seat_get_boolean_property (seat, "autologin-guest");
730     autologin_in_background = seat_get_boolean_property (seat, "autologin-in-background");
731     do_autologin = autologin_username != NULL || autologin_guest;
732
733     /* Background automatic logins need the greeter showing first */
734     if (do_autologin && autologin_in_background && !switch_to_user (seat, NULL, FALSE)) 
735     {
736         g_debug ("Autologin in background, opening greeter first");
737         display = create_display (seat);
738         g_signal_connect (display, "ready", G_CALLBACK (autologin_greeter_ready_cb), seat);
739         if (autologin_timeout > 0)
740             display_set_autologin_user (display, autologin_username, autologin_guest, autologin_timeout);
741         return start_display (seat, display);
742     }
743
744     if (autologin_guest)
745         g_debug ("Starting new display for automatic guest login");
746     else if (autologin_username)
747         g_debug ("Starting new display for automatic login as user %s", autologin_username);
748     else
749         g_debug ("Starting new display for greeter");
750
751     display = create_display (seat);
752     g_signal_connect (display, "ready", G_CALLBACK (display_ready_cb), seat);
753     display_set_autologin_user (display, autologin_username, autologin_guest, autologin_timeout);
754
755     return start_display (seat, display);
756 }
757
758 static void
759 seat_real_set_active_display (Seat *seat, Display *display)
760 {
761     GList *link;
762
763     for (link = seat->priv->displays; link; link = link->next)
764     {
765         Display *d = link->data;
766
767         if (d == display)
768             continue;
769
770         /* Stop any greeters and lock any other sessions */
771         if (!display_get_username (d))
772         {
773             g_debug ("Stopping background greeter");
774             display_stop (d);
775         }
776         else
777             display_lock (d);
778     }  
779 }
780
781 static Display *
782 seat_real_get_active_display (Seat *seat)
783 {
784     return NULL;
785 }
786
787 static void
788 seat_real_stop (Seat *seat)
789 {
790     GList *displays, *link;
791
792     check_stopped (seat);
793     if (seat->priv->stopped)
794         return;
795
796     /* Stop all the displays on the seat. Copy the list as it might be modified if a display stops during this loop */
797     displays = g_list_copy (seat->priv->displays);
798     for (link = displays; link; link = link->next)
799     {
800         Display *display = link->data;
801         display_stop (display);
802     }
803     g_list_free (displays);
804 }
805
806 static void
807 seat_init (Seat *seat)
808 {
809     seat->priv = G_TYPE_INSTANCE_GET_PRIVATE (seat, SEAT_TYPE, SeatPrivate);
810     seat->priv->properties = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
811     seat->priv->share_display_server = TRUE;
812 }
813
814 static void
815 seat_finalize (GObject *object)
816 {
817     Seat *self;
818     GList *link;
819
820     self = SEAT (object);
821
822     g_hash_table_unref (self->priv->properties);
823     g_free (self->priv->guest_username);
824     for (link = self->priv->displays; link; link = link->next)
825     {
826         Display *display = link->data;
827         g_signal_handlers_disconnect_matched (display, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);
828     }  
829     g_list_free_full (self->priv->displays, g_object_unref);
830
831     G_OBJECT_CLASS (seat_parent_class)->finalize (object);
832 }
833
834 static void
835 seat_class_init (SeatClass *klass)
836 {
837     GObjectClass *object_class = G_OBJECT_CLASS (klass);
838
839     klass->setup = seat_real_setup;
840     klass->start = seat_real_start;
841     klass->set_active_display = seat_real_set_active_display;
842     klass->get_active_display = seat_real_get_active_display;
843     klass->run_script = seat_real_run_script;
844     klass->stop = seat_real_stop;
845
846     object_class->finalize = seat_finalize;
847
848     g_type_class_add_private (klass, sizeof (SeatPrivate));
849
850     signals[DISPLAY_ADDED] =
851         g_signal_new ("display-added",
852                       G_TYPE_FROM_CLASS (klass),
853                       G_SIGNAL_RUN_LAST,
854                       G_STRUCT_OFFSET (SeatClass, display_added),
855                       NULL, NULL,
856                       NULL,
857                       G_TYPE_NONE, 1, DISPLAY_TYPE);
858     signals[DISPLAY_REMOVED] =
859         g_signal_new ("display-removed",
860                       G_TYPE_FROM_CLASS (klass),
861                       G_SIGNAL_RUN_LAST,
862                       G_STRUCT_OFFSET (SeatClass, display_removed),
863                       NULL, NULL,
864                       NULL,
865                       G_TYPE_NONE, 1, DISPLAY_TYPE);
866     signals[STOPPED] =
867         g_signal_new ("stopped",
868                       G_TYPE_FROM_CLASS (klass),
869                       G_SIGNAL_RUN_LAST,
870                       G_STRUCT_OFFSET (SeatClass, stopped),
871                       NULL, NULL,
872                       NULL,
873                       G_TYPE_NONE, 0);
874 }