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