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

Last change on this file since 2364 was 2364, checked in by mabarracus, 3 years ago

fixed patch valencian_labels

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