diff options
author | Sean Davis <smd.seandavis@gmail.com> | 2014-09-27 07:40:13 -0400 |
---|---|---|
committer | Sean Davis <smd.seandavis@gmail.com> | 2014-09-27 07:40:13 -0400 |
commit | 1f242190ad9e260bb82241df89aa46a8137c533f (patch) | |
tree | 5a4bc6845cd24a6800d195dba3891a9fd2fcd76a /src/lightdm-gtk-greeter.c | |
parent | 7922fbffbf261761f1a19d77191d6c38a8f0dd50 (diff) | |
parent | 702ed1ae2d61622f2213236ff2b555b0fe1fa2d9 (diff) | |
download | lightdm-gtk-greeter-git-1f242190ad9e260bb82241df89aa46a8137c533f.tar.gz |
Merge one-window-layout branch
Diffstat (limited to 'src/lightdm-gtk-greeter.c')
-rw-r--r-- | src/lightdm-gtk-greeter.c | 1918 |
1 files changed, 1041 insertions, 877 deletions
diff --git a/src/lightdm-gtk-greeter.c b/src/lightdm-gtk-greeter.c index 45c2ad1..0b4187c 100644 --- a/src/lightdm-gtk-greeter.c +++ b/src/lightdm-gtk-greeter.c @@ -1,7 +1,7 @@ /* * Copyright (C) 2010-2011 Robert Ancell. * Author: Robert Ancell <robert.ancell@canonical.com> - * + * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later @@ -53,6 +53,7 @@ #include "src/lightdm-gtk-greeter-css-fallback.h" #include "src/lightdm-gtk-greeter-css-application.h" + static LightDMGreeter *greeter; /* State file */ @@ -60,25 +61,41 @@ static GKeyFile *state; static gchar *state_filename; static void save_state_file (void); -/* Login Window Widgets */ -static GtkWindow *login_window; -static GtkImage *user_image; -static GtkComboBox *user_combo; -static GtkEntry *username_entry, *password_entry; -static GtkLabel *message_label; -static GtkInfoBar *info_bar; -static GtkButton *cancel_button, *login_button; - -/* Panel Widgets */ -static GtkWindow *panel_window; -static GtkWidget *menubar; -static GtkWidget *power_menuitem, *session_menuitem, *language_menuitem, *a11y_menuitem, - *layout_menuitem, *clock_menuitem, *host_menuitem; -static GtkWidget *suspend_menuitem, *hibernate_menuitem, *restart_menuitem, *shutdown_menuitem; -static GtkWidget *contrast_menuitem, *font_menuitem, *keyboard_menuitem, *reader_menuitem; -static GtkWidget *clock_label, *session_badge; -static GtkMenu *session_menu, *language_menu, *layout_menu; - +/* Screen window */ +static GtkOverlay *screen_overlay; + +/* Login window */ +static GtkWidget *login_window; +static GtkImage *user_image; +static GtkComboBox *user_combo; +static GtkEntry *username_entry, *password_entry; +static GtkLabel *message_label; +static GtkInfoBar *info_bar; +static GtkButton *cancel_button, *login_button; + +/* Panel */ +static GtkWidget *panel_window, *menubar; +static GtkWidget *power_menuitem, *session_menuitem, *language_menuitem, *a11y_menuitem, + *layout_menuitem, *clock_menuitem, *host_menuitem; +static GtkWidget *suspend_menuitem, *hibernate_menuitem, *restart_menuitem, *shutdown_menuitem; +static GtkWidget *contrast_menuitem, *font_menuitem, *keyboard_menuitem, *reader_menuitem; +static GtkWidget *clock_label, *session_badge; +static GtkMenu *session_menu, *language_menu, *layout_menu; + +/* Power window */ +static GtkWidget *power_window; +static GtkButton *power_ok_button, *power_cancel_button; +static GtkLabel *power_title, *power_text; +static GtkImage *power_icon; + +static const gchar *POWER_WINDOW_DATA_LOOP = "power-window-loop"; /* <GMainLoop*> */ +static const gchar *POWER_WINDOW_DATA_RESPONSE = "power-window-response"; /* <GtkResponseType> */ + +static gboolean show_power_prompt (const gchar *action, const gchar* icon, const gchar* title, const gchar* message); +void power_button_clicked_cb (GtkButton *button, gpointer user_data); +gboolean power_window_key_press_event_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data); + +/* Handling window position */ typedef struct { gint value; @@ -93,22 +110,40 @@ typedef struct typedef struct { DimensionPosition x, y; + /* Flag to use width and height fileds */ + gboolean use_size; + DimensionPosition width, height; } WindowPosition; +static WindowPosition* key_file_get_position (GKeyFile *key_file, const gchar *group_name, const gchar *key, const WindowPosition *default_value); /* Function translate user defined coordinates to absolute value */ static gint get_absolute_position (const DimensionPosition *p, gint screen, gint window); -static const WindowPosition WINDOW_POS_CENTER = {.x = { 50, +1, TRUE, 0}, .y = { 50, +1, TRUE, 0}}; -static const WindowPosition WINDOW_POS_TOP_LEFT = {.x = { 0, +1, FALSE, -1}, .y = { 0, +1, FALSE, -1}}; -static const WindowPosition ONBOARD_WINDOW_POS = {.x = { 50, +1, TRUE, 0}, .y = { 0, -1, FALSE, +1}}; -static const WindowPosition ONBOARD_WINDOW_SIZE = {.x = {610, 0, FALSE, 0}, .y = {210, 0, FALSE, 0}}; -static WindowPosition main_window_pos; -static WindowPosition panel_window_pos; - -static gchar *default_font_name, *default_theme_name, *default_icon_theme_name; +gboolean screen_overlay_get_child_position_cb (GtkWidget *overlay, GtkWidget *widget, GdkRectangle *allocation, gpointer user_data); + +static const gchar *WINDOW_DATA_POSITION = "window-position"; /* <WindowPosition*> */ + +/* Some default positions */ +static const WindowPosition WINDOW_POS_CENTER = {.x = { 50, +1, TRUE, 0}, .y = { 50, +1, TRUE, 0}, .use_size = FALSE}; +static const WindowPosition KEYBOARD_POSITION = {.x = { 50, +1, TRUE, 0}, .y = { 0, -1, FALSE, +1}, .use_size = TRUE, + .width = {50, 0, TRUE, 0}, .height = {25, 0, TRUE, 0}}; + +/* Configuration */ +static gboolean key_file_get_boolean_extended (GKeyFile *key_file, const gchar *group_name, const gchar *key, gboolean default_value); + +/* Clock */ static gchar *clock_format; +static gboolean clock_timeout_thread (void); + +/* Message label */ +static gboolean message_label_is_empty (void); +static void set_message_label (LightDMMessageType type, const gchar *text); + +/* User image */ static GdkPixbuf *default_user_pixbuf = NULL; static gchar *default_user_icon = "avatar-default"; +static void set_user_image (const gchar *username); +/* External command (keyboard, reader) */ typedef struct { gchar **argv; @@ -121,32 +156,42 @@ typedef struct static MenuCommand *menu_command_parse (const gchar *value, GtkWidget *menu_item); static MenuCommand *menu_command_parse_extended (const gchar *value, GtkWidget *menu_item, - const gchar *xid_supported, const gchar *xid_arg, - const WindowPosition *size); + const gchar *xid_app, const gchar *xid_arg); static gboolean menu_command_run (MenuCommand *command); static gboolean menu_command_stop (MenuCommand *command); -static void command_terminated_cb (GPid pid, gint status, MenuCommand *command); +static void menu_command_terminated_cb (GPid pid, gint status, MenuCommand *command); static MenuCommand *a11y_keyboard_command; static MenuCommand *a11y_reader_command; static void a11y_menuitem_toggled_cb (GtkCheckMenuItem *item, const gchar* name); -/* Pending Questions */ -static GSList *pending_questions = NULL; - -/* Current choices */ +/* Session */ static gchar *current_session; +static gboolean is_valid_session (GList* items, const gchar* session); +static gchar* get_session (void); +static void set_session (const gchar *session); +void session_selected_cb (GtkMenuItem *menuitem, gpointer user_data); + +/* Sesion language */ static gchar *current_language; +static gchar* get_language (void); +static void set_language (const gchar *language); +void language_selected_cb (GtkMenuItem *menuitem, gpointer user_data); /* Screensaver values */ static int timeout, interval, prefer_blanking, allow_exposures; +/* Handling monitors backgrounds */ static GreeterBackground *greeter_background; +/* Authentication state */ static gboolean cancelling = FALSE, prompted = FALSE; static gboolean prompt_active = FALSE, password_prompted = FALSE; +/* Pending questions */ +static GSList *pending_questions = NULL; + typedef struct { gboolean is_prompt; @@ -158,18 +203,11 @@ typedef struct gchar *text; } PAMConversationMessage; -static const gchar *LANGUAGE_DATA_CODE = "language-code"; -static const gchar *SESSION_DATA_KEY = "session-key"; -static const gchar *LAYOUT_DATA_LABEL = "layout-label"; -#ifdef HAVE_LIBXKLAVIER -static const gchar *LAYOUT_DATA_GROUP = "layout-group"; -#else -static const gchar *LAYOUT_DATA_NAME = "layout-name"; -#endif +static void pam_message_finalize (PAMConversationMessage *message); +static void process_prompts (LightDMGreeter *greeter); +static void show_prompt_cb (LightDMGreeter *greeter, const gchar *text, LightDMPromptType type); -#ifdef HAVE_LIBXKLAVIER -static XklEngine *xkl_engine; -#endif +/* Panel and indicators */ typedef enum { @@ -181,7 +219,7 @@ typedef enum static const gchar *PANEL_ITEM_STYLE = "panel-item"; static const gchar *PANEL_ITEM_STYLE_HOVERED = "panel-item-hovered"; -static const gchar *PANEL_ITEM_STYLES[] = +static const gchar *PANEL_ITEM_STYLES[] = { "panel-item-indicator", "panel-item-spacer", @@ -192,24 +230,62 @@ static const gchar *PANEL_ITEM_STYLES[] = static const gchar *PANEL_ITEM_DATA_INDEX = "panel-item-data-index"; #ifdef HAVE_LIBINDICATOR -static const gchar *INDICATOR_ITEM_DATA_OBJECT = "indicator-item-data-object"; -static const gchar *INDICATOR_ITEM_DATA_ENTRY = "indicator-item-data-entry"; -static const gchar *INDICATOR_ITEM_DATA_BOX = "indicator-item-data-box"; -static const gchar *INDICATOR_DATA_MENUITEMS = "indicator-data-menuitems"; +static const gchar *INDICATOR_ITEM_DATA_OBJECT = "indicator-item-data-object"; /* <IndicatorObject*> */ +static const gchar *INDICATOR_ITEM_DATA_ENTRY = "indicator-item-data-entry"; /* <IndicatorObjectEntry*> */ +static const gchar *INDICATOR_ITEM_DATA_BOX = "indicator-item-data-box"; /* <GtkBox*> */ +static const gchar *INDICATOR_DATA_MENUITEMS = "indicator-data-menuitems"; /* <GHashTable*> */ #endif -static gboolean -key_file_get_boolean_extended (GKeyFile *key_file, const gchar *group_name, const gchar *key, gboolean default_value) -{ - GError* error = NULL; - gboolean result = g_key_file_get_boolean (key_file, group_name, key, &error); - if (error) - { - g_clear_error (&error); - return default_value; - } - return result; -} +static const gchar *LANGUAGE_DATA_CODE = "language-code"; /* <gchar*> e.g. "de_DE.UTF-8" */ +static const gchar *SESSION_DATA_KEY = "session-key"; /* <gchar*> session name */ + +/* Layout indicator */ +#ifdef HAVE_LIBXKLAVIER +static XklEngine *xkl_engine; +static const gchar *LAYOUT_DATA_GROUP = "layout-group"; /* <gchar*> */ +#else +static const gchar *LAYOUT_DATA_NAME = "layout-name"; /* <gchar*> */ +#endif +static const gchar *LAYOUT_DATA_LABEL = "layout-label"; /* <gchar*> e.g. "English (US)" */ + +static gboolean panel_item_enter_notify_cb (GtkWidget *widget, GdkEvent *event, gpointer enter); +static void panel_add_item (GtkWidget *widget, gint index, GreeterPanelItemType item_type); +static gboolean menu_item_accel_closure_cb (GtkAccelGroup *accel_group, GObject *acceleratable, guint keyval, GdkModifierType modifier, gpointer data); +/* Maybe unnecessary (in future) trick to enable accelerators for hidden/detached menu items */ +static void reassign_menu_item_accel (GtkWidget *item); + +#ifdef START_INDICATOR_SERVICES +static void init_indicators (GKeyFile* config, GPid* indicator_pid, GPid* spi_pid); +#else +static void init_indicators (GKeyFile* config); +#endif + +static void layout_selected_cb (GtkCheckMenuItem *menuitem, gpointer user_data); +static void update_layouts_menu (void); +static void update_layouts_menu_state (void); +#ifdef HAVE_LIBXKLAVIER +static void xkl_state_changed_cb (XklEngine *engine, XklEngineStateChange change, gint group, gboolean restore, gpointer user_data); +static void xkl_config_changed_cb (XklEngine *engine, gpointer user_data); +static GdkFilterReturn xkl_xevent_filter (GdkXEvent *xev, GdkEvent *event, gpointer data); +#endif + +/* a11y indicator */ +static gchar *default_font_name, + *default_theme_name, + *default_icon_theme_name; +void a11y_font_cb (GtkCheckMenuItem *item); +void a11y_contrast_cb (GtkCheckMenuItem *item); +void a11y_keyboard_cb (GtkCheckMenuItem *item, gpointer user_data); +void a11y_reader_cb (GtkCheckMenuItem *item, gpointer user_data); + +/* Power indciator */ +static void power_menu_cb (GtkWidget *menuitem, gpointer userdata); +void suspend_cb (GtkWidget *widget, LightDMGreeter *greeter); +void hibernate_cb (GtkWidget *widget, LightDMGreeter *greeter); +void restart_cb (GtkWidget *widget, LightDMGreeter *greeter); +void shutdown_cb (GtkWidget *widget, LightDMGreeter *greeter); + +/* State file */ static void save_state_file (void) @@ -236,18 +312,341 @@ save_state_file (void) } } +/* Power window */ + +static gboolean +show_power_prompt (const gchar *action, const gchar* icon, const gchar* title, const gchar* message) +{ + gchar *new_message = NULL; + + /* Check if there are still users logged in, count them and if so, display a warning */ + gint logged_in_users = 0; + GList *items = lightdm_user_list_get_users (lightdm_user_list_get_instance ()); + GList *item; + for (item = items; item; item = item->next) + { + LightDMUser *user = item->data; + if (lightdm_user_get_logged_in (user)) + logged_in_users++; + } + + if (logged_in_users > 0) + { + gchar *warning = g_strdup_printf (ngettext ("Warning: There is still %d user logged in.", + "Warning: There are still %d users logged in.", + logged_in_users), + logged_in_users); + message = new_message = g_markup_printf_escaped ("<b>%s</b>\n%s", warning, message); + g_free (warning); + } + + gchar *dialog_name = g_strconcat (action, "_dialog", NULL); + gchar *button_name = g_strconcat (action, "_button", NULL); + + gtk_widget_set_name (power_window, dialog_name); + gtk_widget_set_name (GTK_WIDGET (power_ok_button), button_name); + gtk_button_set_label (power_ok_button, title); + gtk_label_set_label (power_title, title); + gtk_label_set_markup (power_text, message); + gtk_image_set_from_icon_name (power_icon, icon, GTK_ICON_SIZE_DIALOG); + + g_free (button_name); + g_free (dialog_name); + g_free (new_message); + + GMainLoop *loop = g_main_loop_new (NULL, FALSE); + g_object_set_data (G_OBJECT (power_window), POWER_WINDOW_DATA_LOOP, loop); + g_object_set_data (G_OBJECT (power_window), POWER_WINDOW_DATA_RESPONSE, GINT_TO_POINTER (GTK_RESPONSE_CANCEL)); + + GtkWidget *focused = gtk_window_get_focus (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (screen_overlay)))); + gboolean session_enabled = gtk_widget_get_sensitive (session_menuitem); + gboolean language_enabled = gtk_widget_get_sensitive (language_menuitem); + + gtk_widget_set_sensitive (power_menuitem, FALSE); + gtk_widget_set_sensitive (session_menuitem, FALSE); + gtk_widget_set_sensitive (language_menuitem, FALSE); + gtk_widget_hide (login_window); + gtk_widget_show (power_window); + gtk_widget_grab_focus (GTK_WIDGET (power_ok_button)); + + g_main_loop_run (loop); + GtkResponseType response = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (power_window), POWER_WINDOW_DATA_RESPONSE)); + g_main_loop_unref (loop); + + gtk_widget_hide (power_window); + gtk_widget_show (login_window); + gtk_widget_set_sensitive (power_menuitem, TRUE); + gtk_widget_set_sensitive (session_menuitem, session_enabled); + gtk_widget_set_sensitive (language_menuitem, language_enabled); + + if (focused) + gtk_widget_grab_focus (focused); + + return response == GTK_RESPONSE_YES; +} + +void +power_button_clicked_cb (GtkButton *button, gpointer user_data) +{ + GMainLoop *loop = g_object_get_data (G_OBJECT (power_window), POWER_WINDOW_DATA_LOOP); + if (g_main_loop_is_running (loop)) + g_main_loop_quit (loop); + + g_object_set_data (G_OBJECT (power_window), POWER_WINDOW_DATA_RESPONSE, + GINT_TO_POINTER (button == power_ok_button ? GTK_RESPONSE_YES : GTK_RESPONSE_CANCEL)); +} + +gboolean +power_window_key_press_event_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data) +{ + if (event->keyval == GDK_KEY_Escape) + { + power_button_clicked_cb (power_cancel_button, NULL); + return TRUE; + } + return FALSE; +} + +/* Handling window position */ + +static gboolean +read_position_from_str (const gchar *s, DimensionPosition *x) +{ + DimensionPosition p; + gchar *end = NULL; + gchar **parts = g_strsplit (s, ",", 2); + if (parts[0]) + { + p.value = g_ascii_strtoll (parts[0], &end, 10); + p.percentage = end && end[0] == '%'; + p.sign = (p.value < 0 || (p.value == 0 && parts[0][0] == '-')) ? -1 : +1; + if (p.value < 0) + p.value *= -1; + if (g_strcmp0(parts[1], "start") == 0) + p.anchor = -1; + else if (g_strcmp0(parts[1], "center") == 0) + p.anchor = 0; + else if (g_strcmp0(parts[1], "end") == 0) + p.anchor = +1; + else + p.anchor = p.sign > 0 ? -1 : +1; + *x = p; + } + else + x = NULL; + g_strfreev (parts); + return x != NULL; +} + +static WindowPosition* +key_file_get_position (GKeyFile *key_file, const gchar *group_name, const gchar *key, const WindowPosition *default_value) +{ + WindowPosition* pos = g_new0 (WindowPosition, 1); + gchar *value = g_key_file_get_value (key_file, group_name, key, NULL); + + *pos = *default_value; + + if (value) + { + gchar *x = value; + gchar *y = strchr (value, ' '); + if (y) + (y++)[0] = '\0'; + + if (read_position_from_str (x, &pos->x)) + /* If there is no y-part then y = x */ + if (!y || !read_position_from_str (y, &pos->y)) + pos->y = pos->x; + + gchar *size_delim = strchr (y ? y : x, ';'); + if (size_delim) + { + gchar *x = size_delim + 1; + if (read_position_from_str (x, &pos->width)) + { + y = strchr (x, ' '); + if (y) + (y++)[0] = '\0'; + if (!y || !read_position_from_str (y, &pos->height)) + if (!default_value->use_size) + pos->height = pos->width; + pos->use_size = TRUE; + } + } + + g_free (value); + } + + return pos; +} + +static gint +get_absolute_position (const DimensionPosition *p, gint screen, gint window) +{ + gint x = p->percentage ? (screen*p->value)/100 : p->value; + x = p->sign < 0 ? screen - x : x; + if (p->anchor > 0) + x -= window; + else if (p->anchor == 0) + x -= window/2; + + if (x < 0) /* Offscreen: left/top */ + return 0; + else if (x + window > screen) /* Offscreen: right/bottom */ + return screen - window; + else + return x; +} + +gboolean +screen_overlay_get_child_position_cb (GtkWidget *overlay, GtkWidget *widget, GdkRectangle *allocation, gpointer user_data) +{ + const WindowPosition *pos = g_object_get_data (G_OBJECT (widget), WINDOW_DATA_POSITION); + if (!pos) + return FALSE; + + gint screen_width = gtk_widget_get_allocated_width (overlay); + gint screen_height = gtk_widget_get_allocated_height (overlay); + + if (pos->use_size) + { + allocation->width = get_absolute_position (&pos->width, screen_width, 0); + allocation->height = get_absolute_position (&pos->height, screen_height, 0); + } + else + { + gtk_widget_get_preferred_width (widget, NULL, &allocation->width); + gtk_widget_get_preferred_height (widget, NULL, &allocation->height); + } + + allocation->x = get_absolute_position (&pos->x, screen_width, allocation->width); + allocation->y = get_absolute_position (&pos->y, screen_height, allocation->height); + + /* Do not overlap panel window */ + gint panel_height = gtk_widget_get_allocated_height (panel_window); + if (panel_height && gtk_widget_get_visible (panel_window)) + { + GtkAlign valign = gtk_widget_get_valign (panel_window); + if (valign == GTK_ALIGN_START && allocation->y < panel_height) + allocation->y = panel_height; + else if (valign == GTK_ALIGN_END && screen_height - allocation->y - allocation->height < panel_height) + allocation->y = screen_height - allocation->height - panel_height; + } + + return TRUE; +} + +/* Configuration */ + +static gboolean +key_file_get_boolean_extended (GKeyFile *key_file, const gchar *group_name, const gchar *key, gboolean default_value) +{ + GError* error = NULL; + gboolean result = g_key_file_get_boolean (key_file, group_name, key, &error); + if (error) + { + g_clear_error (&error); + return default_value; + } + return result; +} + +/* Clock */ + +static gboolean +clock_timeout_thread (void) +{ + time_t rawtime; + struct tm * timeinfo; + gchar time_str[50]; + gchar *markup; + + time (&rawtime); + timeinfo = localtime (&rawtime); + + strftime (time_str, 50, clock_format, timeinfo); + markup = g_markup_printf_escaped ("<b>%s</b>", time_str); + if (g_strcmp0 (markup, gtk_label_get_label (GTK_LABEL (clock_label))) != 0) + gtk_label_set_markup (GTK_LABEL (clock_label), markup); + g_free (markup); + + return TRUE; +} + +/* Message label */ + +static gboolean +message_label_is_empty (void) +{ + return gtk_label_get_text (message_label)[0] == '\0'; +} + +static void +set_message_label (LightDMMessageType type, const gchar *text) +{ + if (type == LIGHTDM_MESSAGE_TYPE_INFO) + gtk_info_bar_set_message_type (info_bar, GTK_MESSAGE_INFO); + else + gtk_info_bar_set_message_type (info_bar, GTK_MESSAGE_ERROR); + gtk_label_set_text (message_label, text); + gtk_widget_set_visible (GTK_WIDGET (info_bar), text && text[0]); +} + +/* User image */ + +static void +set_user_image (const gchar *username) +{ + const gchar *path; + LightDMUser *user = NULL; + GdkPixbuf *image = NULL; + GError *error = NULL; + + if (!gtk_widget_get_visible (GTK_WIDGET (user_image))) + return; + + if (username) + user = lightdm_user_list_get_user_by_name (lightdm_user_list_get_instance (), username); + + if (user) + { + path = lightdm_user_get_image (user); + if (path) + { + image = gdk_pixbuf_new_from_file_at_scale (path, 80, 80, FALSE, &error); + if (image) + { + gtk_image_set_from_pixbuf (GTK_IMAGE (user_image), image); + g_object_unref (image); + return; + } + else + { + g_warning ("Failed to load user image: %s", error->message); + g_clear_error (&error); + } + } + } + + if (default_user_pixbuf) + gtk_image_set_from_pixbuf (GTK_IMAGE (user_image), default_user_pixbuf); + else + gtk_image_set_from_icon_name (GTK_IMAGE (user_image), default_user_icon, GTK_ICON_SIZE_DIALOG); +} + /* MenuCommand */ static MenuCommand* menu_command_parse (const gchar *value, GtkWidget *menu_item) { - return menu_command_parse_extended (value, menu_item, NULL, NULL, NULL); + return menu_command_parse_extended (value, menu_item, NULL, NULL); } static MenuCommand* -menu_command_parse_extended (const gchar *value, GtkWidget *menu_item, - const gchar *xid_supported, const gchar *xid_arg, - const WindowPosition *size) +menu_command_parse_extended (const gchar *value, /* String to parse */ + GtkWidget *menu_item, /* Menu item to connect */ + const gchar *xid_app, /* Program that have "xembed" mode support */ + const gchar *xid_arg) /* Argument that must be added to command line */ { if (!value) return NULL; @@ -269,7 +668,7 @@ menu_command_parse_extended (const gchar *value, GtkWidget *menu_item, command->argc = argc; command->argv = argv; - if (g_strcmp0 (argv[0], xid_supported) == 0) + if (g_strcmp0 (argv[0], xid_app) == 0) { gboolean have_xid_arg = FALSE; gint i; @@ -301,15 +700,8 @@ menu_command_parse_extended (const gchar *value, GtkWidget *menu_item, if (have_xid_arg) { - GdkRectangle screen; - command->widget = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gdk_screen_get_monitor_geometry (gdk_screen_get_default (), - /* must be replaced with background->active_monitor */ - gdk_screen_get_primary_monitor (gdk_screen_get_default ()), - &screen); - gtk_widget_set_size_request (command->widget, - get_absolute_position (&size->x, screen.width, 0), - get_absolute_position (&size->y, screen.height, 0)); + command->widget = gtk_event_box_new (); + gtk_overlay_add_overlay (screen_overlay, command->widget); } } return command; @@ -350,7 +742,7 @@ menu_command_run (MenuCommand *command) else g_warning ("Failed to get '%s' socket: unrecognized output", command->argv[0]); - g_free(text); + g_free (text); } } } @@ -360,17 +752,17 @@ menu_command_run (MenuCommand *command) G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &command->pid, &error); if (spawned) - g_child_watch_add (command->pid, (GChildWatchFunc)command_terminated_cb, command); + g_child_watch_add (command->pid, (GChildWatchFunc)menu_command_terminated_cb, command); } - if(!spawned) + if (!spawned) { if (error) g_warning ("Command spawning error: '%s'", error->message); command->pid = 0; gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (command->menu_item), FALSE); } - g_clear_error(&error); + g_clear_error (&error); return spawned; } @@ -393,7 +785,7 @@ menu_command_stop (MenuCommand *command) } static void -command_terminated_cb (GPid pid, gint status, MenuCommand *command) +menu_command_terminated_cb (GPid pid, gint status, MenuCommand *command) { menu_command_stop (command); } @@ -405,6 +797,185 @@ a11y_menuitem_toggled_cb (GtkCheckMenuItem *item, const gchar* name) save_state_file (); } +/* Session */ + +static gboolean +is_valid_session (GList* items, const gchar* session) +{ + for (; items; items = g_list_next (items)) + if (g_strcmp0 (session, lightdm_session_get_key (items->data)) == 0) + return TRUE; + return FALSE; +} + +static gchar* +get_session (void) +{ + return g_strdup (current_session); +} + +static void +set_session (const gchar *session) +{ + gchar *last_session = NULL; + GList *sessions = lightdm_get_sessions (); + + /* Validation */ + if (!session || !is_valid_session (sessions, session)) + { + /* previous session */ + last_session = g_key_file_get_value (state, "greeter", "last-session", NULL); + if (last_session && g_strcmp0 (session, last_session) != 0 && + is_valid_session (sessions, last_session)) + session = last_session; + else + { + /* default */ + const gchar* default_session = lightdm_greeter_get_default_session_hint (greeter); + if (g_strcmp0 (session, default_session) != 0 && + is_valid_session (sessions, default_session)) + session = default_session; + /* first in the sessions list */ + else if (sessions) + session = lightdm_session_get_key (sessions->data); + /* give up */ + else + session = NULL; + } + } + + if (gtk_widget_get_visible (session_menuitem)) + { + GList *menu_iter = NULL; + GList *menu_items = gtk_container_get_children (GTK_CONTAINER (session_menu)); + if (session) + { + for (menu_iter = menu_items; menu_iter != NULL; menu_iter = g_list_next (menu_iter)) + if (g_strcmp0 (session, g_object_get_data (G_OBJECT (menu_iter->data), SESSION_DATA_KEY)) == 0) + { + /* Set menuitem-image to session-badge */ + GtkIconTheme *icon_theme = gtk_icon_theme_get_default (); + gchar* session_name = g_ascii_strdown (session, -1); + gchar* icon_name = g_strdup_printf ("%s_badge-symbolic", session_name); + g_free (session_name); + if (gtk_icon_theme_has_icon (icon_theme, icon_name)) + gtk_image_set_from_icon_name (GTK_IMAGE (session_badge), icon_name, GTK_ICON_SIZE_MENU); + else + gtk_image_set_from_icon_name (GTK_IMAGE (session_badge), "document-properties-symbolic", GTK_ICON_SIZE_MENU); + g_free (icon_name); + break; + } + } + if (!menu_iter) + menu_iter = menu_items; + + if (menu_iter) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_iter->data), TRUE); + } + + g_free (current_session); + current_session = g_strdup (session); + g_free (last_session); +} + +void +session_selected_cb (GtkMenuItem *menuitem, gpointer user_data) +{ + if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem))) + set_session (g_object_get_data (G_OBJECT (menuitem), SESSION_DATA_KEY)); +} + + +/* Session language */ + +static gchar* +get_language (void) +{ + GList *menu_items, *menu_iter; + + /* if the user manually selected a language, use it */ + if (current_language) + return g_strdup (current_language); + + menu_items = gtk_container_get_children (GTK_CONTAINER (language_menu)); + for (menu_iter = menu_items; menu_iter != NULL; menu_iter = g_list_next (menu_iter)) + { + if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menu_iter->data))) + return g_strdup (g_object_get_data (G_OBJECT (menu_iter->data), LANGUAGE_DATA_CODE)); + } + + return NULL; +} + +static void +set_language (const gchar *language) +{ + const gchar *default_language = NULL; + GList *menu_items, *menu_iter; + + if (!gtk_widget_get_visible (language_menuitem)) + { + g_free (current_language); + current_language = g_strdup (language); + return; + } + + menu_items = gtk_container_get_children (GTK_CONTAINER (language_menu)); + + if (language) + { + for (menu_iter = menu_items; menu_iter != NULL; menu_iter = g_list_next (menu_iter)) + { + gchar *s; + gboolean matched; + s = g_strdup (g_object_get_data (G_OBJECT (menu_iter->data), LANGUAGE_DATA_CODE)); + matched = g_strcmp0 (s, language) == 0; + g_free (s); + if (matched) + { + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_iter->data), TRUE); + g_free (current_language); + current_language = g_strdup (language); + gtk_menu_item_set_label (GTK_MENU_ITEM (language_menuitem),language); + return; + } + } + } + + /* If failed to find this language, then try the default */ + if (lightdm_get_language ()) + { + default_language = lightdm_language_get_code (lightdm_get_language ()); + gtk_menu_item_set_label (GTK_MENU_ITEM (language_menuitem), default_language); + } + if (default_language && g_strcmp0 (default_language, language) != 0) + set_language (default_language); + /* If all else fails, just use the first language from the menu */ + else + { + for (menu_iter = menu_items; menu_iter != NULL; menu_iter = g_list_next (menu_iter)) + { + if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menu_iter->data))) + { + gtk_menu_item_set_label (GTK_MENU_ITEM (language_menuitem), g_strdup (g_object_get_data (G_OBJECT (menu_iter->data), LANGUAGE_DATA_CODE))); + break; + } + } + } +} + +void +language_selected_cb (GtkMenuItem *menuitem, gpointer user_data) +{ + if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem))) + { + gchar *language = g_object_get_data (G_OBJECT (menuitem), LANGUAGE_DATA_CODE); + set_language (language); + } +} + +/* Pending questions */ + static void pam_message_finalize (PAMConversationMessage *message) { @@ -412,6 +983,79 @@ pam_message_finalize (PAMConversationMessage *message) g_free (message); } +static void +process_prompts (LightDMGreeter *greeter) +{ + if (!pending_questions) + return; + + /* always allow the user to change username again */ + gtk_widget_set_sensitive (GTK_WIDGET (username_entry), TRUE); + gtk_widget_set_sensitive (GTK_WIDGET (password_entry), TRUE); + + /* Special case: no user selected from list, so PAM asks us for the user + * via a prompt. For that case, use the username field */ + if (!prompted && pending_questions && !pending_questions->next && + ((PAMConversationMessage *) pending_questions->data)->is_prompt && + ((PAMConversationMessage *) pending_questions->data)->type.prompt != LIGHTDM_PROMPT_TYPE_SECRET && + gtk_widget_get_visible ((GTK_WIDGET (username_entry))) && + lightdm_greeter_get_authentication_user (greeter) == NULL) + { + prompted = TRUE; + prompt_active = TRUE; + gtk_widget_grab_focus (GTK_WIDGET (username_entry)); + gtk_widget_show (GTK_WIDGET (password_entry)); + return; + } + + while (pending_questions) + { + PAMConversationMessage *message = (PAMConversationMessage *) pending_questions->data; + pending_questions = g_slist_remove (pending_questions, (gconstpointer) message); + + if (!message->is_prompt) + { + /* FIXME: this doesn't show multiple messages, but that was + * already the case before. */ + set_message_label (message->type.message, message->text); + continue; + } + + gtk_widget_show (GTK_WIDGET (password_entry)); + gtk_widget_grab_focus (GTK_WIDGET (password_entry)); + gtk_entry_set_text (password_entry, ""); + gtk_entry_set_visibility (password_entry, message->type.prompt != LIGHTDM_PROMPT_TYPE_SECRET); + if (message_label_is_empty () && password_prompted) + { + /* No message was provided beforehand and this is not the + * first password prompt, so use the prompt as label, + * otherwise the user will be completely unclear of what + * is going on. Actually, the fact that prompt messages are + * not shown is problematic in general, especially if + * somebody uses a custom PAM module that wants to ask + * something different. */ + gchar *str = message->text; + if (g_str_has_suffix (str, ": ")) + str = g_strndup (str, strlen (str) - 2); + else if (g_str_has_suffix (str, ":")) + str = g_strndup (str, strlen (str) - 1); + set_message_label (LIGHTDM_MESSAGE_TYPE_INFO, str); + if (str != message->text) + g_free (str); + } + gtk_widget_grab_focus (GTK_WIDGET (password_entry)); + prompted = TRUE; + password_prompted = TRUE; + prompt_active = TRUE; + + /* If we have more stuff after a prompt, assume that other prompts are pending, + * so stop here. */ + break; + } +} + +/* Panel and indicators */ + static gboolean panel_item_enter_notify_cb (GtkWidget *widget, GdkEvent *event, gpointer enter) { @@ -442,9 +1086,9 @@ panel_add_item (GtkWidget *widget, gint index, GreeterPanelItemType item_type) if (item_type == PANEL_ITEM_INDICATOR) { g_signal_connect (G_OBJECT (widget), "enter-notify-event", - G_CALLBACK (panel_item_enter_notify_cb), GINT_TO_POINTER(TRUE)); + G_CALLBACK (panel_item_enter_notify_cb), GINT_TO_POINTER (TRUE)); g_signal_connect (G_OBJECT (widget), "leave-notify-event", - G_CALLBACK (panel_item_enter_notify_cb), GINT_TO_POINTER(FALSE)); + G_CALLBACK (panel_item_enter_notify_cb), GINT_TO_POINTER (FALSE)); } gtk_widget_show (widget); @@ -495,7 +1139,7 @@ indicator_entry_create_menuitem (IndicatorObject *io, IndicatorObjectEntry *entr box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 3); menuitem = gtk_menu_item_new (); - gtk_widget_add_events(GTK_WIDGET(menuitem), GDK_SCROLL_MASK); + gtk_widget_add_events (GTK_WIDGET (menuitem), GDK_SCROLL_MASK); g_object_set_data (G_OBJECT (menuitem), INDICATOR_ITEM_DATA_BOX, box); g_object_set_data (G_OBJECT (menuitem), INDICATOR_ITEM_DATA_OBJECT, io); @@ -506,17 +1150,17 @@ indicator_entry_create_menuitem (IndicatorObject *io, IndicatorObjectEntry *entr g_signal_connect (G_OBJECT (menuitem), "scroll-event", G_CALLBACK (indicator_entry_scrolled_cb), NULL); if (entry->image) - gtk_box_pack_start (GTK_BOX(box), GTK_WIDGET(entry->image), FALSE, FALSE, 1); + gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (entry->image), FALSE, FALSE, 1); if (entry->label) - gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(entry->label), FALSE, FALSE, 1); + gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (entry->label), FALSE, FALSE, 1); if (entry->menu) gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), GTK_WIDGET (entry->menu)); gtk_container_add (GTK_CONTAINER (menuitem), box); gtk_widget_show (box); - panel_add_item(menuitem, index, PANEL_ITEM_INDICATOR); + panel_add_item (menuitem, index, PANEL_ITEM_INDICATOR); return menuitem; } @@ -832,170 +1476,286 @@ init_indicators (GKeyFile* config) } } -static gboolean -is_valid_session (GList* items, const gchar* session) -{ - for (; items; items = g_list_next (items)) - if (g_strcmp0 (session, lightdm_session_get_key (items->data)) == 0) - return TRUE; - return FALSE; -} +/* Layout indicator */ -static gchar * -get_session (void) +static void +layout_selected_cb (GtkCheckMenuItem *menuitem, gpointer user_data) { - return g_strdup (current_session); + if (gtk_check_menu_item_get_active (menuitem)) + { + #ifdef HAVE_LIBXKLAVIER + gint group = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menuitem), LAYOUT_DATA_GROUP)); + xkl_engine_lock_group (xkl_engine, group); + #else + const gchar *name = g_object_get_data (G_OBJECT (menuitem), LAYOUT_DATA_NAME); + GList *item; + for (item = lightdm_get_layouts (); item; item = g_list_next (item)) + { + if (g_strcmp0 (name, lightdm_layout_get_name (item->data)) == 0) + { + lightdm_set_layout (item->data); + gtk_menu_item_set_label (GTK_MENU_ITEM (layout_menuitem), + g_object_get_data (G_OBJECT (menuitem), LAYOUT_DATA_LABEL)); + break; + } + } + #endif + } } static void -set_session (const gchar *session) +update_layouts_menu (void) { - gchar *last_session = NULL; - GList *sessions = lightdm_get_sessions (); + #ifdef HAVE_LIBXKLAVIER + XklConfigRegistry *registry; + XklConfigRec *config; + XklConfigItem *config_item; + GSList *menu_group = NULL; + gint i; - /* Validation */ - if (!session || !is_valid_session (sessions, session)) + g_list_free_full (gtk_container_get_children (GTK_CONTAINER (layout_menu)), + (GDestroyNotify)gtk_widget_destroy); + + config = xkl_config_rec_new (); + if (!xkl_config_rec_get_from_server (config, xkl_engine)) { - /* previous session */ - last_session = g_key_file_get_value (state, "greeter", "last-session", NULL); - if (last_session && g_strcmp0 (session, last_session) != 0 && - is_valid_session (sessions, last_session)) - session = last_session; + g_object_unref (config); + g_warning ("Failed to get Xkl configuration from server"); + return; + } + + config_item = xkl_config_item_new (); + registry = xkl_config_registry_get_instance (xkl_engine); + xkl_config_registry_load (registry, FALSE); + + for (i = 0; config->layouts[i] != NULL; ++i) + { + const gchar *layout = config->layouts[i] ? config->layouts[i] : ""; + const gchar *variant = config->variants[i] ? config->variants[i] : ""; + gchar *label = strlen (variant) > 0 ? g_strdup_printf ("%s_%s", layout, variant) : g_strdup (layout); + + GtkWidget *menuitem = gtk_radio_menu_item_new (menu_group); + menu_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (menuitem)); + + g_snprintf (config_item->name, sizeof (config_item->name), "%s", variant); + if (xkl_config_registry_find_variant (registry, layout, config_item)) + gtk_menu_item_set_label (GTK_MENU_ITEM (menuitem), config_item->description); else { - /* default */ - const gchar* default_session = lightdm_greeter_get_default_session_hint (greeter); - if (g_strcmp0 (session, default_session) != 0 && - is_valid_session (sessions, default_session)) - session = default_session; - /* first in the sessions list */ - else if (sessions) - session = lightdm_session_get_key (sessions->data); - /* give up */ + g_snprintf (config_item->name, sizeof (config_item->name), "%s", layout); + if (xkl_config_registry_find_layout (registry, config_item)) + gtk_menu_item_set_label (GTK_MENU_ITEM (menuitem), config_item->description); else - session = NULL; + gtk_menu_item_set_label (GTK_MENU_ITEM (menuitem), label); } + + g_object_set_data_full (G_OBJECT (menuitem), LAYOUT_DATA_LABEL, label, g_free); + g_object_set_data (G_OBJECT (menuitem), LAYOUT_DATA_GROUP, GINT_TO_POINTER (i)); + + g_signal_connect (G_OBJECT (menuitem), "activate", G_CALLBACK (layout_selected_cb), NULL); + gtk_menu_shell_append (GTK_MENU_SHELL (layout_menu), menuitem); + gtk_widget_show (GTK_WIDGET (menuitem)); } - if (gtk_widget_get_visible (session_menuitem)) + g_object_unref (registry); + g_object_unref (config_item); + g_object_unref (config); + #else + GSList *menu_group = NULL; + GList *item; + + g_list_free_full (gtk_container_get_children (GTK_CONTAINER (layout_menu)), + (GDestroyNotify)gtk_widget_destroy); + + for (item = lightdm_get_layouts (); item; item = g_list_next (item)) { - GList *menu_iter = NULL; - GList *menu_items = gtk_container_get_children (GTK_CONTAINER (session_menu)); - if (session) - { - for (menu_iter = menu_items; menu_iter != NULL; menu_iter = g_list_next(menu_iter)) - if (g_strcmp0 (session, g_object_get_data (G_OBJECT (menu_iter->data), SESSION_DATA_KEY)) == 0) - { - /* Set menuitem-image to session-badge */ - GtkIconTheme *icon_theme = gtk_icon_theme_get_default(); - gchar* session_name = g_ascii_strdown (session, -1); - gchar* icon_name = g_strdup_printf ("%s_badge-symbolic", session_name); - g_free (session_name); - if (gtk_icon_theme_has_icon(icon_theme, icon_name)) - gtk_image_set_from_icon_name (GTK_IMAGE(session_badge), icon_name, GTK_ICON_SIZE_MENU); - else - gtk_image_set_from_icon_name (GTK_IMAGE(session_badge), "document-properties-symbolic", GTK_ICON_SIZE_MENU); - g_free (icon_name); - break; - } - } - if (!menu_iter) - menu_iter = menu_items; + LightDMLayout *layout = item->data; + GtkWidget *menuitem = gtk_radio_menu_item_new (menu_group); + menu_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (menuitem)); - if (menu_iter) - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_iter->data), TRUE); - } + g_object_set_data_full (G_OBJECT (menuitem), LAYOUT_DATA_LABEL, + g_strdelimit (g_strdup (lightdm_layout_get_name (layout)), "\t ", '_'), g_free); + g_object_set_data_full (G_OBJECT (menuitem), LAYOUT_DATA_NAME, + g_strdup (lightdm_layout_get_name (layout)), g_free); - g_free (current_session); - current_session = g_strdup(session); - g_free (last_session); + g_signal_connect (G_OBJECT (menuitem), "activate", G_CALLBACK (layout_selected_cb), NULL); + gtk_menu_item_set_label (GTK_MENU_ITEM (menuitem), lightdm_layout_get_description (layout)); + gtk_menu_shell_append (GTK_MENU_SHELL (layout_menu), menuitem); + gtk_widget_show (GTK_WIDGET (menuitem)); + } + #endif } -static gchar * -get_language (void) +static void +update_layouts_menu_state (void) { - GList *menu_items, *menu_iter; + #ifdef HAVE_LIBXKLAVIER + XklState *state = xkl_engine_get_current_state (xkl_engine); + GList *menu_items = gtk_container_get_children (GTK_CONTAINER (layout_menu)); + GtkCheckMenuItem *menu_item = g_list_nth_data (menu_items, state->group); - /* if the user manually selected a language, use it */ - if (current_language) - return g_strdup (current_language); + if (menu_item) + { + gtk_menu_item_set_label (GTK_MENU_ITEM (layout_menuitem), + g_object_get_data (G_OBJECT (menu_item), LAYOUT_DATA_LABEL)); + gtk_check_menu_item_set_active (menu_item, TRUE); + } + else + gtk_menu_item_set_label (GTK_MENU_ITEM (layout_menuitem), "??"); + g_list_free (menu_items); + #else + LightDMLayout *layout = lightdm_get_layout (); + g_return_if_fail (layout != NULL); - menu_items = gtk_container_get_children(GTK_CONTAINER(language_menu)); - for (menu_iter = menu_items; menu_iter != NULL; menu_iter = g_list_next(menu_iter)) + const gchar *name = lightdm_layout_get_name (layout); + GList *menu_items = gtk_container_get_children (GTK_CONTAINER (layout_menu)); + GList *menu_iter; + for (menu_iter = menu_items; menu_iter; menu_iter = g_list_next (menu_iter)) { - if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu_iter->data))) - return g_strdup(g_object_get_data (G_OBJECT (menu_iter->data), LANGUAGE_DATA_CODE)); + if (g_strcmp0 (name, g_object_get_data (G_OBJECT (menu_iter->data), LAYOUT_DATA_NAME)) == 0) + { + gtk_check_menu_item_set_active (menu_iter->data, TRUE); + gtk_menu_item_set_label (GTK_MENU_ITEM (layout_menuitem), + g_object_get_data (G_OBJECT (menu_iter->data), LAYOUT_DATA_LABEL)); + break; + } } + g_list_free (menu_items); + #endif +} - return NULL; +#ifdef HAVE_LIBXKLAVIER +static void +xkl_state_changed_cb (XklEngine *engine, XklEngineStateChange change, gint group, + gboolean restore, gpointer user_data) +{ + if (change == GROUP_CHANGED) + update_layouts_menu_state (); } static void -set_language (const gchar *language) +xkl_config_changed_cb (XklEngine *engine, gpointer user_data) { - const gchar *default_language = NULL; - GList *menu_items, *menu_iter; + /* tip: xkl_config_rec_get_from_server() return old settings */ + update_layouts_menu (); + update_layouts_menu_state (); +} - if (!gtk_widget_get_visible (language_menuitem)) - { - g_free (current_language); - current_language = g_strdup (language); - return; - } +static GdkFilterReturn +xkl_xevent_filter (GdkXEvent *xev, GdkEvent *event, gpointer data) +{ + XEvent *xevent = (XEvent *) xev; + xkl_engine_filter_events (xkl_engine, xevent); + return GDK_FILTER_CONTINUE; +} +#endif - menu_items = gtk_container_get_children(GTK_CONTAINER(language_menu)); +/* a11y indciator */ - if (language) +void +a11y_font_cb (GtkCheckMenuItem *item) +{ + if (gtk_check_menu_item_get_active (item)) { - for (menu_iter = menu_items; menu_iter != NULL; menu_iter = g_list_next(menu_iter)) + gchar *font_name, **tokens; + guint length; + + g_object_get (gtk_settings_get_default (), "gtk-font-name", &font_name, NULL); + tokens = g_strsplit (font_name, " ", -1); + length = g_strv_length (tokens); + if (length > 1) { - gchar *s; - gboolean matched; - s = g_strdup (g_object_get_data (G_OBJECT (menu_iter->data), LANGUAGE_DATA_CODE)); - matched = g_strcmp0 (s, language) == 0; - g_free (s); - if (matched) + gint size = atoi (tokens[length - 1]); + if (size > 0) { - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_iter->data), TRUE); - g_free (current_language); - current_language = g_strdup(language); - gtk_menu_item_set_label(GTK_MENU_ITEM(language_menuitem),language); - return; + g_free (tokens[length - 1]); + tokens[length - 1] = g_strdup_printf ("%d", size + 10); + g_free (font_name); + font_name = g_strjoinv (" ", tokens); } } + g_strfreev (tokens); + + g_object_set (gtk_settings_get_default (), "gtk-font-name", font_name, NULL); } + else + { + g_object_set (gtk_settings_get_default (), "gtk-font-name", default_font_name, NULL); + } +} - /* If failed to find this language, then try the default */ - if (lightdm_get_language ()) +void +a11y_contrast_cb (GtkCheckMenuItem *item) +{ + if (gtk_check_menu_item_get_active (item)) { - default_language = lightdm_language_get_code (lightdm_get_language ()); - gtk_menu_item_set_label(GTK_MENU_ITEM (language_menuitem), default_language); + g_object_set (gtk_settings_get_default (), "gtk-theme-name", "HighContrast", NULL); + g_object_set (gtk_settings_get_default (), "gtk-icon-theme-name", "HighContrast", NULL); } - if (default_language && g_strcmp0 (default_language, language) != 0) - set_language (default_language); - /* If all else fails, just use the first language from the menu */ else { - for (menu_iter = menu_items; menu_iter != NULL; menu_iter = g_list_next(menu_iter)) - { - if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu_iter->data))) - { - gtk_menu_item_set_label (GTK_MENU_ITEM (language_menuitem), g_strdup (g_object_get_data (G_OBJECT (menu_iter->data), LANGUAGE_DATA_CODE))); - break; - } - } + g_object_set (gtk_settings_get_default (), "gtk-theme-name", default_theme_name, NULL); + g_object_set (gtk_settings_get_default (), "gtk-icon-theme-name", default_icon_theme_name, NULL); } } -static void -set_message_label (LightDMMessageType type, const gchar *text) +void +a11y_keyboard_cb (GtkCheckMenuItem *item, gpointer user_data) { - if (type == LIGHTDM_MESSAGE_TYPE_INFO) - gtk_info_bar_set_message_type (info_bar, GTK_MESSAGE_INFO); + if (gtk_check_menu_item_get_active (item)) + menu_command_run (a11y_keyboard_command); else - gtk_info_bar_set_message_type (info_bar, GTK_MESSAGE_ERROR); - gtk_label_set_text (message_label, text); - gtk_widget_set_visible (GTK_WIDGET (info_bar), text && text[0]); + menu_command_stop (a11y_keyboard_command); +} + +void +a11y_reader_cb (GtkCheckMenuItem *item, gpointer user_data) +{ + if (gtk_check_menu_item_get_active (item)) + menu_command_run (a11y_reader_command); + else + menu_command_stop (a11y_reader_command); +} + +/* Power indicator */ + +static void +power_menu_cb (GtkWidget *menuitem, gpointer userdata) +{ + gtk_widget_set_sensitive (suspend_menuitem, lightdm_get_can_suspend ()); + gtk_widget_set_sensitive (hibernate_menuitem, lightdm_get_can_hibernate ()); + gtk_widget_set_sensitive (restart_menuitem, lightdm_get_can_restart ()); + gtk_widget_set_sensitive (shutdown_menuitem, lightdm_get_can_shutdown ()); +} + +void +suspend_cb (GtkWidget *widget, LightDMGreeter *greeter) +{ + lightdm_suspend (NULL); +} + +void +hibernate_cb (GtkWidget *widget, LightDMGreeter *greeter) +{ + lightdm_hibernate (NULL); +} + +void +restart_cb (GtkWidget *widget, LightDMGreeter *greeter) +{ + if (show_power_prompt ("restart", "view-refresh-symbolic", + _("Restart"), + _("Are you sure you want to close all programs and restart the computer?"))) + lightdm_restart (NULL); +} + +void +shutdown_cb (GtkWidget *widget, LightDMGreeter *greeter) +{ + if (show_power_prompt ("shutdown", "system-shutdown-symbolic", + _("Shut Down"), + _("Are you sure you want to close all programs and shut down the computer?"))) + lightdm_shutdown (NULL); } static void @@ -1032,98 +1792,6 @@ set_user_background (const gchar *username) } static void -set_user_image (const gchar *username) -{ - const gchar *path; - LightDMUser *user = NULL; - GdkPixbuf *image = NULL; - GError *error = NULL; - - if(!gtk_widget_get_visible (GTK_WIDGET (user_image))) - return; - - if (username) - user = lightdm_user_list_get_user_by_name (lightdm_user_list_get_instance (), username); - - if (user) - { - path = lightdm_user_get_image (user); - if (path) - { - image = gdk_pixbuf_new_from_file_at_scale (path, 80, 80, FALSE, &error); - if (image) - { - gtk_image_set_from_pixbuf (GTK_IMAGE (user_image), image); - g_object_unref (image); - return; - } - else - { - g_warning ("Failed to load user image: %s", error->message); - g_clear_error (&error); - } - } - } - - if (default_user_pixbuf) - gtk_image_set_from_pixbuf (GTK_IMAGE (user_image), default_user_pixbuf); - else - gtk_image_set_from_icon_name (GTK_IMAGE (user_image), default_user_icon, GTK_ICON_SIZE_DIALOG); -} - -/* Function translate user defined coordinates to absolute value */ -static gint -get_absolute_position (const DimensionPosition *p, gint screen, gint window) -{ - gint x = p->percentage ? (screen*p->value)/100 : p->value; - x = p->sign < 0 ? screen - x : x; - if (p->anchor > 0) - x -= window; - else if (p->anchor == 0) - x -= window/2; - - if (x < 0) /* Offscreen: left/top */ - return 0; - else if (x + window > screen) /* Offscreen: right/bottom */ - return screen - window; - else - return x; -} - -static void -center_window (GtkWindow *window, GtkAllocation *allocation, const WindowPosition *pos) -{ - const GdkRectangle *monitor_geometry = greeter_background_get_active_monitor_geometry (greeter_background); - GtkAllocation *new_allocation = NULL; - if (!allocation) - { - allocation = new_allocation = g_new0 (GtkAllocation, 1); - gtk_widget_get_allocation (GTK_WIDGET (window), new_allocation); - } - if (monitor_geometry) - gtk_window_move (window, - monitor_geometry->x + get_absolute_position (&pos->x, monitor_geometry->width, allocation->width), - monitor_geometry->y + get_absolute_position (&pos->y, monitor_geometry->height, allocation->height)); - g_free (new_allocation); -} - -static void -active_monitor_changed_cb (GreeterBackground *background, gpointer user_data) -{ - const GdkRectangle *monitor_geometry = greeter_background_get_active_monitor_geometry (greeter_background); - if (monitor_geometry) - { - GdkGeometry hints; - hints.min_width = monitor_geometry->width; - hints.max_width = monitor_geometry->width; - hints.min_height = -1; - hints.max_height = -1; - gtk_window_set_geometry_hints (panel_window, GTK_WIDGET(panel_window), - &hints, GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE); - } -} - -static void start_authentication (const gchar *username) { cancelling = FALSE; @@ -1243,38 +1911,6 @@ start_session (void) g_free (session); } -void -session_selected_cb(GtkMenuItem *menuitem, gpointer user_data); -G_MODULE_EXPORT -void -session_selected_cb(GtkMenuItem *menuitem, gpointer user_data) -{ - if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem))) - set_session(g_object_get_data (G_OBJECT (menuitem), SESSION_DATA_KEY)); -} - -void -language_selected_cb(GtkMenuItem *menuitem, gpointer user_data); -G_MODULE_EXPORT -void -language_selected_cb(GtkMenuItem *menuitem, gpointer user_data) -{ - if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem))) - { - gchar *language = g_object_get_data (G_OBJECT (menuitem), LANGUAGE_DATA_CODE); - set_language(language); - } -} - -static void -power_menu_cb (GtkWidget *menuitem, gpointer userdata) -{ - gtk_widget_set_sensitive (suspend_menuitem, lightdm_get_can_suspend()); - gtk_widget_set_sensitive (hibernate_menuitem, lightdm_get_can_hibernate()); - gtk_widget_set_sensitive (restart_menuitem, lightdm_get_can_restart()); - gtk_widget_set_sensitive (shutdown_menuitem, lightdm_get_can_shutdown()); -} - gboolean password_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data); G_MODULE_EXPORT @@ -1282,7 +1918,7 @@ gboolean password_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data) { if ((event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_Down) && - gtk_widget_get_visible(GTK_WIDGET(user_combo))) + gtk_widget_get_visible (GTK_WIDGET (user_combo))) { gboolean available; GtkTreeIter iter; @@ -1318,8 +1954,8 @@ G_MODULE_EXPORT gboolean username_focus_out_cb (GtkWidget *widget, GdkEvent *event, gpointer user_data) { - if (!g_strcmp0(gtk_entry_get_text(username_entry), "") == 0) - start_authentication(gtk_entry_get_text(username_entry)); + if (!g_strcmp0(gtk_entry_get_text (username_entry), "") == 0) + start_authentication (gtk_entry_get_text (username_entry)); return FALSE; } @@ -1355,7 +1991,6 @@ menubar_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data) case GDK_KEY_F9: case GDK_KEY_F10: case GDK_KEY_F11: case GDK_KEY_F12: gtk_menu_shell_cancel (GTK_MENU_SHELL (menubar)); - gtk_window_present (login_window); return TRUE; default: return FALSE; @@ -1400,13 +2035,13 @@ set_displayed_user (LightDMGreeter *greeter, const gchar *username) { gtk_widget_show (GTK_WIDGET (username_entry)); gtk_widget_show (GTK_WIDGET (cancel_button)); - user_tooltip = g_strdup(_("Other")); + user_tooltip = g_strdup (_("Other")); } else { gtk_widget_hide (GTK_WIDGET (username_entry)); gtk_widget_hide (GTK_WIDGET (cancel_button)); - user_tooltip = g_strdup(username); + user_tooltip = g_strdup (username); } /* At this moment we do not have information about possible prompts @@ -1417,7 +2052,7 @@ set_displayed_user (LightDMGreeter *greeter, const gchar *username) if (g_strcmp0 (username, "*guest") == 0) { - user_tooltip = g_strdup(_("Guest Session")); + user_tooltip = g_strdup (_("Guest Session")); gtk_widget_hide (GTK_WIDGET (password_entry)); gtk_widget_grab_focus (GTK_WIDGET (user_combo)); } @@ -1454,90 +2089,13 @@ user_combobox_active_changed_cb (GtkComboBox *widget, LightDMGreeter *greeter) gtk_tree_model_get (GTK_TREE_MODEL (model), &iter, 0, &user, -1); - set_displayed_user(greeter, user); + set_displayed_user (greeter, user); g_free (user); } set_message_label (LIGHTDM_MESSAGE_TYPE_INFO, NULL); } -static const gchar* -get_message_label (void) -{ - return gtk_label_get_text (message_label); -} - -static void -process_prompts (LightDMGreeter *greeter) -{ - if (!pending_questions) - return; - - /* always allow the user to change username again */ - gtk_widget_set_sensitive (GTK_WIDGET (username_entry), TRUE); - gtk_widget_set_sensitive (GTK_WIDGET (password_entry), TRUE); - - /* Special case: no user selected from list, so PAM asks us for the user - * via a prompt. For that case, use the username field */ - if (!prompted && pending_questions && !pending_questions->next && - ((PAMConversationMessage *) pending_questions->data)->is_prompt && - ((PAMConversationMessage *) pending_questions->data)->type.prompt != LIGHTDM_PROMPT_TYPE_SECRET && - gtk_widget_get_visible ((GTK_WIDGET (username_entry))) && - lightdm_greeter_get_authentication_user (greeter) == NULL) - { - prompted = TRUE; - prompt_active = TRUE; - gtk_widget_grab_focus (GTK_WIDGET (username_entry)); - gtk_widget_show (GTK_WIDGET (password_entry)); - return; - } - - while (pending_questions) - { - PAMConversationMessage *message = (PAMConversationMessage *) pending_questions->data; - pending_questions = g_slist_remove (pending_questions, (gconstpointer) message); - - if (!message->is_prompt) - { - /* FIXME: this doesn't show multiple messages, but that was - * already the case before. */ - set_message_label (message->type.message, message->text); - continue; - } - - gtk_widget_show (GTK_WIDGET (password_entry)); - gtk_widget_grab_focus (GTK_WIDGET (password_entry)); - gtk_entry_set_text (password_entry, ""); - gtk_entry_set_visibility (password_entry, message->type.prompt != LIGHTDM_PROMPT_TYPE_SECRET); - if (get_message_label()[0] == 0 && password_prompted) - { - /* No message was provided beforehand and this is not the - * first password prompt, so use the prompt as label, - * otherwise the user will be completely unclear of what - * is going on. Actually, the fact that prompt messages are - * not shown is problematic in general, especially if - * somebody uses a custom PAM module that wants to ask - * something different. */ - gchar *str = message->text; - if (g_str_has_suffix (str, ": ")) - str = g_strndup (str, strlen (str) - 2); - else if (g_str_has_suffix (str, ":")) - str = g_strndup (str, strlen (str) - 1); - set_message_label (LIGHTDM_MESSAGE_TYPE_INFO, str); - if (str != message->text) - g_free (str); - } - gtk_widget_grab_focus (GTK_WIDGET (password_entry)); - prompted = TRUE; - password_prompted = TRUE; - prompt_active = TRUE; - - /* If we have more stuff after a prompt, assume that other prompts are pending, - * so stop here. */ - break; - } -} - void login_cb (GtkWidget *widget); G_MODULE_EXPORT void @@ -1545,7 +2103,7 @@ login_cb (GtkWidget *widget) { /* Reset to default screensaver values */ if (lightdm_greeter_get_lock_hint (greeter)) - XSetScreenSaver(gdk_x11_display_get_xdisplay(gdk_display_get_default ()), timeout, interval, prefer_blanking, allow_exposures); + XSetScreenSaver (gdk_x11_display_get_xdisplay (gdk_display_get_default ()), timeout, interval, prefer_blanking, allow_exposures); gtk_widget_set_sensitive (GTK_WIDGET (username_entry), FALSE); gtk_widget_set_sensitive (GTK_WIDGET (password_entry), FALSE); @@ -1659,7 +2217,7 @@ authentication_complete_cb (LightDMGreeter *greeter) /* If an error message is already printed we do not print it this statement * The error message probably comes from the PAM module that has a better knowledge * of the failure. */ - gboolean have_pam_error = get_message_label()[0] && + gboolean have_pam_error = !message_label_is_empty () && gtk_info_bar_get_message_type (info_bar) != GTK_MESSAGE_ERROR; if (prompted) { @@ -1676,110 +2234,6 @@ authentication_complete_cb (LightDMGreeter *greeter) } } -void suspend_cb (GtkWidget *widget, LightDMGreeter *greeter); -G_MODULE_EXPORT -void -suspend_cb (GtkWidget *widget, LightDMGreeter *greeter) -{ - lightdm_suspend (NULL); -} - -void hibernate_cb (GtkWidget *widget, LightDMGreeter *greeter); -G_MODULE_EXPORT -void -hibernate_cb (GtkWidget *widget, LightDMGreeter *greeter) -{ - lightdm_hibernate (NULL); -} - -static gboolean -show_power_prompt (const gchar* action, const gchar* message, const gchar* icon, - const gchar* dialog_name, const gchar* button_name) -{ - GtkWidget *dialog; - GtkWidget *image; - GtkWidget *button; - gboolean result; - const GList *items, *item; - gint logged_in_users = 0; - gchar *warning; - - /* Check if there are still users logged in, count them and if so, display a warning */ - items = lightdm_user_list_get_users (lightdm_user_list_get_instance ()); - for (item = items; item; item = item->next) - { - LightDMUser *user = item->data; - if (lightdm_user_get_logged_in (user)) - logged_in_users++; - } - if (logged_in_users > 0) - { - if (logged_in_users > 1) - warning = g_strdup_printf (_("Warning: There are still %d users logged in."), logged_in_users); - else - warning = g_strdup_printf (_("Warning: There is still %d user logged in."), logged_in_users); - message = g_markup_printf_escaped ("<b>%s</b>\n%s", warning, message); - g_free (warning); - } - - /* Prepare the dialog */ - dialog = gtk_message_dialog_new (NULL, - GTK_DIALOG_MODAL, - GTK_MESSAGE_OTHER, - GTK_BUTTONS_NONE, - "%s", action); - gtk_message_dialog_format_secondary_markup (GTK_MESSAGE_DIALOG (dialog), "%s", message); - button = gtk_dialog_add_button(GTK_DIALOG (dialog), _("Cancel"), GTK_RESPONSE_CANCEL); - gtk_widget_set_name(button, "cancel_button"); - button = gtk_dialog_add_button(GTK_DIALOG (dialog), action, GTK_RESPONSE_OK); - gtk_widget_set_name(button, button_name); - - /* Add the icon */ - image = gtk_image_new_from_icon_name(icon, GTK_ICON_SIZE_DIALOG); - gtk_message_dialog_set_image(GTK_MESSAGE_DIALOG(dialog), image); - - /* Make the dialog themeable and attractive */ - gtk_style_context_add_class (GTK_STYLE_CONTEXT (gtk_widget_get_style_context (GTK_WIDGET (dialog))), "lightdm-gtk-greeter"); - gtk_widget_set_name (dialog, dialog_name); - gtk_container_set_border_width (GTK_CONTAINER (dialog), 18); - - greeter_background_add_subwindow (greeter_background, GTK_WINDOW (dialog)); - - /* Hide the login window and show the dialog */ - gtk_widget_hide (GTK_WIDGET (login_window)); - gtk_widget_show_all (dialog); - center_window (GTK_WINDOW (dialog), NULL, &WINDOW_POS_CENTER); - - result = gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK; - - greeter_background_remove_subwindow(greeter_background, GTK_WINDOW (dialog)); - gtk_widget_destroy (dialog); - gtk_widget_show (GTK_WIDGET (login_window)); - gtk_widget_queue_resize(GTK_WIDGET (login_window)); - - return result; -} - -void restart_cb (GtkWidget *widget, LightDMGreeter *greeter); -G_MODULE_EXPORT -void -restart_cb (GtkWidget *widget, LightDMGreeter *greeter) -{ - if (show_power_prompt(_("Restart"), _("Are you sure you want to close all programs and restart the computer?"), - "view-refresh-symbolic", "restart_dialog", "restart_button")) - lightdm_restart (NULL); -} - -void shutdown_cb (GtkWidget *widget, LightDMGreeter *greeter); -G_MODULE_EXPORT -void -shutdown_cb (GtkWidget *widget, LightDMGreeter *greeter) -{ - if (show_power_prompt(_("Shut Down"), _("Are you sure you want to close all programs and shut down the computer?"), - "system-shutdown-symbolic", "shutdown_dialog", "shutdown_button")) - lightdm_shutdown (NULL); -} - static void user_added_cb (LightDMUserList *user_list, LightDMUser *user, LightDMGreeter *greeter) { @@ -1856,79 +2310,6 @@ user_removed_cb (LightDMUserList *user_list, LightDMUser *user) gtk_list_store_remove (GTK_LIST_STORE (model), &iter); } -void a11y_font_cb (GtkCheckMenuItem *item); -G_MODULE_EXPORT -void -a11y_font_cb (GtkCheckMenuItem *item) -{ - if (gtk_check_menu_item_get_active (item)) - { - gchar *font_name, **tokens; - guint length; - - g_object_get (gtk_settings_get_default (), "gtk-font-name", &font_name, NULL); - tokens = g_strsplit (font_name, " ", -1); - length = g_strv_length (tokens); - if (length > 1) - { - gint size = atoi (tokens[length - 1]); - if (size > 0) - { - g_free (tokens[length - 1]); - tokens[length - 1] = g_strdup_printf ("%d", size + 10); - g_free (font_name); - font_name = g_strjoinv (" ", tokens); - } - } - g_strfreev (tokens); - - g_object_set (gtk_settings_get_default (), "gtk-font-name", font_name, NULL); - } - else - { - g_object_set (gtk_settings_get_default (), "gtk-font-name", default_font_name, NULL); - } -} - -void a11y_contrast_cb (GtkCheckMenuItem *item); -G_MODULE_EXPORT -void -a11y_contrast_cb (GtkCheckMenuItem *item) -{ - if (gtk_check_menu_item_get_active (item)) - { - g_object_set (gtk_settings_get_default (), "gtk-theme-name", "HighContrast", NULL); - g_object_set (gtk_settings_get_default (), "gtk-icon-theme-name", "HighContrast", NULL); - } - else - { - g_object_set (gtk_settings_get_default (), "gtk-theme-name", default_theme_name, NULL); - g_object_set (gtk_settings_get_default (), "gtk-icon-theme-name", default_icon_theme_name, NULL); - } -} - -void a11y_keyboard_cb (GtkCheckMenuItem *item, gpointer user_data); -G_MODULE_EXPORT -void -a11y_keyboard_cb (GtkCheckMenuItem *item, gpointer user_data) -{ - if (gtk_check_menu_item_get_active (item)) - menu_command_run (a11y_keyboard_command); - else - menu_command_stop (a11y_keyboard_command); -} - -void a11y_reader_cb (GtkCheckMenuItem *item, gpointer user_data); -G_MODULE_EXPORT -void -a11y_reader_cb (GtkCheckMenuItem *item, gpointer user_data) -{ - if (gtk_check_menu_item_get_active (item)) - menu_command_run (a11y_reader_command); - else - menu_command_stop (a11y_reader_command); -} - static void load_user_list (void) { @@ -1988,7 +2369,7 @@ load_user_list (void) { gchar *name; gboolean matched = FALSE; - + if (selected_user) { do @@ -2009,64 +2390,15 @@ load_user_list (void) gtk_tree_model_get_iter_first (model, &iter); gtk_tree_model_get (model, &iter, 0, &name, -1); gtk_combo_box_set_active_iter (user_combo, &iter); - set_displayed_user(greeter, name); - g_free(name); + set_displayed_user (greeter, name); + g_free (name); } - + } g_free (last_user); } -static gboolean -clock_timeout_thread (void) -{ - time_t rawtime; - struct tm * timeinfo; - gchar time_str[50]; - gchar *markup; - - time ( &rawtime ); - timeinfo = localtime ( &rawtime ); - - strftime(time_str, 50, clock_format, timeinfo); - markup = g_markup_printf_escaped("<b>%s</b>", time_str); - if (g_strcmp0(markup, gtk_label_get_label (GTK_LABEL (clock_label))) != 0) - gtk_label_set_markup (GTK_LABEL (clock_label), markup); - g_free(markup); - - return TRUE; -} - -static gboolean -read_position_from_str (const gchar *s, DimensionPosition *x) -{ - DimensionPosition p; - gchar *end = NULL; - gchar **parts = g_strsplit(s, ",", 2); - if (parts[0]) - { - p.value = g_ascii_strtoll(parts[0], &end, 10); - p.percentage = end && end[0] == '%'; - p.sign = (p.value < 0 || (p.value == 0 && parts[0][0] == '-')) ? -1 : +1; - if (p.value < 0) - p.value *= -1; - if (g_strcmp0(parts[1], "start") == 0) - p.anchor = -1; - else if (g_strcmp0(parts[1], "center") == 0) - p.anchor = 0; - else if (g_strcmp0(parts[1], "end") == 0) - p.anchor = +1; - else - p.anchor = p.sign > 0 ? -1 : +1; - *x = p; - } - else - x = NULL; - g_strfreev (parts); - return x != NULL; -} - static GdkFilterReturn focus_upon_map (GdkXEvent *gxevent, GdkEvent *event, gpointer data) { @@ -2112,180 +2444,6 @@ focus_upon_map (GdkXEvent *gxevent, GdkEvent *event, gpointer data) return GDK_FILTER_CONTINUE; } -/* Layout functions and callbacks */ - -static void -layout_selected_cb(GtkCheckMenuItem *menuitem, gpointer user_data) -{ - if (gtk_check_menu_item_get_active (menuitem)) - { - #ifdef HAVE_LIBXKLAVIER - gint group = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menuitem), LAYOUT_DATA_GROUP)); - xkl_engine_lock_group (xkl_engine, group); - #else - const gchar *name = g_object_get_data (G_OBJECT (menuitem), LAYOUT_DATA_NAME); - GList *item; - for (item = lightdm_get_layouts (); item; item = g_list_next (item)) - { - if (g_strcmp0 (name, lightdm_layout_get_name (item->data)) == 0) - { - lightdm_set_layout (item->data); - gtk_menu_item_set_label (GTK_MENU_ITEM (layout_menuitem), - g_object_get_data (G_OBJECT (menuitem), LAYOUT_DATA_LABEL)); - break; - } - } - #endif - } -} - -static void -update_layouts_menu (void) -{ - #ifdef HAVE_LIBXKLAVIER - XklConfigRegistry *registry; - XklConfigRec *config; - XklConfigItem *config_item; - GSList *menu_group = NULL; - gint i; - - g_list_free_full (gtk_container_get_children (GTK_CONTAINER (layout_menu)), - (GDestroyNotify)gtk_widget_destroy); - - config = xkl_config_rec_new (); - if (!xkl_config_rec_get_from_server (config, xkl_engine)) - { - g_object_unref (config); - g_warning ("Failed to get Xkl configuration from server"); - return; - } - - config_item = xkl_config_item_new (); - registry = xkl_config_registry_get_instance (xkl_engine); - xkl_config_registry_load (registry, FALSE); - - for (i = 0; config->layouts[i] != NULL; ++i) - { - const gchar *layout = config->layouts[i] ? config->layouts[i] : ""; - const gchar *variant = config->variants[i] ? config->variants[i] : ""; - gchar *label = strlen (variant) > 0 ? g_strdup_printf ("%s_%s", layout, variant) : g_strdup (layout); - - GtkWidget *menuitem = gtk_radio_menu_item_new (menu_group); - menu_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (menuitem)); - - g_snprintf (config_item->name, sizeof (config_item->name), "%s", variant); - if (xkl_config_registry_find_variant (registry, layout, config_item)) - gtk_menu_item_set_label (GTK_MENU_ITEM (menuitem), config_item->description); - else - { - g_snprintf (config_item->name, sizeof (config_item->name), "%s", layout); - if (xkl_config_registry_find_layout (registry, config_item)) - gtk_menu_item_set_label (GTK_MENU_ITEM (menuitem), config_item->description); - else - gtk_menu_item_set_label (GTK_MENU_ITEM (menuitem), label); - } - - g_object_set_data_full (G_OBJECT (menuitem), LAYOUT_DATA_LABEL, label, g_free); - g_object_set_data (G_OBJECT (menuitem), LAYOUT_DATA_GROUP, GINT_TO_POINTER (i)); - - g_signal_connect (G_OBJECT (menuitem), "activate", G_CALLBACK (layout_selected_cb), NULL); - gtk_menu_shell_append (GTK_MENU_SHELL (layout_menu), menuitem); - gtk_widget_show (GTK_WIDGET (menuitem)); - } - - g_object_unref (registry); - g_object_unref (config_item); - g_object_unref (config); - #else - GSList *menu_group = NULL; - GList *item; - - g_list_free_full (gtk_container_get_children (GTK_CONTAINER (layout_menu)), - (GDestroyNotify)gtk_widget_destroy); - - for (item = lightdm_get_layouts (); item; item = g_list_next (item)) - { - LightDMLayout *layout = item->data; - GtkWidget *menuitem = gtk_radio_menu_item_new (menu_group); - menu_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (menuitem)); - - g_object_set_data_full (G_OBJECT (menuitem), LAYOUT_DATA_LABEL, - g_strdelimit (g_strdup (lightdm_layout_get_name (layout)), "\t ", '_'), g_free); - g_object_set_data_full (G_OBJECT (menuitem), LAYOUT_DATA_NAME, - g_strdup (lightdm_layout_get_name (layout)), g_free); - - g_signal_connect (G_OBJECT (menuitem), "activate", G_CALLBACK (layout_selected_cb), NULL); - gtk_menu_item_set_label (GTK_MENU_ITEM (menuitem), lightdm_layout_get_description (layout)); - gtk_menu_shell_append (GTK_MENU_SHELL (layout_menu), menuitem); - gtk_widget_show (GTK_WIDGET (menuitem)); - } - #endif -} - -static void -update_layouts_menu_state (void) -{ - #ifdef HAVE_LIBXKLAVIER - XklState *state = xkl_engine_get_current_state (xkl_engine); - GList *menu_items = gtk_container_get_children (GTK_CONTAINER (layout_menu)); - GtkCheckMenuItem *menu_item = g_list_nth_data (menu_items, state->group); - - if (menu_item) - { - gtk_menu_item_set_label (GTK_MENU_ITEM (layout_menuitem), - g_object_get_data (G_OBJECT (menu_item), LAYOUT_DATA_LABEL)); - gtk_check_menu_item_set_active(menu_item, TRUE); - } - else - gtk_menu_item_set_label (GTK_MENU_ITEM (layout_menuitem), "??"); - g_list_free (menu_items); - #else - LightDMLayout *layout = lightdm_get_layout (); - g_return_if_fail (layout != NULL); - - const gchar *name = lightdm_layout_get_name (layout); - GList *menu_items = gtk_container_get_children (GTK_CONTAINER (layout_menu)); - GList *menu_iter; - for (menu_iter = menu_items; menu_iter; menu_iter = g_list_next (menu_iter)) - { - if (g_strcmp0 (name, g_object_get_data (G_OBJECT (menu_iter->data), LAYOUT_DATA_NAME)) == 0) - { - gtk_check_menu_item_set_active (menu_iter->data, TRUE); - gtk_menu_item_set_label (GTK_MENU_ITEM (layout_menuitem), - g_object_get_data (G_OBJECT (menu_iter->data), LAYOUT_DATA_LABEL)); - break; - } - } - g_list_free (menu_items); - #endif -} - -#ifdef HAVE_LIBXKLAVIER -static void -xkl_state_changed_cb (XklEngine *engine, XklEngineStateChange change, gint group, - gboolean restore, gpointer user_data) -{ - if (change == GROUP_CHANGED) - update_layouts_menu_state (); -} - -static void -xkl_config_changed_cb (XklEngine *engine, gpointer user_data) -{ - /* tip: xkl_config_rec_get_from_server() return old settings */ - update_layouts_menu (); - update_layouts_menu_state (); -} - -static GdkFilterReturn -xkl_xevent_filter (GdkXEvent *xev, GdkEvent *event, gpointer data) -{ - XEvent *xevent = (XEvent *) xev; - xkl_engine_filter_events (xkl_engine, xevent); - return GDK_FILTER_CONTINUE; -} -#endif - int main (int argc, char **argv) { @@ -2318,11 +2476,11 @@ main (int argc, char **argv) bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); - g_unix_signal_add(SIGTERM, (GSourceFunc)gtk_main_quit, NULL); + g_unix_signal_add (SIGTERM, (GSourceFunc)gtk_main_quit, NULL); /* init gtk */ gtk_init (&argc, &argv); - + #ifdef HAVE_LIBIDO ido_init (); #endif @@ -2345,7 +2503,7 @@ main (int argc, char **argv) g_clear_error (&error); greeter = lightdm_greeter_new (); - g_signal_connect (greeter, "show-prompt", G_CALLBACK (show_prompt_cb), NULL); + g_signal_connect (greeter, "show-prompt", G_CALLBACK (show_prompt_cb), NULL); g_signal_connect (greeter, "show-message", G_CALLBACK (show_message_cb), NULL); g_signal_connect (greeter, "authentication-complete", G_CALLBACK (authentication_complete_cb), NULL); g_signal_connect (greeter, "autologin-timer-expired", G_CALLBACK (lightdm_greeter_authenticate_autologin), NULL); @@ -2362,8 +2520,8 @@ main (int argc, char **argv) if (value) screensaver_timeout = g_ascii_strtoll (value, &end_ptr, 0); g_free (value); - - display = gdk_x11_display_get_xdisplay(gdk_display_get_default ()); + + display = gdk_x11_display_get_xdisplay (gdk_display_get_default ()); if (lightdm_greeter_get_lock_hint (greeter)) { XGetScreenSaver (display, &timeout, &interval, &prefer_blanking, &allow_exposures); @@ -2400,10 +2558,10 @@ main (int argc, char **argv) } else { - value = g_strdup("Sans 10"); + value = g_strdup ("Sans 10"); g_object_set (gtk_settings_get_default (), "gtk-font-name", value, NULL); } - g_object_get (gtk_settings_get_default (), "gtk-font-name", &default_font_name, NULL); + g_object_get (gtk_settings_get_default (), "gtk-font-name", &default_font_name, NULL); value = g_key_file_get_value (config, "greeter", "xft-dpi", NULL); if (value) g_object_set (gtk_settings_get_default (), "gtk-xft-dpi", (int) (1024 * atof (value)), NULL); @@ -2429,9 +2587,12 @@ main (int argc, char **argv) return EXIT_FAILURE; } g_clear_error (&error); - + + /* Screen window */ + screen_overlay = GTK_OVERLAY (gtk_builder_get_object (builder, "screen_overlay")); + /* Login window */ - login_window = GTK_WINDOW (gtk_builder_get_object (builder, "login_window")); + login_window = GTK_WIDGET (gtk_builder_get_object (builder, "login_window")); user_image = GTK_IMAGE (gtk_builder_get_object (builder, "user_image")); user_combo = GTK_COMBO_BOX (gtk_builder_get_object (builder, "user_combobox")); username_entry = GTK_ENTRY (gtk_builder_get_object (builder, "username_entry")); @@ -2441,8 +2602,8 @@ main (int argc, char **argv) cancel_button = GTK_BUTTON (gtk_builder_get_object (builder, "cancel_button")); login_button = GTK_BUTTON (gtk_builder_get_object (builder, "login_button")); - /* Panel */ - panel_window = GTK_WINDOW (gtk_builder_get_object (builder, "panel_window")); + /* Panel window*/ + panel_window = GTK_WIDGET (gtk_builder_get_object (builder, "panel_window")); menubar = GTK_WIDGET (gtk_builder_get_object (builder, "menubar")); session_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "session_menuitem")); session_menu = GTK_MENU (gtk_builder_get_object (builder, "session_menu")); @@ -2455,10 +2616,22 @@ main (int argc, char **argv) reader_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "reader_menuitem")); power_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "power_menuitem")); layout_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "layout_menuitem")); - layout_menu = GTK_MENU(gtk_builder_get_object (builder, "layout_menu")); + layout_menu = GTK_MENU (gtk_builder_get_object (builder, "layout_menu")); clock_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "clock_menuitem")); host_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "host_menuitem")); + /* Power dialog */ + power_window = GTK_WIDGET (gtk_builder_get_object (builder, "power_window")); + power_ok_button = GTK_BUTTON (gtk_builder_get_object (builder, "power_ok_button")); + power_cancel_button = GTK_BUTTON (gtk_builder_get_object (builder, "power_cancel_button")); + power_title = GTK_LABEL (gtk_builder_get_object (builder, "power_title")); + power_text = GTK_LABEL (gtk_builder_get_object (builder, "power_text")); + power_icon = GTK_IMAGE (gtk_builder_get_object (builder, "power_icon")); + + gtk_overlay_add_overlay (screen_overlay, login_window); + gtk_overlay_add_overlay (screen_overlay, panel_window); + gtk_overlay_add_overlay (screen_overlay, power_window); + gtk_accel_map_add_entry ("<Login>/a11y/font", GDK_KEY_F1, 0); gtk_accel_map_add_entry ("<Login>/a11y/contrast", GDK_KEY_F2, 0); gtk_accel_map_add_entry ("<Login>/a11y/keyboard", GDK_KEY_F3, 0); @@ -2471,7 +2644,14 @@ main (int argc, char **argv) init_indicators (config); #endif - if (g_key_file_get_boolean(config, "greeter", "hide-user-image", NULL)) + /* Hide empty panel */ + GList *menubar_items = gtk_container_get_children (GTK_CONTAINER (menubar)); + if (!menubar_items) + gtk_widget_hide (GTK_WIDGET (panel_window)); + else + g_list_free (menubar_items); + + if (g_key_file_get_boolean (config, "greeter", "hide-user-image", NULL)) { gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (builder, "user_image_border"))); gtk_widget_hide (GTK_WIDGET (user_image)); /* Hide to mark image is disabled */ @@ -2519,8 +2699,8 @@ main (int argc, char **argv) radiomenuitem = gtk_radio_menu_item_new_with_label (sessions, lightdm_session_get_name (session)); g_object_set_data (G_OBJECT (radiomenuitem), SESSION_DATA_KEY, (gpointer) lightdm_session_get_key (session)); sessions = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (radiomenuitem)); - g_signal_connect(G_OBJECT(radiomenuitem), "activate", G_CALLBACK(session_selected_cb), NULL); - gtk_menu_shell_append (GTK_MENU_SHELL(session_menu), radiomenuitem); + g_signal_connect (G_OBJECT (radiomenuitem), "activate", G_CALLBACK (session_selected_cb), NULL); + gtk_menu_shell_append (GTK_MENU_SHELL (session_menu), radiomenuitem); gtk_widget_show (GTK_WIDGET (radiomenuitem)); } set_session (NULL); @@ -2556,8 +2736,8 @@ main (int argc, char **argv) radiomenuitem = gtk_radio_menu_item_new_with_label (languages, label); g_object_set_data (G_OBJECT (radiomenuitem), LANGUAGE_DATA_CODE, (gpointer) code); languages = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (radiomenuitem)); - g_signal_connect(G_OBJECT(radiomenuitem), "activate", G_CALLBACK(language_selected_cb), NULL); - gtk_menu_shell_append (GTK_MENU_SHELL(language_menu), radiomenuitem); + g_signal_connect (G_OBJECT (radiomenuitem), "activate", G_CALLBACK (language_selected_cb), NULL); + gtk_menu_shell_append (GTK_MENU_SHELL (language_menu), radiomenuitem); gtk_widget_show (GTK_WIDGET (radiomenuitem)); } set_language (NULL); @@ -2566,7 +2746,7 @@ main (int argc, char **argv) /* a11y menu */ if (gtk_widget_get_visible (a11y_menuitem)) { - if (gtk_icon_theme_has_icon(icon_theme, "preferences-desktop-accessibility-symbolic")) + if (gtk_icon_theme_has_icon (icon_theme, "preferences-desktop-accessibility-symbolic")) image = gtk_image_new_from_icon_name ("preferences-desktop-accessibility-symbolic", GTK_ICON_SIZE_MENU); else image = gtk_image_new_from_icon_name ("preferences-desktop-accessibility", GTK_ICON_SIZE_MENU); @@ -2575,13 +2755,10 @@ main (int argc, char **argv) } value = g_key_file_get_value (config, "greeter", "keyboard", NULL); - a11y_keyboard_command = menu_command_parse_extended (value, keyboard_menuitem, "onboard", "--xid", - &ONBOARD_WINDOW_SIZE); + a11y_keyboard_command = menu_command_parse_extended (value, keyboard_menuitem, "onboard", "--xid"); g_free (value); gtk_widget_set_visible (keyboard_menuitem, a11y_keyboard_command != NULL); - if (a11y_keyboard_command) - g_signal_connect (a11y_keyboard_command->widget, "size-allocate", G_CALLBACK (center_window), (gpointer)&ONBOARD_WINDOW_POS); value = g_key_file_get_value (config, "greeter", "reader", NULL); a11y_reader_command = menu_command_parse (value, reader_menuitem); @@ -2591,7 +2768,7 @@ main (int argc, char **argv) /* Power menu */ if (gtk_widget_get_visible (power_menuitem)) { - if (gtk_icon_theme_has_icon(icon_theme, "system-shutdown-symbolic")) + if (gtk_icon_theme_has_icon (icon_theme, "system-shutdown-symbolic")) image = gtk_image_new_from_icon_name ("system-shutdown-symbolic", GTK_ICON_SIZE_MENU); else image = gtk_image_new_from_icon_name ("system-shutdown", GTK_ICON_SIZE_MENU); @@ -2603,7 +2780,7 @@ main (int argc, char **argv) restart_menuitem = (GTK_WIDGET (gtk_builder_get_object (builder, "restart_menuitem"))); shutdown_menuitem = (GTK_WIDGET (gtk_builder_get_object (builder, "shutdown_menuitem"))); - g_signal_connect (G_OBJECT (power_menuitem),"activate", G_CALLBACK(power_menu_cb), NULL); + g_signal_connect (G_OBJECT (power_menuitem),"activate", G_CALLBACK (power_menu_cb), NULL); } /* Layout menu */ @@ -2656,8 +2833,8 @@ main (int argc, char **argv) GdkRGBA lightdm_gtk_greeter_override_defaults; css_provider = gtk_css_provider_new (); gtk_css_provider_load_from_data (css_provider, lightdm_gtk_greeter_css_application, lightdm_gtk_greeter_css_application_length, NULL); - gtk_style_context_add_provider_for_screen(gdk_screen_get_default (), GTK_STYLE_PROVIDER (css_provider), - GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), GTK_STYLE_PROVIDER (css_provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); css_provider = gtk_css_provider_new (); guint fallback_css_priority = GTK_STYLE_PROVIDER_PRIORITY_APPLICATION; if (gtk_style_context_lookup_color (gtk_widget_get_style_context (GTK_WIDGET (login_window)), @@ -2665,11 +2842,11 @@ main (int argc, char **argv) &lightdm_gtk_greeter_override_defaults)) fallback_css_priority = GTK_STYLE_PROVIDER_PRIORITY_FALLBACK; gtk_css_provider_load_from_data (css_provider, lightdm_gtk_greeter_css_fallback, lightdm_gtk_greeter_css_fallback_length, NULL); - gtk_style_context_add_provider_for_screen(gdk_screen_get_default (), GTK_STYLE_PROVIDER (css_provider), - fallback_css_priority); + gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), GTK_STYLE_PROVIDER (css_provider), + fallback_css_priority); /* Background */ - greeter_background = greeter_background_new (); + greeter_background = greeter_background_new (GTK_WIDGET (screen_overlay)); value = g_key_file_get_value (config, "greeter", "active-monitor", NULL); greeter_background_set_active_monitor_config (greeter_background, value ? value : "#cursor"); @@ -2688,7 +2865,7 @@ main (int argc, char **argv) { if (!g_str_has_prefix (*config_group, CONFIG_MONITOR_PREFIX)) continue; - const gchar *name = *config_group + sizeof(CONFIG_MONITOR_PREFIX); + const gchar *name = *config_group + sizeof (CONFIG_MONITOR_PREFIX); while (*name && g_ascii_isspace (*name)) ++name; g_debug ("Monitor configuration found: '%s'", name); @@ -2708,9 +2885,9 @@ main (int argc, char **argv) } g_strfreev (config_groups); - g_signal_connect (G_OBJECT (greeter_background), "active-monitor-changed", G_CALLBACK (active_monitor_changed_cb), NULL); - greeter_background_add_subwindow (greeter_background, login_window); - greeter_background_add_subwindow (greeter_background, panel_window); + greeter_background_add_accel_group (greeter_background, GTK_ACCEL_GROUP (gtk_builder_get_object (builder, "a11y_accelgroup"))); + greeter_background_add_accel_group (greeter_background, GTK_ACCEL_GROUP (gtk_builder_get_object (builder, "power_accelgroup"))); + greeter_background_connect (greeter_background, gdk_screen_get_default ()); if (lightdm_greeter_get_hide_users_hint (greeter)) @@ -2726,34 +2903,19 @@ main (int argc, char **argv) } /* Windows positions */ - main_window_pos = WINDOW_POS_CENTER; - value = g_key_file_get_value (config, "greeter", "position", NULL); - if (value) - { - gchar *x = value; - gchar *y = strchr(value, ' '); - if (y) - (y++)[0] = '\0'; - - if (read_position_from_str (x, &main_window_pos.x)) - /* If there is no y-part then y = x */ - if (!y || !read_position_from_str (y, &main_window_pos.y)) - main_window_pos.y = main_window_pos.x; - - g_free (value); - } - panel_window_pos = WINDOW_POS_TOP_LEFT; + g_object_set_data_full (G_OBJECT (login_window), WINDOW_DATA_POSITION, + key_file_get_position (config, "greeter", "position", &WINDOW_POS_CENTER), g_free); - gtk_builder_connect_signals(builder, greeter); + value = g_key_file_get_value (config, "greeter", "panel-position", NULL); + if (g_strcmp0 (value, "bottom") == 0) + gtk_widget_set_valign (panel_window, GTK_ALIGN_END); + g_free (value); - gtk_widget_show (GTK_WIDGET (panel_window)); - center_window (panel_window, NULL, &panel_window_pos); - g_signal_connect (GTK_WIDGET (panel_window), "size-allocate", G_CALLBACK (center_window), &panel_window_pos); + if (a11y_keyboard_command) + g_object_set_data_full (G_OBJECT (a11y_keyboard_command->widget), WINDOW_DATA_POSITION, + key_file_get_position (config, "greeter", "keyboard-position", &KEYBOARD_POSITION), g_free); - gtk_widget_show (GTK_WIDGET (login_window)); - center_window (login_window, NULL, &main_window_pos); - g_signal_connect (GTK_WIDGET (login_window), "size-allocate", G_CALLBACK (center_window), &main_window_pos); - gdk_window_focus (gtk_widget_get_window (GTK_WIDGET (login_window)), GDK_CURRENT_TIME); + gtk_builder_connect_signals (builder, greeter); values = g_key_file_get_string_list (config, "greeter", "a11y-states", NULL, NULL); if (values && *values) @@ -2799,6 +2961,8 @@ main (int argc, char **argv) gdk_window_set_events (root_window, gdk_window_get_events (root_window) | GDK_SUBSTRUCTURE_MASK); gdk_window_add_filter (root_window, focus_upon_map, NULL); + gtk_widget_show (GTK_WIDGET (screen_overlay)); + gtk_main (); #ifdef START_INDICATOR_SERVICES |