source: lightdm-gtk-greeter/trunk/fuentes/src/lightdm-gtk-greeter.c

Last change on this file was 8247, checked in by hectorgh, 13 months ago

reverting to orig

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