1 /*
2  * Copyright (C) 2010 - 2011, Robert Ancell <robert.ancell@canonical.com>
3  * Copyright (C) 2011, Gunnar Hjalmarsson <ubuntu@gunnar.cc>
4  * Copyright (C) 2012 - 2013, Lionel Le Folgoc <mrpouit@ubuntu.com>
5  * Copyright (C) 2012, Julien Lavergne <gilir@ubuntu.com>
6  * Copyright (C) 2013 - 2015, Simon Steinbeiß <ochosi@shimmerproject.org>
7  * Copyright (C) 2013 - 2020, Sean Davis <sean@bluesabre.org>
8  * Copyright (C) 2014, Andrew P. <pan.pav.7c5@gmail.com>
9  *
10  * This program is free software: you can redistribute it and/or modify it under
11  * the terms of the GNU General Public License as published by the Free Software
12  * Foundation, either version 3 of the License, or (at your option) any later
13  * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
14  * license.
15  */
16 
17 #ifdef HAVE_CONFIG_H
18 #include <config.h>
19 #endif
20 
21 #ifdef HAVE_STDLIB_H
22 #include <stdlib.h>
23 #endif
24 
25 #include <glib-unix.h>
26 
27 #include <locale.h>
28 #include <gdk/gdkx.h>
29 #include <gtk/gtk.h>
30 #include <glib/gi18n.h>
31 #include <sys/mman.h>
32 #include <sys/wait.h>
33 #include <glib.h>
34 #include <gtk/gtkx.h>
35 #include <glib/gslist.h>
36 
37 #ifdef HAVE_LIBINDICATOR
38     #ifdef HAVE_UNITY_LIBINDICATOR
39         #include <libindicator/indicator-object.h>
40     #else
41         #include <libayatana-indicator/indicator-object.h>
42     #endif
43     #ifdef HAVE_LIBINDICATOR_NG
44         #ifdef HAVE_UNITY_LIBINDICATOR_NG
45             #include <libindicator/indicator-ng.h>
46         #else
47             #include <libayatana-indicator/indicator-ng.h>
48         #endif
49     #endif
50 #endif
51 
52 /* Some indicators need ido library */
53 #ifdef HAVE_LIBIDO
54     #ifdef HAVE_UNITY_LIBIDO
55         #include <libido/libido.h>
56     #else
57         #include <libayatana-ido/libayatana-ido.h>
58     #endif
59 #endif
60 
61 #ifdef HAVE_LIBXKLAVIER
62 #include <libxklavier/xklavier.h>
63 #endif
64 
65 #include <lightdm.h>
66 
67 #include "src/greeterconfiguration.h"
68 #include "src/greetermenubar.h"
69 #include "src/greeterbackground.h"
70 #include "src/lightdm-gtk-greeter-ui.h"
71 #include "src/lightdm-gtk-greeter-css-fallback.h"
72 #include "src/lightdm-gtk-greeter-css-application.h"
73 
74 
75 static LightDMGreeter *greeter;
76 
77 /* List of spawned processes */
78 static GSList *pids_to_close = NULL;
79 static GPid spawn_argv_pid (gchar **argv, GSpawnFlags flags, gint *pfd, GError **perror);
80 #if defined(AT_SPI_COMMAND) || defined(INDICATOR_SERVICES_COMMAND)
81 static GPid spawn_line_pid (const gchar *line, GSpawnFlags flags, GError **perror);
82 #endif
83 static void close_pid (GPid pid, gboolean remove);
84 static void sigterm_cb (gpointer user_data);
85 
86 /* Screen window */
87 static GtkOverlay   *screen_overlay;
88 static GtkWidget    *screen_overlay_child;
89 
90 /* Login window */
91 static GtkWidget    *login_window;
92 static GtkImage     *user_image;
93 static GtkComboBox  *user_combo;
94 static GtkEntry     *username_entry, *password_entry;
95 static GtkLabel     *message_label;
96 static GtkInfoBar   *info_bar;
97 static GtkButton    *cancel_button, *login_button;
98 
99 /* Panel */
100 static GtkWidget    *panel_window, *menubar;
101 static GtkWidget    *power_menuitem, *session_menuitem, *language_menuitem, *a11y_menuitem,
102                     *layout_menuitem, *clock_menuitem, *host_menuitem;
103 static GtkWidget    *suspend_menuitem, *hibernate_menuitem, *restart_menuitem, *shutdown_menuitem;
104 static GtkWidget    *contrast_menuitem, *font_menuitem, *keyboard_menuitem, *reader_menuitem;
105 static GtkWidget    *clock_label, *session_badge;
106 static GtkMenu      *session_menu, *language_menu, *layout_menu;
107 
108 /* Power window */
109 static GtkWidget    *power_window;
110 static GtkButton    *power_ok_button, *power_cancel_button;
111 static GtkLabel     *power_title, *power_text;
112 static GtkImage     *power_icon;
113 
114 static const gchar *DEFAULT_LAYOUT[] = {"~spacer", "~spacer", "~host", "~spacer",
115                                         "~session", "~a11y", "~clock", "~power", NULL};
116 
117 static const gchar *POWER_WINDOW_DATA_LOOP = "power-window-loop";           /* <GMainLoop*> */
118 static const gchar *POWER_WINDOW_DATA_RESPONSE = "power-window-response";   /* <GtkResponseType> */
119 
120 static gboolean show_power_prompt (const gchar *action, const gchar* icon, const gchar* title, const gchar* message);
121 void power_button_clicked_cb (GtkButton *button, gpointer user_data);
122 gboolean power_window_key_press_event_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data);
123 
124 /* Handling window position */
125 typedef struct
126 {
127     gint value;
128     /* +0 and -0 */
129     gint sign;
130     /* interpret 'value' as percentage of screen width/height */
131     gboolean percentage;
132     /* -1: left/top, 0: center, +1: right,bottom */
133     gint anchor;
134 } DimensionPosition;
135 
136 typedef struct
137 {
138     DimensionPosition x, y;
139     /* Flag to use width and height fileds */
140     gboolean use_size;
141     DimensionPosition width, height;
142 } WindowPosition;
143 
144 static WindowPosition* str_to_position (const gchar *str, const WindowPosition *default_value);
145 /* Function translate user defined coordinates to absolute value */
146 static gint get_absolute_position (const DimensionPosition *p, gint screen, gint window);
147 gboolean screen_overlay_get_child_position_cb (GtkWidget *overlay, GtkWidget *widget, GdkRectangle *allocation, gpointer user_data);
148 
149 static const gchar *WINDOW_DATA_POSITION = "window-position"; /* <WindowPosition*> */
150 
151 /* Some default positions */
152 static const WindowPosition WINDOW_POS_CENTER   = {.x = { 50, +1, TRUE,   0}, .y = { 50, +1, TRUE,   0}, .use_size = FALSE};
153 static const WindowPosition KEYBOARD_POSITION   = {.x = { 50, +1, TRUE,   0}, .y = {  0, -1, FALSE, +1}, .use_size = TRUE,
154                                                    .width = {50, 0, TRUE, 0}, .height = {25, 0, TRUE, 0}};
155 
156 /* Clock */
157 static gchar *clock_format;
158 static gboolean clock_timeout_thread (void);
159 
160 /* Message label */
161 static gboolean message_label_is_empty (void);
162 static void set_message_label (LightDMMessageType type, const gchar *text);
163 
164 /* User image */
165 static GdkPixbuf *default_user_pixbuf = NULL;
166 static gchar *default_user_icon = NULL;
167 static void set_user_image (const gchar *username);
168 
169 /* External command (keyboard, reader) */
170 typedef struct
171 {
172     const gchar *name;
173 
174     gchar **argv;
175     gint argc;
176 
177     GPid pid;
178     GtkWidget *menu_item;
179     GtkWidget *widget;
180 } MenuCommand;
181 
182 static MenuCommand *menu_command_parse (const gchar *name, const gchar *value, GtkWidget *menu_item);
183 static MenuCommand *menu_command_parse_extended (const gchar *name,
184                                                  const gchar *value, GtkWidget *menu_item,
185                                                  const gchar *xid_app, const gchar *xid_arg);
186 static gboolean menu_command_run (MenuCommand *command);
187 static gboolean menu_command_stop (MenuCommand *command);
188 static void menu_command_terminated_cb (GPid pid, gint status, MenuCommand *command);
189 
190 static MenuCommand *a11y_keyboard_command;
191 static MenuCommand *a11y_reader_command;
192 
193 static void a11y_menuitem_toggled_cb (GtkCheckMenuItem *item, const gchar* name);
194 
195 /* Session */
196 static gchar *current_session;
197 static gboolean is_valid_session (GList* items, const gchar* session);
198 static gchar* get_session (void);
199 static void set_session (const gchar *session);
200 void session_selected_cb (GtkMenuItem *menuitem, gpointer user_data);
201 
202 /* Sesion language */
203 static gchar *current_language;
204 static gchar* get_language (void);
205 static void set_language (const gchar *language);
206 void language_selected_cb (GtkMenuItem *menuitem, gpointer user_data);
207 
208 /* Screensaver values */
209 static int timeout, interval, prefer_blanking, allow_exposures;
210 
211 /* Handling monitors backgrounds */
212 static const gint USER_BACKGROUND_DELAY = 250;
213 static GreeterBackground *greeter_background;
214 
215 /* Authentication state */
216 static gboolean cancelling = FALSE, prompted = FALSE;
217 static gboolean prompt_active = FALSE, password_prompted = FALSE;
218 
219 /* Pending questions */
220 static GSList *pending_questions = NULL;
221 
222 typedef struct
223 {
224     gboolean is_prompt;
225     union
226     {
227         LightDMMessageType message;
228         LightDMPromptType prompt;
229     } type;
230     gchar *text;
231 } PAMConversationMessage;
232 
233 static void pam_message_finalize (PAMConversationMessage *message);
234 static void process_prompts (LightDMGreeter *greeter);
235 static void show_prompt_cb (LightDMGreeter *greeter, const gchar *text, LightDMPromptType type);
236 
237 /* Panel and indicators */
238 
239 typedef enum
240 {
241     PANEL_ITEM_INDICATOR,
242     PANEL_ITEM_SPACER,
243     PANEL_ITEM_SEPARATOR,
244     PANEL_ITEM_TEXT
245 } GreeterPanelItemType;
246 
247 static const gchar *PANEL_ITEM_STYLE = "panel-item";
248 static const gchar *PANEL_ITEM_STYLE_HOVERED = "panel-item-hovered";
249 static const gchar *PANEL_ITEM_STYLES[] =
250 {
251     "panel-item-indicator",
252     "panel-item-spacer",
253     "panel-item-separator",
254     "panel-item-text"
255 };
256 
257 static const gchar *PANEL_ITEM_DATA_INDEX = "panel-item-data-index";
258 
259 #ifdef HAVE_LIBINDICATOR
260 static const gchar *INDICATOR_ITEM_DATA_OBJECT = "indicator-item-data-object";  /* <IndicatorObject*> */
261 static const gchar *INDICATOR_ITEM_DATA_ENTRY  = "indicator-item-data-entry";   /* <IndicatorObjectEntry*> */
262 static const gchar *INDICATOR_ITEM_DATA_BOX    = "indicator-item-data-box";     /* <GtkBox*> */
263 static const gchar *INDICATOR_DATA_MENUITEMS   = "indicator-data-menuitems";    /* <GHashTable*> */
264 #endif
265 
266 static const gchar *LANGUAGE_DATA_CODE = "language-code";   /* <gchar*> e.g. "de_DE.UTF-8" */
267 static const gchar *SESSION_DATA_KEY = "session-key";       /* <gchar*> session name */
268 
269 /* Layout indicator */
270 #ifdef HAVE_LIBXKLAVIER
271 static XklEngine *xkl_engine;
272 static const gchar *LAYOUT_DATA_GROUP = "layout-group";     /* <gchar*> */
273 #else
274 static const gchar *LAYOUT_DATA_NAME = "layout-name";       /* <gchar*> */
275 #endif
276 static const gchar *LAYOUT_DATA_LABEL = "layout-label";     /* <gchar*> e.g. "English (US)" */
277 
278 static gboolean panel_item_enter_notify_cb (GtkWidget *widget, GdkEvent *event, gpointer enter);
279 static void panel_add_item (GtkWidget *widget, gint index, GreeterPanelItemType item_type);
280 static gboolean menu_item_accel_closure_cb (GtkAccelGroup *accel_group, GObject *acceleratable, guint keyval, GdkModifierType modifier, gpointer data);
281 /* Maybe unnecessary (in future) trick to enable accelerators for hidden/detached menu items */
282 static void reassign_menu_item_accel (GtkWidget *item);
283 
284 static void init_indicators (void);
285 
286 static void layout_selected_cb (GtkCheckMenuItem *menuitem, gpointer user_data);
287 static void update_layouts_menu (void);
288 static void update_layouts_menu_state (void);
289 #ifdef HAVE_LIBXKLAVIER
290 static void xkl_state_changed_cb (XklEngine *engine, XklEngineStateChange change, gint group, gboolean restore, gpointer user_data);
291 static void xkl_config_changed_cb (XklEngine *engine, gpointer user_data);
292 static GdkFilterReturn xkl_xevent_filter (GdkXEvent *xev, GdkEvent *event, gpointer  data);
293 #endif
294 
295 /* a11y indicator */
296 static gchar *default_font_name,
297              *default_theme_name,
298              *default_icon_theme_name,
299              *default_cursor_theme_name;
300 void a11y_font_cb (GtkCheckMenuItem *item);
301 void a11y_contrast_cb (GtkCheckMenuItem *item);
302 void a11y_keyboard_cb (GtkCheckMenuItem *item, gpointer user_data);
303 void a11y_reader_cb (GtkCheckMenuItem *item, gpointer user_data);
304 
305 /* Power indicator */
306 static void power_menu_cb (GtkWidget *menuitem, gpointer userdata);
307 void suspend_cb (GtkWidget *widget, LightDMGreeter *greeter);
308 void hibernate_cb (GtkWidget *widget, LightDMGreeter *greeter);
309 void restart_cb (GtkWidget *widget, LightDMGreeter *greeter);
310 void shutdown_cb (GtkWidget *widget, LightDMGreeter *greeter);
311 
312 static void read_monitor_configuration (const gchar *group, const gchar *name);
313 
314 struct SavedFocusData
315 {
316     GtkWidget *widget;
317     gint editable_pos;
318 };
319 
320 gpointer greeter_save_focus(GtkWidget* widget);
321 void greeter_restore_focus(const gpointer saved_data);
322 
323 
324 static void
read_monitor_configuration(const gchar * group,const gchar * name)325 read_monitor_configuration (const gchar *group, const gchar *name)
326 {
327     gchar *background;
328 
329     g_debug ("[Configuration] Monitor configuration found: '%s'", name);
330 
331     background = config_get_string (group, CONFIG_KEY_BACKGROUND, NULL);
332     greeter_background_set_monitor_config (greeter_background, name, background,
333                                            config_get_bool (group, CONFIG_KEY_USER_BACKGROUND, -1),
334                                            config_get_bool (group, CONFIG_KEY_LAPTOP, -1),
335                                            config_get_int (group, CONFIG_KEY_T_DURATION, -1),
336                                            config_get_enum (group, CONFIG_KEY_T_TYPE,
337                                                 TRANSITION_TYPE_FALLBACK,
338                                                 "none",         TRANSITION_TYPE_NONE,
339                                                 "linear",       TRANSITION_TYPE_LINEAR,
340                                                 "ease-in-out",  TRANSITION_TYPE_EASE_IN_OUT, NULL));
341     g_free (background);
342 }
343 
344 gpointer
greeter_save_focus(GtkWidget * widget)345 greeter_save_focus(GtkWidget* widget)
346 {
347     GtkWidget             *window;
348     struct SavedFocusData *data;
349 
350     window = gtk_widget_get_toplevel(widget);
351     if (!GTK_IS_WINDOW (window))
352         return NULL;
353 
354     data = g_new0 (struct SavedFocusData, 1);
355     data->widget = gtk_window_get_focus (GTK_WINDOW (window));
356     data->editable_pos = GTK_IS_EDITABLE(data->widget) ? gtk_editable_get_position (GTK_EDITABLE (data->widget)) : -1;
357 
358     return data;
359 }
360 
361 void
greeter_restore_focus(const gpointer saved_data)362 greeter_restore_focus(const gpointer saved_data)
363 {
364     struct SavedFocusData *data = saved_data;
365 
366     if (!saved_data || !GTK_IS_WIDGET (data->widget))
367         return;
368 
369     gtk_widget_grab_focus (data->widget);
370     if (GTK_IS_EDITABLE(data->widget) && data->editable_pos > -1)
371         gtk_editable_set_position(GTK_EDITABLE(data->widget), data->editable_pos);
372 }
373 
374 static void
infobar_revealed_cb_710888(GObject * gobject,GParamSpec * pspec,gpointer user_data)375 infobar_revealed_cb_710888 (GObject *gobject, GParamSpec *pspec, gpointer user_data)
376 {
377     gtk_widget_set_visible (GTK_WIDGET (info_bar), !message_label_is_empty ());
378 }
379 
380 /* Terminating */
381 
382 static GPid
spawn_argv_pid(gchar ** argv,GSpawnFlags flags,gint * pfd,GError ** perror)383 spawn_argv_pid (gchar **argv, GSpawnFlags flags, gint *pfd, GError **perror)
384 {
385     GPid pid = 0;
386     GError *error = NULL;
387     gboolean spawned = FALSE;
388 
389     if (pfd)
390         spawned = g_spawn_async_with_pipes (NULL, argv, NULL, flags, NULL, NULL, &pid, NULL, pfd, NULL, perror);
391     else
392         spawned = g_spawn_async (NULL, argv, NULL, flags, NULL, NULL, &pid, &error);
393 
394     if (spawned)
395     {
396         pids_to_close = g_slist_prepend (pids_to_close, GINT_TO_POINTER (pid));
397         g_debug ("[PIDs] Command executed (#%d): %s", pid, argv[0]);
398     }
399     else if (perror)
400     {
401         *perror = error;
402     }
403     else
404     {
405         g_warning ("[PIDs] Failed to execute command: %s", argv[0]);
406         g_clear_error (&error);
407     }
408 
409     return pid;
410 }
411 
412 #if defined(AT_SPI_COMMAND) || defined(INDICATOR_SERVICES_COMMAND)
413 static GPid
spawn_line_pid(const gchar * line,GSpawnFlags flags,GError ** perror)414 spawn_line_pid (const gchar *line, GSpawnFlags flags, GError **perror)
415 {
416     gint argc = 0;
417     gchar **argv = NULL;
418     GError *error = NULL;
419 
420     if (g_shell_parse_argv (line, &argc, &argv, &error))
421     {
422         GPid pid = spawn_argv_pid (argv, flags, NULL, perror);
423         g_strfreev (argv);
424         return pid;
425     }
426     else if (!perror && error)
427     {
428         g_warning ("[PIDs] Failed to parse command line: %s, %s", error->message, line);
429         g_clear_error (&error);
430     }
431     else if (error)
432         *perror = error;
433 
434     return 0;
435 }
436 #endif
437 
438 static void
close_pid(GPid pid,gboolean remove)439 close_pid (GPid pid, gboolean remove)
440 {
441     if (!pid)
442         return;
443 
444     if (remove)
445         pids_to_close = g_slist_remove (pids_to_close, GINT_TO_POINTER (pid));
446 
447     if (kill (pid, SIGTERM) == 0)
448         g_debug ("[PIDs] Process terminated: #%d", pid);
449     else
450         g_warning ("[PIDs] Failed to terminate process #%d: %s", pid, g_strerror (errno));
451 
452     g_spawn_close_pid (pid);
453 }
454 
455 static void
sigterm_cb(gpointer user_data)456 sigterm_cb (gpointer user_data)
457 {
458     gboolean is_callback = GPOINTER_TO_INT (user_data);
459 
460     if (is_callback)
461         g_debug ("SIGTERM received");
462 
463     if (pids_to_close)
464     {
465         g_slist_foreach (pids_to_close, (GFunc)close_pid, GINT_TO_POINTER (FALSE));
466         g_slist_free (pids_to_close);
467         pids_to_close = NULL;
468     }
469 
470     if (is_callback)
471     {
472         gtk_main_quit ();
473         #ifdef KILL_ON_SIGTERM
474         /* LP: #1445461 */
475         g_debug ("Killing greeter with exit()...");
476         exit (EXIT_SUCCESS);
477         #endif
478     }
479 }
480 
481 /* Power window */
482 
483 static gboolean
show_power_prompt(const gchar * action,const gchar * icon,const gchar * title,const gchar * message)484 show_power_prompt (const gchar *action, const gchar* icon, const gchar* title, const gchar* message)
485 {
486     GMainLoop        *loop;
487     GtkWidget        *focused;
488 
489     gboolean          session_enabled;
490     gboolean          language_enabled;
491     gboolean          power_present = FALSE;
492 
493     gsize             length;
494     guint             i;
495     gint              logged_in_users = 0;
496 
497     gchar           **names;
498     GList            *items;
499     GList            *item;
500 
501     gchar            *new_message = NULL;
502     gchar            *dialog_name = NULL;
503     gchar            *button_name = NULL;
504     GtkResponseType   response;
505 
506     /* Do anything only when power indicator is present */
507     names = config_get_string_list (NULL, CONFIG_KEY_INDICATORS, NULL);
508     if (!names)
509        names = (gchar**)DEFAULT_LAYOUT;
510     length = g_strv_length (names);
511     for (i = 0; i < length; ++i)
512     {
513         if (g_strcmp0 (names[i], "~power") == 0)
514         {   /* Power menu is present */
515             power_present = TRUE;
516             break;
517         }
518     }
519     if (names && names != (gchar**)DEFAULT_LAYOUT)
520         g_strfreev (names);
521 
522     if (power_present != TRUE) {
523         return FALSE;
524     }
525 
526     /* Check if there are still users logged in, count them and if so, display a warning */
527     items = lightdm_user_list_get_users (lightdm_user_list_get_instance ());
528     for (item = items; item; item = item->next)
529     {
530         LightDMUser *user = item->data;
531         if (lightdm_user_get_logged_in (user))
532             logged_in_users++;
533     }
534 
535     if (logged_in_users > 0)
536     {
537         gchar *warning = g_strdup_printf (ngettext ("Warning: There is still %d user logged in.",
538                                                     "Warning: There are still %d users logged in.",
539                                                     logged_in_users),
540                                           logged_in_users);
541         message = new_message = g_markup_printf_escaped ("<b>%s</b>\n%s", warning, message);
542         g_free (warning);
543     }
544 
545     dialog_name = g_strconcat (action, "_dialog", NULL);
546     button_name = g_strconcat (action, "_button", NULL);
547 
548     gtk_widget_set_name (power_window, dialog_name);
549     gtk_widget_set_name (GTK_WIDGET (power_ok_button), button_name);
550     gtk_button_set_label (power_ok_button, title);
551     gtk_label_set_label (power_title, title);
552     gtk_label_set_markup (power_text, message);
553     gtk_image_set_from_icon_name (power_icon, icon, GTK_ICON_SIZE_DIALOG);
554 
555     g_free (button_name);
556     g_free (dialog_name);
557     g_free (new_message);
558 
559     loop = g_main_loop_new (NULL, FALSE);
560     g_object_set_data (G_OBJECT (power_window), POWER_WINDOW_DATA_LOOP, loop);
561     g_object_set_data (G_OBJECT (power_window), POWER_WINDOW_DATA_RESPONSE, GINT_TO_POINTER (GTK_RESPONSE_CANCEL));
562 
563     focused = gtk_window_get_focus (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (screen_overlay))));
564     session_enabled = gtk_widget_get_sensitive (session_menuitem);
565     language_enabled = gtk_widget_get_sensitive (language_menuitem);
566 
567     gtk_widget_set_sensitive (power_menuitem, FALSE);
568     gtk_widget_set_sensitive (session_menuitem, FALSE);
569     gtk_widget_set_sensitive (language_menuitem, FALSE);
570     gtk_widget_hide (login_window);
571     gtk_widget_show (power_window);
572     gtk_widget_grab_focus (GTK_WIDGET (power_ok_button));
573 
574     g_main_loop_run (loop);
575     response = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (power_window), POWER_WINDOW_DATA_RESPONSE));
576     g_main_loop_unref (loop);
577 
578     gtk_widget_hide (power_window);
579     gtk_widget_show (login_window);
580     gtk_widget_set_sensitive (power_menuitem, TRUE);
581     gtk_widget_set_sensitive (session_menuitem, session_enabled);
582     gtk_widget_set_sensitive (language_menuitem, language_enabled);
583 
584     if (focused)
585         gtk_widget_grab_focus (focused);
586 
587     return response == GTK_RESPONSE_YES;
588 }
589 
590 void
power_button_clicked_cb(GtkButton * button,gpointer user_data)591 power_button_clicked_cb (GtkButton *button, gpointer user_data)
592 {
593     GMainLoop *loop = g_object_get_data (G_OBJECT (power_window), POWER_WINDOW_DATA_LOOP);
594     if (g_main_loop_is_running (loop))
595         g_main_loop_quit (loop);
596 
597     g_object_set_data (G_OBJECT (power_window), POWER_WINDOW_DATA_RESPONSE,
598                        GINT_TO_POINTER (button == power_ok_button ? GTK_RESPONSE_YES : GTK_RESPONSE_CANCEL));
599 }
600 
601 gboolean
power_window_key_press_event_cb(GtkWidget * widget,GdkEventKey * event,gpointer user_data)602 power_window_key_press_event_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
603 {
604     if (event->keyval == GDK_KEY_Escape)
605     {
606         power_button_clicked_cb (power_cancel_button, NULL);
607         return TRUE;
608     }
609     return FALSE;
610 }
611 
612 /* Handling window position */
613 
614 static gboolean
read_position_from_str(const gchar * s,DimensionPosition * x)615 read_position_from_str (const gchar *s, DimensionPosition *x)
616 {
617     DimensionPosition p;
618     gchar *end = NULL;
619     gchar **parts = g_strsplit (s, ",", 2);
620     if (parts[0])
621     {
622         p.value = g_ascii_strtoll (parts[0], &end, 10);
623         p.percentage = end && end[0] == '%';
624         p.sign = (p.value < 0 || (p.value == 0 && parts[0][0] == '-')) ? -1 : +1;
625         if (p.value < 0)
626             p.value *= -1;
627         if (g_strcmp0(parts[1], "start") == 0)
628             p.anchor = -1;
629         else if (g_strcmp0(parts[1], "center") == 0)
630             p.anchor = 0;
631         else if (g_strcmp0(parts[1], "end") == 0)
632             p.anchor = +1;
633         else
634             p.anchor = p.sign > 0 ? -1 : +1;
635         *x = p;
636     }
637     else
638         x = NULL;
639     g_strfreev (parts);
640     return x != NULL;
641 }
642 
643 static WindowPosition*
str_to_position(const gchar * str,const WindowPosition * default_value)644 str_to_position (const gchar *str, const WindowPosition *default_value)
645 {
646     WindowPosition  *pos = g_new0 (WindowPosition, 1);
647     gchar           *size_delim;
648     gchar           *value;
649     gchar           *x;
650     gchar           *y;
651 
652     *pos = *default_value;
653 
654     if (str)
655     {
656         value = g_strdup (str);
657         x = value;
658         y = strchr (value, ' ');
659         if (y)
660             (y++)[0] = '\0';
661 
662         if (read_position_from_str (x, &pos->x))
663             /* If there is no y-part then y = x */
664             if (!y || !read_position_from_str (y, &pos->y))
665                 pos->y = pos->x;
666 
667         size_delim = strchr (y ? y : x, ';');
668         if (size_delim)
669         {
670             x = size_delim + 1;
671             if (read_position_from_str (x, &pos->width))
672             {
673                 y = strchr (x, ' ');
674                 if (y)
675                     (y++)[0] = '\0';
676                 if (!y || !read_position_from_str (y, &pos->height))
677                     if (!default_value->use_size)
678                         pos->height = pos->width;
679                 pos->use_size = TRUE;
680             }
681         }
682 
683         g_free (value);
684     }
685 
686     return pos;
687 }
688 
689 static gint
get_absolute_position(const DimensionPosition * p,gint screen,gint window)690 get_absolute_position (const DimensionPosition *p, gint screen, gint window)
691 {
692     gint x = p->percentage ? (screen*p->value)/100 : p->value;
693     x = p->sign < 0 ? screen - x : x;
694     if (p->anchor > 0)
695         x -= window;
696     else if (p->anchor == 0)
697         x -= window/2;
698 
699     if (x < 0)                     /* Offscreen: left/top */
700         return 0;
701     else if (x + window > screen)  /* Offscreen: right/bottom */
702         return screen - window;
703     else
704         return x;
705 }
706 
707 gboolean
screen_overlay_get_child_position_cb(GtkWidget * overlay,GtkWidget * widget,GdkRectangle * allocation,gpointer user_data)708 screen_overlay_get_child_position_cb (GtkWidget *overlay, GtkWidget *widget, GdkRectangle *allocation, gpointer user_data)
709 {
710     const WindowPosition *pos = g_object_get_data (G_OBJECT (widget), WINDOW_DATA_POSITION);
711     gint                  screen_width;
712     gint                  screen_height;
713     gint                  panel_height;
714 
715     if (!pos)
716         return FALSE;
717 
718     screen_width = gtk_widget_get_allocated_width (overlay);
719     screen_height = gtk_widget_get_allocated_height (overlay);
720 
721     if (pos->use_size)
722     {
723         allocation->width = get_absolute_position (&pos->width, screen_width, 0);
724         allocation->height = get_absolute_position (&pos->height, screen_height, 0);
725     }
726     else
727     {
728         gtk_widget_get_preferred_width (widget, NULL, &allocation->width);
729         gtk_widget_get_preferred_height (widget, NULL, &allocation->height);
730     }
731 
732     allocation->x = get_absolute_position (&pos->x, screen_width, allocation->width);
733     allocation->y = get_absolute_position (&pos->y, screen_height, allocation->height);
734 
735     /* Do not overlap panel window */
736     panel_height = gtk_widget_get_allocated_height (panel_window);
737     if (panel_height && gtk_widget_get_visible (panel_window))
738     {
739         GtkAlign valign = gtk_widget_get_valign (panel_window);
740         if (valign == GTK_ALIGN_START && allocation->y < panel_height)
741             allocation->y = panel_height;
742         else if (valign == GTK_ALIGN_END && screen_height - allocation->y - allocation->height < panel_height)
743             allocation->y = screen_height - allocation->height - panel_height;
744     }
745 
746     return TRUE;
747 }
748 
749 /* Clock */
750 
751 #pragma GCC diagnostic push
752 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
753 
754 static gboolean
clock_timeout_thread(void)755 clock_timeout_thread (void)
756 {
757     time_t rawtime;
758     struct tm * timeinfo;
759     gchar time_str[50];
760     gchar *markup;
761 
762     time (&rawtime);
763     timeinfo = localtime (&rawtime);
764 
765     strftime (time_str, 50, clock_format, timeinfo);
766     markup = g_markup_printf_escaped ("<b>%s</b>", time_str);
767     if (g_strcmp0 (markup, gtk_label_get_label (GTK_LABEL (clock_label))) != 0)
768         gtk_label_set_markup (GTK_LABEL (clock_label), markup);
769     g_free (markup);
770 
771     return TRUE;
772 }
773 
774 #pragma GCC diagnostic pop
775 
776 /* Message label */
777 
778 static gboolean
message_label_is_empty(void)779 message_label_is_empty (void)
780 {
781     return gtk_label_get_text (message_label)[0] == '\0';
782 }
783 
784 static void
set_message_label(LightDMMessageType type,const gchar * text)785 set_message_label (LightDMMessageType type, const gchar *text)
786 {
787     if (type == LIGHTDM_MESSAGE_TYPE_INFO)
788         gtk_info_bar_set_message_type (info_bar, GTK_MESSAGE_INFO);
789     else
790         gtk_info_bar_set_message_type (info_bar, GTK_MESSAGE_ERROR);
791     gtk_label_set_text (message_label, text);
792     gtk_widget_set_visible (GTK_WIDGET (info_bar), text && text[0]);
793 }
794 
795 /* User image */
796 
797 static void
set_user_image(const gchar * username)798 set_user_image (const gchar *username)
799 {
800     const gchar *path;
801     LightDMUser *user = NULL;
802     GdkPixbuf *image = NULL;
803     GError *error = NULL;
804 
805     if (!gtk_widget_get_visible (GTK_WIDGET (user_image)))
806         return;
807 
808     if (username)
809         user = lightdm_user_list_get_user_by_name (lightdm_user_list_get_instance (), username);
810 
811     if (user)
812     {
813         path = lightdm_user_get_image (user);
814         if (path)
815         {
816             image = gdk_pixbuf_new_from_file_at_scale (path, 80, 80, FALSE, &error);
817             if (image)
818             {
819                 gtk_image_set_from_pixbuf (GTK_IMAGE (user_image), image);
820                 g_object_unref (image);
821                 return;
822             }
823             else
824             {
825                 g_debug ("Failed to load user image: %s", error->message);
826                 g_clear_error (&error);
827             }
828         }
829     }
830 
831     if (default_user_pixbuf)
832         gtk_image_set_from_pixbuf (GTK_IMAGE (user_image), default_user_pixbuf);
833     else
834         gtk_image_set_from_icon_name (GTK_IMAGE (user_image), default_user_icon, GTK_ICON_SIZE_DIALOG);
835 }
836 
837 /* MenuCommand */
838 
839 static MenuCommand*
menu_command_parse(const gchar * name,const gchar * value,GtkWidget * menu_item)840 menu_command_parse (const gchar *name, const gchar *value, GtkWidget *menu_item)
841 {
842     return menu_command_parse_extended (name, value, menu_item, NULL, NULL);
843 }
844 
845 static MenuCommand*
menu_command_parse_extended(const gchar * name,const gchar * value,GtkWidget * menu_item,const gchar * xid_app,const gchar * xid_arg)846 menu_command_parse_extended (const gchar *name,
847                              const gchar *value,    /* String to parse */
848                              GtkWidget   *menu_item,  /* Menu item to connect */
849                              const gchar *xid_app,  /* Program that have "xembed" mode support */
850                              const gchar *xid_arg)  /* Argument that must be added to command line */
851 {
852     MenuCommand  *command;
853     GError       *error = NULL;
854     gchar       **argv;
855     gint          argc = 0;
856 
857     if (!value)
858         return NULL;
859 
860     if (!g_shell_parse_argv (value, &argc, &argv, &error))
861     {
862         if (error)
863             g_warning ("[Command/%s] Failed to parse command line: %s", name, error->message);
864         g_clear_error (&error);
865         return NULL;
866     }
867 
868     command = g_new0 (MenuCommand, 1);
869     command->menu_item = menu_item;
870     command->argc = argc;
871     command->argv = argv;
872 
873     if (g_strcmp0 (argv[0], xid_app) == 0)
874     {
875         gboolean have_xid_arg = FALSE;
876         gint i;
877         for (i = 1; i < argc; ++i)
878             if (g_strcmp0 (argv[i], xid_arg) == 0)
879             {
880                 have_xid_arg = TRUE;
881                 break;
882             }
883         if (!have_xid_arg)
884         {
885             gchar *new_value = g_strdup_printf ("%s %s", value, xid_arg);
886 
887             if (g_shell_parse_argv (new_value, &argc, &argv, &error))
888             {
889                 g_strfreev (command->argv);
890                 command->argc = argc;
891                 command->argv = argv;
892                 have_xid_arg = TRUE;
893             }
894             else
895             {
896                 if (error)
897                     g_warning ("[Command/%s] Failed to parse command line: %s", name, error->message);
898                 g_clear_error (&error);
899             }
900             g_free (new_value);
901         }
902 
903         if (have_xid_arg)
904         {
905             command->widget = gtk_event_box_new ();
906             gtk_overlay_add_overlay (screen_overlay, command->widget);
907         }
908     }
909     command->name = name;
910     return command;
911 }
912 
913 static gboolean
menu_command_run(MenuCommand * command)914 menu_command_run (MenuCommand *command)
915 {
916     GError *error = NULL;
917 
918     g_return_val_if_fail (command && g_strv_length (command->argv), FALSE);
919 
920     command->pid = 0;
921 
922     g_debug ("[Command/%s] Running command", command->name);
923 
924     if (command->widget)
925     {
926         GtkSocket* socket = NULL;
927         gint out_fd = 0;
928         GPid pid = spawn_argv_pid (command->argv, G_SPAWN_SEARCH_PATH, &out_fd, &error);
929 
930         if (pid && out_fd)
931         {
932             gchar* text = NULL;
933             GIOChannel* out_channel = g_io_channel_unix_new (out_fd);
934             if (g_io_channel_read_line (out_channel, &text, NULL, NULL, &error) == G_IO_STATUS_NORMAL)
935             {
936                 gchar* end_ptr = NULL;
937                 gint id;
938 
939                 text = g_strstrip (text);
940                 id = g_ascii_strtoll (text, &end_ptr, 0);
941 
942                 if (id != 0 && end_ptr > text)
943                 {
944                     socket = GTK_SOCKET (gtk_socket_new ());
945                     gtk_container_foreach (GTK_CONTAINER (command->widget), (GtkCallback)gtk_widget_destroy, NULL);
946                     gtk_container_add (GTK_CONTAINER (command->widget), GTK_WIDGET (socket));
947                     gtk_socket_add_id (socket, id);
948                     gtk_widget_show_all (GTK_WIDGET (command->widget));
949 
950                     command->pid = pid;
951                 }
952                 else
953                     g_warning ("[Command/%s] Failed to get '%s' socket for: unrecognized output",
954                                command->name, command->argv[0]);
955 
956                 g_free (text);
957             }
958         }
959 
960         if (!command->pid && pid)
961             close_pid (pid, TRUE);
962     }
963     else
964     {
965         command->pid = spawn_argv_pid (command->argv, G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, NULL, &error);
966         if (command->pid)
967             g_child_watch_add (command->pid, (GChildWatchFunc)menu_command_terminated_cb, command);
968     }
969 
970     if (!command->pid)
971     {
972         if (error)
973             g_warning ("[Command/%s] Failed to run: %s", command->name, error->message);
974         gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (command->menu_item), FALSE);
975     }
976 
977     g_clear_error (&error);
978 
979     return command->pid;
980 }
981 
982 static gboolean
menu_command_stop(MenuCommand * command)983 menu_command_stop (MenuCommand *command)
984 {
985     g_return_val_if_fail (command, FALSE);
986 
987     if (command->pid)
988     {
989         g_debug ("[Command/%s] Stopping command", command->name);
990         close_pid (command->pid, TRUE);
991         command->pid = 0;
992         if (command->menu_item)
993             gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (command->menu_item), FALSE);
994         if (command->widget)
995             gtk_widget_hide (command->widget);
996     }
997     return TRUE;
998 }
999 
1000 static void
menu_command_terminated_cb(GPid pid,gint status,MenuCommand * command)1001 menu_command_terminated_cb (GPid pid, gint status, MenuCommand *command)
1002 {
1003     menu_command_stop (command);
1004 }
1005 
1006 static void
a11y_menuitem_toggled_cb(GtkCheckMenuItem * item,const gchar * name)1007 a11y_menuitem_toggled_cb (GtkCheckMenuItem *item, const gchar* name)
1008 {
1009     config_set_bool (STATE_SECTION_A11Y, name, gtk_check_menu_item_get_active (item));
1010 }
1011 
1012 /* Session */
1013 
1014 static gboolean
is_valid_session(GList * items,const gchar * session)1015 is_valid_session (GList* items, const gchar* session)
1016 {
1017     for (; items; items = g_list_next (items))
1018         if (g_strcmp0 (session, lightdm_session_get_key (items->data)) == 0)
1019             return TRUE;
1020     return FALSE;
1021 }
1022 
1023 static gchar*
get_session(void)1024 get_session (void)
1025 {
1026     return g_strdup (current_session);
1027 }
1028 
1029 static void
set_session(const gchar * session)1030 set_session (const gchar *session)
1031 {
1032     gchar *last_session = NULL;
1033     GList *sessions = lightdm_get_sessions ();
1034 
1035     /* Validation */
1036     if (!session || !is_valid_session (sessions, session))
1037     {
1038         /* previous session */
1039         last_session = config_get_string (STATE_SECTION_GREETER, STATE_KEY_LAST_SESSION, NULL);
1040         if (last_session && g_strcmp0 (session, last_session) != 0 &&
1041             is_valid_session (sessions, last_session))
1042             session = last_session;
1043         else
1044         {
1045             /* default */
1046             const gchar* default_session = lightdm_greeter_get_default_session_hint (greeter);
1047             if (g_strcmp0 (session, default_session) != 0 &&
1048                 is_valid_session (sessions, default_session))
1049                 session = default_session;
1050             /* first in the sessions list */
1051             else if (sessions)
1052                 session = lightdm_session_get_key (sessions->data);
1053             /* give up */
1054             else
1055                 session = NULL;
1056         }
1057     }
1058 
1059     if (gtk_widget_get_visible (session_menuitem))
1060     {
1061         GList *menu_iter = NULL;
1062         GList *menu_items = gtk_container_get_children (GTK_CONTAINER (session_menu));
1063         if (session)
1064         {
1065             for (menu_iter = menu_items; menu_iter != NULL; menu_iter = g_list_next (menu_iter))
1066                 if (g_strcmp0 (session, g_object_get_data (G_OBJECT (menu_iter->data), SESSION_DATA_KEY)) == 0)
1067                 {
1068                     /* Set menuitem-image to session-badge */
1069                     GtkIconTheme *icon_theme = gtk_icon_theme_get_default ();
1070                     gchar* session_name = g_ascii_strdown (session, -1);
1071                     gchar* icon_name = g_strdup_printf ("%s_badge-symbolic", session_name);
1072                     g_free (session_name);
1073                     if (gtk_icon_theme_has_icon (icon_theme, icon_name))
1074                         gtk_image_set_from_icon_name (GTK_IMAGE (session_badge), icon_name, GTK_ICON_SIZE_MENU);
1075                     else
1076                         gtk_image_set_from_icon_name (GTK_IMAGE (session_badge), "document-properties-symbolic", GTK_ICON_SIZE_MENU);
1077                     g_free (icon_name);
1078                     break;
1079                 }
1080         }
1081         if (!menu_iter)
1082             menu_iter = menu_items;
1083 
1084         if (menu_iter)
1085 	        gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_iter->data), TRUE);
1086     }
1087 
1088     g_free (current_session);
1089     current_session = g_strdup (session);
1090     g_free (last_session);
1091 }
1092 
1093 void
session_selected_cb(GtkMenuItem * menuitem,gpointer user_data)1094 session_selected_cb (GtkMenuItem *menuitem, gpointer user_data)
1095 {
1096     if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem)))
1097        set_session (g_object_get_data (G_OBJECT (menuitem), SESSION_DATA_KEY));
1098 }
1099 
1100 
1101 /* Session language */
1102 
1103 static gchar*
get_language(void)1104 get_language (void)
1105 {
1106     GList *menu_items, *menu_iter;
1107 
1108     /* if the user manually selected a language, use it */
1109     if (current_language)
1110         return g_strdup (current_language);
1111 
1112     menu_items = gtk_container_get_children (GTK_CONTAINER (language_menu));
1113     for (menu_iter = menu_items; menu_iter != NULL; menu_iter = g_list_next (menu_iter))
1114     {
1115         if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menu_iter->data)))
1116             return g_strdup (g_object_get_data (G_OBJECT (menu_iter->data), LANGUAGE_DATA_CODE));
1117     }
1118 
1119     return NULL;
1120 }
1121 
1122 static void
set_language(const gchar * language)1123 set_language (const gchar *language)
1124 {
1125     const gchar *default_language = NULL;
1126     GList *menu_items, *menu_iter;
1127 
1128     if (!gtk_widget_get_visible (language_menuitem))
1129     {
1130         g_free (current_language);
1131         current_language = g_strdup (language);
1132         return;
1133     }
1134 
1135     menu_items = gtk_container_get_children (GTK_CONTAINER (language_menu));
1136 
1137     if (language)
1138     {
1139         for (menu_iter = menu_items; menu_iter != NULL; menu_iter = g_list_next (menu_iter))
1140         {
1141             gchar *s;
1142             gboolean matched;
1143             s = g_strdup (g_object_get_data (G_OBJECT (menu_iter->data), LANGUAGE_DATA_CODE));
1144             matched = g_strcmp0 (s, language) == 0;
1145             g_free (s);
1146             if (matched)
1147             {
1148                 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_iter->data), TRUE);
1149                 g_free (current_language);
1150                 current_language = g_strdup (language);
1151                 gtk_menu_item_set_label (GTK_MENU_ITEM (language_menuitem),language);
1152                 return;
1153             }
1154         }
1155     }
1156 
1157     /* If failed to find this language, then try the default */
1158     if (lightdm_get_language ())
1159     {
1160         default_language = lightdm_language_get_code (lightdm_get_language ());
1161         gtk_menu_item_set_label (GTK_MENU_ITEM (language_menuitem), default_language);
1162     }
1163     if (default_language && g_strcmp0 (default_language, language) != 0)
1164         set_language (default_language);
1165     /* If all else fails, just use the first language from the menu */
1166     else
1167     {
1168         for (menu_iter = menu_items; menu_iter != NULL; menu_iter = g_list_next (menu_iter))
1169         {
1170             if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menu_iter->data)))
1171             {
1172                 gtk_menu_item_set_label (GTK_MENU_ITEM (language_menuitem), g_strdup (g_object_get_data (G_OBJECT (menu_iter->data), LANGUAGE_DATA_CODE)));
1173                 break;
1174             }
1175         }
1176     }
1177 }
1178 
1179 void
language_selected_cb(GtkMenuItem * menuitem,gpointer user_data)1180 language_selected_cb (GtkMenuItem *menuitem, gpointer user_data)
1181 {
1182     if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem)))
1183     {
1184        gchar *language = g_object_get_data (G_OBJECT (menuitem), LANGUAGE_DATA_CODE);
1185        set_language (language);
1186     }
1187 }
1188 
1189 /* Pending questions */
1190 
1191 static void
pam_message_finalize(PAMConversationMessage * message)1192 pam_message_finalize (PAMConversationMessage *message)
1193 {
1194     g_free (message->text);
1195     g_free (message);
1196 }
1197 
1198 static void
process_prompts(LightDMGreeter * ldm)1199 process_prompts (LightDMGreeter *ldm)
1200 {
1201     if (!pending_questions)
1202         return;
1203 
1204     /* always allow the user to change username again */
1205     gtk_widget_set_sensitive (GTK_WIDGET (username_entry), TRUE);
1206     gtk_widget_set_sensitive (GTK_WIDGET (password_entry), TRUE);
1207 
1208     /* Special case: no user selected from list, so PAM asks us for the user
1209      * via a prompt. For that case, use the username field */
1210     if (!prompted && pending_questions && !pending_questions->next &&
1211         ((PAMConversationMessage *) pending_questions->data)->is_prompt &&
1212         ((PAMConversationMessage *) pending_questions->data)->type.prompt != LIGHTDM_PROMPT_TYPE_SECRET &&
1213         gtk_widget_get_visible ((GTK_WIDGET (username_entry))) &&
1214         lightdm_greeter_get_authentication_user (ldm) == NULL)
1215     {
1216         prompted = TRUE;
1217         prompt_active = TRUE;
1218         gtk_widget_grab_focus (GTK_WIDGET (username_entry));
1219         gtk_widget_show (GTK_WIDGET (password_entry));
1220         return;
1221     }
1222 
1223     while (pending_questions)
1224     {
1225         PAMConversationMessage *message = (PAMConversationMessage *) pending_questions->data;
1226         pending_questions = g_slist_remove (pending_questions, (gconstpointer) message);
1227 
1228         if (!message->is_prompt)
1229         {
1230             /* FIXME: this doesn't show multiple messages, but that was
1231              * already the case before. */
1232             set_message_label (message->type.message, message->text);
1233             continue;
1234         }
1235 
1236         gtk_widget_show (GTK_WIDGET (password_entry));
1237         gtk_widget_grab_focus (GTK_WIDGET (password_entry));
1238         gtk_entry_set_text (password_entry, "");
1239         gtk_entry_set_visibility (password_entry, message->type.prompt != LIGHTDM_PROMPT_TYPE_SECRET);
1240         if (message_label_is_empty () && password_prompted)
1241         {
1242             /* No message was provided beforehand and this is not the
1243              * first password prompt, so use the prompt as label,
1244              * otherwise the user will be completely unclear of what
1245              * is going on. Actually, the fact that prompt messages are
1246              * not shown is problematic in general, especially if
1247              * somebody uses a custom PAM module that wants to ask
1248              * something different. */
1249             gchar *str = message->text;
1250             if (g_str_has_suffix (str, ": "))
1251                 str = g_strndup (str, strlen (str) - 2);
1252             else if (g_str_has_suffix (str, ":"))
1253                 str = g_strndup (str, strlen (str) - 1);
1254             set_message_label (LIGHTDM_MESSAGE_TYPE_INFO, str);
1255             if (str != message->text)
1256                 g_free (str);
1257         }
1258         gtk_widget_grab_focus (GTK_WIDGET (password_entry));
1259         prompted = TRUE;
1260         password_prompted = TRUE;
1261         prompt_active = TRUE;
1262 
1263         /* If we have more stuff after a prompt, assume that other prompts are pending,
1264          * so stop here. */
1265         break;
1266     }
1267 }
1268 
1269 /* Panel and indicators */
1270 
1271 static gboolean
panel_item_enter_notify_cb(GtkWidget * widget,GdkEvent * event,gpointer enter)1272 panel_item_enter_notify_cb (GtkWidget *widget, GdkEvent *event, gpointer enter)
1273 {
1274     GtkStyleContext *context = gtk_widget_get_style_context (widget);
1275     if (GPOINTER_TO_INT (enter))
1276         gtk_style_context_add_class (context, PANEL_ITEM_STYLE_HOVERED);
1277     else
1278         gtk_style_context_remove_class (context, PANEL_ITEM_STYLE_HOVERED);
1279     return FALSE;
1280 }
1281 
1282 static void
panel_add_item(GtkWidget * widget,gint index,GreeterPanelItemType item_type)1283 panel_add_item (GtkWidget *widget, gint index, GreeterPanelItemType item_type)
1284 {
1285     gint insert_pos = 0;
1286     GList* items = gtk_container_get_children (GTK_CONTAINER (menubar));
1287     GList* item;
1288     for (item = items; item; item = item->next)
1289     {
1290         if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item->data), PANEL_ITEM_DATA_INDEX)) < index)
1291             break;
1292         insert_pos++;
1293     }
1294     g_list_free (items);
1295 
1296     gtk_style_context_add_class (gtk_widget_get_style_context (widget), PANEL_ITEM_STYLE);
1297     gtk_style_context_add_class (gtk_widget_get_style_context (widget), PANEL_ITEM_STYLES[item_type]);
1298     if (item_type == PANEL_ITEM_INDICATOR)
1299     {
1300         g_signal_connect (G_OBJECT (widget), "enter-notify-event",
1301                           G_CALLBACK (panel_item_enter_notify_cb), GINT_TO_POINTER (TRUE));
1302         g_signal_connect (G_OBJECT (widget), "leave-notify-event",
1303                           G_CALLBACK (panel_item_enter_notify_cb), GINT_TO_POINTER (FALSE));
1304     }
1305 
1306     gtk_widget_show (widget);
1307     gtk_menu_shell_insert (GTK_MENU_SHELL (menubar), widget, insert_pos);
1308 }
1309 
1310 #ifdef HAVE_LIBINDICATOR
1311 static gboolean
indicator_entry_scrolled_cb(GtkWidget * menuitem,GdkEventScroll * event,gpointer data)1312 indicator_entry_scrolled_cb (GtkWidget *menuitem, GdkEventScroll *event, gpointer data)
1313 {
1314     IndicatorObject      *io;
1315     IndicatorObjectEntry *entry;
1316 
1317     g_return_val_if_fail (GTK_IS_WIDGET (menuitem), FALSE);
1318 
1319     io = g_object_get_data (G_OBJECT (menuitem), INDICATOR_ITEM_DATA_OBJECT);
1320     entry = g_object_get_data (G_OBJECT (menuitem), INDICATOR_ITEM_DATA_ENTRY);
1321 
1322     g_return_val_if_fail (INDICATOR_IS_OBJECT (io), FALSE);
1323 
1324     g_signal_emit_by_name(io, INDICATOR_OBJECT_SIGNAL_ENTRY_SCROLLED, entry, 1, event->direction);
1325 
1326     return FALSE;
1327 }
1328 
1329 static void
indicator_entry_activated_cb(GtkWidget * widget,gpointer user_data)1330 indicator_entry_activated_cb (GtkWidget *widget, gpointer user_data)
1331 {
1332     IndicatorObject      *io;
1333     IndicatorObjectEntry *entry;
1334 
1335     g_return_if_fail (GTK_IS_WIDGET (widget));
1336 
1337     io = g_object_get_data (G_OBJECT (widget), INDICATOR_ITEM_DATA_OBJECT);
1338     entry = g_object_get_data (G_OBJECT (widget), INDICATOR_ITEM_DATA_ENTRY);
1339 
1340     g_return_if_fail (INDICATOR_IS_OBJECT (io));
1341 
1342     return indicator_object_entry_activate (io, entry, gtk_get_current_event_time ());
1343 }
1344 
1345 static GtkWidget*
indicator_entry_create_menuitem(IndicatorObject * io,IndicatorObjectEntry * entry,GtkWidget * mbar)1346 indicator_entry_create_menuitem (IndicatorObject *io, IndicatorObjectEntry *entry, GtkWidget *mbar)
1347 {
1348     GtkWidget *box, *menuitem;
1349     gint index = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (io), PANEL_ITEM_DATA_INDEX));
1350     box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 3);
1351     menuitem = gtk_menu_item_new ();
1352 
1353     gtk_widget_add_events (GTK_WIDGET (menuitem), GDK_SCROLL_MASK);
1354 
1355     g_object_set_data (G_OBJECT (menuitem), INDICATOR_ITEM_DATA_BOX, box);
1356     g_object_set_data (G_OBJECT (menuitem), INDICATOR_ITEM_DATA_OBJECT, io);
1357     g_object_set_data (G_OBJECT (menuitem), INDICATOR_ITEM_DATA_ENTRY, entry);
1358     g_object_set_data (G_OBJECT (menuitem), PANEL_ITEM_DATA_INDEX, GINT_TO_POINTER (index));
1359 
1360     g_signal_connect (G_OBJECT (menuitem), "activate", G_CALLBACK (indicator_entry_activated_cb), NULL);
1361     g_signal_connect (G_OBJECT (menuitem), "scroll-event", G_CALLBACK (indicator_entry_scrolled_cb), NULL);
1362 
1363     if (entry->image)
1364         gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (entry->image), FALSE, FALSE, 1);
1365 
1366     if (entry->label)
1367         gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (entry->label), FALSE, FALSE, 1);
1368 
1369     if (entry->menu)
1370         gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), GTK_WIDGET (entry->menu));
1371 
1372     gtk_container_add (GTK_CONTAINER (menuitem), box);
1373     gtk_widget_show (box);
1374     panel_add_item (menuitem, index, PANEL_ITEM_INDICATOR);
1375 
1376     return menuitem;
1377 }
1378 
1379 static void
indicator_entry_added_cb(IndicatorObject * io,IndicatorObjectEntry * entry,gpointer user_data)1380 indicator_entry_added_cb (IndicatorObject *io, IndicatorObjectEntry *entry, gpointer user_data)
1381 {
1382     GHashTable *menuitem_lookup;
1383     GtkWidget  *menuitem;
1384 
1385     /* if the menuitem doesn't already exist, create it now */
1386     menuitem_lookup = g_object_get_data (G_OBJECT (io), INDICATOR_DATA_MENUITEMS);
1387     g_return_if_fail (menuitem_lookup);
1388     menuitem = g_hash_table_lookup (menuitem_lookup, entry);
1389     if (!GTK_IS_WIDGET (menuitem))
1390     {
1391         menuitem = indicator_entry_create_menuitem (io, entry, GTK_WIDGET (user_data));
1392         g_hash_table_insert (menuitem_lookup, entry, menuitem);
1393     }
1394 
1395     gtk_widget_show (menuitem);
1396 }
1397 
1398 static void
remove_indicator_entry_cb(GtkWidget * widget,gpointer userdata)1399 remove_indicator_entry_cb (GtkWidget *widget, gpointer userdata)
1400 {
1401     IndicatorObject *io;
1402     GHashTable      *menuitem_lookup;
1403     GtkWidget       *menuitem;
1404     gpointer         entry;
1405 
1406     io = g_object_get_data (G_OBJECT (widget), INDICATOR_ITEM_DATA_OBJECT);
1407     if (!INDICATOR_IS_OBJECT (io))
1408         return;
1409 
1410     entry = g_object_get_data (G_OBJECT (widget), INDICATOR_ITEM_DATA_ENTRY);
1411     if (entry != userdata)
1412         return;
1413 
1414     menuitem_lookup = g_object_get_data (G_OBJECT (io), INDICATOR_DATA_MENUITEMS);
1415     g_return_if_fail (menuitem_lookup);
1416     menuitem = g_hash_table_lookup (menuitem_lookup, entry);
1417     if (GTK_IS_WIDGET (menuitem))
1418         gtk_widget_hide (menuitem);
1419 
1420     gtk_widget_destroy (widget);
1421 }
1422 
1423 static void
indicator_entry_removed_cb(IndicatorObject * io,IndicatorObjectEntry * entry,gpointer user_data)1424 indicator_entry_removed_cb (IndicatorObject *io, IndicatorObjectEntry *entry, gpointer user_data)
1425 {
1426     gtk_container_foreach (GTK_CONTAINER (user_data), remove_indicator_entry_cb, entry);
1427 }
1428 
1429 static void
indicator_menu_show_cb(IndicatorObject * io,IndicatorObjectEntry * entry,guint32 timestamp,gpointer user_data)1430 indicator_menu_show_cb (IndicatorObject *io, IndicatorObjectEntry *entry, guint32 timestamp, gpointer user_data)
1431 {
1432     IndicatorObjectEntry *entrydata;
1433     GtkWidget            *menuitem;
1434     GList                *entries, *lp;
1435 
1436     menuitem = GTK_WIDGET (user_data);
1437 
1438     if (!entry)
1439     {
1440         /* Close any open menus instead of opening one */
1441         entries = indicator_object_get_entries (io);
1442         for (lp = entries; lp; lp = g_list_next (lp))
1443         {
1444             entrydata = lp->data;
1445             gtk_menu_popdown (entrydata->menu);
1446         }
1447         g_list_free (entries);
1448 
1449         /* And tell the menuitem to exit activation mode too */
1450         gtk_menu_shell_cancel (GTK_MENU_SHELL (menuitem));
1451     }
1452 }
1453 
1454 static void
greeter_set_env(const gchar * key,const gchar * value)1455 greeter_set_env (const gchar* key, const gchar* value)
1456 {
1457     GDBusProxy      *proxy;
1458     GVariantBuilder *builder;
1459     GVariant        *result;
1460 
1461     g_setenv (key, value, TRUE);
1462 
1463     proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
1464                                            G_DBUS_PROXY_FLAGS_NONE,
1465                                            NULL,
1466                                            "org.freedesktop.DBus",
1467                                            "/org/freedesktop/DBus",
1468                                            "org.freedesktop.DBus",
1469                                            NULL, NULL);
1470     builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
1471     g_variant_builder_add (builder, "{ss}", key, value);
1472     result = g_dbus_proxy_call_sync (proxy, "UpdateActivationEnvironment", g_variant_new ("(a{ss})", builder),
1473                                      G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL);
1474     g_variant_unref (result);
1475     g_variant_builder_unref (builder);
1476     g_object_unref (proxy);
1477 }
1478 #endif
1479 
1480 static gboolean
menu_item_accel_closure_cb(GtkAccelGroup * accel_group,GObject * acceleratable,guint keyval,GdkModifierType modifier,gpointer data)1481 menu_item_accel_closure_cb (GtkAccelGroup *accel_group,
1482                             GObject *acceleratable, guint keyval,
1483                             GdkModifierType modifier, gpointer data)
1484 {
1485     gtk_menu_item_activate (data);
1486     return FALSE;
1487 }
1488 
1489 /* Maybe unnecessary (in future) trick to enable accelerators for hidden/detached menu items */
1490 static void
reassign_menu_item_accel(GtkWidget * item)1491 reassign_menu_item_accel (GtkWidget *item)
1492 {
1493     GtkWidget   *submenu;
1494     GtkAccelKey  key;
1495     const gchar *accel_path = gtk_menu_item_get_accel_path (GTK_MENU_ITEM (item));
1496 
1497     if (accel_path && gtk_accel_map_lookup_entry (accel_path, &key))
1498     {
1499         GClosure *closure = g_cclosure_new (G_CALLBACK (menu_item_accel_closure_cb), item, NULL);
1500         gtk_accel_group_connect (gtk_menu_get_accel_group (GTK_MENU (gtk_widget_get_parent (item))),
1501                                  key.accel_key, key.accel_mods, key.accel_flags, closure);
1502         g_closure_unref (closure);
1503     }
1504 
1505     submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (item));
1506     if (submenu)
1507         gtk_container_foreach (GTK_CONTAINER (submenu), (GtkCallback)reassign_menu_item_accel, NULL);
1508 }
1509 
1510 gboolean
greeter_g_key_file_load_from_config_dirs(GKeyFile * key_file,const gchar * file,gchar ** full_path,GKeyFileFlags flags,GError ** error)1511 greeter_g_key_file_load_from_config_dirs (GKeyFile       *key_file,
1512                                           const gchar    *file,
1513                                           gchar         **full_path,
1514                                           GKeyFileFlags   flags,
1515                                           GError        **error)
1516 {
1517   gchar **all_config_dirs;
1518   const gchar * user_config_dir;
1519   const gchar * const * system_config_dirs;
1520   gsize i, j;
1521   gboolean found_file;
1522 
1523   g_return_val_if_fail (key_file != NULL, FALSE);
1524   g_return_val_if_fail (!g_path_is_absolute (file), FALSE);
1525 
1526   user_config_dir = g_get_user_config_dir ();
1527   system_config_dirs = g_get_system_config_dirs ();
1528   all_config_dirs = g_new (gchar *, g_strv_length ((gchar **)system_config_dirs) + 2);
1529 
1530   i = 0;
1531   all_config_dirs[i++] = g_strdup (user_config_dir);
1532 
1533   j = 0;
1534   while (system_config_dirs[j] != NULL)
1535     all_config_dirs[i++] = g_strdup (system_config_dirs[j++]);
1536   all_config_dirs[i] = NULL;
1537 
1538   found_file = g_key_file_load_from_dirs (key_file,
1539                                           file,
1540                                           (const gchar **)all_config_dirs,
1541                                           full_path,
1542                                           flags,
1543                                           error);
1544 
1545   g_strfreev (all_config_dirs);
1546 
1547   return found_file;
1548 }
1549 
1550 static gchar*
find_indicator_exec(const gchar * name)1551 find_indicator_exec (const gchar *name)
1552 {
1553     gchar *indicator;
1554     gchar *desktop;
1555     gchar *exec = NULL;
1556     GKeyFile *keyfile;
1557 
1558     #ifdef HAVE_UNITY_LIBINDICATOR_NG
1559         indicator = g_strdup_printf ("indicator-%s", name);
1560     #else
1561         indicator = g_strdup_printf ("ayatana-indicator-%s", name);
1562     #endif
1563 
1564     desktop = g_strdup_printf ("autostart/%s.desktop", indicator);
1565 
1566     keyfile = g_key_file_new ();
1567     if (greeter_g_key_file_load_from_config_dirs (keyfile, desktop, NULL, G_KEY_FILE_NONE, NULL)) {
1568         exec = g_key_file_get_string (keyfile, "Desktop Entry", "Exec", NULL);
1569     } else {
1570         g_free (desktop);
1571 
1572         desktop = g_strdup_printf ("%s/%s.service", SYSTEMD_SERVICE_DIR, indicator);
1573 
1574         if (g_key_file_load_from_file (keyfile, desktop, G_KEY_FILE_NONE, NULL)) {
1575             exec = g_key_file_get_string (keyfile, "Service", "ExecStart", NULL);
1576         }
1577     }
1578 
1579     g_key_file_free (keyfile);
1580     g_free (desktop);
1581 
1582     return exec;
1583 }
1584 
1585 static void
init_indicators(void)1586 init_indicators (void)
1587 {
1588     GHashTable       *builtin_items = NULL;
1589     GHashTableIter    iter;
1590     gpointer          iter_value;
1591     gsize             length = 0;
1592     guint             i;
1593     GError           *error = NULL;
1594 
1595     #ifdef HAVE_LIBINDICATOR
1596     IndicatorObject  *io = NULL;
1597     gboolean          inited = FALSE;
1598     gchar            *path = NULL;
1599     #endif
1600 
1601     gchar           **names = config_get_string_list (NULL, CONFIG_KEY_INDICATORS, NULL);
1602 
1603     if (!names)
1604         names = (gchar**)DEFAULT_LAYOUT;
1605     length = g_strv_length (names);
1606 
1607     builtin_items = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify)g_free, NULL);
1608 
1609     g_hash_table_insert (builtin_items, g_strdup("~power"), power_menuitem);
1610     g_hash_table_insert (builtin_items, g_strdup("~session"), session_menuitem);
1611     g_hash_table_insert (builtin_items, g_strdup("~language"), language_menuitem);
1612     g_hash_table_insert (builtin_items, g_strdup("~a11y"), a11y_menuitem);
1613     g_hash_table_insert (builtin_items, g_strdup("~layout"), layout_menuitem);
1614     g_hash_table_insert (builtin_items, g_strdup("~host"), host_menuitem);
1615     g_hash_table_insert (builtin_items, g_strdup("~clock"), clock_menuitem);
1616 
1617     g_hash_table_iter_init (&iter, builtin_items);
1618     while (g_hash_table_iter_next (&iter, NULL, &iter_value))
1619         gtk_container_remove (GTK_CONTAINER (menubar), iter_value);
1620 
1621     for (i = 0; i < length; ++i)
1622     {
1623         if (names[i][0] == '~')
1624         {   /* Built-in indicators */
1625             GreeterPanelItemType item_type = PANEL_ITEM_INDICATOR;
1626             if (g_hash_table_lookup_extended (builtin_items, names[i], NULL, &iter_value))
1627                 g_hash_table_remove (builtin_items, (gconstpointer)names[i]);
1628             else if (g_strcmp0 (names[i], "~separator") == 0)
1629             {
1630                 GtkWidget *separator = gtk_separator_new (GTK_ORIENTATION_VERTICAL);
1631                 item_type = PANEL_ITEM_SEPARATOR;
1632                 iter_value = gtk_separator_menu_item_new ();
1633                 gtk_widget_show (separator);
1634                 gtk_container_add (iter_value, separator);
1635             }
1636             else if (g_strcmp0 (names[i], "~spacer") == 0)
1637             {
1638                 item_type = PANEL_ITEM_SPACER;
1639                 iter_value = gtk_separator_menu_item_new ();
1640                 gtk_menu_item_set_label (iter_value, "");
1641                 gtk_widget_set_hexpand (iter_value, TRUE);
1642             }
1643             else if (names[i][1] == '~')
1644             {
1645                 item_type = PANEL_ITEM_TEXT;
1646                 iter_value = gtk_separator_menu_item_new ();
1647                 gtk_menu_item_set_label (iter_value, &names[i][2]);
1648             }
1649             else
1650                 continue;
1651 
1652             g_object_set_data (G_OBJECT (iter_value), PANEL_ITEM_DATA_INDEX, GINT_TO_POINTER (i));
1653             panel_add_item (iter_value, i, item_type);
1654             continue;
1655         }
1656 
1657         #ifdef HAVE_LIBINDICATOR
1658         if (!inited)
1659         {
1660             /* Set indicators to run with reduced functionality */
1661             greeter_set_env ("INDICATOR_GREETER_MODE", "1");
1662             /* Don't allow virtual file systems? */
1663             greeter_set_env ("GIO_USE_VFS", "local");
1664             greeter_set_env ("GVFS_DISABLE_FUSE", "1");
1665             inited = TRUE;
1666         }
1667 
1668         if (g_path_is_absolute (names[i]))
1669         {   /* library with absolute path */
1670             io = indicator_object_new_from_file (names[i]);
1671         }
1672         else if (g_str_has_suffix (names[i], G_MODULE_SUFFIX))
1673         {   /* library */
1674             path = g_build_filename (INDICATOR_DIR, names[i], NULL);
1675             io = indicator_object_new_from_file (path);
1676         }
1677         #ifdef HAVE_LIBINDICATOR_NG
1678         else
1679         {   /* service file */
1680             #ifdef HAVE_UNITY_LIBINDICATOR_NG
1681             if (strchr (names[i], '.'))
1682                 path = g_strdup_printf ("%s/%s", UNITY_INDICATOR_DIR, names[i]);
1683             else
1684                 path = g_strdup_printf ("%s/com.canonical.indicator.%s", UNITY_INDICATOR_DIR, names[i]);
1685             #else
1686             if (strchr (names[i], '.'))
1687                 path = g_strdup_printf ("%s/%s", AYATANA_INDICATOR_DIR, names[i]);
1688             else
1689                 path = g_strdup_printf ("%s/org.ayatana.indicator.%s", AYATANA_INDICATOR_DIR, names[i]);
1690             #endif
1691             io = INDICATOR_OBJECT (indicator_ng_new_for_profile (path, "desktop_greeter", &error));
1692             if (io) {
1693                 gchar *exec = find_indicator_exec (names[i]);
1694                 if (exec) {
1695                     spawn_line_pid (exec, G_SPAWN_SEARCH_PATH, NULL);
1696                     g_free (exec);
1697                 }
1698             }
1699         }
1700         #endif
1701 
1702         if (io)
1703         {
1704             GList *entries, *lp;
1705 
1706             /* used to store/fetch menu entries */
1707             g_object_set_data_full (G_OBJECT (io), INDICATOR_DATA_MENUITEMS,
1708                                     g_hash_table_new (g_direct_hash, g_direct_equal),
1709                                     (GDestroyNotify) g_hash_table_destroy);
1710             g_object_set_data (G_OBJECT (io), PANEL_ITEM_DATA_INDEX, GINT_TO_POINTER (i));
1711 
1712             g_signal_connect (G_OBJECT (io), INDICATOR_OBJECT_SIGNAL_ENTRY_ADDED,
1713                               G_CALLBACK (indicator_entry_added_cb), menubar);
1714             g_signal_connect (G_OBJECT (io), INDICATOR_OBJECT_SIGNAL_ENTRY_REMOVED,
1715                               G_CALLBACK (indicator_entry_removed_cb), menubar);
1716             g_signal_connect (G_OBJECT (io), INDICATOR_OBJECT_SIGNAL_MENU_SHOW,
1717                               G_CALLBACK (indicator_menu_show_cb), menubar);
1718 
1719             entries = indicator_object_get_entries (io);
1720             for (lp = entries; lp; lp = g_list_next (lp))
1721                 indicator_entry_added_cb (io, lp->data, menubar);
1722             g_list_free (entries);
1723         }
1724         else
1725         {
1726             if (error != NULL) {
1727                 g_warning ("Indicator \"%s\": Failed to load from %s: %s", names[i], path, error->message);
1728                 g_clear_error (&error);
1729             } else {
1730                 g_warning ("Indicator \"%s\": failed to load", names[i]);
1731             }
1732         }
1733 
1734         if (error != NULL)
1735             g_clear_error (&error);
1736 
1737         g_free (path);
1738         #endif
1739     }
1740     if (names && names != (gchar**)DEFAULT_LAYOUT)
1741         g_strfreev (names);
1742 
1743     if (builtin_items)
1744     {
1745         g_hash_table_iter_init (&iter, builtin_items);
1746         while (g_hash_table_iter_next (&iter, NULL, &iter_value))
1747         {
1748             reassign_menu_item_accel (iter_value);
1749             gtk_widget_hide (iter_value);
1750         }
1751 
1752         g_hash_table_unref (builtin_items);
1753     }
1754 }
1755 
1756 /* Layout indicator */
1757 
1758 static void
layout_selected_cb(GtkCheckMenuItem * menuitem,gpointer user_data)1759 layout_selected_cb (GtkCheckMenuItem *menuitem, gpointer user_data)
1760 {
1761     if (gtk_check_menu_item_get_active (menuitem))
1762     {
1763         #ifdef HAVE_LIBXKLAVIER
1764         gint group = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menuitem), LAYOUT_DATA_GROUP));
1765         xkl_engine_lock_group (xkl_engine, group);
1766         #else
1767         const gchar *name = g_object_get_data (G_OBJECT (menuitem), LAYOUT_DATA_NAME);
1768         GList *item;
1769         for (item = lightdm_get_layouts (); item; item = g_list_next (item))
1770         {
1771             if (g_strcmp0 (name, lightdm_layout_get_name (item->data)) == 0)
1772             {
1773                 lightdm_set_layout (item->data);
1774                 gtk_menu_item_set_label (GTK_MENU_ITEM (layout_menuitem),
1775                                          g_object_get_data (G_OBJECT (menuitem), LAYOUT_DATA_LABEL));
1776                 break;
1777             }
1778         }
1779         #endif
1780     }
1781 }
1782 
1783 static void
update_layouts_menu(void)1784 update_layouts_menu (void)
1785 {
1786     #ifdef HAVE_LIBXKLAVIER
1787     XklConfigRegistry *registry;
1788     XklConfigRec *config;
1789     XklConfigItem *config_item;
1790     GSList *menu_group = NULL;
1791     gint i;
1792 
1793     g_list_free_full (gtk_container_get_children (GTK_CONTAINER (layout_menu)),
1794                       (GDestroyNotify)gtk_widget_destroy);
1795 
1796     config = xkl_config_rec_new ();
1797     if (!xkl_config_rec_get_from_server (config, xkl_engine))
1798     {
1799         g_object_unref (config);
1800         g_warning ("Failed to get Xkl configuration from server");
1801         return;
1802     }
1803 
1804     config_item = xkl_config_item_new ();
1805     registry = xkl_config_registry_get_instance (xkl_engine);
1806     xkl_config_registry_load (registry, FALSE);
1807 
1808     for (i = 0; config->layouts[i] != NULL; ++i)
1809     {
1810         const gchar *layout = config->layouts[i] ? config->layouts[i] : "";
1811         const gchar *variant = config->variants[i] ? config->variants[i] : "";
1812         gchar *label = strlen (variant) > 0 ? g_strdup_printf ("%s_%s", layout, variant) : g_strdup (layout);
1813 
1814         GtkWidget *menuitem = gtk_radio_menu_item_new (menu_group);
1815         menu_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (menuitem));
1816 
1817         g_snprintf (config_item->name, sizeof (config_item->name), "%s", variant);
1818         if (xkl_config_registry_find_variant (registry, layout, config_item))
1819             gtk_menu_item_set_label (GTK_MENU_ITEM (menuitem), config_item->description);
1820         else
1821         {
1822             g_snprintf (config_item->name, sizeof (config_item->name), "%s", layout);
1823             if (xkl_config_registry_find_layout (registry, config_item))
1824                 gtk_menu_item_set_label (GTK_MENU_ITEM (menuitem), config_item->description);
1825             else
1826                 gtk_menu_item_set_label (GTK_MENU_ITEM (menuitem), label);
1827         }
1828 
1829         g_object_set_data_full (G_OBJECT (menuitem), LAYOUT_DATA_LABEL, label, g_free);
1830         g_object_set_data (G_OBJECT (menuitem), LAYOUT_DATA_GROUP, GINT_TO_POINTER (i));
1831 
1832         g_signal_connect (G_OBJECT (menuitem), "activate", G_CALLBACK (layout_selected_cb), NULL);
1833         gtk_menu_shell_append (GTK_MENU_SHELL (layout_menu), menuitem);
1834         gtk_widget_show (GTK_WIDGET (menuitem));
1835     }
1836 
1837     g_object_unref (registry);
1838     g_object_unref (config_item);
1839     g_object_unref (config);
1840     #else
1841     GSList *menu_group = NULL;
1842     GList *item;
1843 
1844     g_list_free_full (gtk_container_get_children (GTK_CONTAINER (layout_menu)),
1845                       (GDestroyNotify)gtk_widget_destroy);
1846 
1847     for (item = lightdm_get_layouts (); item; item = g_list_next (item))
1848     {
1849         LightDMLayout *layout = item->data;
1850         GtkWidget *menuitem = gtk_radio_menu_item_new (menu_group);
1851         menu_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (menuitem));
1852 
1853         g_object_set_data_full (G_OBJECT (menuitem), LAYOUT_DATA_LABEL,
1854                                 g_strdelimit (g_strdup (lightdm_layout_get_name (layout)), "\t ", '_'), g_free);
1855         g_object_set_data_full (G_OBJECT (menuitem), LAYOUT_DATA_NAME,
1856                                 g_strdup (lightdm_layout_get_name (layout)), g_free);
1857 
1858         g_signal_connect (G_OBJECT (menuitem), "activate", G_CALLBACK (layout_selected_cb), NULL);
1859         gtk_menu_item_set_label (GTK_MENU_ITEM (menuitem), lightdm_layout_get_description (layout));
1860         gtk_menu_shell_append (GTK_MENU_SHELL (layout_menu), menuitem);
1861         gtk_widget_show (GTK_WIDGET (menuitem));
1862     }
1863     #endif
1864 }
1865 
1866 static void
update_layouts_menu_state(void)1867 update_layouts_menu_state (void)
1868 {
1869 #ifdef HAVE_LIBXKLAVIER
1870     XklState         *state;
1871     GList            *menu_items;
1872     GtkCheckMenuItem *menu_item;
1873 #else
1874     const gchar      *name;
1875     GList            *menu_items;
1876     GList            *menu_iter;
1877     LightDMLayout    *layout;
1878 #endif
1879 
1880 #ifdef HAVE_LIBXKLAVIER
1881     state = xkl_engine_get_current_state (xkl_engine);
1882     menu_items = gtk_container_get_children (GTK_CONTAINER (layout_menu));
1883     menu_item = g_list_nth_data (menu_items, state->group);
1884 
1885     if (menu_item)
1886     {
1887         gtk_menu_item_set_label (GTK_MENU_ITEM (layout_menuitem),
1888                                  g_object_get_data (G_OBJECT (menu_item), LAYOUT_DATA_LABEL));
1889         gtk_check_menu_item_set_active (menu_item, TRUE);
1890     }
1891     else
1892         gtk_menu_item_set_label (GTK_MENU_ITEM (layout_menuitem), "??");
1893     g_list_free (menu_items);
1894 #else
1895     layout = lightdm_get_layout ();
1896     g_return_if_fail (layout != NULL);
1897 
1898     name = lightdm_layout_get_name (layout);
1899     menu_items = gtk_container_get_children (GTK_CONTAINER (layout_menu));
1900     for (menu_iter = menu_items; menu_iter; menu_iter = g_list_next (menu_iter))
1901     {
1902         if (g_strcmp0 (name, g_object_get_data (G_OBJECT (menu_iter->data), LAYOUT_DATA_NAME)) == 0)
1903         {
1904             gtk_check_menu_item_set_active (menu_iter->data, TRUE);
1905             gtk_menu_item_set_label (GTK_MENU_ITEM (layout_menuitem),
1906                                      g_object_get_data (G_OBJECT (menu_iter->data), LAYOUT_DATA_LABEL));
1907             break;
1908         }
1909     }
1910     g_list_free (menu_items);
1911 #endif
1912 }
1913 
1914 #ifdef HAVE_LIBXKLAVIER
1915 static void
xkl_state_changed_cb(XklEngine * engine,XklEngineStateChange change,gint group,gboolean restore,gpointer user_data)1916 xkl_state_changed_cb (XklEngine *engine, XklEngineStateChange change, gint group,
1917                       gboolean restore, gpointer user_data)
1918 {
1919     if (change == GROUP_CHANGED)
1920         update_layouts_menu_state ();
1921 }
1922 
1923 static void
xkl_config_changed_cb(XklEngine * engine,gpointer user_data)1924 xkl_config_changed_cb (XklEngine *engine, gpointer user_data)
1925 {
1926     /* tip: xkl_config_rec_get_from_server() return old settings */
1927     update_layouts_menu ();
1928     update_layouts_menu_state ();
1929 }
1930 
1931 static GdkFilterReturn
xkl_xevent_filter(GdkXEvent * xev,GdkEvent * event,gpointer data)1932 xkl_xevent_filter (GdkXEvent *xev, GdkEvent *event, gpointer  data)
1933 {
1934     XEvent *xevent = (XEvent *) xev;
1935     xkl_engine_filter_events (xkl_engine, xevent);
1936     return GDK_FILTER_CONTINUE;
1937 }
1938 #endif
1939 
1940 /* a11y indciator */
1941 
1942 void
a11y_font_cb(GtkCheckMenuItem * item)1943 a11y_font_cb (GtkCheckMenuItem *item)
1944 {
1945     if (gtk_check_menu_item_get_active (item))
1946     {
1947         gchar *font_name, **tokens;
1948         guint length;
1949 
1950         g_object_get (gtk_settings_get_default (), "gtk-font-name", &font_name, NULL);
1951         tokens = g_strsplit (font_name, " ", -1);
1952         length = g_strv_length (tokens);
1953         if (length > 1)
1954         {
1955             gint size = atoi (tokens[length - 1]);
1956             if (size > 0)
1957             {
1958                 g_free (tokens[length - 1]);
1959                 tokens[length - 1] = g_strdup_printf ("%d", size + 10);
1960                 g_free (font_name);
1961                 font_name = g_strjoinv (" ", tokens);
1962             }
1963         }
1964         g_strfreev (tokens);
1965 
1966         g_object_set (gtk_settings_get_default (), "gtk-font-name", font_name, NULL);
1967     }
1968     else
1969     {
1970         g_object_set (gtk_settings_get_default (), "gtk-font-name", default_font_name, NULL);
1971     }
1972 }
1973 
1974 void
a11y_contrast_cb(GtkCheckMenuItem * item)1975 a11y_contrast_cb (GtkCheckMenuItem *item)
1976 {
1977     if (gtk_check_menu_item_get_active (item))
1978     {
1979         g_object_set (gtk_settings_get_default (), "gtk-theme-name", "HighContrast", NULL);
1980         g_object_set (gtk_settings_get_default (), "gtk-icon-theme-name", "HighContrast", NULL);
1981     }
1982     else
1983     {
1984         g_object_set (gtk_settings_get_default (), "gtk-theme-name", default_theme_name, NULL);
1985         g_object_set (gtk_settings_get_default (), "gtk-icon-theme-name", default_icon_theme_name, NULL);
1986     }
1987 }
1988 
1989 void
a11y_keyboard_cb(GtkCheckMenuItem * item,gpointer user_data)1990 a11y_keyboard_cb (GtkCheckMenuItem *item, gpointer user_data)
1991 {
1992     if (gtk_check_menu_item_get_active (item))
1993         menu_command_run (a11y_keyboard_command);
1994     else
1995         menu_command_stop (a11y_keyboard_command);
1996 }
1997 
1998 void
a11y_reader_cb(GtkCheckMenuItem * item,gpointer user_data)1999 a11y_reader_cb (GtkCheckMenuItem *item, gpointer user_data)
2000 {
2001     if (gtk_check_menu_item_get_active (item))
2002         menu_command_run (a11y_reader_command);
2003     else
2004         menu_command_stop (a11y_reader_command);
2005 }
2006 
2007 /* Power indicator */
2008 
2009 static void
power_menu_cb(GtkWidget * menuitem,gpointer userdata)2010 power_menu_cb (GtkWidget *menuitem, gpointer userdata)
2011 {
2012     gtk_widget_set_sensitive (suspend_menuitem, lightdm_get_can_suspend ());
2013     gtk_widget_set_sensitive (hibernate_menuitem, lightdm_get_can_hibernate ());
2014     gtk_widget_set_sensitive (restart_menuitem, lightdm_get_can_restart ());
2015     gtk_widget_set_sensitive (shutdown_menuitem, lightdm_get_can_shutdown ());
2016 }
2017 
2018 void
suspend_cb(GtkWidget * widget,LightDMGreeter * ldm)2019 suspend_cb (GtkWidget *widget, LightDMGreeter *ldm)
2020 {
2021     lightdm_suspend (NULL);
2022 }
2023 
2024 void
hibernate_cb(GtkWidget * widget,LightDMGreeter * ldm)2025 hibernate_cb (GtkWidget *widget, LightDMGreeter *ldm)
2026 {
2027     lightdm_hibernate (NULL);
2028 }
2029 
2030 void
restart_cb(GtkWidget * widget,LightDMGreeter * ldm)2031 restart_cb (GtkWidget *widget, LightDMGreeter *ldm)
2032 {
2033     if (show_power_prompt ("restart", "view-refresh-symbolic",
2034                            _("Restart"),
2035                            _("Are you sure you want to close all programs and restart the computer?")))
2036         lightdm_restart (NULL);
2037 }
2038 
2039 void
shutdown_cb(GtkWidget * widget,LightDMGreeter * ldm)2040 shutdown_cb (GtkWidget *widget, LightDMGreeter *ldm)
2041 {
2042     if (show_power_prompt ("shutdown", "system-shutdown-symbolic",
2043                            _("Shut Down"),
2044                            _("Are you sure you want to close all programs and shut down the computer?")))
2045         lightdm_shutdown (NULL);
2046 }
2047 
2048 static void
set_login_button_label(LightDMGreeter * ldm,const gchar * username)2049 set_login_button_label (LightDMGreeter *ldm, const gchar *username)
2050 {
2051     LightDMUser *user;
2052     gboolean logged_in = FALSE;
2053 
2054     user = lightdm_user_list_get_user_by_name (lightdm_user_list_get_instance (), username);
2055     if (user)
2056         logged_in = lightdm_user_get_logged_in (user);
2057     if (logged_in)
2058         gtk_button_set_label (login_button, _("Unlock"));
2059     else
2060         gtk_button_set_label (login_button, _("Log In"));
2061     /* and disable the session and language widgets */
2062     gtk_widget_set_sensitive (GTK_WIDGET (session_menuitem), !logged_in);
2063     gtk_widget_set_sensitive (GTK_WIDGET (language_menuitem), !logged_in);
2064 }
2065 
2066 static guint set_user_background_delayed_id = 0;
2067 
2068 static gboolean
set_user_background_delayed_cb(const gchar * value)2069 set_user_background_delayed_cb (const gchar *value)
2070 {
2071     greeter_background_set_custom_background (greeter_background, value);
2072     set_user_background_delayed_id = 0;
2073     return G_SOURCE_REMOVE;
2074 }
2075 
2076 static void
set_user_background(const gchar * user_name)2077 set_user_background (const gchar *user_name)
2078 {
2079     const gchar *value = NULL;
2080     if (user_name)
2081     {
2082         LightDMUser *user = lightdm_user_list_get_user_by_name (lightdm_user_list_get_instance (), user_name);
2083         if (user)
2084             value = lightdm_user_get_background (user);
2085     }
2086 
2087     if (set_user_background_delayed_id)
2088     {
2089         g_source_remove (set_user_background_delayed_id);
2090         set_user_background_delayed_id = 0;
2091     }
2092 
2093     if (!value)
2094         greeter_background_set_custom_background (greeter_background, NULL);
2095     else
2096     {
2097         /* Small delay before changing background */
2098         set_user_background_delayed_id = g_timeout_add_full (G_PRIORITY_DEFAULT, USER_BACKGROUND_DELAY,
2099                                                              (GSourceFunc)set_user_background_delayed_cb,
2100                                                              g_strdup (value), g_free);
2101     }
2102 }
2103 
2104 static void
start_authentication(const gchar * username)2105 start_authentication (const gchar *username)
2106 {
2107     cancelling = FALSE;
2108     prompted = FALSE;
2109     password_prompted = FALSE;
2110     prompt_active = FALSE;
2111 
2112     if (pending_questions)
2113     {
2114         g_slist_free_full (pending_questions, (GDestroyNotify) pam_message_finalize);
2115         pending_questions = NULL;
2116     }
2117 
2118     config_set_string (STATE_SECTION_GREETER, STATE_KEY_LAST_USER, username);
2119 
2120     if (g_strcmp0 (username, "*other") == 0)
2121     {
2122         gtk_widget_show (GTK_WIDGET (username_entry));
2123         gtk_widget_show (GTK_WIDGET (cancel_button));
2124 #ifdef HAVE_LIBLIGHTDMGOBJECT_1_19_2
2125         lightdm_greeter_authenticate (greeter, NULL, NULL);
2126 #else
2127         lightdm_greeter_authenticate (greeter, NULL);
2128 #endif
2129 
2130 		if (lightdm_greeter_get_lock_hint (greeter))
2131 		{
2132 			GList * items = lightdm_user_list_get_users (lightdm_user_list_get_instance ());
2133 			for (GList * item = items; item; item = item->next)
2134 			{
2135 				LightDMUser *user = item->data;
2136 				if( lightdm_user_get_logged_in (user))
2137 				{
2138 					gtk_entry_set_text (username_entry,lightdm_user_get_name(user));
2139 					break;
2140 				}
2141 			}
2142 		}
2143     }
2144     else if (g_strcmp0 (username, "*guest") == 0)
2145     {
2146 #ifdef HAVE_LIBLIGHTDMGOBJECT_1_19_2
2147         lightdm_greeter_authenticate_as_guest (greeter, NULL);
2148 #else
2149         lightdm_greeter_authenticate_as_guest (greeter);
2150 #endif
2151     }
2152     else
2153     {
2154         LightDMUser *user;
2155 
2156         user = lightdm_user_list_get_user_by_name (lightdm_user_list_get_instance (), username);
2157         if (user)
2158         {
2159             if (!current_session)
2160                 set_session (lightdm_user_get_session (user));
2161             if (!current_language)
2162                 set_language (lightdm_user_get_language (user));
2163         }
2164         else
2165         {
2166             set_session (NULL);
2167             set_language (NULL);
2168         }
2169 #ifdef HAVE_LIBLIGHTDMGOBJECT_1_19_2
2170         lightdm_greeter_authenticate (greeter, username, NULL);
2171 #else
2172         lightdm_greeter_authenticate (greeter, username);
2173 #endif
2174     }
2175 }
2176 
2177 static void
cancel_authentication(void)2178 cancel_authentication (void)
2179 {
2180     GtkTreeModel *model;
2181     GtkTreeIter iter;
2182     gboolean other = FALSE;
2183 
2184     if (pending_questions)
2185     {
2186         g_slist_free_full (pending_questions, (GDestroyNotify) pam_message_finalize);
2187         pending_questions = NULL;
2188     }
2189 
2190     /* If in authentication then stop that first */
2191     cancelling = FALSE;
2192     if (lightdm_greeter_get_in_authentication (greeter))
2193     {
2194         cancelling = TRUE;
2195 #ifdef HAVE_LIBLIGHTDMGOBJECT_1_19_2
2196         lightdm_greeter_cancel_authentication (greeter, NULL);
2197 #else
2198         lightdm_greeter_cancel_authentication (greeter);
2199 #endif
2200         set_message_label (LIGHTDM_MESSAGE_TYPE_INFO, NULL);
2201     }
2202 
2203     /* Make sure password entry is back to normal */
2204     gtk_entry_set_visibility (password_entry, FALSE);
2205 
2206     /* Force refreshing the prompt_box for "Other" */
2207     model = gtk_combo_box_get_model (user_combo);
2208 
2209     if (gtk_combo_box_get_active_iter (user_combo, &iter))
2210     {
2211         gchar *user;
2212 
2213         gtk_tree_model_get (GTK_TREE_MODEL (model), &iter, 0, &user, -1);
2214         other = (g_strcmp0 (user, "*other") == 0);
2215         g_free (user);
2216     }
2217 
2218     /* Start a new login or return to the user list */
2219     if (other || lightdm_greeter_get_hide_users_hint (greeter))
2220         start_authentication ("*other");
2221     else
2222         gtk_widget_grab_focus (GTK_WIDGET (user_combo));
2223 }
2224 
2225 static void
start_session(void)2226 start_session (void)
2227 {
2228     gchar *language;
2229     gchar *session;
2230 
2231     language = get_language ();
2232     if (language)
2233 #ifdef HAVE_LIBLIGHTDMGOBJECT_1_19_2
2234         lightdm_greeter_set_language (greeter, language, NULL);
2235 #else
2236         lightdm_greeter_set_language (greeter, language);
2237 #endif
2238     g_free (language);
2239 
2240     session = get_session ();
2241 
2242     /* Remember last choice */
2243     config_set_string (STATE_SECTION_GREETER, STATE_KEY_LAST_SESSION, session);
2244 
2245     greeter_background_save_xroot (greeter_background);
2246 
2247     if (!lightdm_greeter_start_session_sync (greeter, session, NULL))
2248     {
2249         set_message_label (LIGHTDM_MESSAGE_TYPE_ERROR, _("Failed to start session"));
2250         start_authentication (lightdm_greeter_get_authentication_user (greeter));
2251     }
2252     g_free (session);
2253 }
2254 
2255 gboolean
2256 password_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data);
2257 G_MODULE_EXPORT
2258 gboolean
password_key_press_cb(GtkWidget * widget,GdkEventKey * event,gpointer user_data)2259 password_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
2260 {
2261     if ((event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_Down) &&
2262         gtk_widget_get_visible (GTK_WIDGET (user_combo)))
2263     {
2264         gboolean available;
2265         GtkTreeIter iter;
2266         GtkTreeModel *model = gtk_combo_box_get_model (user_combo);
2267 
2268         /* Back to username_entry if it is available */
2269         if (event->keyval == GDK_KEY_Up &&
2270             gtk_widget_get_visible (GTK_WIDGET (username_entry)) && widget == GTK_WIDGET (password_entry))
2271         {
2272             gtk_widget_grab_focus (GTK_WIDGET (username_entry));
2273             return TRUE;
2274         }
2275 
2276         if (!gtk_combo_box_get_active_iter (user_combo, &iter))
2277             return FALSE;
2278 
2279         if (event->keyval == GDK_KEY_Up)
2280             available = gtk_tree_model_iter_previous (model, &iter);
2281         else
2282             available = gtk_tree_model_iter_next (model, &iter);
2283 
2284         if (available)
2285             gtk_combo_box_set_active_iter (user_combo, &iter);
2286 
2287         return TRUE;
2288     }
2289     return FALSE;
2290 }
2291 
2292 gboolean
2293 username_focus_out_cb (GtkWidget *widget, GdkEvent *event, gpointer user_data);
2294 G_MODULE_EXPORT
2295 gboolean
username_focus_out_cb(GtkWidget * widget,GdkEvent * event,gpointer user_data)2296 username_focus_out_cb (GtkWidget *widget, GdkEvent *event, gpointer user_data)
2297 {
2298     if (!g_strcmp0(gtk_entry_get_text (username_entry), "") == 0)
2299         start_authentication (gtk_entry_get_text (username_entry));
2300     return FALSE;
2301 }
2302 
2303 gboolean
2304 username_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data);
2305 G_MODULE_EXPORT
2306 gboolean
username_key_press_cb(GtkWidget * widget,GdkEventKey * event,gpointer user_data)2307 username_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
2308 {
2309     /* Acts as password_entry */
2310     if (event->keyval == GDK_KEY_Up)
2311         return password_key_press_cb (widget, event, user_data);
2312     /* Enter activates the password entry */
2313     else if (event->keyval == GDK_KEY_Return && gtk_widget_get_visible (GTK_WIDGET (password_entry)))
2314     {
2315         gtk_widget_grab_focus (GTK_WIDGET (password_entry));
2316         return TRUE;
2317     }
2318     else
2319         return FALSE;
2320 }
2321 
2322 gboolean
2323 menubar_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data);
2324 G_MODULE_EXPORT
2325 gboolean
menubar_key_press_cb(GtkWidget * widget,GdkEventKey * event,gpointer user_data)2326 menubar_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
2327 {
2328     switch (event->keyval)
2329     {
2330     case GDK_KEY_Tab: case GDK_KEY_Escape:
2331     case GDK_KEY_Super_L: case GDK_KEY_Super_R:
2332     case GDK_KEY_F9: case GDK_KEY_F10:
2333     case GDK_KEY_F11: case GDK_KEY_F12:
2334         gtk_menu_shell_cancel (GTK_MENU_SHELL (menubar));
2335         return TRUE;
2336     default:
2337         return FALSE;
2338     };
2339 }
2340 
2341 gboolean
2342 login_window_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data);
2343 G_MODULE_EXPORT
2344 gboolean
login_window_key_press_cb(GtkWidget * widget,GdkEventKey * event,gpointer user_data)2345 login_window_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
2346 {
2347     GtkWidget *item = NULL;
2348 
2349     if (event->keyval == GDK_KEY_F9)
2350         item = session_menuitem;
2351     else if (event->keyval == GDK_KEY_F10)
2352         item = language_menuitem;
2353     else if (event->keyval == GDK_KEY_F11)
2354         item = a11y_menuitem;
2355     else if (event->keyval == GDK_KEY_F12)
2356         item = power_menuitem;
2357     else if (event->keyval != GDK_KEY_Escape &&
2358              event->keyval != GDK_KEY_Super_L &&
2359              event->keyval != GDK_KEY_Super_R)
2360         return FALSE;
2361 
2362     if (GTK_IS_MENU_ITEM (item) && gtk_widget_is_sensitive (item) && gtk_widget_get_visible (item))
2363         gtk_menu_shell_select_item (GTK_MENU_SHELL (menubar), item);
2364     else
2365         gtk_menu_shell_select_first (GTK_MENU_SHELL (menubar), TRUE);
2366     return TRUE;
2367 }
2368 
2369 static void
set_displayed_user(LightDMGreeter * ldm,const gchar * username)2370 set_displayed_user (LightDMGreeter *ldm, const gchar *username)
2371 {
2372     gchar *user_tooltip;
2373     LightDMUser *user;
2374 
2375     if (g_strcmp0 (username, "*other") == 0)
2376     {
2377         gtk_widget_show (GTK_WIDGET (username_entry));
2378         gtk_widget_show (GTK_WIDGET (cancel_button));
2379         user_tooltip = g_strdup (_("Other"));
2380     }
2381     else
2382     {
2383         gtk_widget_hide (GTK_WIDGET (username_entry));
2384         gtk_widget_hide (GTK_WIDGET (cancel_button));
2385         user_tooltip = g_strdup (username);
2386     }
2387 
2388     /* At this moment we do not have information about possible prompts
2389      * for current user (except *guest). So, password_entry.visible changed in:
2390      *   auth_complete_cb
2391      *   process_prompts
2392      *   and here - for *guest */
2393 
2394     if (g_strcmp0 (username, "*guest") == 0)
2395     {
2396         user_tooltip = g_strdup (_("Guest Session"));
2397         gtk_widget_hide (GTK_WIDGET (password_entry));
2398         gtk_widget_grab_focus (GTK_WIDGET (user_combo));
2399     }
2400 
2401     set_login_button_label (ldm, username);
2402     set_user_background (username);
2403     set_user_image (username);
2404     user = lightdm_user_list_get_user_by_name (lightdm_user_list_get_instance (), username);
2405     if (user)
2406     {
2407         set_language (lightdm_user_get_language (user));
2408         set_session (lightdm_user_get_session (user));
2409     }
2410     else
2411     {
2412         set_language (lightdm_language_get_code (lightdm_get_language ()));
2413         set_session (lightdm_greeter_get_default_session_hint (ldm));
2414     }
2415     gtk_widget_set_tooltip_text (GTK_WIDGET (user_combo), user_tooltip);
2416     start_authentication (username);
2417     g_free (user_tooltip);
2418 }
2419 
2420 void user_combobox_active_changed_cb (GtkComboBox *widget, LightDMGreeter *greeter);
2421 G_MODULE_EXPORT
2422 void
user_combobox_active_changed_cb(GtkComboBox * widget,LightDMGreeter * ldm)2423 user_combobox_active_changed_cb (GtkComboBox *widget, LightDMGreeter *ldm)
2424 {
2425     GtkTreeModel *model;
2426     GtkTreeIter iter;
2427 
2428     model = gtk_combo_box_get_model (user_combo);
2429 
2430     if (gtk_combo_box_get_active_iter (user_combo, &iter))
2431     {
2432         gchar *user;
2433 
2434         gtk_tree_model_get (GTK_TREE_MODEL (model), &iter, 0, &user, -1);
2435 
2436         set_displayed_user (ldm, user);
2437 
2438         g_free (user);
2439     }
2440     set_message_label (LIGHTDM_MESSAGE_TYPE_INFO, NULL);
2441 }
2442 
2443 void login_cb (GtkWidget *widget);
2444 G_MODULE_EXPORT
2445 void
login_cb(GtkWidget * widget)2446 login_cb (GtkWidget *widget)
2447 {
2448     /* Reset to default screensaver values */
2449     if (lightdm_greeter_get_lock_hint (greeter))
2450         XSetScreenSaver (gdk_x11_display_get_xdisplay (gdk_display_get_default ()), timeout, interval, prefer_blanking, allow_exposures);
2451 
2452     gtk_widget_set_sensitive (GTK_WIDGET (username_entry), FALSE);
2453     gtk_widget_set_sensitive (GTK_WIDGET (password_entry), FALSE);
2454     set_message_label (LIGHTDM_MESSAGE_TYPE_INFO, NULL);
2455     prompt_active = FALSE;
2456 
2457     if (lightdm_greeter_get_is_authenticated (greeter))
2458         start_session ();
2459     else if (lightdm_greeter_get_in_authentication (greeter))
2460     {
2461 #ifdef HAVE_LIBLIGHTDMGOBJECT_1_19_2
2462         lightdm_greeter_respond (greeter, gtk_entry_get_text (password_entry), NULL);
2463 #else
2464         lightdm_greeter_respond (greeter, gtk_entry_get_text (password_entry));
2465 #endif
2466         /* If we have questions pending, then we continue processing
2467          * those, until we are done. (Otherwise, authentication will
2468          * not complete.) */
2469         if (pending_questions)
2470             process_prompts (greeter);
2471     }
2472     else
2473         start_authentication (lightdm_greeter_get_authentication_user (greeter));
2474 }
2475 
2476 void cancel_cb (GtkWidget *widget);
2477 G_MODULE_EXPORT
2478 void
cancel_cb(GtkWidget * widget)2479 cancel_cb (GtkWidget *widget)
2480 {
2481     cancel_authentication ();
2482 }
2483 
2484 gboolean
2485 user_combo_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data);
2486 G_MODULE_EXPORT
2487 gboolean
user_combo_key_press_cb(GtkWidget * widget,GdkEventKey * event,gpointer user_data)2488 user_combo_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
2489 {
2490     if (event->keyval == GDK_KEY_Return)
2491     {
2492         if (gtk_widget_get_visible (GTK_WIDGET (username_entry)))
2493             gtk_widget_grab_focus (GTK_WIDGET (username_entry));
2494         else if (gtk_widget_get_visible (GTK_WIDGET (password_entry)))
2495             gtk_widget_grab_focus (GTK_WIDGET (password_entry));
2496         else
2497             login_cb (GTK_WIDGET (login_button));
2498         return TRUE;
2499     }
2500     return FALSE;
2501 }
2502 
2503 static void
show_prompt_cb(LightDMGreeter * ldm,const gchar * text,LightDMPromptType type)2504 show_prompt_cb (LightDMGreeter *ldm, const gchar *text, LightDMPromptType type)
2505 {
2506     PAMConversationMessage *message_obj = g_new (PAMConversationMessage, 1);
2507     if (message_obj)
2508     {
2509         message_obj->is_prompt = TRUE;
2510         message_obj->type.prompt = type;
2511         message_obj->text = g_strdup (text);
2512         pending_questions = g_slist_append (pending_questions, message_obj);
2513     }
2514 
2515     if (!prompt_active)
2516         process_prompts (ldm);
2517 }
2518 
2519 static void
show_message_cb(LightDMGreeter * ldm,const gchar * text,LightDMMessageType type)2520 show_message_cb (LightDMGreeter *ldm, const gchar *text, LightDMMessageType type)
2521 {
2522     PAMConversationMessage *message_obj = g_new (PAMConversationMessage, 1);
2523     if (message_obj)
2524     {
2525         message_obj->is_prompt = FALSE;
2526         message_obj->type.message = type;
2527         message_obj->text = g_strdup (text);
2528         pending_questions = g_slist_append (pending_questions, message_obj);
2529     }
2530 
2531     if (!prompt_active)
2532         process_prompts (ldm);
2533 }
2534 
2535 static void
timed_autologin_cb(LightDMGreeter * ldm)2536 timed_autologin_cb (LightDMGreeter *ldm)
2537 {
2538     /* Don't trigger autologin if user locks screen with light-locker (thanks to Andrew P.). */
2539     if (!lightdm_greeter_get_lock_hint (ldm))
2540     {
2541         /* Select autologin-session if configured */
2542         if (lightdm_greeter_get_hint (greeter, "autologin-session"))
2543         {
2544             set_session (lightdm_greeter_get_hint (greeter, "autologin-session"));
2545         }
2546 
2547         if (lightdm_greeter_get_is_authenticated (ldm))
2548         {
2549             /* Configured autologin user may be already selected in user list. */
2550             if (lightdm_greeter_get_authentication_user (ldm))
2551                 /* Selected user matches configured autologin-user option. */
2552                 start_session ();
2553             else if (lightdm_greeter_get_autologin_guest_hint (ldm))
2554                 /* "Guest session" is selected and autologin-guest is enabled. */
2555                 start_session ();
2556             else if (lightdm_greeter_get_autologin_user_hint (ldm))
2557             {
2558                 /* "Guest session" is selected, but autologin-user is configured. */
2559                 start_authentication (lightdm_greeter_get_autologin_user_hint (ldm));
2560                 prompted = TRUE;
2561             }
2562         }
2563         else
2564 #ifdef HAVE_LIBLIGHTDMGOBJECT_1_19_2
2565             lightdm_greeter_authenticate_autologin (ldm, NULL);
2566 #else
2567             lightdm_greeter_authenticate_autologin (ldm);
2568 #endif
2569     }
2570 }
2571 
2572 static void
authentication_complete_cb(LightDMGreeter * ldm)2573 authentication_complete_cb (LightDMGreeter *ldm)
2574 {
2575     prompt_active = FALSE;
2576     gtk_entry_set_text (password_entry, "");
2577 
2578     if (cancelling)
2579     {
2580         cancel_authentication ();
2581         return;
2582     }
2583 
2584     if (pending_questions)
2585     {
2586         g_slist_free_full (pending_questions, (GDestroyNotify) pam_message_finalize);
2587         pending_questions = NULL;
2588     }
2589 
2590     if (lightdm_greeter_get_is_authenticated (ldm))
2591     {
2592         if (prompted)
2593             start_session ();
2594         else
2595         {
2596             gtk_widget_hide (GTK_WIDGET (password_entry));
2597             gtk_widget_grab_focus (GTK_WIDGET (user_combo));
2598         }
2599     }
2600     else
2601     {
2602         /* If an error message is already printed we do not print it this statement
2603          * The error message probably comes from the PAM module that has a better knowledge
2604          * of the failure. */
2605         gboolean have_pam_error = !message_label_is_empty () &&
2606                                   gtk_info_bar_get_message_type (info_bar) != GTK_MESSAGE_ERROR;
2607         if (prompted)
2608         {
2609             if (!have_pam_error)
2610                 set_message_label (LIGHTDM_MESSAGE_TYPE_ERROR, _("Your password is incorrect. Please try again."));
2611             start_authentication (lightdm_greeter_get_authentication_user (ldm));
2612         }
2613         else
2614         {
2615             g_warning ("Failed to authenticate");
2616             if (!have_pam_error)
2617                 set_message_label (LIGHTDM_MESSAGE_TYPE_ERROR, _("Failed to authenticate"));
2618         }
2619     }
2620 }
2621 
2622 static void
user_added_cb(LightDMUserList * user_list,LightDMUser * user,LightDMGreeter * ldm)2623 user_added_cb (LightDMUserList *user_list, LightDMUser *user, LightDMGreeter *ldm)
2624 {
2625     GtkTreeModel *model;
2626     GtkTreeIter iter;
2627     gboolean logged_in = FALSE;
2628 
2629     model = gtk_combo_box_get_model (user_combo);
2630 
2631     logged_in = lightdm_user_get_logged_in (user);
2632 
2633     gtk_list_store_append (GTK_LIST_STORE (model), &iter);
2634     gtk_list_store_set (GTK_LIST_STORE (model), &iter,
2635                         0, lightdm_user_get_name (user),
2636                         1, lightdm_user_get_display_name (user),
2637                         2, logged_in ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL,
2638                         -1);
2639 }
2640 
2641 static gboolean
get_user_iter(const gchar * username,GtkTreeIter * iter)2642 get_user_iter (const gchar *username, GtkTreeIter *iter)
2643 {
2644     GtkTreeModel *model;
2645 
2646     model = gtk_combo_box_get_model (user_combo);
2647 
2648     if (!gtk_tree_model_get_iter_first (model, iter))
2649         return FALSE;
2650     do
2651     {
2652         gchar *name;
2653         gboolean matched;
2654 
2655         gtk_tree_model_get (model, iter, 0, &name, -1);
2656         matched = g_strcmp0 (name, username) == 0;
2657         g_free (name);
2658         if (matched)
2659             return TRUE;
2660     } while (gtk_tree_model_iter_next (model, iter));
2661 
2662     return FALSE;
2663 }
2664 
2665 static void
user_changed_cb(LightDMUserList * user_list,LightDMUser * user,LightDMGreeter * ldm)2666 user_changed_cb (LightDMUserList *user_list, LightDMUser *user, LightDMGreeter *ldm)
2667 {
2668     GtkTreeModel *model;
2669     GtkTreeIter iter;
2670     gboolean logged_in = FALSE;
2671 
2672     if (!get_user_iter (lightdm_user_get_name (user), &iter))
2673         return;
2674     logged_in = lightdm_user_get_logged_in (user);
2675 
2676     model = gtk_combo_box_get_model (user_combo);
2677 
2678     gtk_list_store_set (GTK_LIST_STORE (model), &iter,
2679                         0, lightdm_user_get_name (user),
2680                         1, lightdm_user_get_display_name (user),
2681                         2, logged_in ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL,
2682                         -1);
2683 }
2684 
2685 static void
user_removed_cb(LightDMUserList * user_list,LightDMUser * user)2686 user_removed_cb (LightDMUserList *user_list, LightDMUser *user)
2687 {
2688     GtkTreeModel *model;
2689     GtkTreeIter iter;
2690 
2691     if (!get_user_iter (lightdm_user_get_name (user), &iter))
2692         return;
2693 
2694     model = gtk_combo_box_get_model (user_combo);
2695     gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
2696 }
2697 
2698 static void
load_user_list(void)2699 load_user_list (void)
2700 {
2701     GtkTreeModel *model;
2702     GtkTreeIter   iter;
2703 
2704     const GList  *items;
2705     const GList  *item;
2706 
2707     const gchar  *selected_user;
2708     gchar        *last_user;
2709     gboolean      logged_in = FALSE;
2710 
2711     g_signal_connect (lightdm_user_list_get_instance (), "user-added", G_CALLBACK (user_added_cb), greeter);
2712     g_signal_connect (lightdm_user_list_get_instance (), "user-changed", G_CALLBACK (user_changed_cb), greeter);
2713     g_signal_connect (lightdm_user_list_get_instance (), "user-removed", G_CALLBACK (user_removed_cb), NULL);
2714     model = gtk_combo_box_get_model (user_combo);
2715     items = lightdm_user_list_get_users (lightdm_user_list_get_instance ());
2716     for (item = items; item; item = item->next)
2717     {
2718         LightDMUser *user = item->data;
2719         logged_in = lightdm_user_get_logged_in (user);
2720 
2721         gtk_list_store_append (GTK_LIST_STORE (model), &iter);
2722         gtk_list_store_set (GTK_LIST_STORE (model), &iter,
2723                             0, lightdm_user_get_name (user),
2724                             1, lightdm_user_get_display_name (user),
2725                             2, logged_in ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL,
2726                             -1);
2727     }
2728     if (lightdm_greeter_get_has_guest_account_hint (greeter))
2729     {
2730         gtk_list_store_append (GTK_LIST_STORE (model), &iter);
2731         gtk_list_store_set (GTK_LIST_STORE (model), &iter,
2732                             0, "*guest",
2733                             1, _("Guest Session"),
2734                             2, PANGO_WEIGHT_NORMAL,
2735                             -1);
2736     }
2737 
2738     gtk_list_store_append (GTK_LIST_STORE (model), &iter);
2739     gtk_list_store_set (GTK_LIST_STORE (model), &iter,
2740                         0, "*other",
2741                         1, _("Other..."),
2742                         2, PANGO_WEIGHT_NORMAL,
2743                         -1);
2744 
2745     last_user = config_get_string (STATE_SECTION_GREETER, STATE_KEY_LAST_USER, NULL);
2746 
2747     if (lightdm_greeter_get_select_user_hint (greeter))
2748         selected_user = lightdm_greeter_get_select_user_hint (greeter);
2749     else if (lightdm_greeter_get_select_guest_hint (greeter))
2750         selected_user = "*guest";
2751     else if (last_user)
2752         selected_user = last_user;
2753     else
2754         selected_user = NULL;
2755 
2756     if (gtk_tree_model_get_iter_first (model, &iter))
2757     {
2758         gchar *name;
2759         gboolean matched = FALSE;
2760 
2761         if (selected_user)
2762         {
2763             do
2764             {
2765                 gtk_tree_model_get (model, &iter, 0, &name, -1);
2766                 matched = g_strcmp0 (name, selected_user) == 0;
2767                 g_free (name);
2768                 if (matched)
2769                 {
2770                     gtk_combo_box_set_active_iter (user_combo, &iter);
2771                     set_displayed_user (greeter, selected_user);
2772                     break;
2773                 }
2774             } while (gtk_tree_model_iter_next (model, &iter));
2775         }
2776         if (!matched)
2777         {
2778             gtk_tree_model_get_iter_first (model, &iter);
2779             gtk_tree_model_get (model, &iter, 0, &name, -1);
2780             gtk_combo_box_set_active_iter (user_combo, &iter);
2781             set_displayed_user (greeter, name);
2782             g_free (name);
2783         }
2784     }
2785 
2786     g_free (last_user);
2787 }
2788 
2789 static GdkFilterReturn
wm_window_filter(GdkXEvent * gxevent,GdkEvent * event,gpointer data)2790 wm_window_filter (GdkXEvent *gxevent, GdkEvent *event, gpointer  data)
2791 {
2792     XEvent *xevent = (XEvent*)gxevent;
2793     if (xevent->type == MapNotify)
2794     {
2795         GdkDisplay *display = gdk_x11_lookup_xdisplay (xevent->xmap.display);
2796         GdkWindow *win = gdk_x11_window_foreign_new_for_display (display, xevent->xmap.window);
2797         GdkWindowTypeHint win_type = gdk_window_get_type_hint (win);
2798 
2799         if (win_type != GDK_WINDOW_TYPE_HINT_COMBO &&
2800             win_type != GDK_WINDOW_TYPE_HINT_TOOLTIP &&
2801             win_type != GDK_WINDOW_TYPE_HINT_NOTIFICATION)
2802         /*
2803         if (win_type == GDK_WINDOW_TYPE_HINT_DESKTOP ||
2804             win_type == GDK_WINDOW_TYPE_HINT_DIALOG)
2805         */
2806             gdk_window_focus (win, GDK_CURRENT_TIME);
2807     }
2808     else if (xevent->type == UnmapNotify)
2809     {
2810         Window xwin;
2811         int revert_to = RevertToNone;
2812 
2813         XGetInputFocus (xevent->xunmap.display, &xwin, &revert_to);
2814         if (revert_to == RevertToNone)
2815             gdk_window_lower (gtk_widget_get_window (gtk_widget_get_toplevel (GTK_WIDGET (screen_overlay))));
2816     }
2817 
2818     return GDK_FILTER_CONTINUE;
2819 }
2820 
2821 static void
debug_log_handler(const gchar * log_domain,GLogLevelFlags log_level,const gchar * message,gpointer user_data)2822 debug_log_handler (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data)
2823 {
2824     gchar *new_domain = NULL;
2825     if (log_level == G_LOG_LEVEL_DEBUG)
2826     {
2827         log_level = G_LOG_LEVEL_MESSAGE;
2828         if (log_domain)
2829             log_domain = new_domain = g_strdup_printf ("DEBUG/%s", log_domain);
2830         else
2831             log_domain = "DEBUG";
2832     }
2833     g_log_default_handler (log_domain, log_level, message, user_data);
2834     g_free (new_domain);
2835 }
2836 
2837 int
main(int argc,char ** argv)2838 main (int argc, char **argv)
2839 {
2840     GtkBuilder      *builder;
2841     GdkWindow       *root_window;
2842     GtkWidget       *image;
2843 
2844     GError          *error = NULL;
2845 
2846     const GList     *items;
2847     const GList     *item;
2848     GList           *menubar_items;
2849 
2850     gchar          **config_groups;
2851     gchar          **config_group;
2852     gchar          **a11y_states;
2853 
2854     gchar           *value;
2855 
2856     GtkCssProvider  *css_provider;
2857     GdkRGBA          lightdm_gtk_greeter_override_defaults;
2858     guint            fallback_css_priority = GTK_STYLE_PROVIDER_PRIORITY_APPLICATION;
2859     GtkIconTheme    *icon_theme;
2860 
2861     /* Protect memory from being paged to disk, as we deal with passwords
2862 
2863         According to systemd-dev,
2864 
2865         "mlockall() is generally a bad idea and certainly has no place in a graphical program.
2866         A program like this uses lots of memory and it is crucial that this memory can be paged
2867         out to relieve memory pressure."
2868 
2869         With systemd version 239 the ulimit for RLIMIT_MEMLOCK was set to 16 MiB
2870         and therefore the mlockall call would fail. This is lucky becasue the subsequent mmap would not fail.
2871 
2872         With systemd version 240 the RLIMIT_MEMLOCK is now set to 64 MiB
2873         and now the mlockall no longer fails. However, it not possible to mmap in all
2874         the memory and because that would still exceed the MEMLOCK limit.
2875         "
2876         See https://bugzilla.redhat.com/show_bug.cgi?id=1662857 &
2877         https://github.com/CanonicalLtd/lightdm/issues/55
2878 
2879         RLIMIT_MEMLOCK = 64 MiB means, arctica-greeter will most likely fail with 64 bit and
2880         will always fail on 32 bit systems.
2881 
2882         Hence we better disable it. */
2883 
2884     /*mlockall (MCL_CURRENT | MCL_FUTURE);*/
2885 
2886     g_message ("Starting %s (%s, %s)", PACKAGE_STRING, __DATE__, __TIME__);
2887 
2888     /* Disable global menus */
2889     g_unsetenv ("UBUNTU_MENUPROXY");
2890 
2891     /* LP: #1024482 */
2892     g_setenv ("GDK_CORE_DEVICE_EVENTS", "1", TRUE);
2893 
2894     /* Initialize i18n */
2895     setlocale (LC_ALL, "");
2896     bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
2897     bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
2898     textdomain (GETTEXT_PACKAGE);
2899 
2900     g_unix_signal_add (SIGTERM, (GSourceFunc)sigterm_cb, /* is_callback */ GINT_TO_POINTER (TRUE));
2901 
2902     default_user_icon = g_strdup("avatar-default");
2903 
2904     config_init ();
2905 
2906     if (config_get_bool (NULL, CONFIG_KEY_DEBUGGING, FALSE))
2907         g_log_set_default_handler (debug_log_handler, NULL);
2908 
2909     /* init gtk */
2910     gtk_init (&argc, &argv);
2911 
2912     /* Disabling GtkInspector shortcuts.
2913        It is still possible to run GtkInspector with GTK_DEBUG=interactive.
2914        Assume that user knows what he's doing. */
2915     if (!config_get_bool (NULL, CONFIG_KEY_DEBUGGING, FALSE))
2916     {
2917         GtkWidget *fake_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2918         GtkBindingSet *set = gtk_binding_set_by_class (G_OBJECT_GET_CLASS (fake_window));
2919         GtkBindingEntry *entry = NULL;
2920         GtkBindingSignal *signals = NULL;
2921         GSList *bindings = NULL;
2922         GSList *iter;
2923 
2924         for (entry = set->entries; entry; entry = entry->set_next)
2925         {
2926             for (signals = entry->signals; signals; signals = signals->next)
2927             {
2928                 if (g_strcmp0 (signals->signal_name, "enable-debugging") == 0)
2929                 {
2930                     bindings = g_slist_prepend (bindings, entry);
2931                     break;
2932                 }
2933             }
2934         }
2935 
2936         for (iter = bindings; iter; iter = g_slist_next (iter))
2937         {
2938             entry = iter->data;
2939             gtk_binding_entry_remove (set, entry->keyval, entry->modifiers);
2940         }
2941 
2942         g_slist_free (bindings);
2943         gtk_widget_destroy (fake_window);
2944     }
2945 
2946 #ifdef HAVE_LIBIDO
2947     g_debug ("Initializing IDO library");
2948     ido_init ();
2949 #endif
2950 
2951     greeter = lightdm_greeter_new ();
2952     g_signal_connect (greeter, "show-prompt", G_CALLBACK (show_prompt_cb), NULL);
2953     g_signal_connect (greeter, "show-message", G_CALLBACK (show_message_cb), NULL);
2954     g_signal_connect (greeter, "authentication-complete", G_CALLBACK (authentication_complete_cb), NULL);
2955     g_signal_connect (greeter, "autologin-timer-expired", G_CALLBACK (timed_autologin_cb), NULL);
2956     if (!lightdm_greeter_connect_sync (greeter, NULL))
2957         return EXIT_FAILURE;
2958 
2959     /* Set default cursor */
2960     gdk_window_set_cursor (gdk_get_default_root_window (), gdk_cursor_new_for_display (gdk_display_get_default (), GDK_LEFT_PTR));
2961 
2962     /* Make the greeter behave a bit more like a screensaver if used as un/lock-screen by blanking the screen */
2963     if (lightdm_greeter_get_lock_hint (greeter))
2964     {
2965         Display *display = gdk_x11_display_get_xdisplay (gdk_display_get_default ());
2966         XGetScreenSaver (display, &timeout, &interval, &prefer_blanking, &allow_exposures);
2967         XForceScreenSaver (display, ScreenSaverActive);
2968         XSetScreenSaver (display, config_get_int (NULL, CONFIG_KEY_SCREENSAVER_TIMEOUT, 60), 0,
2969                          ScreenSaverActive, DefaultExposures);
2970     }
2971 
2972     /* Set GTK+ settings */
2973     value = config_get_string (NULL, CONFIG_KEY_THEME, NULL);
2974     if (value)
2975     {
2976         g_debug ("[Configuration] Changing GTK+ theme to '%s'", value);
2977         g_object_set (gtk_settings_get_default (), "gtk-theme-name", value, NULL);
2978         g_free (value);
2979     }
2980     g_object_get (gtk_settings_get_default (), "gtk-theme-name", &default_theme_name, NULL);
2981     g_debug ("[Configuration] GTK+ theme: '%s'", default_theme_name);
2982 
2983     value = config_get_string (NULL, CONFIG_KEY_ICON_THEME, NULL);
2984     if (value)
2985     {
2986         g_debug ("[Configuration] Changing icons theme to '%s'", value);
2987         g_object_set (gtk_settings_get_default (), "gtk-icon-theme-name", value, NULL);
2988         g_free (value);
2989     }
2990     g_object_get (gtk_settings_get_default (), "gtk-icon-theme-name", &default_icon_theme_name, NULL);
2991     g_debug ("[Configuration] Icons theme: '%s'", default_icon_theme_name);
2992 
2993     value = config_get_string (NULL, CONFIG_KEY_CURSOR_THEME, NULL);
2994     if (value)
2995     {
2996         g_debug ("[Configuration] Changing cursor theme to '%s'", value);
2997         g_object_set (gtk_settings_get_default (), "gtk-cursor-theme-name", value, NULL);
2998         g_free (value);
2999     }
3000     g_object_get (gtk_settings_get_default (), "gtk-cursor-theme-name", &default_cursor_theme_name, NULL);
3001     g_debug ("[Configuration] Cursor theme: '%s'", default_cursor_theme_name);
3002 
3003     if (config_has_key(NULL, CONFIG_KEY_CURSOR_THEME_SIZE))
3004     {
3005         g_object_set (gtk_settings_get_default (), "gtk-cursor-theme-size", config_get_int (NULL, CONFIG_KEY_CURSOR_THEME_SIZE, 16), NULL);
3006     }
3007 
3008     value = config_get_string (NULL, CONFIG_KEY_FONT, "Sans 10");
3009     if (value)
3010     {
3011         g_debug ("[Configuration] Changing font to '%s'", value);
3012         g_object_set (gtk_settings_get_default (), "gtk-font-name", value, NULL);
3013         g_free (value);
3014     }
3015     g_object_get (gtk_settings_get_default (), "gtk-font-name", &default_font_name, NULL);
3016     g_debug ("[Configuration] Font: '%s'", default_font_name);
3017 
3018     if (config_has_key (NULL, CONFIG_KEY_DPI))
3019         g_object_set (gtk_settings_get_default (), "gtk-xft-dpi", 1024*config_get_int (NULL, CONFIG_KEY_DPI, 96), NULL);
3020 
3021     if (config_has_key (NULL, CONFIG_KEY_ANTIALIAS))
3022         g_object_set (gtk_settings_get_default (), "gtk-xft-antialias", config_get_bool (NULL, CONFIG_KEY_ANTIALIAS, FALSE), NULL);
3023 
3024     value = config_get_string (NULL, CONFIG_KEY_HINT_STYLE, NULL);
3025     if (value)
3026     {
3027         g_object_set (gtk_settings_get_default (), "gtk-xft-hintstyle", value, NULL);
3028         g_free (value);
3029     }
3030 
3031     value = config_get_string (NULL, CONFIG_KEY_RGBA, NULL);
3032     if (value)
3033     {
3034         g_object_set (gtk_settings_get_default (), "gtk-xft-rgba", value, NULL);
3035         g_free (value);
3036     }
3037 
3038     #ifdef AT_SPI_COMMAND
3039     if (config_has_key (NULL, CONFIG_KEY_AT_SPI_ENABLED) && config_get_bool (NULL, CONFIG_KEY_AT_SPI_ENABLED, TRUE) == FALSE)
3040     {
3041         // AT_SPI is user-disabled
3042     }
3043     else
3044     {
3045         spawn_line_pid (AT_SPI_COMMAND, G_SPAWN_SEARCH_PATH, NULL);
3046     }
3047     #endif
3048 
3049     #ifdef INDICATOR_SERVICES_COMMAND
3050     spawn_line_pid (INDICATOR_SERVICES_COMMAND, G_SPAWN_SEARCH_PATH, NULL);
3051     #endif
3052 
3053     builder = gtk_builder_new ();
3054     if (!gtk_builder_add_from_string (builder, lightdm_gtk_greeter_ui,
3055                                       lightdm_gtk_greeter_ui_length, &error))
3056     {
3057         g_warning ("Error loading UI: %s", error->message);
3058         return EXIT_FAILURE;
3059     }
3060     g_clear_error (&error);
3061 
3062     /* Screen window */
3063     screen_overlay = GTK_OVERLAY (gtk_builder_get_object (builder, "screen_overlay"));
3064     screen_overlay_child = GTK_WIDGET (gtk_builder_get_object (builder, "screen_overlay_child"));
3065 
3066     /* Login window */
3067     login_window = GTK_WIDGET (gtk_builder_get_object (builder, "login_window"));
3068     user_image = GTK_IMAGE (gtk_builder_get_object (builder, "user_image"));
3069     user_combo = GTK_COMBO_BOX (gtk_builder_get_object (builder, "user_combobox"));
3070     username_entry = GTK_ENTRY (gtk_builder_get_object (builder, "username_entry"));
3071     password_entry = GTK_ENTRY (gtk_builder_get_object (builder, "password_entry"));
3072     info_bar = GTK_INFO_BAR (gtk_builder_get_object (builder, "greeter_infobar"));
3073     message_label = GTK_LABEL (gtk_builder_get_object (builder, "message_label"));
3074     cancel_button = GTK_BUTTON (gtk_builder_get_object (builder, "cancel_button"));
3075     login_button = GTK_BUTTON (gtk_builder_get_object (builder, "login_button"));
3076 
3077     /* Panel window*/
3078     panel_window = GTK_WIDGET (gtk_builder_get_object (builder, "panel_window"));
3079     menubar = GTK_WIDGET (gtk_builder_get_object (builder, "menubar"));
3080     session_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "session_menuitem"));
3081     session_menu = GTK_MENU (gtk_builder_get_object (builder, "session_menu"));
3082     language_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "language_menuitem"));
3083     language_menu = GTK_MENU (gtk_builder_get_object (builder, "language_menu"));
3084     a11y_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "a11y_menuitem"));
3085     contrast_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "high_contrast_menuitem"));
3086     font_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "large_font_menuitem"));
3087     keyboard_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "keyboard_menuitem"));
3088     reader_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "reader_menuitem"));
3089     power_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "power_menuitem"));
3090     layout_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "layout_menuitem"));
3091     layout_menu = GTK_MENU (gtk_builder_get_object (builder, "layout_menu"));
3092     clock_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "clock_menuitem"));
3093     host_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "host_menuitem"));
3094 
3095     /* Power dialog */
3096     power_window = GTK_WIDGET (gtk_builder_get_object (builder, "power_window"));
3097     power_ok_button = GTK_BUTTON (gtk_builder_get_object (builder, "power_ok_button"));
3098     power_cancel_button = GTK_BUTTON (gtk_builder_get_object (builder, "power_cancel_button"));
3099     power_title = GTK_LABEL (gtk_builder_get_object (builder, "power_title"));
3100     power_text = GTK_LABEL (gtk_builder_get_object (builder, "power_text"));
3101     power_icon = GTK_IMAGE (gtk_builder_get_object (builder, "power_icon"));
3102 
3103     gtk_overlay_add_overlay (screen_overlay, login_window);
3104     gtk_overlay_add_overlay (screen_overlay, panel_window);
3105     gtk_overlay_add_overlay (screen_overlay, power_window);
3106 
3107     gtk_accel_map_add_entry ("<Login>/a11y/font", GDK_KEY_F1, 0);
3108     gtk_accel_map_add_entry ("<Login>/a11y/contrast", GDK_KEY_F2, 0);
3109     gtk_accel_map_add_entry ("<Login>/a11y/keyboard", GDK_KEY_F3, 0);
3110     gtk_accel_map_add_entry ("<Login>/a11y/reader", GDK_KEY_F4, 0);
3111     gtk_accel_map_add_entry ("<Login>/power/shutdown", GDK_KEY_F4, GDK_MOD1_MASK);
3112 
3113     init_indicators ();
3114 
3115     /* https://bugzilla.gnome.org/show_bug.cgi?id=710888
3116        > GtkInfoBar not shown after calling gtk_widget_show
3117        Assume they will fix it someday. */
3118     if (gtk_get_major_version () == 3 && gtk_get_minor_version () < 18)
3119     {
3120         GList *children = gtk_container_get_children (GTK_CONTAINER (info_bar));
3121         if (g_list_length (children) == 1 && GTK_IS_REVEALER (children->data))
3122             g_signal_connect_after(children->data, "notify::child-revealed", (GCallback)infobar_revealed_cb_710888, NULL);
3123         g_list_free (children);
3124     }
3125 
3126     /* Hide empty panel */
3127     menubar_items = gtk_container_get_children (GTK_CONTAINER (menubar));
3128     if (!menubar_items)
3129         gtk_widget_hide (GTK_WIDGET (panel_window));
3130     else
3131         g_list_free (menubar_items);
3132 
3133     if (config_get_bool (NULL, CONFIG_KEY_HIDE_USER_IMAGE, FALSE))
3134     {
3135         gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (builder, "user_image_border")));
3136         gtk_widget_hide (GTK_WIDGET (user_image));  /* Hide to mark image is disabled */
3137         gtk_widget_set_size_request (GTK_WIDGET (user_combo), 250, -1);
3138     }
3139     else
3140     {
3141         value = config_get_string (NULL, CONFIG_KEY_DEFAULT_USER_IMAGE, NULL);
3142         if (value)
3143         {
3144             if (value[0] == '#')
3145             {
3146                 g_free (default_user_icon);
3147                 default_user_icon = g_strdup (value + 1);
3148             }
3149             else
3150             {
3151                 default_user_pixbuf = gdk_pixbuf_new_from_file_at_scale (value, 80, 80, FALSE, &error);
3152                 if (!default_user_pixbuf)
3153                 {
3154                     g_warning ("Failed to load default user image: %s", error->message);
3155                     g_clear_error (&error);
3156                 }
3157             }
3158             g_free (value);
3159         }
3160     }
3161 
3162     icon_theme = gtk_icon_theme_get_default ();
3163 
3164     /* Session menu */
3165     if (gtk_widget_get_visible (session_menuitem))
3166     {
3167         GSList *sessions = NULL;
3168 
3169         if (gtk_icon_theme_has_icon (icon_theme, "document-properties-symbolic"))
3170             session_badge = gtk_image_new_from_icon_name ("document-properties-symbolic", GTK_ICON_SIZE_MENU);
3171         else
3172             session_badge = gtk_image_new_from_icon_name ("document-properties", GTK_ICON_SIZE_MENU);
3173         gtk_widget_show (session_badge);
3174         gtk_container_add (GTK_CONTAINER (session_menuitem), session_badge);
3175 
3176         items = lightdm_get_sessions ();
3177         for (item = items; item; item = item->next)
3178         {
3179             LightDMSession *session = item->data;
3180             GtkWidget *radiomenuitem;
3181 
3182             radiomenuitem = gtk_radio_menu_item_new_with_label (sessions, lightdm_session_get_name (session));
3183             g_object_set_data (G_OBJECT (radiomenuitem), SESSION_DATA_KEY, (gpointer) lightdm_session_get_key (session));
3184             sessions = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (radiomenuitem));
3185             g_signal_connect (G_OBJECT (radiomenuitem), "activate", G_CALLBACK (session_selected_cb), NULL);
3186             gtk_menu_shell_append (GTK_MENU_SHELL (session_menu), radiomenuitem);
3187             gtk_widget_show (GTK_WIDGET (radiomenuitem));
3188         }
3189         set_session (NULL);
3190     }
3191 
3192     /* Language menu */
3193     if (gtk_widget_get_visible (language_menuitem))
3194     {
3195         GSList *languages = NULL;
3196         gchar *modifier;
3197         items = lightdm_get_languages ();
3198         for (item = items; item; item = item->next)
3199         {
3200             LightDMLanguage *language = item->data;
3201             const gchar *country, *code;
3202             gchar *label;
3203             GtkWidget *radiomenuitem;
3204 
3205 	    label = g_strdup (lightdm_language_get_code (language));
3206 
3207             code = lightdm_language_get_code (language);
3208             modifier = strchr (code, '@');
3209             if (modifier != NULL)
3210             {
3211                 gchar *label_new = g_strdup_printf ("%s [%s]", label, modifier+1);
3212                 g_free (label);
3213                 label = label_new;
3214             }
3215 
3216             radiomenuitem = gtk_radio_menu_item_new_with_label (languages, label);
3217             g_object_set_data (G_OBJECT (radiomenuitem), LANGUAGE_DATA_CODE, (gpointer) code);
3218             languages = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (radiomenuitem));
3219             g_signal_connect (G_OBJECT (radiomenuitem), "activate", G_CALLBACK (language_selected_cb), NULL);
3220             gtk_menu_shell_append (GTK_MENU_SHELL (language_menu), radiomenuitem);
3221             gtk_widget_show (GTK_WIDGET (radiomenuitem));
3222         }
3223         set_language (NULL);
3224     }
3225 
3226     /* a11y menu */
3227     if (gtk_widget_get_visible (a11y_menuitem))
3228     {
3229         if (gtk_icon_theme_has_icon (icon_theme, "preferences-desktop-accessibility-symbolic"))
3230             image = gtk_image_new_from_icon_name ("preferences-desktop-accessibility-symbolic", GTK_ICON_SIZE_MENU);
3231         else
3232             image = gtk_image_new_from_icon_name ("preferences-desktop-accessibility", GTK_ICON_SIZE_MENU);
3233         gtk_widget_show (image);
3234         gtk_container_add (GTK_CONTAINER (a11y_menuitem), image);
3235     }
3236 
3237     value = config_get_string (NULL, CONFIG_KEY_KEYBOARD, NULL);
3238     if (value)
3239     {
3240         a11y_keyboard_command = menu_command_parse_extended ("keyboard", value, keyboard_menuitem, "onboard", "--xid");
3241         g_free (value);
3242     }
3243     gtk_widget_set_visible (keyboard_menuitem, a11y_keyboard_command != NULL);
3244 
3245 
3246 
3247     value = config_get_string (NULL, CONFIG_KEY_READER, NULL);
3248     if (value)
3249     {
3250         a11y_reader_command = menu_command_parse ("reader", value, reader_menuitem);
3251         g_free (value);
3252     }
3253     gtk_widget_set_visible (reader_menuitem, a11y_reader_command != NULL);
3254 
3255     /* Power menu */
3256     if (gtk_widget_get_visible (power_menuitem))
3257     {
3258         if (gtk_icon_theme_has_icon (icon_theme, "system-shutdown-symbolic"))
3259             image = gtk_image_new_from_icon_name ("system-shutdown-symbolic", GTK_ICON_SIZE_MENU);
3260         else
3261             image = gtk_image_new_from_icon_name ("system-shutdown", GTK_ICON_SIZE_MENU);
3262         gtk_widget_show (image);
3263         gtk_container_add (GTK_CONTAINER (power_menuitem), image);
3264 
3265         suspend_menuitem = (GTK_WIDGET (gtk_builder_get_object (builder, "suspend_menuitem")));
3266         hibernate_menuitem = (GTK_WIDGET (gtk_builder_get_object (builder, "hibernate_menuitem")));
3267         restart_menuitem = (GTK_WIDGET (gtk_builder_get_object (builder, "restart_menuitem")));
3268         shutdown_menuitem = (GTK_WIDGET (gtk_builder_get_object (builder, "shutdown_menuitem")));
3269 
3270         g_signal_connect (G_OBJECT (power_menuitem),"activate", G_CALLBACK (power_menu_cb), NULL);
3271     }
3272 
3273     /* Layout menu */
3274     if (gtk_widget_get_visible (layout_menuitem))
3275     {
3276         #ifdef HAVE_LIBXKLAVIER
3277         xkl_engine = xkl_engine_get_instance (XOpenDisplay (NULL));
3278         if (xkl_engine)
3279         {
3280             xkl_engine_start_listen (xkl_engine, XKLL_TRACK_KEYBOARD_STATE);
3281             g_signal_connect (xkl_engine, "X-state-changed",
3282                               G_CALLBACK (xkl_state_changed_cb), NULL);
3283             g_signal_connect (xkl_engine, "X-config-changed",
3284                               G_CALLBACK (xkl_config_changed_cb), NULL);
3285             gdk_window_add_filter (NULL, (GdkFilterFunc) xkl_xevent_filter, NULL);
3286 
3287             /* refresh */
3288             XklConfigRec *config_rec = xkl_config_rec_new ();
3289             if (xkl_config_rec_get_from_server (config_rec, xkl_engine))
3290                 xkl_config_rec_activate (config_rec, xkl_engine);
3291             g_object_unref (config_rec);
3292         }
3293         else
3294         {
3295             g_warning ("Failed to get XklEngine instance");
3296             gtk_widget_hide (layout_menuitem);
3297         }
3298         #endif
3299         update_layouts_menu ();
3300         update_layouts_menu_state ();
3301     }
3302 
3303     /* Host label */
3304     if (gtk_widget_get_visible (host_menuitem))
3305         gtk_menu_item_set_label (GTK_MENU_ITEM (host_menuitem), lightdm_get_hostname ());
3306 
3307     /* Clock label */
3308     if (gtk_widget_get_visible (clock_menuitem))
3309     {
3310         gtk_menu_item_set_label (GTK_MENU_ITEM (clock_menuitem), "");
3311         clock_label = gtk_bin_get_child (GTK_BIN (clock_menuitem));
3312         clock_format = config_get_string (NULL, CONFIG_KEY_CLOCK_FORMAT, "%a, %H:%M");
3313         clock_timeout_thread ();
3314         gdk_threads_add_timeout (1000, (GSourceFunc) clock_timeout_thread, NULL);
3315     }
3316 
3317     /* A bit of CSS */
3318     css_provider = gtk_css_provider_new ();
3319     gtk_css_provider_load_from_data (css_provider, lightdm_gtk_greeter_css_application, lightdm_gtk_greeter_css_application_length, NULL);
3320     gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), GTK_STYLE_PROVIDER (css_provider),
3321                                                GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
3322     css_provider = gtk_css_provider_new ();
3323     if (gtk_style_context_lookup_color (gtk_widget_get_style_context (GTK_WIDGET (login_window)),
3324                                         "lightdm-gtk-greeter-override-defaults",
3325                                         &lightdm_gtk_greeter_override_defaults))
3326         fallback_css_priority = GTK_STYLE_PROVIDER_PRIORITY_FALLBACK;
3327     gtk_css_provider_load_from_data (css_provider, lightdm_gtk_greeter_css_fallback, lightdm_gtk_greeter_css_fallback_length, NULL);
3328     gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), GTK_STYLE_PROVIDER (css_provider),
3329                                                fallback_css_priority);
3330 
3331     /* Background */
3332     greeter_background = greeter_background_new (GTK_WIDGET (screen_overlay));
3333 
3334     value = config_get_string (NULL, CONFIG_KEY_ACTIVE_MONITOR, NULL);
3335     greeter_background_set_active_monitor_config (greeter_background, value ? value : "#cursor");
3336     g_free (value);
3337 
3338     read_monitor_configuration (CONFIG_GROUP_DEFAULT, GREETER_BACKGROUND_DEFAULT);
3339 
3340     config_groups = config_get_groups (CONFIG_GROUP_MONITOR);
3341     for (config_group = config_groups; *config_group; ++config_group)
3342     {
3343         const gchar *name = *config_group + sizeof (CONFIG_GROUP_MONITOR);
3344         while (*name && g_ascii_isspace (*name))
3345             ++name;
3346 
3347         read_monitor_configuration (*config_group, name);
3348     }
3349     g_strfreev (config_groups);
3350 
3351     greeter_background_add_accel_group (greeter_background, GTK_ACCEL_GROUP (gtk_builder_get_object (builder, "a11y_accelgroup")));
3352     greeter_background_add_accel_group (greeter_background, GTK_ACCEL_GROUP (gtk_builder_get_object (builder, "power_accelgroup")));
3353 
3354     greeter_background_connect (greeter_background, gdk_screen_get_default ());
3355 
3356     if (lightdm_greeter_get_hide_users_hint (greeter))
3357     {
3358         set_user_image (NULL);
3359         start_authentication ("*other");
3360     }
3361     else
3362     {
3363         load_user_list ();
3364         gtk_widget_hide (GTK_WIDGET (cancel_button));
3365         gtk_widget_show (GTK_WIDGET (user_combo));
3366     }
3367 
3368     /* Windows positions */
3369     value = config_get_string (NULL, CONFIG_KEY_POSITION, NULL);
3370     g_object_set_data_full (G_OBJECT (login_window), WINDOW_DATA_POSITION, str_to_position (value, &WINDOW_POS_CENTER), g_free);
3371     g_free (value);
3372 
3373 
3374     gtk_widget_set_valign (panel_window, config_get_enum (NULL, CONFIG_KEY_PANEL_POSITION, GTK_ALIGN_START,
3375                                                           "bottom", GTK_ALIGN_END,
3376                                                           "top", GTK_ALIGN_START, NULL));
3377 
3378     if (a11y_keyboard_command)
3379     {
3380         value = config_get_string (NULL, CONFIG_KEY_KEYBOARD_POSITION, NULL);
3381         g_object_set_data_full (G_OBJECT (a11y_keyboard_command->widget), WINDOW_DATA_POSITION, str_to_position (value, &KEYBOARD_POSITION), g_free);
3382         g_free (value);
3383     }
3384 
3385     gtk_builder_connect_signals (builder, greeter);
3386 
3387     a11y_states = config_get_string_list (NULL, CONFIG_KEY_A11Y_STATES, NULL);
3388     if (a11y_states && *a11y_states)
3389     {
3390         gpointer a11y_item;
3391         gchar **values_iter;
3392 
3393         GHashTable *a11y_items = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify)g_free, NULL);
3394         g_hash_table_insert (a11y_items, g_strdup("contrast"), contrast_menuitem);
3395         g_hash_table_insert (a11y_items, g_strdup("font"), font_menuitem);
3396         g_hash_table_insert (a11y_items, g_strdup("keyboard"), keyboard_menuitem);
3397         g_hash_table_insert (a11y_items, g_strdup("reader"), reader_menuitem);
3398 
3399         for (values_iter = a11y_states; *values_iter; ++values_iter)
3400         {
3401             value = *values_iter;
3402             switch (value[0])
3403             {
3404             case '-':
3405                 continue;
3406             case '+':
3407                 if (g_hash_table_lookup_extended (a11y_items, &value[1], NULL, &a11y_item) &&
3408                     gtk_widget_get_visible (GTK_WIDGET (a11y_item)))
3409                         gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (a11y_item), TRUE);
3410                 break;
3411             default:
3412                 if (g_hash_table_lookup_extended (a11y_items, value, NULL, &a11y_item) &&
3413                     gtk_widget_get_visible (GTK_WIDGET (a11y_item)))
3414                 {
3415                     gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (a11y_item),
3416                                                     config_get_bool (STATE_SECTION_A11Y, value, FALSE));
3417                     g_signal_connect (G_OBJECT (a11y_item), "toggled", G_CALLBACK (a11y_menuitem_toggled_cb), g_strdup (value));
3418                 }
3419             }
3420         }
3421         g_hash_table_unref (a11y_items);
3422     }
3423     g_strfreev (a11y_states);
3424 
3425     /* There is no window manager, so we need to implement some of its functionality */
3426     root_window = gdk_get_default_root_window ();
3427     gdk_window_set_events (root_window, gdk_window_get_events (root_window) | GDK_SUBSTRUCTURE_MASK);
3428     gdk_window_add_filter (root_window, wm_window_filter, NULL);
3429 
3430     gtk_widget_show (GTK_WIDGET (screen_overlay));
3431 
3432     g_debug ("Run Gtk loop...");
3433     gtk_main ();
3434     g_debug ("Gtk loop exits");
3435 
3436     sigterm_cb (/* is_callback */ GINT_TO_POINTER (FALSE));
3437 
3438     {
3439         Display *display = gdk_x11_display_get_xdisplay (gdk_display_get_default ());
3440         int screen = XDefaultScreen (display);
3441         Window w = RootWindow (display, screen);
3442         Atom id = XInternAtom (display, "AT_SPI_BUS", True);
3443         if (id != None)
3444             {
3445                 XDeleteProperty (display, w, id);
3446                 XSync (display, FALSE);
3447             }
3448     }
3449 
3450     return EXIT_SUCCESS;
3451 }
3452