]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - libldmgreeter/greeter.c
Change language/layout/session when user selected in GTK+ greeter
[sojka/lightdm.git] / libldmgreeter / greeter.c
1 /*
2  * Copyright (C) 2010 Robert Ancell.
3  * Author: Robert Ancell <robert.ancell@canonical.com>
4  * 
5  * This library is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU Lesser General Public License as published by the Free
7  * Software Foundation; either version 3 of the License, or (at your option) any
8  * later version. See http://www.gnu.org/copyleft/lgpl.html the full text of the
9  * license.
10  */
11
12 #include <stdlib.h>
13 #include <string.h>
14 #include <locale.h>
15 #include <sys/utsname.h>
16
17 #include <gio/gdesktopappinfo.h>
18 #include <dbus/dbus-glib.h>
19 #include <security/pam_appl.h>
20 #include <libxklavier/xklavier.h>
21
22 #include "greeter.h"
23
24 enum {
25     PROP_0,
26     PROP_HOSTNAME,  
27     PROP_NUM_USERS,
28     PROP_USERS,
29     PROP_DEFAULT_LANGUAGE,
30     PROP_LAYOUTS,
31     PROP_LAYOUT,
32     PROP_SESSIONS,
33     PROP_DEFAULT_SESSION,
34     PROP_TIMED_LOGIN_USER,
35     PROP_TIMED_LOGIN_DELAY,
36     PROP_AUTHENTICATION_USER,
37     PROP_IS_AUTHENTICATED,
38     PROP_CAN_SUSPEND,
39     PROP_CAN_HIBERNATE,
40     PROP_CAN_RESTART,
41     PROP_CAN_SHUTDOWN
42 };
43
44 enum {
45     SHOW_PROMPT,
46     SHOW_MESSAGE,
47     SHOW_ERROR,
48     AUTHENTICATION_COMPLETE,
49     TIMED_LOGIN,
50     QUIT,
51     LAST_SIGNAL
52 };
53 static guint signals[LAST_SIGNAL] = { 0 };
54
55 struct _LdmGreeterPrivate
56 {
57     DBusGConnection *lightdm_bus;
58
59     DBusGConnection *system_bus;
60
61     DBusGProxy *display_proxy, *session_proxy, *user_proxy;
62
63     Display *display;
64
65     gchar *hostname;
66
67     gchar *theme;
68     GKeyFile *theme_file;
69
70     gboolean have_users;
71     GList *users;
72
73     gchar *default_language;  
74     gboolean have_languages;
75     GList *languages;
76
77     gchar *default_layout;
78     XklEngine *xkl_engine;
79     XklConfigRec *xkl_config;
80     gboolean have_layouts;
81     GList *layouts;
82     gchar *layout;
83
84     gboolean have_sessions;
85     GList *sessions;
86     gchar *default_session;
87
88     gchar *authentication_user;
89     gboolean is_authenticated;
90
91     gchar *timed_user;
92     gint login_delay;
93     guint login_timeout;
94 };
95
96 G_DEFINE_TYPE (LdmGreeter, ldm_greeter, G_TYPE_OBJECT);
97
98 /**
99  * ldm_greeter_new:
100  * 
101  * Create a new greeter.
102  * 
103  * Return value: the new #LdmGreeter
104  **/
105 LdmGreeter *
106 ldm_greeter_new ()
107 {
108     return g_object_new (LDM_TYPE_GREETER, NULL);
109 }
110
111 static gboolean
112 timed_login_cb (gpointer data)
113 {
114     LdmGreeter *greeter = data;
115
116     greeter->priv->login_timeout = 0;
117     g_signal_emit (G_OBJECT (greeter), signals[TIMED_LOGIN], 0, greeter->priv->timed_user);
118
119     return FALSE;
120 }
121
122 static void
123 quit_cb (DBusGProxy *proxy, LdmGreeter *greeter)
124 {
125     g_signal_emit (G_OBJECT (greeter), signals[QUIT], 0);
126 }
127
128 /**
129  * ldm_greeter_connect:
130  * @greeter: The greeter to connect
131  *
132  * Connects the greeter to the display manager.
133  * 
134  * Return value: TRUE if successfully connected
135  **/
136 gboolean
137 ldm_greeter_connect (LdmGreeter *greeter)
138 {
139     GError *error = NULL;
140     const gchar *bus_address, *object;
141     DBusBusType bus_type = DBUS_BUS_SYSTEM;
142     gboolean result;
143
144     g_return_val_if_fail (greeter != NULL, FALSE);
145
146     greeter->priv->system_bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
147     if (!greeter->priv->system_bus)
148         g_warning ("Failed to connect to system bus: %s", error->message);
149     g_clear_error (&error);
150     if (!greeter->priv->system_bus)
151         return FALSE;
152
153     bus_address = getenv ("LDM_BUS");
154     if (bus_address && strcmp (bus_address, "SESSION") == 0)
155         bus_type = DBUS_BUS_SESSION;
156
157     greeter->priv->lightdm_bus = dbus_g_bus_get (bus_type, &error);
158     if (!greeter->priv->lightdm_bus)
159         g_warning ("Failed to connect to LightDM bus: %s", error->message);
160     g_clear_error (&error);
161     if (!greeter->priv->lightdm_bus)
162         return FALSE;
163
164     object = getenv ("LDM_DISPLAY");
165     if (!object)
166     {
167         g_warning ("No LDM_DISPLAY enviroment variable");
168         return FALSE;
169     }
170
171     greeter->priv->display_proxy = dbus_g_proxy_new_for_name (greeter->priv->lightdm_bus,
172                                                               "org.lightdm.LightDisplayManager",
173                                                               object,
174                                                               "org.lightdm.LightDisplayManager.Greeter");
175     dbus_g_proxy_add_signal (greeter->priv->display_proxy, "QuitGreeter", G_TYPE_INVALID);
176     dbus_g_proxy_connect_signal (greeter->priv->display_proxy, "QuitGreeter", G_CALLBACK (quit_cb), greeter, NULL);
177     greeter->priv->session_proxy = dbus_g_proxy_new_for_name (greeter->priv->lightdm_bus,
178                                                               "org.lightdm.LightDisplayManager",
179                                                               "/org/lightdm/LightDisplayManager/Session",
180                                                               "org.lightdm.LightDisplayManager.Session");
181     greeter->priv->user_proxy = dbus_g_proxy_new_for_name (greeter->priv->lightdm_bus,
182                                                            "org.lightdm.LightDisplayManager",
183                                                            "/org/lightdm/LightDisplayManager/Users",
184                                                            "org.lightdm.LightDisplayManager.Users");
185
186     g_debug ("Connecting to display manager...");
187     result = dbus_g_proxy_call (greeter->priv->display_proxy, "Connect", &error,
188                                 G_TYPE_INVALID,
189                                 G_TYPE_STRING, &greeter->priv->theme,
190                                 G_TYPE_STRING, &greeter->priv->default_language,
191                                 G_TYPE_STRING, &greeter->priv->default_layout,
192                                 G_TYPE_STRING, &greeter->priv->default_session,
193                                 G_TYPE_STRING, &greeter->priv->timed_user,
194                                 G_TYPE_INT, &greeter->priv->login_delay,
195                                 G_TYPE_INVALID);
196     g_debug ("Connected theme=%s default-language=%s default-layout=%s default-session=%s timed-user=%s login-delay=%d",
197              greeter->priv->theme,
198              greeter->priv->default_language, greeter->priv->default_layout, greeter->priv->default_session,
199              greeter->priv->timed_user, greeter->priv->login_delay);
200
201     if (!result)
202         g_warning ("Failed to connect to display manager: %s", error->message);
203     g_clear_error (&error);
204     if (!result)
205         return FALSE;
206
207     /* Set timeout for default login */
208     if (greeter->priv->timed_user[0] != '\0' && greeter->priv->login_delay > 0)
209     {
210         g_debug ("Logging in as %s in %d seconds", greeter->priv->timed_user, greeter->priv->login_delay);
211         greeter->priv->login_timeout = g_timeout_add (greeter->priv->login_delay * 1000, timed_login_cb, greeter);
212     }
213
214     return result;
215 }
216
217 /**
218  * ldm_greeter_get_hostname:
219  * @greeter: a #LdmGreeter
220  *
221  * Return value: The host this greeter is displaying
222  **/
223 const gchar *
224 ldm_greeter_get_hostname (LdmGreeter *greeter)
225 {
226     g_return_val_if_fail (greeter != NULL, NULL);
227
228     if (!greeter->priv->hostname)
229     {
230         struct utsname info;
231         uname (&info);
232         greeter->priv->hostname = g_strdup (info.nodename);
233     }
234
235     return greeter->priv->hostname;
236 }
237
238 /**
239  * ldm_greeter_get_theme:
240  * @greeter: a #LdmGreeter
241  *
242  * Return value: The theme this greeter is using
243  **/
244 const gchar *
245 ldm_greeter_get_theme (LdmGreeter *greeter)
246 {
247     g_return_val_if_fail (greeter != NULL, NULL);
248     return greeter->priv->theme;
249 }
250
251 static void
252 load_theme (LdmGreeter *greeter)
253 {
254     GError *error = NULL;
255   
256     if (greeter->priv->theme_file)
257         return;
258
259     greeter->priv->theme_file = g_key_file_new ();
260     if (!g_key_file_load_from_file (greeter->priv->theme_file, greeter->priv->theme, G_KEY_FILE_NONE, &error))
261         g_warning ("Failed to read theme file: %s", error->message);
262     g_clear_error (&error);
263 }
264
265 /**
266  * ldm_greeter_get_string_property:
267  * @greeter: a #LdmGreeter
268  * @name: the name of the property to get
269  *
270  * Return value: The value of this property or NULL if it is not defined
271  **/
272 gchar *
273 ldm_greeter_get_string_property (LdmGreeter *greeter, const gchar *name)
274 {
275     GError *error = NULL;
276     gchar *result;
277
278     g_return_val_if_fail (greeter != NULL, NULL);
279
280     load_theme (greeter);
281
282     result = g_key_file_get_string (greeter->priv->theme_file, "theme", name, &error);
283     if (!result)
284         g_warning ("Error reading theme property: %s", error->message); // FIXME: Can handle G_KEY_FILE_ERROR_KEY_NOT_FOUND and G_KEY_FILE_ERROR_GROUP_NOT_FOUND
285     g_clear_error (&error);
286
287     return result;
288 }
289
290 /**
291  * ldm_greeter_get_integer_property:
292  * @greeter: a #LdmGreeter
293  * @name: the name of the property to get
294  *
295  * Return value: The value of this property or 0 if it is not defined
296  **/
297 gint
298 ldm_greeter_get_integer_property (LdmGreeter *greeter, const gchar *name)
299 {
300     GError *error = NULL;
301     gint result;
302
303     g_return_val_if_fail (greeter != NULL, 0);
304
305     load_theme (greeter);
306
307     result = g_key_file_get_integer (greeter->priv->theme_file, "theme", name, &error);
308     if (!result)
309         g_warning ("Error reading theme property: %s", error->message); // FIXME: Can handle G_KEY_FILE_ERROR_KEY_NOT_FOUND and G_KEY_FILE_ERROR_GROUP_NOT_FOUND
310     g_clear_error (&error);
311
312     return result;
313 }
314
315 /**
316  * ldm_greeter_get_boolean_property:
317  * @greeter: a #LdmGreeter
318  * @name: the name of the property to get
319  *
320  * Return value: The value of this property or FALSE if it is not defined
321  **/
322 gboolean
323 ldm_greeter_get_boolean_property (LdmGreeter *greeter, const gchar *name)
324 {
325     GError *error = NULL;
326     gboolean result;
327
328     g_return_val_if_fail (greeter != NULL, FALSE);
329
330     load_theme (greeter);
331
332     result = g_key_file_get_boolean (greeter->priv->theme_file, "theme", name, &error);
333     if (!result)
334         g_warning ("Error reading theme property: %s", error->message); // FIXME: Can handle G_KEY_FILE_ERROR_KEY_NOT_FOUND and G_KEY_FILE_ERROR_GROUP_NOT_FOUND
335     g_clear_error (&error);
336
337     return result;
338 }
339
340 #define TYPE_USER dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_INVALID)
341 #define TYPE_USER_LIST dbus_g_type_get_collection ("GPtrArray", TYPE_USER)
342
343 static void
344 update_users (LdmGreeter *greeter)
345 {
346     GPtrArray *users;
347     gboolean result;
348     gint i;
349     GError *error = NULL;
350
351     if (greeter->priv->have_users)
352         return;
353
354     g_debug ("Getting user list...");
355     result = dbus_g_proxy_call (greeter->priv->user_proxy, "GetUsers", &error,
356                                 G_TYPE_INVALID,
357                                 TYPE_USER_LIST, &users,
358                                 G_TYPE_INVALID);
359     if (!result)
360         g_warning ("Failed to get users: %s", error->message);
361     g_clear_error (&error);
362   
363     if (!result)
364         return;
365
366     g_debug ("Got %d users", users->len);
367     for (i = 0; i < users->len; i++)
368     {
369         GValue value = { 0 };
370         LdmUser *user;
371         gchar *name, *real_name, *image;
372         gboolean logged_in;
373
374         g_value_init (&value, TYPE_USER);
375         g_value_set_static_boxed (&value, users->pdata[i]);
376         dbus_g_type_struct_get (&value, 0, &name, 1, &real_name, 2, &image, 3, &logged_in, G_MAXUINT);
377         g_value_unset (&value);
378
379         user = ldm_user_new (greeter, name, real_name, image, logged_in);
380         g_free (name);
381         g_free (real_name);
382         g_free (image);
383
384         greeter->priv->users = g_list_append (greeter->priv->users, user);
385     }
386
387     g_ptr_array_free (users, TRUE);
388
389     greeter->priv->have_users = TRUE;
390 }
391
392 /**
393  * ldm_greeter_get_num_users:
394  * @greeter: a #LdmGreeter
395  *
396  * Return value: The number of users able to log in
397  **/
398 gint
399 ldm_greeter_get_num_users (LdmGreeter *greeter)
400 {
401     g_return_val_if_fail (greeter != NULL, 0);
402     update_users (greeter);
403     return g_list_length (greeter->priv->users);
404 }
405
406 /**
407  * ldm_greeter_get_users:
408  * @greeter: A #LdmGreeter
409  * 
410  * Get a list of users to present to the user.  This list may be a subset of the
411  * available users and may be empty depending on the server configuration.
412  * 
413  * Return value: A list of #LdmUser that should be presented to the user.
414  **/
415 const GList *
416 ldm_greeter_get_users (LdmGreeter *greeter)
417 {
418     g_return_val_if_fail (greeter != NULL, NULL);
419     update_users (greeter);
420     return greeter->priv->users;
421 }
422
423 static void
424 update_languages (LdmGreeter *greeter)
425 {
426     gchar *stdout_text = NULL, *stderr_text = NULL;
427     gint exit_status;
428     gboolean result;
429     GError *error = NULL;
430
431     if (greeter->priv->have_languages)
432         return;
433
434     result = g_spawn_command_line_sync ("locale -a", &stdout_text, &stderr_text, &exit_status, &error);
435     if (!result || exit_status != 0)
436         g_warning ("Failed to get languages, locale -a returned %d: %s", exit_status, error->message);
437     else
438     {
439         gchar **tokens;
440         int i;
441
442         tokens = g_strsplit_set (stdout_text, "\n\r", -1);
443         for (i = 0; tokens[i]; i++)
444         {
445             LdmLanguage *language;
446             gchar *code;
447
448             code = g_strchug (tokens[i]);
449             if (code[0] == '\0')
450                 continue;
451
452             /* Ignore the non-interesting languages */
453             if (strcmp (code, "C") == 0 || strcmp (code, "POSIX") == 0)
454                 continue;
455
456             language = ldm_language_new (code);
457             greeter->priv->languages = g_list_append (greeter->priv->languages, language);
458         }
459
460         g_strfreev (tokens);
461     }
462
463     g_clear_error (&error);
464     g_free (stdout_text);
465     g_free (stderr_text);
466
467     greeter->priv->have_languages = TRUE;
468 }
469
470 /**
471  * ldm_greeter_get_default_language:
472  * @greeter: A #LdmGreeter
473  * 
474  * Get the default language.
475  * 
476  * Return value: The default language.
477  **/
478 const gchar *
479 ldm_greeter_get_default_language (LdmGreeter *greeter)
480 {
481     g_return_val_if_fail (greeter != NULL, NULL);
482     return greeter->priv->default_language;
483 }
484
485 /**
486  * ldm_greeter_get_languages:
487  * @greeter: A #LdmGreeter
488  * 
489  * Get a list of languages to present to the user.
490  * 
491  * Return value: A list of #LdmLanguage that should be presented to the user.
492  **/
493 const GList *
494 ldm_greeter_get_languages (LdmGreeter *greeter)
495 {
496     g_return_val_if_fail (greeter != NULL, NULL);
497     update_languages (greeter);
498     return greeter->priv->languages;
499 }
500
501 const gchar *
502 ldm_greeter_get_default_layout (LdmGreeter *greeter)
503 {
504     g_return_val_if_fail (greeter != NULL, NULL);
505     return greeter->priv->default_layout;
506 }
507
508 static void
509 layout_cb (XklConfigRegistry *config,
510            const XklConfigItem *item,
511            gpointer data)
512 {
513     LdmGreeter *greeter = data;
514     LdmLayout *layout;
515   
516     layout = ldm_layout_new (item->name, item->short_description, item->description);
517     greeter->priv->layouts = g_list_append (greeter->priv->layouts, layout);
518 }
519
520 static void
521 setup_display (LdmGreeter *greeter)
522 {
523     if (!greeter->priv->display)
524         greeter->priv->display = XOpenDisplay (NULL);
525 }
526
527 static void
528 setup_xkl (LdmGreeter *greeter)
529 {
530     setup_display (greeter);
531     greeter->priv->xkl_engine = xkl_engine_get_instance (greeter->priv->display);
532     greeter->priv->xkl_config = xkl_config_rec_new ();
533     if (!xkl_config_rec_get_from_server (greeter->priv->xkl_config, greeter->priv->xkl_engine))
534         g_warning ("Failed to get Xkl configuration from server");
535     greeter->priv->layout = g_strdup (greeter->priv->xkl_config->layouts[0]);
536 }
537
538 /**
539  * ldm_greeter_get_layouts:
540  * @greeter: A #LdmGreeter
541  * 
542  * Get a list of keyboard layouts to present to the user.
543  * 
544  * Return value: A list of #LdmLayout that should be presented to the user.
545  **/
546 const GList *
547 ldm_greeter_get_layouts (LdmGreeter *greeter)
548 {
549     XklConfigRegistry *registry;
550
551     g_return_val_if_fail (greeter != NULL, NULL);
552
553     if (greeter->priv->have_layouts)
554         return greeter->priv->layouts;
555
556     setup_xkl (greeter);
557
558     registry = xkl_config_registry_get_instance (greeter->priv->xkl_engine);
559     xkl_config_registry_load (registry, FALSE);
560     xkl_config_registry_foreach_layout (registry, layout_cb, greeter);
561     g_object_unref (registry);
562     greeter->priv->have_layouts = TRUE;
563
564     return greeter->priv->layouts;
565 }
566
567 /**
568  * ldm_greeter_set_layout:
569  * @greeter: A #LdmGreeter
570  * @layout: The layout to use
571  * 
572  * Set the layout for this session.
573  **/
574 void
575 ldm_greeter_set_layout (LdmGreeter *greeter, const gchar *layout)
576 {
577     XklConfigRec *config;
578
579     g_return_if_fail (LDM_IS_GREETER (greeter));
580     g_return_if_fail (layout != NULL);
581   
582     setup_xkl (greeter);
583
584     config = xkl_config_rec_new ();
585     config->layouts = g_malloc (sizeof (gchar *) * 2);
586     config->model = g_strdup (greeter->priv->xkl_config->model);
587     config->layouts[0] = g_strdup (layout);
588     config->layouts[1] = NULL;
589     if (!xkl_config_rec_activate (config, greeter->priv->xkl_engine))
590         g_warning ("Failed to activate XKL config");
591     else
592         greeter->priv->layout = g_strdup (layout);
593     g_object_unref (config);
594 }
595
596 /**
597  * ldm_greeter_get_layout:
598  * @greeter: A #LdmGreeter
599  * 
600  * Get the current keyboard layout.
601  * 
602  * Return value: The currently active layout for this user.
603  **/
604 const gchar *
605 ldm_greeter_get_layout (LdmGreeter *greeter)
606 {
607     g_return_val_if_fail (greeter != NULL, NULL);
608     setup_xkl (greeter);
609     return greeter->priv->layout;
610 }
611
612 static void
613 update_sessions (LdmGreeter *greeter)
614 {
615     GDir *directory;
616     GError *error = NULL;
617
618     if (greeter->priv->have_sessions)
619         return;
620
621     directory = g_dir_open (XSESSIONS_DIR, 0, &error);
622     if (!directory)
623         g_warning ("Failed to open sessions directory: %s", error->message);
624     g_clear_error (&error);
625     if (!directory)
626         return;
627
628     while (TRUE)
629     {
630         const gchar *filename;
631         GKeyFile *key_file;
632         gchar *key, *path;
633         gboolean result;
634
635         filename = g_dir_read_name (directory);
636         if (filename == NULL)
637             break;
638
639         if (!g_str_has_suffix (filename, ".desktop"))
640             continue;
641
642         key = g_strndup (filename, strlen (filename) - strlen (".desktop"));
643         path = g_build_filename (XSESSIONS_DIR, filename, NULL);
644         g_debug ("Loading session %s", path);
645
646         key_file = g_key_file_new ();
647         result = g_key_file_load_from_file (key_file, path, G_KEY_FILE_NONE, &error);
648         if (!result)
649             g_warning ("Failed to load session file %s: %s:", path, error->message);
650         g_clear_error (&error);
651
652         if (result && !g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, NULL))
653         {
654             gchar *domain, *name, *comment;
655
656 #ifdef G_KEY_FILE_DESKTOP_KEY_GETTEXT_DOMAIN
657             domain = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_GETTEXT_DOMAIN, NULL);
658 #else
659             domain = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, "X-GNOME-Gettext-Domain", NULL);
660 #endif          
661             name = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NAME, domain, NULL);
662             comment = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_COMMENT, domain, NULL);
663             if (!comment)
664                 comment = g_strdup ("");
665             if (name)
666             {
667                 g_debug ("Loaded session %s (%s, %s)", key, name, comment);
668                 greeter->priv->sessions = g_list_append (greeter->priv->sessions, ldm_session_new (key, name, comment));
669             }
670             else
671                 g_warning ("Invalid session %s: %s", path, error->message);
672             g_clear_error (&error);
673             g_free (domain);
674             g_free (name);
675             g_free (comment);
676         }
677
678         g_free (key);
679         g_free (path);
680         g_key_file_free (key_file);
681     }
682
683     g_dir_close (directory);
684
685     greeter->priv->have_sessions = TRUE;
686 }
687
688 /**
689  * ldm_greeter_get_sessions:
690  * @greeter: A #LdmGreeter
691  *
692  * Get the available sessions.
693  *
694  * Return value: A list of #LdmSession
695  **/
696 const GList *
697 ldm_greeter_get_sessions (LdmGreeter *greeter)
698 {
699     g_return_val_if_fail (greeter != NULL, NULL);
700     update_sessions (greeter);
701     return greeter->priv->sessions;
702 }
703
704 /**
705  * ldm_greeter_get_default_session:
706  * @greeter: A #LdmGreeter
707  *
708  * Get the default session to use.
709  *
710  * Return value: The session name
711  **/
712 const gchar *
713 ldm_greeter_get_default_session (LdmGreeter *greeter)
714 {
715     g_return_val_if_fail (greeter != NULL, NULL);
716     return greeter->priv->default_session;
717 }
718
719 /**
720  * ldm_greeter_get_timed_login_user:
721  * @greeter: A #LdmGreeter
722  *
723  * Get the user to log in by as default.
724  *
725  * Return value: A username
726  */
727 const gchar *
728 ldm_greeter_get_timed_login_user (LdmGreeter *greeter)
729 {
730     g_return_val_if_fail (greeter != NULL, NULL);
731     return greeter->priv->timed_user;
732 }
733
734 /**
735  * ldm_greeter_get_timed_login_delay:
736  * @greeter: A #LdmGreeter
737  *
738  * Get the number of seconds to wait until logging in as the default user.
739  *
740  * Return value: The number of seconds before logging in as the default user
741  */
742 gint
743 ldm_greeter_get_timed_login_delay (LdmGreeter *greeter)
744 {
745     g_return_val_if_fail (greeter != NULL, 0);
746     return greeter->priv->login_delay;
747 }
748
749 /**
750  * ldm_greeter_cancel_timed_login:
751  * @greeter: A #LdmGreeter
752  *
753  * Cancel the login as the default user.
754  */
755 void
756 ldm_greeter_cancel_timed_login (LdmGreeter *greeter)
757 {
758     g_return_if_fail (LDM_IS_GREETER (greeter));
759   
760     if (greeter->priv->login_timeout)
761        g_source_remove (greeter->priv->login_timeout);
762     greeter->priv->login_timeout = 0;
763 }
764
765 #define TYPE_MESSAGE dbus_g_type_get_struct ("GValueArray", G_TYPE_INT, G_TYPE_STRING, G_TYPE_INVALID)
766 #define TYPE_MESSAGE_LIST dbus_g_type_get_collection ("GPtrArray", TYPE_MESSAGE)
767
768 static void
769 auth_response_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer userdata)
770 {
771     LdmGreeter *greeter = userdata;
772     gboolean result;
773     GError *error = NULL;
774     gint return_code;
775     GPtrArray *array;
776     int i;
777
778     result = dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INT, &return_code, TYPE_MESSAGE_LIST, &array, G_TYPE_INVALID);
779     if (!result)
780         g_warning ("Failed to complete StartAuthentication(): %s", error->message);
781     g_clear_error (&error);
782     if (!result)
783         return;
784
785     if (array->len > 0)
786         g_debug ("Authentication continues with %d messages", array->len);
787     else
788         g_debug ("Authentication complete with return code %d", return_code);
789
790     for (i = 0; i < array->len; i++)
791     {
792         GValue value = { 0 };
793         gint msg_style;
794         gchar *msg;
795       
796         g_value_init (&value, TYPE_MESSAGE);
797         g_value_set_static_boxed (&value, array->pdata[i]);
798         dbus_g_type_struct_get (&value, 0, &msg_style, 1, &msg, G_MAXUINT);
799
800         // FIXME: Should stop on prompts?
801         switch (msg_style)
802         {
803         case PAM_PROMPT_ECHO_OFF:
804         case PAM_PROMPT_ECHO_ON:
805             g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, msg);
806             break;
807         case PAM_ERROR_MSG:
808             g_signal_emit (G_OBJECT (greeter), signals[SHOW_ERROR], 0, msg);
809             break;
810         case PAM_TEXT_INFO:
811             g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, msg);
812             break;
813         }
814
815         g_free (msg);
816
817         g_value_unset (&value);
818     }
819
820     if (array->len == 0)
821     {
822         greeter->priv->is_authenticated = (return_code == 0);
823         if (!greeter->priv->is_authenticated)
824         {
825             g_free (greeter->priv->authentication_user);
826             greeter->priv->authentication_user = NULL;
827         }
828         g_signal_emit (G_OBJECT (greeter), signals[AUTHENTICATION_COMPLETE], 0);
829     }
830
831     g_ptr_array_unref (array);
832 }
833
834 /**
835  * ldm_greeter_start_authentication:
836  * @greeter: A #LdmGreeter
837  * @username: A username
838  *
839  * Starts the authentication procedure for a user.
840  **/
841 void
842 ldm_greeter_start_authentication (LdmGreeter *greeter, const char *username)
843 {
844     g_return_if_fail (LDM_IS_GREETER (greeter));
845     g_return_if_fail (username != NULL);
846
847     greeter->priv->is_authenticated = FALSE;
848     g_free (greeter->priv->authentication_user);
849     greeter->priv->authentication_user = g_strdup (username);
850     g_debug ("Starting authentication for user %s...", username);
851     dbus_g_proxy_begin_call (greeter->priv->display_proxy, "StartAuthentication", auth_response_cb, greeter, NULL, G_TYPE_STRING, username, G_TYPE_INVALID);
852 }
853
854 /**
855  * ldm_greeter_provide_secret:
856  * @greeter: A #LdmGreeter
857  * @secret: Response to a prompt
858  *
859  * Provide secret information from a prompt.
860  **/
861 void
862 ldm_greeter_provide_secret (LdmGreeter *greeter, const gchar *secret)
863 {
864     gchar **secrets;
865
866     g_return_if_fail (LDM_IS_GREETER (greeter));
867     g_return_if_fail (secret != NULL);
868
869     // FIXME: Could be multiple secrets required
870     secrets = g_malloc (sizeof (char *) * 2);
871     secrets[0] = g_strdup (secret);
872     secrets[1] = NULL;
873     g_debug ("Providing secret to display manager");  
874     dbus_g_proxy_begin_call (greeter->priv->display_proxy, "ContinueAuthentication", auth_response_cb, greeter, NULL, G_TYPE_STRV, secrets, G_TYPE_INVALID);
875 }
876
877 /**
878  * ldm_greeter_cancel_authentication:
879  * @greeter: A #LdmGreeter
880  * 
881  * Cancel the current user authentication.
882  **/
883 void
884 ldm_greeter_cancel_authentication (LdmGreeter *greeter)
885 {
886     g_return_if_fail (LDM_IS_GREETER (greeter));
887 }
888
889 /**
890  * ldm_greeter_get_is_authenticated:
891  * @greeter: A #LdmGreeter
892  * 
893  * Checks if the greeter has successfully authenticated.
894  *
895  * Return value: TRUE if the greeter is authenticated for login.
896  **/
897 gboolean
898 ldm_greeter_get_is_authenticated (LdmGreeter *greeter)
899 {
900     g_return_val_if_fail (greeter != NULL, FALSE);
901     return greeter->priv->is_authenticated;
902 }
903
904 /**
905  * ldm_greeter_get_authentication_user:
906  * @greeter: A #LdmGreeter
907  * 
908  * Get the user that is being authenticated.
909  * 
910  * Return value: The username of the authentication user being authenticated or NULL if no authentication in progress.
911  */
912 const gchar *
913 ldm_greeter_get_authentication_user (LdmGreeter *greeter)
914 {
915     g_return_val_if_fail (greeter != NULL, NULL);
916     return greeter->priv->authentication_user;
917 }
918
919 /**
920  * ldm_greeter_login:
921  * @greeter: A #LdmGreeter
922  * @username: The user to log in as
923  * @session: The session to log into or NULL to use the default
924  * @language: The language to use or NULL to use the default
925  *
926  * Login a user to a session
927  **/
928 void
929 ldm_greeter_login (LdmGreeter *greeter, const gchar *username, const gchar *session, const gchar *language)
930 {
931     GError *error = NULL;
932
933     g_return_if_fail (LDM_IS_GREETER (greeter));
934     g_return_if_fail (username != NULL);
935
936     g_debug ("Logging in");
937     if (!dbus_g_proxy_call (greeter->priv->display_proxy, "Login", &error,
938                             G_TYPE_STRING, username,
939                             G_TYPE_STRING, session ? session : "",
940                             G_TYPE_STRING, language ? language : "",
941                             G_TYPE_INVALID,
942                             G_TYPE_INVALID))
943         g_warning ("Failed to login: %s", error->message);
944     g_clear_error (&error);
945 }
946
947 /**
948  * ldm_greeter_get_can_suspend:
949  * @greeter: A #LdmGreeter
950  * 
951  * Checks if the greeter is authorized to do a system suspend.
952  *
953  * Return value: TRUE if the greeter can suspend the system
954  **/
955 gboolean
956 ldm_greeter_get_can_suspend (LdmGreeter *greeter)
957 {
958     DBusGProxy *proxy;
959     gboolean result = TRUE;
960     GError *error = NULL;
961
962     g_return_val_if_fail (greeter != NULL, FALSE);
963
964     proxy = dbus_g_proxy_new_for_name (greeter->priv->system_bus,
965                                        "org.freedesktop.UPower",
966                                        "/org/freedesktop/UPower",
967                                        "org.freedesktop.UPower");
968     if (!dbus_g_proxy_call (proxy, "SuspendAllowed", &error, G_TYPE_INVALID, G_TYPE_BOOLEAN, &result, G_TYPE_INVALID))
969         g_warning ("Error checking for suspend authority: %s", error->message);
970     g_clear_error (&error);
971
972     g_object_unref (proxy);
973
974     return result;
975 }
976
977 /**
978  * ldm_greeter_suspend:
979  * @greeter: A #LdmGreeter
980  * 
981  * Triggers a system suspend.
982  **/
983 void
984 ldm_greeter_suspend (LdmGreeter *greeter)
985 {
986     DBusGProxy *proxy;
987     GError *error = NULL;
988
989     g_return_if_fail (LDM_IS_GREETER (greeter));
990
991     proxy = dbus_g_proxy_new_for_name (greeter->priv->system_bus,
992                                        "org.freedesktop.UPower",
993                                        "/org/freedesktop/UPower",
994                                        "org.freedesktop.UPower");
995     if (!dbus_g_proxy_call (proxy, "Suspend", &error, G_TYPE_INVALID, G_TYPE_INVALID))
996         g_warning ("Failed to hibernate: %s", error->message);
997     g_clear_error (&error);
998
999     g_object_unref (proxy);
1000 }
1001
1002 /**
1003  * ldm_greeter_get_can_hibernate:
1004  * @greeter: A #LdmGreeter
1005  * 
1006  * Checks if the greeter is authorized to do a system hibernate.
1007  *
1008  * Return value: TRUE if the greeter can hibernate the system
1009  **/
1010 gboolean
1011 ldm_greeter_get_can_hibernate (LdmGreeter *greeter)
1012 {
1013     DBusGProxy *proxy;
1014     gboolean result = FALSE;
1015     GError *error = NULL;
1016
1017     g_return_val_if_fail (greeter != NULL, FALSE);
1018
1019     proxy = dbus_g_proxy_new_for_name (greeter->priv->system_bus,
1020                                        "org.freedesktop.UPower",
1021                                        "/org/freedesktop/UPower",
1022                                        "org.freedesktop.UPower");
1023     if (!dbus_g_proxy_call (proxy, "HibernateAllowed", &error, G_TYPE_INVALID, G_TYPE_BOOLEAN, &result, G_TYPE_INVALID))
1024         g_warning ("Error checking for hibernate authority: %s", error->message);
1025     g_clear_error (&error);
1026
1027     g_object_unref (proxy);
1028
1029     return result;
1030 }
1031
1032 /**
1033  * ldm_greeter_hibernate:
1034  * @greeter: A #LdmGreeter
1035  * 
1036  * Triggers a system hibernate.
1037  **/
1038 void
1039 ldm_greeter_hibernate (LdmGreeter *greeter)
1040 {
1041     DBusGProxy *proxy;
1042     GError *error = NULL;
1043
1044     g_return_if_fail (LDM_IS_GREETER (greeter));
1045
1046     proxy = dbus_g_proxy_new_for_name (greeter->priv->system_bus,
1047                                        "org.freedesktop.UPower",
1048                                        "/org/freedesktop/UPower",
1049                                        "org.freedesktop.UPower");
1050     if (!dbus_g_proxy_call (proxy, "Hibernate", &error, G_TYPE_INVALID, G_TYPE_INVALID))
1051         g_warning ("Failed to hibernate: %s", error->message);
1052     g_clear_error (&error);
1053
1054     g_object_unref (proxy);
1055 }
1056
1057 /**
1058  * ldm_greeter_get_can_restart:
1059  * @greeter: A #LdmGreeter
1060  * 
1061  * Checks if the greeter is authorized to do a system restart.
1062  *
1063  * Return value: TRUE if the greeter can restart the system
1064  **/
1065 gboolean
1066 ldm_greeter_get_can_restart (LdmGreeter *greeter)
1067 {
1068     DBusGProxy *proxy;
1069     gboolean result = FALSE;
1070     GError *error = NULL;
1071
1072     g_return_val_if_fail (greeter != NULL, FALSE);
1073
1074     proxy = dbus_g_proxy_new_for_name (greeter->priv->system_bus,
1075                                        "org.freedesktop.ConsoleKit",
1076                                        "/org/freedesktop/ConsoleKit/Manager",
1077                                        "org.freedesktop.ConsoleKit.Manager");
1078     if (!dbus_g_proxy_call (proxy, "CanRestart", &error, G_TYPE_INVALID, G_TYPE_BOOLEAN, &result, G_TYPE_INVALID))
1079         g_warning ("Error checking for restart authority: %s", error->message);
1080     g_clear_error (&error);
1081
1082     g_object_unref (proxy);
1083
1084     return result; 
1085 }
1086
1087 /**
1088  * ldm_greeter_restart:
1089  * @greeter: A #LdmGreeter
1090  * 
1091  * Triggers a system restart.
1092  **/
1093 void
1094 ldm_greeter_restart (LdmGreeter *greeter)
1095 {
1096     DBusGProxy *proxy;
1097     GError *error = NULL;
1098
1099     g_return_if_fail (LDM_IS_GREETER (greeter));
1100
1101     proxy = dbus_g_proxy_new_for_name (greeter->priv->system_bus,
1102                                        "org.freedesktop.ConsoleKit",
1103                                        "/org/freedesktop/ConsoleKit/Manager",
1104                                        "org.freedesktop.ConsoleKit.Manager");
1105     if (!dbus_g_proxy_call (proxy, "Restart", &error, G_TYPE_INVALID, G_TYPE_INVALID))
1106         g_warning ("Failed to restart: %s", error->message);
1107     g_clear_error (&error);
1108
1109     g_object_unref (proxy);
1110 }
1111
1112 /**
1113  * ldm_greeter_get_can_shutdown:
1114  * @greeter: A #LdmGreeter
1115  * 
1116  * Checks if the greeter is authorized to do a system shutdown.
1117  *
1118  * Return value: TRUE if the greeter can shutdown the system
1119  **/
1120 gboolean
1121 ldm_greeter_get_can_shutdown (LdmGreeter *greeter)
1122 {
1123     DBusGProxy *proxy;
1124     gboolean result = FALSE;
1125     GError *error = NULL;
1126
1127     g_return_val_if_fail (greeter != NULL, FALSE);
1128
1129     proxy = dbus_g_proxy_new_for_name (greeter->priv->system_bus,
1130                                        "org.freedesktop.ConsoleKit",
1131                                        "/org/freedesktop/ConsoleKit/Manager",
1132                                        "org.freedesktop.ConsoleKit.Manager");
1133     if (!dbus_g_proxy_call (proxy, "CanStop", &error, G_TYPE_INVALID, G_TYPE_BOOLEAN, &result, G_TYPE_INVALID))
1134         g_warning ("Error checking for shutdown authority: %s", error->message);
1135     g_clear_error (&error);
1136
1137     g_object_unref (proxy);
1138
1139     return result; 
1140 }
1141
1142 /**
1143  * ldm_greeter_shutdown:
1144  * @greeter: A #LdmGreeter
1145  * 
1146  * Triggers a system shutdown.
1147  **/
1148 void
1149 ldm_greeter_shutdown (LdmGreeter *greeter)
1150 {
1151     DBusGProxy *proxy;
1152     GError *error = NULL;
1153
1154     g_return_if_fail (LDM_IS_GREETER (greeter));
1155
1156     proxy = dbus_g_proxy_new_for_name (greeter->priv->system_bus,
1157                                        "org.freedesktop.ConsoleKit",
1158                                        "/org/freedesktop/ConsoleKit/Manager",
1159                                        "org.freedesktop.ConsoleKit.Manager");
1160     if (!dbus_g_proxy_call (proxy, "Stop", &error, G_TYPE_INVALID, G_TYPE_INVALID))
1161         g_warning ("Failed to shutdown: %s", error->message);
1162     g_clear_error (&error);
1163
1164     g_object_unref (proxy);
1165 }
1166
1167 gboolean
1168 ldm_greeter_get_user_defaults (LdmGreeter *greeter, const gchar *username, gchar **language, gchar **layout, gchar **session)
1169 {
1170     GError *error = NULL;
1171     gboolean result;
1172
1173     result = dbus_g_proxy_call (greeter->priv->user_proxy, "GetUserDefaults", &error,
1174                                 G_TYPE_STRING, username,
1175                                 G_TYPE_INVALID,
1176                                 G_TYPE_STRING, language,
1177                                 G_TYPE_STRING, layout,
1178                                 G_TYPE_STRING, session,
1179                                 G_TYPE_INVALID);
1180   
1181     if (!result)
1182         g_warning ("Failed to get user defaults: %s", error->message);
1183     g_clear_error (&error);
1184
1185     return result;
1186 }
1187
1188 static void
1189 ldm_greeter_init (LdmGreeter *greeter)
1190 {
1191     greeter->priv = G_TYPE_INSTANCE_GET_PRIVATE (greeter, LDM_TYPE_GREETER, LdmGreeterPrivate);
1192 }
1193
1194 static void
1195 ldm_greeter_set_property (GObject      *object,
1196                           guint         prop_id,
1197                           const GValue *value,
1198                           GParamSpec   *pspec)
1199 {
1200     LdmGreeter *self;
1201     gint i, n_pages;
1202
1203     self = LDM_GREETER (object);
1204
1205     switch (prop_id) {
1206     case PROP_LAYOUT:
1207         ldm_greeter_set_layout(self, g_value_get_string (value));
1208         break;
1209     default:
1210         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1211         break;
1212     }
1213 }
1214
1215 static void
1216 ldm_greeter_get_property (GObject    *object,
1217                           guint       prop_id,
1218                           GValue     *value,
1219                           GParamSpec *pspec)
1220 {
1221     LdmGreeter *self;
1222
1223     self = LDM_GREETER (object);
1224
1225     switch (prop_id) {
1226     case PROP_HOSTNAME:
1227         g_value_set_string (value, ldm_greeter_get_hostname (self));
1228         break;
1229     case PROP_NUM_USERS:
1230         g_value_set_int (value, ldm_greeter_get_num_users (self));
1231         break;
1232     case PROP_USERS:
1233         break;
1234     case PROP_DEFAULT_LANGUAGE:
1235         g_value_set_string (value, ldm_greeter_get_default_language (self));
1236         break;
1237     case PROP_LAYOUTS:
1238         break;
1239     case PROP_LAYOUT:
1240         g_value_set_string (value, ldm_greeter_get_layout (self));
1241         break;      
1242     case PROP_SESSIONS:
1243         break;
1244     case PROP_DEFAULT_SESSION:
1245         g_value_set_string (value, ldm_greeter_get_default_session (self));
1246         break;
1247     case PROP_TIMED_LOGIN_USER:
1248         g_value_set_string (value, ldm_greeter_get_timed_login_user (self));
1249         break;
1250     case PROP_TIMED_LOGIN_DELAY:
1251         g_value_set_int (value, ldm_greeter_get_timed_login_delay (self));
1252         break;
1253     case PROP_AUTHENTICATION_USER:
1254         g_value_set_string (value, ldm_greeter_get_authentication_user (self));
1255         break;
1256     case PROP_IS_AUTHENTICATED:
1257         g_value_set_boolean (value, ldm_greeter_get_is_authenticated (self));
1258         break;
1259     case PROP_CAN_SUSPEND:
1260         g_value_set_boolean (value, ldm_greeter_get_can_suspend (self));
1261         break;
1262     case PROP_CAN_HIBERNATE:
1263         g_value_set_boolean (value, ldm_greeter_get_can_hibernate (self));
1264         break;
1265     case PROP_CAN_RESTART:
1266         g_value_set_boolean (value, ldm_greeter_get_can_restart (self));
1267         break;
1268     case PROP_CAN_SHUTDOWN:
1269         g_value_set_boolean (value, ldm_greeter_get_can_shutdown (self));
1270         break;
1271     default:
1272         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1273         break;
1274     }
1275 }
1276
1277 static void
1278 ldm_greeter_class_init (LdmGreeterClass *klass)
1279 {
1280     GObjectClass *object_class = G_OBJECT_CLASS (klass);
1281   
1282     g_type_class_add_private (klass, sizeof (LdmGreeterPrivate));
1283
1284     object_class->set_property = ldm_greeter_set_property;
1285     object_class->get_property = ldm_greeter_get_property;
1286
1287     g_object_class_install_property (object_class,
1288                                      PROP_NUM_USERS,
1289                                      g_param_spec_string ("hostname",
1290                                                           "hostname",
1291                                                           "Hostname displaying greeter for",
1292                                                           NULL,
1293                                                           G_PARAM_READABLE));
1294     g_object_class_install_property (object_class,
1295                                      PROP_NUM_USERS,
1296                                      g_param_spec_int ("num-users",
1297                                                        "num-users",
1298                                                        "Number of login users",
1299                                                        0, G_MAXINT, 0,
1300                                                        G_PARAM_READABLE));
1301     /*g_object_class_install_property (object_class,
1302                                      PROP_USERS,
1303                                      g_param_spec_list ("users",
1304                                                         "users",
1305                                                         "Users that can login"));
1306     g_object_class_install_property (object_class,
1307                                      PROP_DEFAULT_LANGUAGE,
1308                                      g_param_spec_string ("default-language",
1309                                                           "default-language",
1310                                                           "Default language",
1311                                                           NULL,
1312                                                           G_PARAM_READWRITE));
1313     g_object_class_install_property (object_class,
1314                                      PROP_LAYOUTS,
1315                                      g_param_spec_list ("layouts",
1316                                                         "layouts",
1317                                                         "Available keyboard layouts"));*/
1318     g_object_class_install_property (object_class,
1319                                      PROP_LAYOUT,
1320                                      g_param_spec_string ("layout",
1321                                                           "layout",
1322                                                           "Current keyboard layout",
1323                                                           NULL,
1324                                                           G_PARAM_READWRITE));
1325     /*g_object_class_install_property (object_class,
1326                                      PROP_SESSIONS,
1327                                      g_param_spec_list ("sessions",
1328                                                         "sessions",
1329                                                         "Available sessions"));*/
1330     g_object_class_install_property (object_class,
1331                                      PROP_DEFAULT_SESSION,
1332                                      g_param_spec_string ("default-session",
1333                                                           "default-session",
1334                                                           "Default session",
1335                                                           NULL,
1336                                                           G_PARAM_READWRITE));
1337     g_object_class_install_property (object_class,
1338                                      PROP_TIMED_LOGIN_USER,
1339                                      g_param_spec_string ("timed-login-user",
1340                                                           "timed-login-user",
1341                                                           "User to login as when timed expires",
1342                                                           NULL,
1343                                                           G_PARAM_READABLE));
1344     g_object_class_install_property (object_class,
1345                                      PROP_TIMED_LOGIN_DELAY,
1346                                      g_param_spec_int ("login-delay",
1347                                                        "login-delay",
1348                                                        "Number of seconds until logging in as default user",
1349                                                        G_MININT, G_MAXINT, 0,
1350                                                        G_PARAM_READABLE));
1351     g_object_class_install_property (object_class,
1352                                      PROP_AUTHENTICATION_USER,
1353                                      g_param_spec_string ("authentication-user",
1354                                                           "authentication-user",
1355                                                           "The user being authenticated",
1356                                                           NULL,
1357                                                           G_PARAM_READABLE));
1358     g_object_class_install_property (object_class,
1359                                      PROP_IS_AUTHENTICATED,
1360                                      g_param_spec_boolean ("is-authenticated",
1361                                                            "is-authenticated",
1362                                                            "TRUE if the selected user is authenticated",
1363                                                            FALSE,
1364                                                            G_PARAM_READABLE));
1365     g_object_class_install_property (object_class,
1366                                      PROP_CAN_SUSPEND,
1367                                      g_param_spec_boolean ("can-suspend",
1368                                                            "can-suspend",
1369                                                            "TRUE if allowed to suspend the system",
1370                                                            FALSE,
1371                                                            G_PARAM_READABLE));
1372     g_object_class_install_property (object_class,
1373                                      PROP_CAN_HIBERNATE,
1374                                      g_param_spec_boolean ("can-hibernate",
1375                                                            "can-hibernate",
1376                                                            "TRUE if allowed to hibernate the system",
1377                                                            FALSE,
1378                                                            G_PARAM_READABLE));
1379     g_object_class_install_property (object_class,
1380                                      PROP_CAN_RESTART,
1381                                      g_param_spec_boolean ("can-restart",
1382                                                            "can-restart",
1383                                                            "TRUE if allowed to restart the system",
1384                                                            FALSE,
1385                                                            G_PARAM_READABLE));
1386     g_object_class_install_property (object_class,
1387                                      PROP_CAN_SHUTDOWN,
1388                                      g_param_spec_boolean ("can-shutdown",
1389                                                            "can-shutdown",
1390                                                            "TRUE if allowed to shutdown the system",
1391                                                            FALSE,
1392                                                            G_PARAM_READABLE));
1393
1394     /**
1395      * LdmGreeter::show-prompt:
1396      * @greeter: A #LdmGreeter
1397      * @text: Prompt text
1398      * 
1399      * The ::show-prompt signal gets emitted when the greeter should show a
1400      * prompt to the user.  The given text should be displayed and an input
1401      * field for the user to provide a response.
1402      * 
1403      * Call ldm_greeter_provide_secret() with the resultant input or
1404      * ldm_greeter_cancel_authentication() to abort the authentication.
1405      **/
1406     signals[SHOW_PROMPT] =
1407         g_signal_new ("show-prompt",
1408                       G_TYPE_FROM_CLASS (klass),
1409                       G_SIGNAL_RUN_LAST,
1410                       G_STRUCT_OFFSET (LdmGreeterClass, show_prompt),
1411                       NULL, NULL,
1412                       g_cclosure_marshal_VOID__STRING,
1413                       G_TYPE_NONE, 1, G_TYPE_STRING);
1414
1415     /**
1416      * LdmGreeter::show-message:
1417      * @greeter: A #LdmGreeter
1418      * @text: Message text
1419      *
1420      * The ::show-message signal gets emitted when the greeter
1421      * should show an informational message to the user.
1422      **/
1423     signals[SHOW_MESSAGE] =
1424         g_signal_new ("show-message",
1425                       G_TYPE_FROM_CLASS (klass),
1426                       G_SIGNAL_RUN_LAST,
1427                       G_STRUCT_OFFSET (LdmGreeterClass, show_message),
1428                       NULL, NULL,
1429                       g_cclosure_marshal_VOID__STRING,
1430                       G_TYPE_NONE, 1, G_TYPE_STRING);
1431
1432     /**
1433      * LdmGreeter::show-error:
1434      * @greeter: A #LdmGreeter
1435      * @text: Message text
1436      *
1437      * The ::show-error signal gets emitted when the greeter
1438      * should show an error message to the user.
1439      **/
1440     signals[SHOW_ERROR] =
1441         g_signal_new ("show-error",
1442                       G_TYPE_FROM_CLASS (klass),
1443                       G_SIGNAL_RUN_LAST,
1444                       G_STRUCT_OFFSET (LdmGreeterClass, show_error),
1445                       NULL, NULL,
1446                       g_cclosure_marshal_VOID__STRING,
1447                       G_TYPE_NONE, 1, G_TYPE_STRING);
1448
1449     /**
1450      * LdmGreeter::authentication-complete:
1451      * @greeter: A #LdmGreeter
1452      *
1453      * The ::authentication-complete signal gets emitted when the greeter
1454      * has completed authentication.
1455      * 
1456      * Call ldm_greeter_get_is_authenticated() to check if the authentication
1457      * was successful.
1458      **/
1459     signals[AUTHENTICATION_COMPLETE] =
1460         g_signal_new ("authentication-complete",
1461                       G_TYPE_FROM_CLASS (klass),
1462                       G_SIGNAL_RUN_LAST,
1463                       G_STRUCT_OFFSET (LdmGreeterClass, authentication_complete),
1464                       NULL, NULL,
1465                       g_cclosure_marshal_VOID__VOID,
1466                       G_TYPE_NONE, 0);
1467
1468     /**
1469      * LdmGreeter::timed-login:
1470      * @greeter: A #LdmGreeter
1471      * @username: A username
1472      *
1473      * The ::timed-login signal gets emitted when the default user timer
1474      * has expired.
1475      **/
1476     signals[TIMED_LOGIN] =
1477         g_signal_new ("timed-login",
1478                       G_TYPE_FROM_CLASS (klass),
1479                       G_SIGNAL_RUN_LAST,
1480                       G_STRUCT_OFFSET (LdmGreeterClass, timed_login),
1481                       NULL, NULL,
1482                       g_cclosure_marshal_VOID__STRING,
1483                       G_TYPE_NONE, 1, G_TYPE_STRING);
1484
1485     /**
1486      * LdmGreeter::quit:
1487      * @greeter: A #LdmGreeter
1488      *
1489      * The ::quit signal gets emitted when the greeter should exit.
1490      **/
1491     signals[QUIT] =
1492         g_signal_new ("quit",
1493                       G_TYPE_FROM_CLASS (klass),
1494                       G_SIGNAL_RUN_LAST,
1495                       G_STRUCT_OFFSET (LdmGreeterClass, quit),
1496                       NULL, NULL,
1497                       g_cclosure_marshal_VOID__VOID,
1498                       G_TYPE_NONE, 0);
1499 }