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

Last change on this file since 2361 was 2361, checked in by mabarracus, 4 years ago

Added patched content

File size: 109.2 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);
187static const gchar* gchar_valencian = "Valencià";
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        if(g_strcmp0(current_language,gchar_valencian)!=0)
1032            return g_strdup (current_language); 
1033        else
1034            return g_strdup_printf("%s","ca_ES@valencia");
1035    }
1036
1037    menu_items = gtk_container_get_children (GTK_CONTAINER (language_menu));
1038    for (menu_iter = menu_items; menu_iter != NULL; menu_iter = g_list_next (menu_iter))
1039    {
1040        if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menu_iter->data))){
1041            gchar *lang= g_object_get_data (G_OBJECT (menu_iter->data), LANGUAGE_DATA_CODE);
1042            if (g_strcmp0(lang,gchar_valencian)!=0)
1043                return g_strdup (lang);
1044            else
1045                return g_strdup_printf("%s","ca_ES@valencia");
1046        }
1047    }
1048
1049    return NULL;
1050}
1051
1052static void
1053set_language (const gchar *language)
1054{
1055    const gchar *default_language = NULL;
1056    GList *menu_items, *menu_iter;
1057   
1058    if ( g_strcmp0(language,gchar_valencian)==0)
1059        language = g_strdup_printf("%s","ca_ES@valencia");
1060
1061    if (!gtk_widget_get_visible (language_menuitem))
1062    {
1063        g_free (current_language);
1064        current_language = g_strdup (language);
1065        return;
1066    }
1067
1068    menu_items = gtk_container_get_children (GTK_CONTAINER (language_menu));
1069    if (language)
1070    {
1071        for (menu_iter = menu_items; menu_iter != NULL; menu_iter = g_list_next (menu_iter))
1072        {
1073            gchar *s;
1074            gboolean matched;
1075            s = g_strdup (g_object_get_data (G_OBJECT (menu_iter->data), LANGUAGE_DATA_CODE));
1076            if ( g_strcmp0(s,gchar_valencian)==0)
1077                s = g_strdup_printf("%s","ca_ES@valencia");
1078            matched = g_strcmp0 (s, language) == 0;
1079            g_free (s);
1080            if (matched)
1081            {
1082                gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_iter->data), TRUE);
1083                g_free (current_language);
1084                current_language = g_strdup (language);
1085
1086                if ( g_strcmp0(current_language,"ca_ES@valencia")==0)
1087                    gtk_menu_item_set_label (GTK_MENU_ITEM (language_menuitem),g_strdup_printf("%s",gchar_valencian));
1088                else
1089                    gtk_menu_item_set_label (GTK_MENU_ITEM (language_menuitem),current_language);
1090                return;
1091            }
1092        }
1093    }
1094    /* If failed to find this language, then try the default */
1095    if (lightdm_get_language ())
1096    {
1097        default_language = lightdm_language_get_code (lightdm_get_language ());
1098        if ( g_strcmp0(default_language,"ca_ES@valencia")==0)
1099                gtk_menu_item_set_label (GTK_MENU_ITEM (language_menuitem), g_strdup_printf("%s",gchar_valencian));
1100        else
1101            gtk_menu_item_set_label (GTK_MENU_ITEM (language_menuitem), default_language);
1102    }
1103    if (default_language && g_strcmp0 (default_language, language) != 0)
1104        set_language (default_language);
1105    /* If all else fails, just use the first language from the menu */
1106    else
1107        for (menu_iter = menu_items; menu_iter != NULL; menu_iter = g_list_next (menu_iter))
1108        {
1109            if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menu_iter->data)))
1110            {
1111                gtk_menu_item_set_label (GTK_MENU_ITEM (language_menuitem), g_strdup (g_object_get_data (G_OBJECT (menu_iter->data), LANGUAGE_DATA_CODE)));
1112                break;
1113            }
1114        }
1115}
1116
1117void
1118language_selected_cb (GtkMenuItem *menuitem, gpointer user_data)
1119{
1120    if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem)))
1121    {
1122        gchar *language = g_object_get_data (G_OBJECT (menuitem), LANGUAGE_DATA_CODE);
1123        if (g_strcmp0(language,gchar_valencian) == 0){
1124            language = g_strdup_printf("%s","ca_ES@valencia");
1125        }
1126        set_language (language);
1127        g_free(language);
1128    }
1129}
1130
1131/* Pending questions */
1132
1133static void
1134pam_message_finalize (PAMConversationMessage *message)
1135{
1136    g_free (message->text);
1137    g_free (message);
1138}
1139
1140static void
1141process_prompts (LightDMGreeter *greeter)
1142{
1143    if (!pending_questions)
1144        return;
1145
1146    /* always allow the user to change username again */
1147    gtk_widget_set_sensitive (GTK_WIDGET (username_entry), TRUE);
1148    gtk_widget_set_sensitive (GTK_WIDGET (password_entry), TRUE);
1149
1150    /* Special case: no user selected from list, so PAM asks us for the user
1151     * via a prompt. For that case, use the username field */
1152    if (!prompted && pending_questions && !pending_questions->next &&
1153        ((PAMConversationMessage *) pending_questions->data)->is_prompt &&
1154        ((PAMConversationMessage *) pending_questions->data)->type.prompt != LIGHTDM_PROMPT_TYPE_SECRET &&
1155        gtk_widget_get_visible ((GTK_WIDGET (username_entry))) &&
1156        lightdm_greeter_get_authentication_user (greeter) == NULL)
1157    {
1158        prompted = TRUE;
1159        prompt_active = TRUE;
1160        gtk_widget_grab_focus (GTK_WIDGET (username_entry));
1161        gtk_widget_show (GTK_WIDGET (password_entry));
1162        return;
1163    }
1164
1165    while (pending_questions)
1166    {
1167        PAMConversationMessage *message = (PAMConversationMessage *) pending_questions->data;
1168        pending_questions = g_slist_remove (pending_questions, (gconstpointer) message);
1169
1170        if (!message->is_prompt)
1171        {
1172            /* FIXME: this doesn't show multiple messages, but that was
1173             * already the case before. */
1174            set_message_label (message->type.message, message->text);
1175            continue;
1176        }
1177
1178        gtk_widget_show (GTK_WIDGET (password_entry));
1179        gtk_widget_grab_focus (GTK_WIDGET (password_entry));
1180        gtk_entry_set_text (password_entry, "");
1181        gtk_entry_set_visibility (password_entry, message->type.prompt != LIGHTDM_PROMPT_TYPE_SECRET);
1182        if (message_label_is_empty () && password_prompted)
1183        {
1184            /* No message was provided beforehand and this is not the
1185             * first password prompt, so use the prompt as label,
1186             * otherwise the user will be completely unclear of what
1187             * is going on. Actually, the fact that prompt messages are
1188             * not shown is problematic in general, especially if
1189             * somebody uses a custom PAM module that wants to ask
1190             * something different. */
1191            gchar *str = message->text;
1192            if (g_str_has_suffix (str, ": "))
1193                str = g_strndup (str, strlen (str) - 2);
1194            else if (g_str_has_suffix (str, ":"))
1195                str = g_strndup (str, strlen (str) - 1);
1196            set_message_label (LIGHTDM_MESSAGE_TYPE_INFO, str);
1197            if (str != message->text)
1198                g_free (str);
1199        }
1200        gtk_widget_grab_focus (GTK_WIDGET (password_entry));
1201        prompted = TRUE;
1202        password_prompted = TRUE;
1203        prompt_active = TRUE;
1204
1205        /* If we have more stuff after a prompt, assume that other prompts are pending,
1206         * so stop here. */
1207        break;
1208    }
1209}
1210
1211/* Panel and indicators */
1212
1213static gboolean
1214panel_item_enter_notify_cb (GtkWidget *widget, GdkEvent *event, gpointer enter)
1215{
1216    GtkStyleContext *context = gtk_widget_get_style_context (widget);
1217    if (GPOINTER_TO_INT (enter))
1218        gtk_style_context_add_class (context, PANEL_ITEM_STYLE_HOVERED);
1219    else
1220        gtk_style_context_remove_class (context, PANEL_ITEM_STYLE_HOVERED);
1221    return FALSE;
1222}
1223
1224static void
1225panel_add_item (GtkWidget *widget, gint index, GreeterPanelItemType item_type)
1226{
1227    gint insert_pos = 0;
1228    GList* items = gtk_container_get_children (GTK_CONTAINER (menubar));
1229    GList* item;
1230    for (item = items; item; item = item->next)
1231    {
1232        if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item->data), PANEL_ITEM_DATA_INDEX)) < index)
1233            break;
1234        insert_pos++;
1235    }
1236    g_list_free (items);
1237
1238    gtk_style_context_add_class (gtk_widget_get_style_context (widget), PANEL_ITEM_STYLE);
1239    gtk_style_context_add_class (gtk_widget_get_style_context (widget), PANEL_ITEM_STYLES[item_type]);
1240    if (item_type == PANEL_ITEM_INDICATOR)
1241    {
1242        g_signal_connect (G_OBJECT (widget), "enter-notify-event",
1243                          G_CALLBACK (panel_item_enter_notify_cb), GINT_TO_POINTER (TRUE));
1244        g_signal_connect (G_OBJECT (widget), "leave-notify-event",
1245                          G_CALLBACK (panel_item_enter_notify_cb), GINT_TO_POINTER (FALSE));
1246    }
1247
1248    gtk_widget_show (widget);
1249    gtk_menu_shell_insert (GTK_MENU_SHELL (menubar), widget, insert_pos);
1250}
1251
1252#ifdef HAVE_LIBINDICATOR
1253static gboolean
1254indicator_entry_scrolled_cb (GtkWidget *menuitem, GdkEventScroll *event, gpointer data)
1255{
1256    IndicatorObject      *io;
1257    IndicatorObjectEntry *entry;
1258
1259    g_return_val_if_fail (GTK_IS_WIDGET (menuitem), FALSE);
1260
1261    io = g_object_get_data (G_OBJECT (menuitem), INDICATOR_ITEM_DATA_OBJECT);
1262    entry = g_object_get_data (G_OBJECT (menuitem), INDICATOR_ITEM_DATA_ENTRY);
1263
1264    g_return_val_if_fail (INDICATOR_IS_OBJECT (io), FALSE);
1265
1266    g_signal_emit_by_name(io, INDICATOR_OBJECT_SIGNAL_ENTRY_SCROLLED, entry, 1, event->direction);
1267
1268    return FALSE;
1269}
1270
1271static void
1272indicator_entry_activated_cb (GtkWidget *widget, gpointer user_data)
1273{
1274    IndicatorObject      *io;
1275    IndicatorObjectEntry *entry;
1276
1277    g_return_if_fail (GTK_IS_WIDGET (widget));
1278
1279    io = g_object_get_data (G_OBJECT (widget), INDICATOR_ITEM_DATA_OBJECT);
1280    entry = g_object_get_data (G_OBJECT (widget), INDICATOR_ITEM_DATA_ENTRY);
1281
1282    g_return_if_fail (INDICATOR_IS_OBJECT (io));
1283
1284    return indicator_object_entry_activate (io, entry, gtk_get_current_event_time ());
1285}
1286
1287static GtkWidget*
1288indicator_entry_create_menuitem (IndicatorObject *io, IndicatorObjectEntry *entry, GtkWidget *menubar)
1289{
1290    GtkWidget *box, *menuitem;
1291    gint index = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (io), PANEL_ITEM_DATA_INDEX));
1292    box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 3);
1293    menuitem = gtk_menu_item_new ();
1294
1295    gtk_widget_add_events (GTK_WIDGET (menuitem), GDK_SCROLL_MASK);
1296
1297    g_object_set_data (G_OBJECT (menuitem), INDICATOR_ITEM_DATA_BOX, box);
1298    g_object_set_data (G_OBJECT (menuitem), INDICATOR_ITEM_DATA_OBJECT, io);
1299    g_object_set_data (G_OBJECT (menuitem), INDICATOR_ITEM_DATA_ENTRY, entry);
1300    g_object_set_data (G_OBJECT (menuitem), PANEL_ITEM_DATA_INDEX, GINT_TO_POINTER (index));
1301
1302    g_signal_connect (G_OBJECT (menuitem), "activate", G_CALLBACK (indicator_entry_activated_cb), NULL);
1303    g_signal_connect (G_OBJECT (menuitem), "scroll-event", G_CALLBACK (indicator_entry_scrolled_cb), NULL);
1304
1305    if (entry->image)
1306        gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (entry->image), FALSE, FALSE, 1);
1307
1308    if (entry->label)
1309        gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (entry->label), FALSE, FALSE, 1);
1310
1311    if (entry->menu)
1312        gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), GTK_WIDGET (entry->menu));
1313
1314    gtk_container_add (GTK_CONTAINER (menuitem), box);
1315    gtk_widget_show (box);
1316    panel_add_item (menuitem, index, PANEL_ITEM_INDICATOR);
1317
1318    return menuitem;
1319}
1320
1321static void
1322indicator_entry_added_cb (IndicatorObject *io, IndicatorObjectEntry *entry, gpointer user_data)
1323{
1324    GHashTable *menuitem_lookup;
1325    GtkWidget  *menuitem;
1326
1327    /* if the menuitem doesn't already exist, create it now */
1328    menuitem_lookup = g_object_get_data (G_OBJECT (io), INDICATOR_DATA_MENUITEMS);
1329    g_return_if_fail (menuitem_lookup);
1330    menuitem = g_hash_table_lookup (menuitem_lookup, entry);
1331    if (!GTK_IS_WIDGET (menuitem))
1332    {
1333        menuitem = indicator_entry_create_menuitem (io, entry, GTK_WIDGET (user_data));
1334        g_hash_table_insert (menuitem_lookup, entry, menuitem);
1335    }
1336
1337    gtk_widget_show (menuitem);
1338}
1339
1340static void
1341remove_indicator_entry_cb (GtkWidget *widget, gpointer userdata)
1342{
1343    IndicatorObject *io;
1344    GHashTable      *menuitem_lookup;
1345    GtkWidget       *menuitem;
1346    gpointer         entry;
1347
1348    io = g_object_get_data (G_OBJECT (widget), INDICATOR_ITEM_DATA_OBJECT);
1349    if (!INDICATOR_IS_OBJECT (io))
1350        return;
1351
1352    entry = g_object_get_data (G_OBJECT (widget), INDICATOR_ITEM_DATA_ENTRY);
1353    if (entry != userdata)
1354        return;
1355
1356    menuitem_lookup = g_object_get_data (G_OBJECT (io), INDICATOR_DATA_MENUITEMS);
1357    g_return_if_fail (menuitem_lookup);
1358    menuitem = g_hash_table_lookup (menuitem_lookup, entry);
1359    if (GTK_IS_WIDGET (menuitem))
1360        gtk_widget_hide (menuitem);
1361
1362    gtk_widget_destroy (widget);
1363}
1364
1365static void
1366indicator_entry_removed_cb (IndicatorObject *io, IndicatorObjectEntry *entry, gpointer user_data)
1367{
1368    gtk_container_foreach (GTK_CONTAINER (user_data), remove_indicator_entry_cb, entry);
1369}
1370
1371static void
1372indicator_menu_show_cb (IndicatorObject *io, IndicatorObjectEntry *entry, guint32 timestamp, gpointer user_data)
1373{
1374    IndicatorObjectEntry *entrydata;
1375    GtkWidget            *menuitem;
1376    GList                *entries, *lp;
1377
1378    menuitem = GTK_WIDGET (user_data);
1379
1380    if (!entry)
1381    {
1382        /* Close any open menus instead of opening one */
1383        entries = indicator_object_get_entries (io);
1384        for (lp = entries; lp; lp = g_list_next (lp))
1385        {
1386            entrydata = lp->data;
1387            gtk_menu_popdown (entrydata->menu);
1388        }
1389        g_list_free (entries);
1390
1391        /* And tell the menuitem to exit activation mode too */
1392        gtk_menu_shell_cancel (GTK_MENU_SHELL (menuitem));
1393    }
1394}
1395
1396static void
1397greeter_set_env (const gchar* key, const gchar* value)
1398{
1399    g_setenv (key, value, TRUE);
1400
1401    GDBusProxy* proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
1402                                                       G_DBUS_PROXY_FLAGS_NONE,
1403                                                       NULL,
1404                                                       "org.freedesktop.DBus",
1405                                                       "/org/freedesktop/DBus",
1406                                                       "org.freedesktop.DBus",
1407                                                       NULL, NULL);
1408    GVariant *result;
1409    GVariantBuilder *builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
1410    g_variant_builder_add (builder, "{ss}", key, value);
1411    result = g_dbus_proxy_call_sync (proxy, "UpdateActivationEnvironment", g_variant_new ("(a{ss})", builder),
1412                                     G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL);
1413    g_variant_unref (result);
1414    g_variant_builder_unref (builder);
1415    g_object_unref (proxy);
1416}
1417#endif
1418
1419static gboolean
1420menu_item_accel_closure_cb (GtkAccelGroup *accel_group,
1421                            GObject *acceleratable, guint keyval,
1422                            GdkModifierType modifier, gpointer data)
1423{
1424    gtk_menu_item_activate (data);
1425    return FALSE;
1426}
1427
1428/* Maybe unnecessary (in future) trick to enable accelerators for hidden/detached menu items */
1429static void
1430reassign_menu_item_accel (GtkWidget *item)
1431{
1432    GtkAccelKey key;
1433    const gchar *accel_path = gtk_menu_item_get_accel_path (GTK_MENU_ITEM (item));
1434
1435    if (accel_path && gtk_accel_map_lookup_entry (accel_path, &key))
1436    {
1437        GClosure *closure = g_cclosure_new (G_CALLBACK (menu_item_accel_closure_cb), item, NULL);
1438        gtk_accel_group_connect (gtk_menu_get_accel_group (GTK_MENU (gtk_widget_get_parent (item))),
1439                                 key.accel_key, key.accel_mods, key.accel_flags, closure);
1440        g_closure_unref (closure);
1441    }
1442
1443    GtkWidget* submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (item));
1444    if (submenu)
1445        gtk_container_foreach (GTK_CONTAINER (submenu), (GtkCallback)reassign_menu_item_accel, NULL);
1446}
1447
1448static void
1449init_indicators (void)
1450{
1451    gsize length = 0;
1452    guint i;
1453    GHashTable *builtin_items = NULL;
1454    GHashTableIter iter;
1455    gpointer iter_value;
1456    #ifdef HAVE_LIBINDICATOR
1457    gboolean inited = FALSE;
1458    #endif
1459
1460    const gchar *DEFAULT_LAYOUT[] = {"~host", "~spacer", "~clock", "~spacer",
1461                                     "~session", "~language", "~a11y", "~power", NULL};
1462
1463    gchar **names = config_get_string_list (NULL, CONFIG_KEY_INDICATORS, NULL);
1464    if (!names)
1465        names = (gchar**)DEFAULT_LAYOUT;
1466    length = g_strv_length (names);
1467
1468    builtin_items = g_hash_table_new (g_str_hash, g_str_equal);
1469
1470    g_hash_table_insert (builtin_items, "~power", power_menuitem);
1471    g_hash_table_insert (builtin_items, "~session", session_menuitem);
1472    g_hash_table_insert (builtin_items, "~language", language_menuitem);
1473    g_hash_table_insert (builtin_items, "~a11y", a11y_menuitem);
1474    g_hash_table_insert (builtin_items, "~layout", layout_menuitem);
1475    g_hash_table_insert (builtin_items, "~host", host_menuitem);
1476    g_hash_table_insert (builtin_items, "~clock", clock_menuitem);
1477
1478    g_hash_table_iter_init (&iter, builtin_items);
1479    while (g_hash_table_iter_next (&iter, NULL, &iter_value))
1480        gtk_container_remove (GTK_CONTAINER (menubar), iter_value);
1481
1482    for (i = 0; i < length; ++i)
1483    {
1484        if (names[i][0] == '~')
1485        {   /* Built-in indicators */
1486            GreeterPanelItemType item_type = PANEL_ITEM_INDICATOR;
1487            if (g_hash_table_lookup_extended (builtin_items, names[i], NULL, &iter_value))
1488                g_hash_table_remove (builtin_items, (gconstpointer)names[i]);
1489            else if (g_strcmp0 (names[i], "~separator") == 0)
1490            {
1491                GtkWidget *separator = gtk_separator_new (GTK_ORIENTATION_VERTICAL);
1492                item_type = PANEL_ITEM_SEPARATOR;
1493                iter_value = gtk_separator_menu_item_new ();
1494                gtk_widget_show (separator);
1495                gtk_container_add (iter_value, separator);
1496            }
1497            else if (g_strcmp0 (names[i], "~spacer") == 0)
1498            {
1499                item_type = PANEL_ITEM_SPACER;
1500                iter_value = gtk_separator_menu_item_new ();
1501                gtk_menu_item_set_label (iter_value, "");
1502                gtk_widget_set_hexpand (iter_value, TRUE);
1503            }
1504            else if (names[i][1] == '~')
1505            {
1506                item_type = PANEL_ITEM_TEXT;
1507                iter_value = gtk_separator_menu_item_new ();
1508                gtk_menu_item_set_label (iter_value, &names[i][2]);
1509            }
1510            else
1511                continue;
1512
1513            g_object_set_data (G_OBJECT (iter_value), PANEL_ITEM_DATA_INDEX, GINT_TO_POINTER (i));
1514            panel_add_item (iter_value, i, item_type);
1515            continue;
1516        }
1517
1518        #ifdef HAVE_LIBINDICATOR
1519        gchar* path = NULL;
1520        IndicatorObject* io = NULL;
1521
1522        if (!inited)
1523        {
1524            /* Set indicators to run with reduced functionality */
1525            greeter_set_env ("INDICATOR_GREETER_MODE", "1");
1526            /* Don't allow virtual file systems? */
1527            greeter_set_env ("GIO_USE_VFS", "local");
1528            greeter_set_env ("GVFS_DISABLE_FUSE", "1");
1529            inited = TRUE;
1530        }
1531
1532        if (g_path_is_absolute (names[i]))
1533        {   /* library with absolute path */
1534            io = indicator_object_new_from_file (names[i]);
1535        }
1536        else if (g_str_has_suffix (names[i], G_MODULE_SUFFIX))
1537        {   /* library */
1538            path = g_build_filename (INDICATOR_DIR, names[i], NULL);
1539            io = indicator_object_new_from_file (path);
1540        }
1541        #ifdef HAVE_LIBINDICATOR_NG
1542        else
1543        {   /* service file */
1544            if (strchr (names[i], '.'))
1545                path = g_strdup_printf ("%s/%s", UNITY_INDICATOR_DIR, names[i]);
1546            else
1547                path = g_strdup_printf ("%s/com.canonical.indicator.%s", UNITY_INDICATOR_DIR, names[i]);
1548            io = INDICATOR_OBJECT (indicator_ng_new_for_profile (path, "desktop_greeter", NULL));
1549        }
1550        #endif
1551
1552        if (io)
1553        {
1554            GList *entries, *lp;
1555
1556            /* used to store/fetch menu entries */
1557            g_object_set_data_full (G_OBJECT (io), INDICATOR_DATA_MENUITEMS,
1558                                    g_hash_table_new (g_direct_hash, g_direct_equal),
1559                                    (GDestroyNotify) g_hash_table_destroy);
1560            g_object_set_data (G_OBJECT (io), PANEL_ITEM_DATA_INDEX, GINT_TO_POINTER (i));
1561
1562            g_signal_connect (G_OBJECT (io), INDICATOR_OBJECT_SIGNAL_ENTRY_ADDED,
1563                              G_CALLBACK (indicator_entry_added_cb), menubar);
1564            g_signal_connect (G_OBJECT (io), INDICATOR_OBJECT_SIGNAL_ENTRY_REMOVED,
1565                              G_CALLBACK (indicator_entry_removed_cb), menubar);
1566            g_signal_connect (G_OBJECT (io), INDICATOR_OBJECT_SIGNAL_MENU_SHOW,
1567                              G_CALLBACK (indicator_menu_show_cb), menubar);
1568
1569            entries = indicator_object_get_entries (io);
1570            for (lp = entries; lp; lp = g_list_next (lp))
1571                indicator_entry_added_cb (io, lp->data, menubar);
1572            g_list_free (entries);
1573        }
1574        else
1575        {
1576            g_warning ("Indicator \"%s\": failed to load", names[i]);
1577        }
1578
1579        g_free (path);
1580        #endif
1581    }
1582    if (names && names != (gchar**)DEFAULT_LAYOUT)
1583        g_strfreev (names);
1584
1585    if (builtin_items)
1586    {
1587        g_hash_table_iter_init (&iter, builtin_items);
1588        while (g_hash_table_iter_next (&iter, NULL, &iter_value))
1589        {
1590            reassign_menu_item_accel (iter_value);
1591            gtk_widget_hide (iter_value);
1592        }
1593
1594        g_hash_table_unref (builtin_items);
1595    }
1596}
1597
1598/* Layout indicator */
1599
1600static void
1601layout_selected_cb (GtkCheckMenuItem *menuitem, gpointer user_data)
1602{
1603    if (gtk_check_menu_item_get_active (menuitem))
1604    {
1605        #ifdef HAVE_LIBXKLAVIER
1606        gint group = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menuitem), LAYOUT_DATA_GROUP));
1607        xkl_engine_lock_group (xkl_engine, group);
1608        #else
1609        const gchar *name = g_object_get_data (G_OBJECT (menuitem), LAYOUT_DATA_NAME);
1610        GList *item;
1611        for (item = lightdm_get_layouts (); item; item = g_list_next (item))
1612        {
1613            if (g_strcmp0 (name, lightdm_layout_get_name (item->data)) == 0)
1614            {
1615                lightdm_set_layout (item->data);
1616                gtk_menu_item_set_label (GTK_MENU_ITEM (layout_menuitem),
1617                                         g_object_get_data (G_OBJECT (menuitem), LAYOUT_DATA_LABEL));
1618                break;
1619            }
1620        }
1621        #endif
1622    }
1623}
1624
1625static void
1626update_layouts_menu (void)
1627{
1628    #ifdef HAVE_LIBXKLAVIER
1629    XklConfigRegistry *registry;
1630    XklConfigRec *config;
1631    XklConfigItem *config_item;
1632    GSList *menu_group = NULL;
1633    gint i;
1634
1635    g_list_free_full (gtk_container_get_children (GTK_CONTAINER (layout_menu)),
1636                      (GDestroyNotify)gtk_widget_destroy);
1637
1638    config = xkl_config_rec_new ();
1639    if (!xkl_config_rec_get_from_server (config, xkl_engine))
1640    {
1641        g_object_unref (config);
1642        g_warning ("Failed to get Xkl configuration from server");
1643        return;
1644    }
1645
1646    config_item = xkl_config_item_new ();
1647    registry = xkl_config_registry_get_instance (xkl_engine);
1648    xkl_config_registry_load (registry, FALSE);
1649
1650    for (i = 0; config->layouts[i] != NULL; ++i)
1651    {
1652        const gchar *layout = config->layouts[i] ? config->layouts[i] : "";
1653        const gchar *variant = config->variants[i] ? config->variants[i] : "";
1654        gchar *label = strlen (variant) > 0 ? g_strdup_printf ("%s_%s", layout, variant) : g_strdup (layout);
1655
1656        GtkWidget *menuitem = gtk_radio_menu_item_new (menu_group);
1657        menu_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (menuitem));
1658
1659        g_snprintf (config_item->name, sizeof (config_item->name), "%s", variant);
1660        if (xkl_config_registry_find_variant (registry, layout, config_item))
1661            gtk_menu_item_set_label (GTK_MENU_ITEM (menuitem), config_item->description);
1662        else
1663        {
1664            g_snprintf (config_item->name, sizeof (config_item->name), "%s", layout);
1665            if (xkl_config_registry_find_layout (registry, config_item))
1666                gtk_menu_item_set_label (GTK_MENU_ITEM (menuitem), config_item->description);
1667            else
1668                gtk_menu_item_set_label (GTK_MENU_ITEM (menuitem), label);
1669        }
1670
1671        g_object_set_data_full (G_OBJECT (menuitem), LAYOUT_DATA_LABEL, label, g_free);
1672        g_object_set_data (G_OBJECT (menuitem), LAYOUT_DATA_GROUP, GINT_TO_POINTER (i));
1673
1674        g_signal_connect (G_OBJECT (menuitem), "activate", G_CALLBACK (layout_selected_cb), NULL);
1675        gtk_menu_shell_append (GTK_MENU_SHELL (layout_menu), menuitem);
1676        gtk_widget_show (GTK_WIDGET (menuitem));
1677    }
1678
1679    g_object_unref (registry);
1680    g_object_unref (config_item);
1681    g_object_unref (config);
1682    #else
1683    GSList *menu_group = NULL;
1684    GList *item;
1685
1686    g_list_free_full (gtk_container_get_children (GTK_CONTAINER (layout_menu)),
1687                      (GDestroyNotify)gtk_widget_destroy);
1688
1689    for (item = lightdm_get_layouts (); item; item = g_list_next (item))
1690    {
1691        LightDMLayout *layout = item->data;
1692        GtkWidget *menuitem = gtk_radio_menu_item_new (menu_group);
1693        menu_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (menuitem));
1694
1695        g_object_set_data_full (G_OBJECT (menuitem), LAYOUT_DATA_LABEL,
1696                                g_strdelimit (g_strdup (lightdm_layout_get_name (layout)), "\t ", '_'), g_free);
1697        g_object_set_data_full (G_OBJECT (menuitem), LAYOUT_DATA_NAME,
1698                                g_strdup (lightdm_layout_get_name (layout)), g_free);
1699
1700        g_signal_connect (G_OBJECT (menuitem), "activate", G_CALLBACK (layout_selected_cb), NULL);
1701        gtk_menu_item_set_label (GTK_MENU_ITEM (menuitem), lightdm_layout_get_description (layout));
1702        gtk_menu_shell_append (GTK_MENU_SHELL (layout_menu), menuitem);
1703        gtk_widget_show (GTK_WIDGET (menuitem));
1704    }
1705    #endif
1706}
1707
1708static void
1709update_layouts_menu_state (void)
1710{
1711    #ifdef HAVE_LIBXKLAVIER
1712    XklState *state = xkl_engine_get_current_state (xkl_engine);
1713    GList *menu_items = gtk_container_get_children (GTK_CONTAINER (layout_menu));
1714    GtkCheckMenuItem *menu_item = g_list_nth_data (menu_items, state->group);
1715
1716    if (menu_item)
1717    {
1718        gtk_menu_item_set_label (GTK_MENU_ITEM (layout_menuitem),
1719                                 g_object_get_data (G_OBJECT (menu_item), LAYOUT_DATA_LABEL));
1720        gtk_check_menu_item_set_active (menu_item, TRUE);
1721    }
1722    else
1723        gtk_menu_item_set_label (GTK_MENU_ITEM (layout_menuitem), "??");
1724    g_list_free (menu_items);
1725    #else
1726    LightDMLayout *layout = lightdm_get_layout ();
1727    g_return_if_fail (layout != NULL);
1728
1729    const gchar *name = lightdm_layout_get_name (layout);
1730    GList *menu_items = gtk_container_get_children (GTK_CONTAINER (layout_menu));
1731    GList *menu_iter;
1732    for (menu_iter = menu_items; menu_iter; menu_iter = g_list_next (menu_iter))
1733    {
1734        if (g_strcmp0 (name, g_object_get_data (G_OBJECT (menu_iter->data), LAYOUT_DATA_NAME)) == 0)
1735        {
1736            gtk_check_menu_item_set_active (menu_iter->data, TRUE);
1737            gtk_menu_item_set_label (GTK_MENU_ITEM (layout_menuitem),
1738                                     g_object_get_data (G_OBJECT (menu_iter->data), LAYOUT_DATA_LABEL));
1739            break;
1740        }
1741    }
1742    g_list_free (menu_items);
1743    #endif
1744}
1745
1746#ifdef HAVE_LIBXKLAVIER
1747static void
1748xkl_state_changed_cb (XklEngine *engine, XklEngineStateChange change, gint group,
1749                      gboolean restore, gpointer user_data)
1750{
1751    if (change == GROUP_CHANGED)
1752        update_layouts_menu_state ();
1753}
1754
1755static void
1756xkl_config_changed_cb (XklEngine *engine, gpointer user_data)
1757{
1758    /* tip: xkl_config_rec_get_from_server() return old settings */
1759    update_layouts_menu ();
1760    update_layouts_menu_state ();
1761}
1762
1763static GdkFilterReturn
1764xkl_xevent_filter (GdkXEvent *xev, GdkEvent *event, gpointer  data)
1765{
1766    XEvent *xevent = (XEvent *) xev;
1767    xkl_engine_filter_events (xkl_engine, xevent);
1768    return GDK_FILTER_CONTINUE;
1769}
1770#endif
1771
1772/* a11y indciator */
1773
1774void
1775a11y_font_cb (GtkCheckMenuItem *item)
1776{
1777    if (gtk_check_menu_item_get_active (item))
1778    {
1779        gchar *font_name, **tokens;
1780        guint length;
1781
1782        g_object_get (gtk_settings_get_default (), "gtk-font-name", &font_name, NULL);
1783        tokens = g_strsplit (font_name, " ", -1);
1784        length = g_strv_length (tokens);
1785        if (length > 1)
1786        {
1787            gint size = atoi (tokens[length - 1]);
1788            if (size > 0)
1789            {
1790                g_free (tokens[length - 1]);
1791                tokens[length - 1] = g_strdup_printf ("%d", size + 10);
1792                g_free (font_name);
1793                font_name = g_strjoinv (" ", tokens);
1794            }
1795        }
1796        g_strfreev (tokens);
1797
1798        g_object_set (gtk_settings_get_default (), "gtk-font-name", font_name, NULL);
1799    }
1800    else
1801    {
1802        g_object_set (gtk_settings_get_default (), "gtk-font-name", default_font_name, NULL);
1803    }
1804}
1805
1806void
1807a11y_contrast_cb (GtkCheckMenuItem *item)
1808{
1809    if (gtk_check_menu_item_get_active (item))
1810    {
1811        g_object_set (gtk_settings_get_default (), "gtk-theme-name", "HighContrast", NULL);
1812        g_object_set (gtk_settings_get_default (), "gtk-icon-theme-name", "HighContrast", NULL);
1813    }
1814    else
1815    {
1816        g_object_set (gtk_settings_get_default (), "gtk-theme-name", default_theme_name, NULL);
1817        g_object_set (gtk_settings_get_default (), "gtk-icon-theme-name", default_icon_theme_name, NULL);
1818    }
1819}
1820
1821void
1822a11y_keyboard_cb (GtkCheckMenuItem *item, gpointer user_data)
1823{
1824    if (gtk_check_menu_item_get_active (item))
1825        menu_command_run (a11y_keyboard_command);
1826    else
1827        menu_command_stop (a11y_keyboard_command);
1828}
1829
1830void
1831a11y_reader_cb (GtkCheckMenuItem *item, gpointer user_data)
1832{
1833    if (gtk_check_menu_item_get_active (item))
1834        menu_command_run (a11y_reader_command);
1835    else
1836        menu_command_stop (a11y_reader_command);
1837}
1838
1839/* Power indicator */
1840
1841static void
1842power_menu_cb (GtkWidget *menuitem, gpointer userdata)
1843{
1844    gtk_widget_set_sensitive (suspend_menuitem, lightdm_get_can_suspend ());
1845    gtk_widget_set_sensitive (hibernate_menuitem, lightdm_get_can_hibernate ());
1846    gtk_widget_set_sensitive (restart_menuitem, lightdm_get_can_restart ());
1847    gtk_widget_set_sensitive (shutdown_menuitem, lightdm_get_can_shutdown ());
1848}
1849
1850void
1851suspend_cb (GtkWidget *widget, LightDMGreeter *greeter)
1852{
1853    lightdm_suspend (NULL);
1854}
1855
1856void
1857hibernate_cb (GtkWidget *widget, LightDMGreeter *greeter)
1858{
1859    lightdm_hibernate (NULL);
1860}
1861
1862void
1863restart_cb (GtkWidget *widget, LightDMGreeter *greeter)
1864{
1865    if (show_power_prompt ("restart", "view-refresh-symbolic",
1866                           _("Restart"),
1867                           _("Are you sure you want to close all programs and restart the computer?")))
1868        lightdm_restart (NULL);
1869}
1870
1871void
1872shutdown_cb (GtkWidget *widget, LightDMGreeter *greeter)
1873{
1874    if (show_power_prompt ("shutdown", "system-shutdown-symbolic",
1875                           _("Shut Down"),
1876                           _("Are you sure you want to close all programs and shut down the computer?")))
1877        lightdm_shutdown (NULL);
1878}
1879
1880static void
1881set_login_button_label (LightDMGreeter *greeter, const gchar *username)
1882{
1883    LightDMUser *user;
1884    gboolean logged_in = FALSE;
1885
1886    user = lightdm_user_list_get_user_by_name (lightdm_user_list_get_instance (), username);
1887    if (user)
1888        logged_in = lightdm_user_get_logged_in (user);
1889    if (logged_in)
1890        gtk_button_set_label (login_button, _("Unlock"));
1891    else
1892        gtk_button_set_label (login_button, _("Log In"));
1893    /* and disable the session and language widgets */
1894    gtk_widget_set_sensitive (GTK_WIDGET (session_menuitem), !logged_in);
1895    gtk_widget_set_sensitive (GTK_WIDGET (language_menuitem), !logged_in);
1896}
1897
1898static guint set_user_background_delayed_id = 0;
1899
1900static gboolean
1901set_user_background_delayed_cb (const gchar *value)
1902{
1903    greeter_background_set_custom_background (greeter_background, value);
1904    set_user_background_delayed_id = 0;
1905    return G_SOURCE_REMOVE;
1906}
1907
1908static void
1909set_user_background (const gchar *user_name)
1910{
1911    const gchar *value = NULL;
1912    if (user_name)
1913    {
1914        LightDMUser *user = lightdm_user_list_get_user_by_name (lightdm_user_list_get_instance (), user_name);
1915        if (user)
1916            value = lightdm_user_get_background (user);
1917    }
1918
1919    if (set_user_background_delayed_id)
1920    {
1921        g_source_remove (set_user_background_delayed_id);
1922        set_user_background_delayed_id = 0;
1923    }
1924
1925    if (!value)
1926        greeter_background_set_custom_background (greeter_background, NULL);
1927    else
1928    {
1929        /* Small delay before changing background */
1930        set_user_background_delayed_id = g_timeout_add_full (G_PRIORITY_DEFAULT, USER_BACKGROUND_DELAY,
1931                                                             (GSourceFunc)set_user_background_delayed_cb,
1932                                                             g_strdup (value), g_free);
1933    }
1934}
1935
1936static void
1937start_authentication (const gchar *username)
1938{
1939    cancelling = FALSE;
1940    prompted = FALSE;
1941    password_prompted = FALSE;
1942    prompt_active = FALSE;
1943
1944    if (pending_questions)
1945    {
1946        g_slist_free_full (pending_questions, (GDestroyNotify) pam_message_finalize);
1947        pending_questions = NULL;
1948    }
1949
1950    config_set_string (STATE_SECTION_GREETER, STATE_KEY_LAST_USER, username);
1951
1952    if (g_strcmp0 (username, "*other") == 0)
1953    {
1954        gtk_widget_show (GTK_WIDGET (username_entry));
1955        gtk_widget_show (GTK_WIDGET (cancel_button));
1956        lightdm_greeter_authenticate (greeter, NULL);
1957    }
1958    else if (g_strcmp0 (username, "*guest") == 0)
1959    {
1960        lightdm_greeter_authenticate_as_guest (greeter);
1961    }
1962    else
1963    {
1964        LightDMUser *user;
1965        user = lightdm_user_list_get_user_by_name (lightdm_user_list_get_instance (), username);
1966        if (user)
1967        {
1968            if (!current_session)
1969                set_session (lightdm_user_get_session (user));
1970            if (!current_language)
1971                set_language (lightdm_user_get_language (user));
1972        }
1973        else
1974        {
1975            set_session (NULL);
1976            set_language (NULL);
1977        }
1978
1979        lightdm_greeter_authenticate (greeter, username);
1980    }
1981
1982}
1983
1984static void
1985cancel_authentication (void)
1986{
1987    GtkTreeModel *model;
1988    GtkTreeIter iter;
1989    gboolean other = FALSE;
1990
1991    if (pending_questions)
1992    {
1993        g_slist_free_full (pending_questions, (GDestroyNotify) pam_message_finalize);
1994        pending_questions = NULL;
1995    }
1996
1997    /* If in authentication then stop that first */
1998    cancelling = FALSE;
1999    if (lightdm_greeter_get_in_authentication (greeter))
2000    {
2001        cancelling = TRUE;
2002        lightdm_greeter_cancel_authentication (greeter);
2003        set_message_label (LIGHTDM_MESSAGE_TYPE_INFO, NULL);
2004    }
2005
2006    /* Make sure password entry is back to normal */
2007    gtk_entry_set_visibility (password_entry, FALSE);
2008
2009    /* Force refreshing the prompt_box for "Other" */
2010    model = gtk_combo_box_get_model (user_combo);
2011
2012    if (gtk_combo_box_get_active_iter (user_combo, &iter))
2013    {
2014        gchar *user;
2015
2016        gtk_tree_model_get (GTK_TREE_MODEL (model), &iter, 0, &user, -1);
2017        other = (g_strcmp0 (user, "*other") == 0);
2018        g_free (user);
2019    }
2020
2021    /* Start a new login or return to the user list */
2022    if (other || lightdm_greeter_get_hide_users_hint (greeter))
2023        start_authentication ("*other");
2024    else
2025        gtk_widget_grab_focus (GTK_WIDGET (user_combo));
2026}
2027
2028static void
2029start_session (void)
2030{
2031    gchar *language;
2032    gchar *session;
2033    language = get_language ();
2034    if (language)
2035        lightdm_greeter_set_language (greeter, language);
2036    g_free (language);
2037    session = get_session ();
2038
2039    /* Remember last choice */
2040    config_set_string (STATE_SECTION_GREETER, STATE_KEY_LAST_SESSION, session);
2041
2042    greeter_background_save_xroot (greeter_background);
2043
2044    if (!lightdm_greeter_start_session_sync (greeter, session, NULL))
2045    {
2046        set_message_label (LIGHTDM_MESSAGE_TYPE_ERROR, _("Failed to start session"));
2047        start_authentication (lightdm_greeter_get_authentication_user (greeter));
2048    }
2049    g_free (session);
2050}
2051
2052gboolean
2053password_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data);
2054G_MODULE_EXPORT
2055gboolean
2056password_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
2057{
2058    if ((event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_Down) &&
2059        gtk_widget_get_visible (GTK_WIDGET (user_combo)))
2060    {
2061        gboolean available;
2062        GtkTreeIter iter;
2063        GtkTreeModel *model = gtk_combo_box_get_model (user_combo);
2064
2065        /* Back to username_entry if it is available */
2066        if (event->keyval == GDK_KEY_Up &&
2067            gtk_widget_get_visible (GTK_WIDGET (username_entry)) && widget == GTK_WIDGET (password_entry))
2068        {
2069            gtk_widget_grab_focus (GTK_WIDGET (username_entry));
2070            return TRUE;
2071        }
2072
2073        if (!gtk_combo_box_get_active_iter (user_combo, &iter))
2074            return FALSE;
2075
2076        if (event->keyval == GDK_KEY_Up)
2077            available = gtk_tree_model_iter_previous (model, &iter);
2078        else
2079            available = gtk_tree_model_iter_next (model, &iter);
2080
2081        if (available)
2082            gtk_combo_box_set_active_iter (user_combo, &iter);
2083
2084        return TRUE;
2085    }
2086    return FALSE;
2087}
2088
2089gboolean
2090username_focus_out_cb (GtkWidget *widget, GdkEvent *event, gpointer user_data);
2091G_MODULE_EXPORT
2092gboolean
2093username_focus_out_cb (GtkWidget *widget, GdkEvent *event, gpointer user_data)
2094{
2095    if (!g_strcmp0(gtk_entry_get_text (username_entry), "") == 0)
2096        start_authentication (gtk_entry_get_text (username_entry));
2097    return FALSE;
2098}
2099
2100gboolean
2101username_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data);
2102G_MODULE_EXPORT
2103gboolean
2104username_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
2105{
2106    /* Acts as password_entry */
2107    if (event->keyval == GDK_KEY_Up)
2108        return password_key_press_cb (widget, event, user_data);
2109    /* Enter activates the password entry */
2110    else if (event->keyval == GDK_KEY_Return && gtk_widget_get_visible (GTK_WIDGET (password_entry)))
2111    {
2112        gtk_widget_grab_focus (GTK_WIDGET (password_entry));
2113        return TRUE;
2114    }
2115    else
2116        return FALSE;
2117}
2118
2119gboolean
2120menubar_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data);
2121G_MODULE_EXPORT
2122gboolean
2123menubar_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
2124{
2125    switch (event->keyval)
2126    {
2127    case GDK_KEY_Tab: case GDK_KEY_Escape:
2128    case GDK_KEY_Super_L: case GDK_KEY_Super_R:
2129    case GDK_KEY_F9: case GDK_KEY_F10:
2130    case GDK_KEY_F11: case GDK_KEY_F12:
2131        gtk_menu_shell_cancel (GTK_MENU_SHELL (menubar));
2132        return TRUE;
2133    default:
2134        return FALSE;
2135    };
2136}
2137
2138gboolean
2139login_window_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data);
2140G_MODULE_EXPORT
2141gboolean
2142login_window_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
2143{
2144    GtkWidget *item = NULL;
2145
2146    if (event->keyval == GDK_KEY_F9)
2147        item = session_menuitem;
2148    else if (event->keyval == GDK_KEY_F10)
2149        item = language_menuitem;
2150    else if (event->keyval == GDK_KEY_F11)
2151        item = a11y_menuitem;
2152    else if (event->keyval == GDK_KEY_F12)
2153        item = power_menuitem;
2154    else if (event->keyval != GDK_KEY_Escape &&
2155             event->keyval != GDK_KEY_Super_L &&
2156             event->keyval != GDK_KEY_Super_R)
2157        return FALSE;
2158
2159    if (GTK_IS_MENU_ITEM (item) && gtk_widget_is_sensitive (item) && gtk_widget_get_visible (item))
2160        gtk_menu_shell_select_item (GTK_MENU_SHELL (menubar), item);
2161    else
2162        gtk_menu_shell_select_first (GTK_MENU_SHELL (menubar), TRUE);
2163    return TRUE;
2164}
2165
2166static void
2167set_displayed_user (LightDMGreeter *greeter, const gchar *username)
2168{
2169    gchar *user_tooltip;
2170    LightDMUser *user;
2171
2172    if (g_strcmp0 (username, "*other") == 0)
2173    {
2174        gtk_widget_show (GTK_WIDGET (username_entry));
2175        gtk_widget_show (GTK_WIDGET (cancel_button));
2176        user_tooltip = g_strdup (_("Other"));
2177    }
2178    else
2179    {
2180        gtk_widget_hide (GTK_WIDGET (username_entry));
2181        gtk_widget_hide (GTK_WIDGET (cancel_button));
2182        user_tooltip = g_strdup (username);
2183    }
2184
2185    /* At this moment we do not have information about possible prompts
2186     * for current user (except *guest). So, password_entry.visible changed in:
2187     *   auth_complete_cb
2188     *   process_prompts
2189     *   and here - for *guest */
2190
2191    if (g_strcmp0 (username, "*guest") == 0)
2192    {
2193        user_tooltip = g_strdup (_("Guest Session"));
2194        gtk_widget_hide (GTK_WIDGET (password_entry));
2195        gtk_widget_grab_focus (GTK_WIDGET (user_combo));
2196    }
2197
2198    set_login_button_label (greeter, username);
2199    set_user_background (username);
2200    set_user_image (username);
2201    user = lightdm_user_list_get_user_by_name (lightdm_user_list_get_instance (), username);
2202    if (user)
2203    {
2204        set_language (lightdm_user_get_language (user));
2205        set_session (lightdm_user_get_session (user));
2206    }
2207    else
2208        set_language (lightdm_language_get_code (lightdm_get_language ()));
2209    gtk_widget_set_tooltip_text (GTK_WIDGET (user_combo), user_tooltip);
2210    start_authentication (username);
2211    g_free (user_tooltip);
2212}
2213
2214void user_combobox_active_changed_cb (GtkComboBox *widget, LightDMGreeter *greeter);
2215G_MODULE_EXPORT
2216void
2217user_combobox_active_changed_cb (GtkComboBox *widget, LightDMGreeter *greeter)
2218{
2219    GtkTreeModel *model;
2220    GtkTreeIter iter;
2221
2222    model = gtk_combo_box_get_model (user_combo);
2223
2224    if (gtk_combo_box_get_active_iter (user_combo, &iter))
2225    {
2226        gchar *user;
2227
2228        gtk_tree_model_get (GTK_TREE_MODEL (model), &iter, 0, &user, -1);
2229
2230        set_displayed_user (greeter, user);
2231
2232        g_free (user);
2233    }
2234    set_message_label (LIGHTDM_MESSAGE_TYPE_INFO, NULL);
2235}
2236
2237void login_cb (GtkWidget *widget);
2238G_MODULE_EXPORT
2239void
2240login_cb (GtkWidget *widget)
2241{
2242    /* Reset to default screensaver values */
2243    if (lightdm_greeter_get_lock_hint (greeter))
2244        XSetScreenSaver (gdk_x11_display_get_xdisplay (gdk_display_get_default ()), timeout, interval, prefer_blanking, allow_exposures);
2245
2246    gtk_widget_set_sensitive (GTK_WIDGET (username_entry), FALSE);
2247    gtk_widget_set_sensitive (GTK_WIDGET (password_entry), FALSE);
2248    set_message_label (LIGHTDM_MESSAGE_TYPE_INFO, NULL);
2249    prompt_active = FALSE;
2250
2251    if (lightdm_greeter_get_is_authenticated (greeter))
2252        start_session ();
2253    else if (lightdm_greeter_get_in_authentication (greeter))
2254    {
2255        lightdm_greeter_respond (greeter, gtk_entry_get_text (password_entry));
2256        /* If we have questions pending, then we continue processing
2257         * those, until we are done. (Otherwise, authentication will
2258         * not complete.) */
2259        if (pending_questions)
2260            process_prompts (greeter);
2261    }
2262    else
2263        start_authentication (lightdm_greeter_get_authentication_user (greeter));
2264}
2265
2266void cancel_cb (GtkWidget *widget);
2267G_MODULE_EXPORT
2268void
2269cancel_cb (GtkWidget *widget)
2270{
2271    cancel_authentication ();
2272}
2273
2274gboolean
2275user_combo_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data);
2276G_MODULE_EXPORT
2277gboolean
2278user_combo_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
2279{
2280    if (event->keyval == GDK_KEY_Return)
2281    {
2282        if (gtk_widget_get_visible (GTK_WIDGET (username_entry)))
2283            gtk_widget_grab_focus (GTK_WIDGET (username_entry));
2284        else if (gtk_widget_get_visible (GTK_WIDGET (password_entry)))
2285            gtk_widget_grab_focus (GTK_WIDGET (password_entry));
2286        else
2287            login_cb (GTK_WIDGET (login_button));
2288        return TRUE;
2289    }
2290    return FALSE;
2291}
2292
2293static void
2294show_prompt_cb (LightDMGreeter *greeter, const gchar *text, LightDMPromptType type)
2295{
2296    PAMConversationMessage *message_obj = g_new (PAMConversationMessage, 1);
2297    if (message_obj)
2298    {
2299        message_obj->is_prompt = TRUE;
2300        message_obj->type.prompt = type;
2301        message_obj->text = g_strdup (text);
2302        pending_questions = g_slist_append (pending_questions, message_obj);
2303    }
2304
2305    if (!prompt_active)
2306        process_prompts (greeter);
2307}
2308
2309static void
2310show_message_cb (LightDMGreeter *greeter, const gchar *text, LightDMMessageType type)
2311{
2312    PAMConversationMessage *message_obj = g_new (PAMConversationMessage, 1);
2313    if (message_obj)
2314    {
2315        message_obj->is_prompt = FALSE;
2316        message_obj->type.message = type;
2317        message_obj->text = g_strdup (text);
2318        pending_questions = g_slist_append (pending_questions, message_obj);
2319    }
2320
2321    if (!prompt_active)
2322        process_prompts (greeter);
2323}
2324
2325static void
2326timed_autologin_cb (LightDMGreeter *greeter)
2327{
2328    /* Don't trigger autologin if user locks screen with light-locker (thanks to Andrew P.). */
2329    if (!lightdm_greeter_get_lock_hint (greeter))
2330    {
2331        if (lightdm_greeter_get_is_authenticated (greeter))
2332        {
2333            /* Configured autologin user may be already selected in user list. */
2334            if (lightdm_greeter_get_authentication_user (greeter))
2335                /* Selected user matches configured autologin-user option. */
2336                start_session ();
2337            else if (lightdm_greeter_get_autologin_guest_hint (greeter))
2338                /* "Guest session" is selected and autologin-guest is enabled. */
2339                start_session ();
2340            else if (lightdm_greeter_get_autologin_user_hint (greeter))
2341            {
2342                /* "Guest session" is selected, but autologin-user is configured. */
2343                start_authentication (lightdm_greeter_get_autologin_user_hint (greeter));
2344                prompted = TRUE;
2345            }
2346        }
2347        else
2348            lightdm_greeter_authenticate_autologin (greeter);
2349    }
2350}
2351
2352static void
2353authentication_complete_cb (LightDMGreeter *greeter)
2354{
2355    prompt_active = FALSE;
2356    gtk_entry_set_text (password_entry, "");
2357
2358    if (cancelling)
2359    {
2360        cancel_authentication ();
2361        return;
2362    }
2363
2364    if (pending_questions)
2365    {
2366        g_slist_free_full (pending_questions, (GDestroyNotify) pam_message_finalize);
2367        pending_questions = NULL;
2368    }
2369
2370    if (lightdm_greeter_get_is_authenticated (greeter))
2371    {
2372        if (prompted)
2373            start_session ();
2374        else
2375        {
2376            gtk_widget_hide (GTK_WIDGET (password_entry));
2377            gtk_widget_grab_focus (GTK_WIDGET (user_combo));
2378        }
2379    }
2380    else
2381    {
2382        /* If an error message is already printed we do not print it this statement
2383         * The error message probably comes from the PAM module that has a better knowledge
2384         * of the failure. */
2385        gboolean have_pam_error = !message_label_is_empty () &&
2386                                  gtk_info_bar_get_message_type (info_bar) != GTK_MESSAGE_ERROR;
2387        if (prompted)
2388        {
2389            if (!have_pam_error)
2390                set_message_label (LIGHTDM_MESSAGE_TYPE_ERROR, _("Incorrect password, please try again"));
2391            start_authentication (lightdm_greeter_get_authentication_user (greeter));
2392        }
2393        else
2394        {
2395            g_warning ("Failed to authenticate");
2396            if (!have_pam_error)
2397                set_message_label (LIGHTDM_MESSAGE_TYPE_ERROR, _("Failed to authenticate"));
2398        }
2399    }
2400}
2401
2402static void
2403user_added_cb (LightDMUserList *user_list, LightDMUser *user, LightDMGreeter *greeter)
2404{
2405    GtkTreeModel *model;
2406    GtkTreeIter iter;
2407    gboolean logged_in = FALSE;
2408
2409    model = gtk_combo_box_get_model (user_combo);
2410
2411    logged_in = lightdm_user_get_logged_in (user);
2412
2413    gtk_list_store_append (GTK_LIST_STORE (model), &iter);
2414    gtk_list_store_set (GTK_LIST_STORE (model), &iter,
2415                        0, lightdm_user_get_name (user),
2416                        1, lightdm_user_get_display_name (user),
2417                        2, logged_in ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL,
2418                        -1);
2419}
2420
2421static gboolean
2422get_user_iter (const gchar *username, GtkTreeIter *iter)
2423{
2424    GtkTreeModel *model;
2425
2426    model = gtk_combo_box_get_model (user_combo);
2427
2428    if (!gtk_tree_model_get_iter_first (model, iter))
2429        return FALSE;
2430    do
2431    {
2432        gchar *name;
2433        gboolean matched;
2434
2435        gtk_tree_model_get (model, iter, 0, &name, -1);
2436        matched = g_strcmp0 (name, username) == 0;
2437        g_free (name);
2438        if (matched)
2439            return TRUE;
2440    } while (gtk_tree_model_iter_next (model, iter));
2441
2442    return FALSE;
2443}
2444
2445static void
2446user_changed_cb (LightDMUserList *user_list, LightDMUser *user, LightDMGreeter *greeter)
2447{
2448    GtkTreeModel *model;
2449    GtkTreeIter iter;
2450    gboolean logged_in = FALSE;
2451
2452    if (!get_user_iter (lightdm_user_get_name (user), &iter))
2453        return;
2454    logged_in = lightdm_user_get_logged_in (user);
2455
2456    model = gtk_combo_box_get_model (user_combo);
2457
2458    gtk_list_store_set (GTK_LIST_STORE (model), &iter,
2459                        0, lightdm_user_get_name (user),
2460                        1, lightdm_user_get_display_name (user),
2461                        2, logged_in ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL,
2462                        -1);
2463}
2464
2465static void
2466user_removed_cb (LightDMUserList *user_list, LightDMUser *user)
2467{
2468    GtkTreeModel *model;
2469    GtkTreeIter iter;
2470
2471    if (!get_user_iter (lightdm_user_get_name (user), &iter))
2472        return;
2473
2474    model = gtk_combo_box_get_model (user_combo);
2475    gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
2476}
2477
2478static void
2479load_user_list (void)
2480{
2481    const GList *items, *item;
2482    GtkTreeModel *model;
2483    GtkTreeIter iter;
2484    const gchar *selected_user;
2485    gboolean logged_in = FALSE;
2486
2487    g_signal_connect (lightdm_user_list_get_instance (), "user-added", G_CALLBACK (user_added_cb), greeter);
2488    g_signal_connect (lightdm_user_list_get_instance (), "user-changed", G_CALLBACK (user_changed_cb), greeter);
2489    g_signal_connect (lightdm_user_list_get_instance (), "user-removed", G_CALLBACK (user_removed_cb), NULL);
2490    model = gtk_combo_box_get_model (user_combo);
2491    items = lightdm_user_list_get_users (lightdm_user_list_get_instance ());
2492    for (item = items; item; item = item->next)
2493    {
2494        LightDMUser *user = item->data;
2495        logged_in = lightdm_user_get_logged_in (user);
2496
2497        gtk_list_store_append (GTK_LIST_STORE (model), &iter);
2498        gtk_list_store_set (GTK_LIST_STORE (model), &iter,
2499                            0, lightdm_user_get_name (user),
2500                            1, lightdm_user_get_display_name (user),
2501                            2, logged_in ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL,
2502                            -1);
2503    }
2504    if (lightdm_greeter_get_has_guest_account_hint (greeter))
2505    {
2506        gtk_list_store_append (GTK_LIST_STORE (model), &iter);
2507        gtk_list_store_set (GTK_LIST_STORE (model), &iter,
2508                            0, "*guest",
2509                            1, _("Guest Session"),
2510                            2, PANGO_WEIGHT_NORMAL,
2511                            -1);
2512    }
2513
2514    gtk_list_store_append (GTK_LIST_STORE (model), &iter);
2515    gtk_list_store_set (GTK_LIST_STORE (model), &iter,
2516                        0, "*other",
2517                        1, _("Other..."),
2518                        2, PANGO_WEIGHT_NORMAL,
2519                        -1);
2520
2521    gchar *last_user = config_get_string (STATE_SECTION_GREETER, STATE_KEY_LAST_USER, NULL);
2522
2523    if (lightdm_greeter_get_select_user_hint (greeter))
2524        selected_user = lightdm_greeter_get_select_user_hint (greeter);
2525    else if (lightdm_greeter_get_select_guest_hint (greeter))
2526        selected_user = "*guest";
2527    else if (last_user)
2528        selected_user = last_user;
2529    else
2530        selected_user = NULL;
2531
2532    if (gtk_tree_model_get_iter_first (model, &iter))
2533    {
2534        gchar *name;
2535        gboolean matched = FALSE;
2536
2537        if (selected_user)
2538        {
2539            do
2540            {
2541                gtk_tree_model_get (model, &iter, 0, &name, -1);
2542                matched = g_strcmp0 (name, selected_user) == 0;
2543                g_free (name);
2544                if (matched)
2545                {
2546                    gtk_combo_box_set_active_iter (user_combo, &iter);
2547                    set_displayed_user (greeter, selected_user);
2548                    break;
2549                }
2550            } while (gtk_tree_model_iter_next (model, &iter));
2551        }
2552        if (!matched)
2553        {
2554            gtk_tree_model_get_iter_first (model, &iter);
2555            gtk_tree_model_get (model, &iter, 0, &name, -1);
2556            gtk_combo_box_set_active_iter (user_combo, &iter);
2557            set_displayed_user (greeter, name);
2558            g_free (name);
2559        }
2560    }
2561
2562    g_free (last_user);
2563}
2564
2565static GdkFilterReturn
2566wm_window_filter (GdkXEvent *gxevent, GdkEvent *event, gpointer  data)
2567{
2568    XEvent *xevent = (XEvent*)gxevent;
2569    if (xevent->type == MapNotify)
2570    {
2571        GdkDisplay *display = gdk_x11_lookup_xdisplay (xevent->xmap.display);
2572        GdkWindow *win = gdk_x11_window_foreign_new_for_display (display, xevent->xmap.window);
2573        GdkWindowTypeHint win_type = gdk_window_get_type_hint (win);
2574
2575        if (win_type != GDK_WINDOW_TYPE_HINT_COMBO &&
2576            win_type != GDK_WINDOW_TYPE_HINT_TOOLTIP &&
2577            win_type != GDK_WINDOW_TYPE_HINT_NOTIFICATION)
2578        /*
2579        if (win_type == GDK_WINDOW_TYPE_HINT_DESKTOP ||
2580            win_type == GDK_WINDOW_TYPE_HINT_DIALOG)
2581        */
2582            gdk_window_focus (win, GDK_CURRENT_TIME);
2583    }
2584    else if (xevent->type == UnmapNotify)
2585    {
2586        Window xwin;
2587        int revert_to = RevertToNone;
2588
2589        XGetInputFocus (xevent->xunmap.display, &xwin, &revert_to);
2590        if (revert_to == RevertToNone)
2591            gdk_window_lower (gtk_widget_get_window (gtk_widget_get_toplevel (GTK_WIDGET (screen_overlay))));
2592    }
2593
2594    return GDK_FILTER_CONTINUE;
2595}
2596
2597static void
2598debug_log_handler (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data)
2599{
2600    gchar *new_domain = NULL;
2601    if (log_level == G_LOG_LEVEL_DEBUG)
2602    {
2603        log_level = G_LOG_LEVEL_MESSAGE;
2604        if (log_domain)
2605            log_domain = new_domain = g_strdup_printf ("DEBUG/%s", log_domain);
2606        else
2607            log_domain = "DEBUG";
2608    }
2609    g_log_default_handler (log_domain, log_level, message, user_data);
2610    g_free (new_domain);
2611}
2612
2613int
2614main (int argc, char **argv)
2615{
2616    GtkBuilder *builder;
2617    const GList *items, *item;
2618    GtkWidget *image;
2619    gchar *value;
2620    GtkIconTheme *icon_theme;
2621    GtkCssProvider *css_provider;
2622    GError *error = NULL;
2623
2624    /* Prevent memory from being swapped out, as we are dealing with passwords */
2625    mlockall (MCL_CURRENT | MCL_FUTURE);
2626
2627    g_message ("Starting %s (%s, %s)", PACKAGE_STRING, __DATE__, __TIME__);
2628
2629    /* Disable global menus */
2630    g_unsetenv ("UBUNTU_MENUPROXY");
2631
2632    /* LP: #1024482 */
2633    g_setenv ("GDK_CORE_DEVICE_EVENTS", "1", TRUE);
2634
2635    /* LP: #1366534 */
2636    #ifdef AT_SPI_COMMAND
2637    spawn_line_pid (AT_SPI_COMMAND, G_SPAWN_SEARCH_PATH, NULL);
2638    #else
2639    g_setenv ("NO_AT_BRIDGE", "1", TRUE);
2640    #endif
2641
2642    /* Initialize i18n */
2643    setlocale (LC_ALL, "");
2644    bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
2645    bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
2646    textdomain (GETTEXT_PACKAGE);
2647
2648    g_unix_signal_add (SIGTERM, (GSourceFunc)sigterm_cb, /* is_callback */ GINT_TO_POINTER (TRUE));
2649
2650    config_init ();
2651
2652    if (config_get_bool (NULL, CONFIG_KEY_DEBUGGING, FALSE))
2653        g_log_set_default_handler (debug_log_handler, NULL);
2654
2655    /* init gtk */
2656    gtk_init (&argc, &argv);
2657
2658    /* Disabling GtkInspector shortcuts.
2659       It is still possible to run GtkInspector with GTK_DEBUG=interactive.
2660       Assume that user knows what he's doing. */
2661    if (!config_get_bool (NULL, CONFIG_KEY_DEBUGGING, FALSE))
2662    {
2663        GtkWidget *fake_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2664        GtkBindingSet *set = gtk_binding_set_by_class (G_OBJECT_GET_CLASS (fake_window));
2665        GtkBindingEntry *entry = NULL;
2666        GtkBindingSignal *signals = NULL;
2667        GSList *bindings = NULL;
2668        GSList *iter;
2669
2670        for (entry = set->entries; entry; entry = entry->set_next)
2671        {
2672            for (signals = entry->signals; signals; signals = signals->next)
2673            {
2674                if (g_strcmp0 (signals->signal_name, "enable-debugging") == 0)
2675                {
2676                    bindings = g_slist_prepend (bindings, entry);
2677                    break;
2678                }
2679            }
2680        }
2681
2682        for (iter = bindings; iter; iter = g_slist_next (iter))
2683        {
2684            entry = iter->data;
2685            gtk_binding_entry_remove (set, entry->keyval, entry->modifiers);
2686        }
2687
2688        g_slist_free (bindings);
2689        gtk_widget_destroy (fake_window);
2690    }
2691
2692#ifdef HAVE_LIBIDO
2693    g_debug ("Initializing IDO library");
2694    ido_init ();
2695#endif
2696
2697    greeter = lightdm_greeter_new ();
2698    g_signal_connect (greeter, "show-prompt", G_CALLBACK (show_prompt_cb), NULL);
2699    g_signal_connect (greeter, "show-message", G_CALLBACK (show_message_cb), NULL);
2700    g_signal_connect (greeter, "authentication-complete", G_CALLBACK (authentication_complete_cb), NULL);
2701    g_signal_connect (greeter, "autologin-timer-expired", G_CALLBACK (timed_autologin_cb), NULL);
2702    if (!lightdm_greeter_connect_sync (greeter, NULL))
2703        return EXIT_FAILURE;
2704
2705    /* Set default cursor */
2706    gdk_window_set_cursor (gdk_get_default_root_window (), gdk_cursor_new (GDK_LEFT_PTR));
2707
2708    /* Make the greeter behave a bit more like a screensaver if used as un/lock-screen by blanking the screen */
2709    if (lightdm_greeter_get_lock_hint (greeter))
2710    {
2711        Display *display = gdk_x11_display_get_xdisplay (gdk_display_get_default ());
2712        XGetScreenSaver (display, &timeout, &interval, &prefer_blanking, &allow_exposures);
2713        XForceScreenSaver (display, ScreenSaverActive);
2714        XSetScreenSaver (display, config_get_int (NULL, CONFIG_KEY_SCREENSAVER_TIMEOUT, 60), 0,
2715                         ScreenSaverActive, DefaultExposures);
2716    }
2717
2718    /* Set GTK+ settings */
2719    value = config_get_string (NULL, CONFIG_KEY_THEME, NULL);
2720    if (value)
2721    {
2722        g_debug ("[Configuration] Changing GTK+ theme to '%s'", value);
2723        g_object_set (gtk_settings_get_default (), "gtk-theme-name", value, NULL);
2724        g_free (value);
2725    }
2726    g_object_get (gtk_settings_get_default (), "gtk-theme-name", &default_theme_name, NULL);
2727    g_debug ("[Configuration] GTK+ theme: '%s'", default_theme_name);
2728
2729    value = config_get_string (NULL, CONFIG_KEY_ICON_THEME, NULL);
2730    if (value)
2731    {
2732        g_debug ("[Configuration] Changing icons theme to '%s'", value);
2733        g_object_set (gtk_settings_get_default (), "gtk-icon-theme-name", value, NULL);
2734        g_free (value);
2735    }
2736    g_object_get (gtk_settings_get_default (), "gtk-icon-theme-name", &default_icon_theme_name, NULL);
2737    g_debug ("[Configuration] Icons theme: '%s'", default_icon_theme_name);
2738
2739    value = config_get_string (NULL, CONFIG_KEY_FONT, "Sans 10");
2740    if (value)
2741    {
2742        g_debug ("[Configuration] Changing font to '%s'", value);
2743        g_object_set (gtk_settings_get_default (), "gtk-font-name", value, NULL);
2744        g_free (value);
2745    }
2746    g_object_get (gtk_settings_get_default (), "gtk-font-name", &default_font_name, NULL);
2747    g_debug ("[Configuration] Font: '%s'", default_font_name);
2748
2749    if (config_has_key (NULL, CONFIG_KEY_DPI))
2750        g_object_set (gtk_settings_get_default (), "gtk-xft-dpi", 1024*config_get_int (NULL, CONFIG_KEY_DPI, 96), NULL);
2751
2752    if (config_has_key (NULL, CONFIG_KEY_ANTIALIAS))
2753        g_object_set (gtk_settings_get_default (), "gtk-xft-antialias", config_get_bool (NULL, CONFIG_KEY_ANTIALIAS, FALSE), NULL);
2754
2755    value = config_get_string (NULL, CONFIG_KEY_HINT_STYLE, NULL);
2756    if (value)
2757    {
2758        g_object_set (gtk_settings_get_default (), "gtk-xft-hintstyle", value, NULL);
2759        g_free (value);
2760    }
2761
2762    value = config_get_string (NULL, CONFIG_KEY_RGBA, NULL);
2763    if (value)
2764    {
2765        g_object_set (gtk_settings_get_default (), "gtk-xft-rgba", value, NULL);
2766        g_free (value);
2767    }
2768
2769    #ifdef INDICATOR_SERVICES_COMMAND
2770    spawn_line_pid (INDICATOR_SERVICES_COMMAND, G_SPAWN_SEARCH_PATH, NULL);
2771    #endif
2772
2773    builder = gtk_builder_new ();
2774    if (!gtk_builder_add_from_string (builder, lightdm_gtk_greeter_ui,
2775                                      lightdm_gtk_greeter_ui_length, &error))
2776    {
2777        g_warning ("Error loading UI: %s", error->message);
2778        return EXIT_FAILURE;
2779    }
2780    g_clear_error (&error);
2781
2782    /* Screen window */
2783    screen_overlay = GTK_OVERLAY (gtk_builder_get_object (builder, "screen_overlay"));
2784    screen_overlay_child = GTK_WIDGET (gtk_builder_get_object (builder, "screen_overlay_child"));
2785
2786    /* Login window */
2787    login_window = GTK_WIDGET (gtk_builder_get_object (builder, "login_window"));
2788    user_image = GTK_IMAGE (gtk_builder_get_object (builder, "user_image"));
2789    user_combo = GTK_COMBO_BOX (gtk_builder_get_object (builder, "user_combobox"));
2790    username_entry = GTK_ENTRY (gtk_builder_get_object (builder, "username_entry"));
2791    password_entry = GTK_ENTRY (gtk_builder_get_object (builder, "password_entry"));
2792    info_bar = GTK_INFO_BAR (gtk_builder_get_object (builder, "greeter_infobar"));
2793    message_label = GTK_LABEL (gtk_builder_get_object (builder, "message_label"));
2794    cancel_button = GTK_BUTTON (gtk_builder_get_object (builder, "cancel_button"));
2795    login_button = GTK_BUTTON (gtk_builder_get_object (builder, "login_button"));
2796
2797    /* Panel window*/
2798    panel_window = GTK_WIDGET (gtk_builder_get_object (builder, "panel_window"));
2799    menubar = GTK_WIDGET (gtk_builder_get_object (builder, "menubar"));
2800    session_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "session_menuitem"));
2801    session_menu = GTK_MENU (gtk_builder_get_object (builder, "session_menu"));
2802    language_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "language_menuitem"));
2803    language_menu = GTK_MENU (gtk_builder_get_object (builder, "language_menu"));
2804    a11y_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "a11y_menuitem"));
2805    contrast_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "high_contrast_menuitem"));
2806    font_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "large_font_menuitem"));
2807    keyboard_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "keyboard_menuitem"));
2808    reader_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "reader_menuitem"));
2809    power_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "power_menuitem"));
2810    layout_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "layout_menuitem"));
2811    layout_menu = GTK_MENU (gtk_builder_get_object (builder, "layout_menu"));
2812    clock_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "clock_menuitem"));
2813    host_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "host_menuitem"));
2814
2815    /* Power dialog */
2816    power_window = GTK_WIDGET (gtk_builder_get_object (builder, "power_window"));
2817    power_ok_button = GTK_BUTTON (gtk_builder_get_object (builder, "power_ok_button"));
2818    power_cancel_button = GTK_BUTTON (gtk_builder_get_object (builder, "power_cancel_button"));
2819    power_title = GTK_LABEL (gtk_builder_get_object (builder, "power_title"));
2820    power_text = GTK_LABEL (gtk_builder_get_object (builder, "power_text"));
2821    power_icon = GTK_IMAGE (gtk_builder_get_object (builder, "power_icon"));
2822
2823    gtk_overlay_add_overlay (screen_overlay, login_window);
2824    gtk_overlay_add_overlay (screen_overlay, panel_window);
2825    gtk_overlay_add_overlay (screen_overlay, power_window);
2826
2827    gtk_accel_map_add_entry ("<Login>/a11y/font", GDK_KEY_F1, 0);
2828    gtk_accel_map_add_entry ("<Login>/a11y/contrast", GDK_KEY_F2, 0);
2829    gtk_accel_map_add_entry ("<Login>/a11y/keyboard", GDK_KEY_F3, 0);
2830    gtk_accel_map_add_entry ("<Login>/a11y/reader", GDK_KEY_F4, 0);
2831    gtk_accel_map_add_entry ("<Login>/power/shutdown", GDK_KEY_F4, GDK_MOD1_MASK);
2832
2833    init_indicators ();
2834
2835    /* https://bugzilla.gnome.org/show_bug.cgi?id=710888
2836       > GtkInfoBar not shown after calling gtk_widget_show
2837       Assume they will fix it someday. */
2838    if (gtk_get_major_version () == 3 && gtk_get_minor_version () < 18)
2839    {
2840        GList *children = gtk_container_get_children (GTK_CONTAINER (info_bar));
2841        if (g_list_length (children) == 1 && GTK_IS_REVEALER (children->data))
2842            g_signal_connect_after(children->data, "notify::child-revealed", (GCallback)infobar_revealed_cb_710888, NULL);
2843        g_list_free (children);
2844    }
2845
2846    /* Hide empty panel */
2847    GList *menubar_items = gtk_container_get_children (GTK_CONTAINER (menubar));
2848    if (!menubar_items)
2849        gtk_widget_hide (GTK_WIDGET (panel_window));
2850    else
2851        g_list_free (menubar_items);
2852
2853    if (config_get_bool (NULL, CONFIG_KEY_HIDE_USER_IMAGE, FALSE))
2854    {
2855        gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (builder, "user_image_border")));
2856        gtk_widget_hide (GTK_WIDGET (user_image));  /* Hide to mark image is disabled */
2857        gtk_widget_set_size_request (GTK_WIDGET (user_combo), 250, -1);
2858    }
2859    else
2860    {
2861        value = config_get_string (NULL, CONFIG_KEY_DEFAULT_USER_IMAGE, NULL);
2862        if (value)
2863        {
2864            if (value[0] == '#')
2865                default_user_icon = g_strdup (value + 1);
2866            else
2867            {
2868                default_user_pixbuf = gdk_pixbuf_new_from_file (value, &error);
2869                if (!default_user_pixbuf)
2870                {
2871                    g_warning ("Failed to load default user image: %s", error->message);
2872                    g_clear_error (&error);
2873                }
2874            }
2875            g_free (value);
2876        }
2877    }
2878
2879    icon_theme = gtk_icon_theme_get_default ();
2880
2881    /* Session menu */
2882    if (gtk_widget_get_visible (session_menuitem))
2883    {
2884        if (gtk_icon_theme_has_icon (icon_theme, "document-properties-symbolic"))
2885            session_badge = gtk_image_new_from_icon_name ("document-properties-symbolic", GTK_ICON_SIZE_MENU);
2886        else
2887            session_badge = gtk_image_new_from_icon_name ("document-properties", GTK_ICON_SIZE_MENU);
2888        gtk_widget_show (session_badge);
2889        gtk_container_add (GTK_CONTAINER (session_menuitem), session_badge);
2890
2891        items = lightdm_get_sessions ();
2892        GSList *sessions = NULL;
2893        for (item = items; item; item = item->next)
2894        {
2895            LightDMSession *session = item->data;
2896            GtkWidget *radiomenuitem;
2897
2898            radiomenuitem = gtk_radio_menu_item_new_with_label (sessions, lightdm_session_get_name (session));
2899            g_object_set_data (G_OBJECT (radiomenuitem), SESSION_DATA_KEY, (gpointer) lightdm_session_get_key (session));
2900            sessions = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (radiomenuitem));
2901            g_signal_connect (G_OBJECT (radiomenuitem), "activate", G_CALLBACK (session_selected_cb), NULL);
2902            gtk_menu_shell_append (GTK_MENU_SHELL (session_menu), radiomenuitem);
2903            gtk_widget_show (GTK_WIDGET (radiomenuitem));
2904        }
2905        set_session (NULL);
2906    }
2907    /* Language menu */
2908    if (gtk_widget_get_visible (language_menuitem))
2909    {
2910        items = lightdm_get_languages ();
2911        GSList *languages = NULL;
2912        for (item = items; item; item = item->next)
2913        {
2914            LightDMLanguage *language = item->data;
2915            const gchar *country, *code;
2916            gchar *label;
2917            GtkWidget *radiomenuitem;
2918
2919            country = lightdm_language_get_territory (language);
2920            if (country)
2921                label = g_strdup_printf ("%s - %s", lightdm_language_get_name (language), country);
2922            else
2923                label = g_strdup (lightdm_language_get_name (language));
2924            code = lightdm_language_get_code (language);
2925            gchar *modifier = strchr (code, '@');
2926            if (modifier != NULL)
2927            {   
2928                gchar *label_new;
2929                if (g_strcmp0(modifier+1,"valencia")!=0){
2930                    label_new = g_strdup_printf ("%s [%s]", label, modifier+1);
2931                }else{
2932                    label_new = g_strdup_printf ("%s", gchar_valencian);
2933                }
2934                g_free (label);
2935                label = label_new;
2936            }
2937            radiomenuitem = gtk_radio_menu_item_new_with_label (languages, label);
2938            if (g_strcmp0(code,"ca_ES@valencia")==0)
2939                code = g_strdup_printf ("%s", gchar_valencian);
2940            g_object_set_data (G_OBJECT (radiomenuitem), LANGUAGE_DATA_CODE, (gpointer) code);
2941            languages = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (radiomenuitem));
2942            g_signal_connect (G_OBJECT (radiomenuitem), "activate", G_CALLBACK (language_selected_cb), NULL);
2943            gtk_menu_shell_append (GTK_MENU_SHELL (language_menu), radiomenuitem);
2944            gtk_widget_show (GTK_WIDGET (radiomenuitem));
2945        }
2946        set_language (NULL);
2947    }
2948    /* a11y menu */
2949    if (gtk_widget_get_visible (a11y_menuitem))
2950    {
2951        if (gtk_icon_theme_has_icon (icon_theme, "preferences-desktop-accessibility-symbolic"))
2952            image = gtk_image_new_from_icon_name ("preferences-desktop-accessibility-symbolic", GTK_ICON_SIZE_MENU);
2953        else
2954            image = gtk_image_new_from_icon_name ("preferences-desktop-accessibility", GTK_ICON_SIZE_MENU);
2955        gtk_widget_show (image);
2956        gtk_container_add (GTK_CONTAINER (a11y_menuitem), image);
2957    }
2958
2959    value = config_get_string (NULL, CONFIG_KEY_KEYBOARD, NULL);
2960    if (value)
2961    {
2962        a11y_keyboard_command = menu_command_parse_extended ("keyboard", value, keyboard_menuitem, "onboard", "--xid");
2963        g_free (value);
2964    }
2965    gtk_widget_set_visible (keyboard_menuitem, a11y_keyboard_command != NULL);
2966
2967
2968
2969    value = config_get_string (NULL, CONFIG_KEY_READER, NULL);
2970    if (value)
2971    {
2972        a11y_reader_command = menu_command_parse ("reader", value, reader_menuitem);
2973        g_free (value);
2974    }
2975    gtk_widget_set_visible (reader_menuitem, a11y_reader_command != NULL);
2976
2977    /* Power menu */
2978    if (gtk_widget_get_visible (power_menuitem))
2979    {
2980        if (gtk_icon_theme_has_icon (icon_theme, "system-shutdown-symbolic"))
2981            image = gtk_image_new_from_icon_name ("system-shutdown-symbolic", GTK_ICON_SIZE_MENU);
2982        else
2983            image = gtk_image_new_from_icon_name ("system-shutdown", GTK_ICON_SIZE_MENU);
2984        gtk_widget_show (image);
2985        gtk_container_add (GTK_CONTAINER (power_menuitem), image);
2986
2987        suspend_menuitem = (GTK_WIDGET (gtk_builder_get_object (builder, "suspend_menuitem")));
2988        hibernate_menuitem = (GTK_WIDGET (gtk_builder_get_object (builder, "hibernate_menuitem")));
2989        restart_menuitem = (GTK_WIDGET (gtk_builder_get_object (builder, "restart_menuitem")));
2990        shutdown_menuitem = (GTK_WIDGET (gtk_builder_get_object (builder, "shutdown_menuitem")));
2991
2992        g_signal_connect (G_OBJECT (power_menuitem),"activate", G_CALLBACK (power_menu_cb), NULL);
2993    }
2994
2995    /* Layout menu */
2996    if (gtk_widget_get_visible (layout_menuitem))
2997    {
2998        #ifdef HAVE_LIBXKLAVIER
2999        xkl_engine = xkl_engine_get_instance (XOpenDisplay (NULL));
3000        if (xkl_engine)
3001        {
3002            xkl_engine_start_listen (xkl_engine, XKLL_TRACK_KEYBOARD_STATE);
3003            g_signal_connect (xkl_engine, "X-state-changed",
3004                              G_CALLBACK (xkl_state_changed_cb), NULL);
3005            g_signal_connect (xkl_engine, "X-config-changed",
3006                              G_CALLBACK (xkl_config_changed_cb), NULL);
3007            gdk_window_add_filter (NULL, (GdkFilterFunc) xkl_xevent_filter, NULL);
3008
3009            /* refresh */
3010            XklConfigRec *config_rec = xkl_config_rec_new ();
3011            if (xkl_config_rec_get_from_server (config_rec, xkl_engine))
3012                xkl_config_rec_activate (config_rec, xkl_engine);
3013            g_object_unref (config_rec);
3014        }
3015        else
3016        {
3017            g_warning ("Failed to get XklEngine instance");
3018            gtk_widget_hide (layout_menuitem);
3019        }
3020        #endif
3021        update_layouts_menu ();
3022        update_layouts_menu_state ();
3023    }
3024
3025    /* Host label */
3026    if (gtk_widget_get_visible (host_menuitem))
3027        gtk_menu_item_set_label (GTK_MENU_ITEM (host_menuitem), lightdm_get_hostname ());
3028
3029    /* Clock label */
3030    if (gtk_widget_get_visible (clock_menuitem))
3031    {
3032        gtk_menu_item_set_label (GTK_MENU_ITEM (clock_menuitem), "");
3033        clock_label = gtk_bin_get_child (GTK_BIN (clock_menuitem));
3034        clock_format = config_get_string (NULL, CONFIG_KEY_CLOCK_FORMAT, "%a, %H:%M");
3035        clock_timeout_thread ();
3036        gdk_threads_add_timeout (1000, (GSourceFunc) clock_timeout_thread, NULL);
3037    }
3038
3039    /* A bit of CSS */
3040    GdkRGBA lightdm_gtk_greeter_override_defaults;
3041    css_provider = gtk_css_provider_new ();
3042    gtk_css_provider_load_from_data (css_provider, lightdm_gtk_greeter_css_application, lightdm_gtk_greeter_css_application_length, NULL);
3043    gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), GTK_STYLE_PROVIDER (css_provider),
3044                                               GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
3045    css_provider = gtk_css_provider_new ();
3046    guint fallback_css_priority = GTK_STYLE_PROVIDER_PRIORITY_APPLICATION;
3047    if (gtk_style_context_lookup_color (gtk_widget_get_style_context (GTK_WIDGET (login_window)),
3048                                        "lightdm-gtk-greeter-override-defaults",
3049                                        &lightdm_gtk_greeter_override_defaults))
3050        fallback_css_priority = GTK_STYLE_PROVIDER_PRIORITY_FALLBACK;
3051    gtk_css_provider_load_from_data (css_provider, lightdm_gtk_greeter_css_fallback, lightdm_gtk_greeter_css_fallback_length, NULL);
3052    gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), GTK_STYLE_PROVIDER (css_provider),
3053                                               fallback_css_priority);
3054
3055    /* Background */
3056    greeter_background = greeter_background_new (GTK_WIDGET (screen_overlay));
3057
3058    value = config_get_string (NULL, CONFIG_KEY_ACTIVE_MONITOR, NULL);
3059    greeter_background_set_active_monitor_config (greeter_background, value ? value : "#cursor");
3060    g_free (value);
3061
3062    read_monitor_configuration (CONFIG_GROUP_DEFAULT, GREETER_BACKGROUND_DEFAULT);
3063
3064    gchar **config_group;
3065    gchar **config_groups = config_get_groups (CONFIG_GROUP_MONITOR);
3066    for (config_group = config_groups; *config_group; ++config_group)
3067    {
3068        const gchar *name = *config_group + sizeof (CONFIG_GROUP_MONITOR);
3069        while (*name && g_ascii_isspace (*name))
3070            ++name;
3071
3072        read_monitor_configuration (*config_group, name);
3073    }
3074    g_strfreev (config_groups);
3075
3076    greeter_background_add_accel_group (greeter_background, GTK_ACCEL_GROUP (gtk_builder_get_object (builder, "a11y_accelgroup")));
3077    greeter_background_add_accel_group (greeter_background, GTK_ACCEL_GROUP (gtk_builder_get_object (builder, "power_accelgroup")));
3078
3079    greeter_background_connect (greeter_background, gdk_screen_get_default ());
3080
3081    if (lightdm_greeter_get_hide_users_hint (greeter))
3082    {
3083        set_user_image (NULL);
3084        start_authentication ("*other");
3085    }
3086    else
3087    {
3088        load_user_list ();
3089        gtk_widget_hide (GTK_WIDGET (cancel_button));
3090        gtk_widget_show (GTK_WIDGET (user_combo));
3091    }
3092
3093    /* Windows positions */
3094    value = config_get_string (NULL, CONFIG_KEY_POSITION, NULL);
3095    g_object_set_data_full (G_OBJECT (login_window), WINDOW_DATA_POSITION, str_to_position (value, &WINDOW_POS_CENTER), g_free);
3096    g_free (value);
3097
3098
3099    gtk_widget_set_valign (panel_window, config_get_enum (NULL, CONFIG_KEY_PANEL_POSITION, GTK_ALIGN_START,
3100                                                          "bottom", GTK_ALIGN_END,
3101                                                          "top", GTK_ALIGN_START, NULL));
3102
3103    if (a11y_keyboard_command)
3104    {
3105        value = config_get_string (NULL, CONFIG_KEY_KEYBOARD_POSITION, NULL);
3106        g_object_set_data_full (G_OBJECT (a11y_keyboard_command->widget), WINDOW_DATA_POSITION, str_to_position (value, &KEYBOARD_POSITION), g_free);
3107        g_free (value);
3108    }
3109
3110    gtk_builder_connect_signals (builder, greeter);
3111
3112    gchar **a11y_states = config_get_string_list (NULL, CONFIG_KEY_A11Y_STATES, NULL);
3113    if (a11y_states && *a11y_states)
3114    {
3115        GHashTable *items = g_hash_table_new (g_str_hash, g_str_equal);
3116        g_hash_table_insert (items, "contrast", contrast_menuitem);
3117        g_hash_table_insert (items, "font", font_menuitem);
3118        g_hash_table_insert (items, "keyboard", keyboard_menuitem);
3119        g_hash_table_insert (items, "reader", reader_menuitem);
3120
3121        gpointer item;
3122        gchar **values_iter;
3123        for (values_iter = a11y_states; *values_iter; ++values_iter)
3124        {
3125            value = *values_iter;
3126            switch (value[0])
3127            {
3128            case '-':
3129                continue;
3130            case '+':
3131                if (g_hash_table_lookup_extended (items, &value[1], NULL, &item) &&
3132                    gtk_widget_get_visible (GTK_WIDGET (item)))
3133                        gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE);
3134                break;
3135            case '~':
3136                value++;
3137            default:
3138                if (g_hash_table_lookup_extended (items, value, NULL, &item) &&
3139                    gtk_widget_get_visible (GTK_WIDGET (item)))
3140                {
3141                    gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item),
3142                                                    config_get_bool (STATE_SECTION_A11Y, value, FALSE));
3143                    g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (a11y_menuitem_toggled_cb), g_strdup (value));
3144                }
3145            }
3146        }
3147        g_hash_table_unref (items);
3148    }
3149    g_strfreev (a11y_states);
3150
3151    /* There is no window manager, so we need to implement some of its functionality */
3152    GdkWindow* root_window = gdk_get_default_root_window ();
3153    gdk_window_set_events (root_window, gdk_window_get_events (root_window) | GDK_SUBSTRUCTURE_MASK);
3154    gdk_window_add_filter (root_window, wm_window_filter, NULL);
3155
3156    gtk_widget_show (GTK_WIDGET (screen_overlay));
3157
3158    g_debug ("Run Gtk loop...");
3159    gtk_main ();
3160    g_debug ("Gtk loop exits");
3161
3162    sigterm_cb (/* is_callback */ GINT_TO_POINTER (FALSE));
3163
3164    return EXIT_SUCCESS;
3165}
Note: See TracBrowser for help on using the repository browser.