src/greeterconfiguration.h | 5 + src/lightdm-gtk-greeter-fallback.css | 10 + src/lightdm-gtk-greeter.c | 841 +++++++++++++++++++++-------------- src/lightdm-gtk-greeter.glade | 354 ++++++++++----- 4 files changed, 762 insertions(+), 448 deletions(-) diff --git a/src/greeterconfiguration.h b/src/greeterconfiguration.h index 6d56dfb..616541c 100644 --- a/src/greeterconfiguration.h +++ b/src/greeterconfiguration.h @@ -38,6 +38,11 @@ #define CONFIG_KEY_KEYBOARD_POSITION "keyboard-position" #define CONFIG_KEY_A11Y_STATES "a11y-states" #define CONFIG_KEY_AT_SPI_ENABLED "at-spi-enabled" +#define CONFIG_KEY_IMPLICIT_MESSAGES "implicit-messages" +#define CONFIG_KEY_RESTART_ON_CANCEL "restart-on-cancel" +#define CONFIG_KEY_HIDE_LOGIN_NOPROMPT "hide-login-noprompt" +#define CONFIG_KEY_HIDE_CANCEL_NOPROMPT "hide-cancel-noprompt" +#define CONFIG_KEY_ENTER_USERNAME "enter-username" #define CONFIG_GROUP_MONITOR "monitor:" #define CONFIG_KEY_BACKGROUND "background" diff --git a/src/lightdm-gtk-greeter-fallback.css b/src/lightdm-gtk-greeter-fallback.css index a9b66c5..016492f 100644 --- a/src/lightdm-gtk-greeter-fallback.css +++ b/src/lightdm-gtk-greeter-fallback.css @@ -15,3 +15,13 @@ #panel_window menubar > separator { background: transparent; } /* Workaround for Adwaita - and other themes - setting a smaller font for the keycap window */ #login_window.keycap, #power_window.keycap { font-size: initial; } + +.question { + color: @theme_fg_color; + background: @question_bg_color; +} + +.error { + color: @error_color; + background-color: transparent; +} diff --git a/src/lightdm-gtk-greeter.c b/src/lightdm-gtk-greeter.c index 27d009f..c38de21 100644 --- a/src/lightdm-gtk-greeter.c +++ b/src/lightdm-gtk-greeter.c @@ -77,12 +77,20 @@ static GtkWidget *screen_overlay_child; /* Login window */ static GtkWidget *login_window; +static GtkLabel *info_message; +static GtkLabel *info_comment; +static GtkBox *user_selector; 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; +static GtkBox *prompt_box; +static GtkBox *echo_on_box; +static GtkEntry *echo_on_entry; +static GtkBox *echo_off_box; +static GtkEntry *echo_off_entry; +static GtkLabel *prompt_text; +static GtkLabel *error_message; +static GtkButton *cancel_button; +static GtkButton *login_button; /* Panel */ static GtkWidget *panel_window, *menubar; @@ -146,8 +154,12 @@ 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); +static void clear_error (void); +static gboolean has_error = FALSE; +static gchar *last_error_message = NULL; +static gchar *current_error_text = NULL; +static gboolean has_new_errors = FALSE; /* User image */ static GdkPixbuf *default_user_pixbuf = NULL; @@ -202,7 +214,8 @@ static GreeterBackground *greeter_background; /* Authentication state */ static gboolean cancelling = FALSE, prompted = FALSE; -static gboolean prompt_active = FALSE, password_prompted = FALSE; +static gboolean prompt_active = FALSE; +static gboolean getting_username = FALSE; /* Pending questions */ static GSList *pending_questions = NULL; @@ -218,6 +231,8 @@ typedef struct gchar *text; } PAMConversationMessage; +static PAMConversationMessage *current_question = NULL; + 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); @@ -308,6 +323,15 @@ struct SavedFocusData gpointer greeter_save_focus(GtkWidget* widget); void greeter_restore_focus(const gpointer saved_data); +static gchar* get_selected_user (void); +static void reset_widgets (void); + +static gboolean implicit_messages = TRUE; +static gboolean restart_on_cancel = FALSE; +static gboolean hide_login_noprompt = FALSE; +static gboolean hide_cancel_noprompt = FALSE; + +static gboolean enter_username = FALSE; static void read_monitor_configuration (const gchar *group, const gchar *name) @@ -359,12 +383,6 @@ greeter_restore_focus(const gpointer saved_data) gtk_editable_set_position(GTK_EDITABLE(data->widget), data->editable_pos); } -static void -infobar_revealed_cb_710888 (GObject *gobject, GParamSpec *pspec, gpointer user_data) -{ - gtk_widget_set_visible (GTK_WIDGET (info_bar), !message_label_is_empty ()); -} - /* Terminating */ static GPid @@ -763,21 +781,77 @@ clock_timeout_thread (void) /* Message label */ -static gboolean -message_label_is_empty (void) +static void clear_error (void) { - return gtk_label_get_text (message_label)[0] == '\0'; + gtk_widget_hide (GTK_WIDGET (error_message)); + gtk_label_set_text (error_message, ""); + has_error = FALSE; + if (last_error_message) + g_free (last_error_message); + last_error_message = NULL; + if (current_error_text) + g_free (current_error_text); + current_error_text = NULL; + has_new_errors = FALSE; } 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]); + switch (type) + { + case LIGHTDM_MESSAGE_TYPE_INFO: + if (text) + { + char *comment = index ((const char*) text, (int) '\n'); + if (comment) + { + *comment = '\0'; + comment++; + } + gtk_label_set_text (info_message, text); + if (comment) + gtk_label_set_text (info_comment, (const gchar*) comment); + else + gtk_label_set_text (info_comment, ""); + } + else + { + gtk_label_set_text (info_message, _("Welcome")); + gtk_label_set_text (info_comment, ""); + } + break; + case LIGHTDM_MESSAGE_TYPE_ERROR: + if (text) + { + has_new_errors = TRUE; + if (last_error_message) + { + if (g_strcmp0 (last_error_message, text) == 0) + break; // Don't duplicate messages + else + g_free (last_error_message); + } + last_error_message = g_strdup (text); + + gchar *appended; + if (current_error_text) + { + if (current_error_text[0]) + appended = g_strconcat (current_error_text, "\n", text, NULL); + else + appended = g_strdup (text); + g_free (current_error_text); + } + else + appended = g_strdup (text); + current_error_text = appended; + gtk_label_set_markup (error_message, current_error_text); + gtk_widget_show (GTK_WIDGET (error_message)); + has_error = TRUE; + } + break; + } } /* User image */ @@ -1183,31 +1257,29 @@ pam_message_finalize (PAMConversationMessage *message) g_free (message); } -static void -process_prompts (LightDMGreeter *ldm) +static gchar* +trim_prompt (gchar *prompt) { - if (!pending_questions) - return; + gchar *last; - /* 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); + if (!prompt) return NULL; + + while (*prompt == ' ' && *prompt != '\0') prompt++; + + last = prompt + strlen (prompt) - 1; + if (last < prompt) return prompt; + while (last >= prompt && *last == ' ') last--; + while (last >= prompt && *last == ':') last--; + while (last >= prompt && *last == ' ') last--; + last++; + *last = '\0'; - /* 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 (ldm) == NULL) - { - prompted = TRUE; - prompt_active = TRUE; - gtk_widget_grab_focus (GTK_WIDGET (username_entry)); - gtk_widget_show (GTK_WIDGET (password_entry)); - return; - } + return prompt; +} +static void +process_prompts (LightDMGreeter *ldm) +{ while (pending_questions) { PAMConversationMessage *message = (PAMConversationMessage *) pending_questions->data; @@ -1215,41 +1287,64 @@ process_prompts (LightDMGreeter *ldm) 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; } + + current_question = message; + + GtkBox *box = NULL; + GtkBox *otherbox = NULL; + GtkEntry *entry = NULL; + + switch (message->type.prompt) + { + case LIGHTDM_PROMPT_TYPE_SECRET: + g_debug ("Secret prompt: %s", message->text); + box = echo_off_box; + otherbox = echo_on_box; + entry = echo_off_entry; + break; + case LIGHTDM_PROMPT_TYPE_QUESTION: + g_debug ("Question prompt: %s", message->text); + box = echo_on_box; + otherbox = echo_off_box; + entry = echo_on_entry; + break; + } + + gchar *prompt = trim_prompt (message->text); + gtk_label_set_text (prompt_text, prompt); + + if (entry) + { + gtk_entry_set_text (entry, ""); + gtk_widget_show (GTK_WIDGET (entry)); + gtk_widget_set_sensitive (GTK_WIDGET (entry), TRUE); + gtk_widget_grab_focus (GTK_WIDGET (entry)); + } + + if (otherbox) + gtk_widget_hide (GTK_WIDGET (otherbox)); + + if (box) + gtk_widget_show (GTK_WIDGET (box)); - 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) + gtk_widget_show (GTK_WIDGET (prompt_box)); + + if (lightdm_greeter_get_in_authentication (ldm)) { - /* 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_show (GTK_WIDGET (login_button)); + gtk_widget_set_sensitive (GTK_WIDGET (login_button), TRUE); } - gtk_widget_grab_focus (GTK_WIDGET (password_entry)); + + gtk_widget_show (GTK_WIDGET (cancel_button)); + gtk_widget_set_sensitive (GTK_WIDGET (cancel_button), TRUE); + + if (has_error) + gtk_widget_show (GTK_WIDGET (error_message)); + 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; } } @@ -1992,44 +2087,91 @@ set_user_background (const gchar *user_name) } static void -start_authentication (const gchar *username) +reset_widgets (void) +{ + gtk_widget_hide (GTK_WIDGET (prompt_box)); + if (!hide_login_noprompt) + gtk_widget_show (GTK_WIDGET (login_button)); +} + +static void +reset_info (void) +{ + set_message_label (LIGHTDM_MESSAGE_TYPE_INFO, NULL); +} + +static void +clear_prompt (void) { - cancelling = FALSE; prompted = FALSE; - password_prompted = FALSE; prompt_active = FALSE; - + if (pending_questions) { g_slist_free_full (pending_questions, (GDestroyNotify) pam_message_finalize); pending_questions = NULL; } + current_question = NULL; + + if (hide_login_noprompt) + gtk_widget_hide (GTK_WIDGET (login_button)); + else + gtk_widget_show (GTK_WIDGET (login_button)); + + if (hide_cancel_noprompt) + gtk_widget_hide (GTK_WIDGET (cancel_button)); - config_set_string (STATE_SECTION_GREETER, STATE_KEY_LAST_USER, username); + gtk_widget_hide (GTK_WIDGET (prompt_box)); +} - if (g_strcmp0 (username, "*other") == 0) +static void +start_authentication (const gchar *username) +{ + if (!username) { - gtk_widget_show (GTK_WIDGET (username_entry)); - gtk_widget_show (GTK_WIDGET (cancel_button)); + const gchar* selected_user = get_selected_user (); + if (selected_user) + { + if (0 == g_strcmp0 (selected_user, "*other")) + username = "*other"; + else if (0 == g_strcmp0 (selected_user, "*guest")) + username = "*guest"; + } + } + + g_debug ("Start authentication for user '%s'", username); + + cancelling = FALSE; + has_new_errors = FALSE; + getting_username = FALSE; + + reset_widgets (); + gtk_widget_set_sensitive (GTK_WIDGET (login_button), FALSE); + clear_prompt (); + reset_info (); + + if (!username || g_strcmp0 (username, "*other") == 0) + { + if (enter_username) + { + gtk_label_set_text (prompt_text, _("Enter your username")); + gtk_widget_show (GTK_WIDGET (echo_on_entry)); + gtk_widget_hide (GTK_WIDGET (echo_off_entry)); + gtk_widget_show (GTK_WIDGET (echo_on_box)); + gtk_widget_show (GTK_WIDGET (prompt_box)); + gtk_widget_set_sensitive (GTK_WIDGET (echo_on_entry), TRUE); + gtk_widget_grab_focus (GTK_WIDGET (echo_on_entry)); + gtk_widget_set_sensitive (GTK_WIDGET (login_button), TRUE); + getting_username = TRUE; + } + else + { #ifdef HAVE_LIBLIGHTDMGOBJECT_1_19_2 - lightdm_greeter_authenticate (greeter, NULL, NULL); + lightdm_greeter_authenticate (greeter, NULL, NULL); #else - lightdm_greeter_authenticate (greeter, NULL); + lightdm_greeter_authenticate (greeter, NULL); #endif - - if (lightdm_greeter_get_lock_hint (greeter)) - { - GList * items = lightdm_user_list_get_users (lightdm_user_list_get_instance ()); - for (GList * item = items; item; item = item->next) - { - LightDMUser *user = item->data; - if( lightdm_user_get_logged_in (user)) - { - gtk_entry_set_text (username_entry,lightdm_user_get_name(user)); - break; - } - } - } + } } else if (g_strcmp0 (username, "*guest") == 0) { @@ -2042,7 +2184,8 @@ start_authentication (const gchar *username) else { LightDMUser *user; - + + config_set_string (STATE_SECTION_GREETER, STATE_KEY_LAST_USER, username); user = lightdm_user_list_get_user_by_name (lightdm_user_list_get_instance (), username); if (user) { @@ -2062,23 +2205,23 @@ start_authentication (const gchar *username) lightdm_greeter_authenticate (greeter, username); #endif } + + if (!hide_cancel_noprompt) + { + gtk_widget_show (GTK_WIDGET (cancel_button)); + gtk_widget_set_sensitive (GTK_WIDGET (cancel_button), TRUE); + } } +static void +authentication_complete_cb (LightDMGreeter *ldm); + static void cancel_authentication (void) { - GtkTreeModel *model; - GtkTreeIter iter; - gboolean other = FALSE; - - if (pending_questions) - { - g_slist_free_full (pending_questions, (GDestroyNotify) pam_message_finalize); - pending_questions = NULL; - } - + gtk_widget_set_sensitive (GTK_WIDGET (cancel_button), FALSE); + /* If in authentication then stop that first */ - cancelling = FALSE; if (lightdm_greeter_get_in_authentication (greeter)) { cancelling = TRUE; @@ -2087,29 +2230,10 @@ cancel_authentication (void) #else lightdm_greeter_cancel_authentication (greeter); #endif - set_message_label (LIGHTDM_MESSAGE_TYPE_INFO, NULL); - } - - /* Make sure password entry is back to normal */ - gtk_entry_set_visibility (password_entry, FALSE); - - /* Force refreshing the prompt_box for "Other" */ - model = gtk_combo_box_get_model (user_combo); - - if (gtk_combo_box_get_active_iter (user_combo, &iter)) - { - gchar *user; - - gtk_tree_model_get (GTK_TREE_MODEL (model), &iter, 0, &user, -1); - other = (g_strcmp0 (user, "*other") == 0); - g_free (user); + } else if (getting_username) { + cancelling = TRUE; + authentication_complete_cb (greeter); } - - /* Start a new login or return to the user list */ - if (other || lightdm_greeter_get_hide_users_hint (greeter)) - start_authentication ("*other"); - else - gtk_widget_grab_focus (GTK_WIDGET (user_combo)); } static void @@ -2142,73 +2266,6 @@ start_session (void) g_free (session); } -gboolean -password_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data); -G_MODULE_EXPORT -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))) - { - gboolean available; - GtkTreeIter iter; - GtkTreeModel *model = gtk_combo_box_get_model (user_combo); - - /* Back to username_entry if it is available */ - if (event->keyval == GDK_KEY_Up && - gtk_widget_get_visible (GTK_WIDGET (username_entry)) && widget == GTK_WIDGET (password_entry)) - { - gtk_widget_grab_focus (GTK_WIDGET (username_entry)); - return TRUE; - } - - if (!gtk_combo_box_get_active_iter (user_combo, &iter)) - return FALSE; - - if (event->keyval == GDK_KEY_Up) - available = gtk_tree_model_iter_previous (model, &iter); - else - available = gtk_tree_model_iter_next (model, &iter); - - if (available) - gtk_combo_box_set_active_iter (user_combo, &iter); - - return TRUE; - } - return FALSE; -} - -gboolean -username_focus_out_cb (GtkWidget *widget, GdkEvent *event, gpointer user_data); -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)); - return FALSE; -} - -gboolean -username_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data); -G_MODULE_EXPORT -gboolean -username_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data) -{ - /* Acts as password_entry */ - if (event->keyval == GDK_KEY_Up) - return password_key_press_cb (widget, event, user_data); - /* Enter activates the password entry */ - else if (event->keyval == GDK_KEY_Return && gtk_widget_get_visible (GTK_WIDGET (password_entry))) - { - gtk_widget_grab_focus (GTK_WIDGET (password_entry)); - return TRUE; - } - else - return FALSE; -} - gboolean menubar_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data); G_MODULE_EXPORT @@ -2260,38 +2317,30 @@ static void set_displayed_user (LightDMGreeter *ldm, const gchar *username) { gchar *user_tooltip; - LightDMUser *user; - - if (g_strcmp0 (username, "*other") == 0) + LightDMUser *user = NULL; + + if (!username || g_strcmp0 (username, "*other") == 0) { - gtk_widget_show (GTK_WIDGET (username_entry)); - gtk_widget_show (GTK_WIDGET (cancel_button)); user_tooltip = g_strdup (_("Other")); } + else if (g_strcmp0 (username, "*guest") == 0) + { + user_tooltip = g_strdup (_("Guest Session")); + gtk_widget_grab_focus (GTK_WIDGET (user_combo)); + } else { - gtk_widget_hide (GTK_WIDGET (username_entry)); - gtk_widget_hide (GTK_WIDGET (cancel_button)); user_tooltip = g_strdup (username); + user = lightdm_user_list_get_user_by_name (lightdm_user_list_get_instance (), username); } - /* At this moment we do not have information about possible prompts - * for current user (except *guest). So, password_entry.visible changed in: - * auth_complete_cb - * process_prompts - * and here - for *guest */ - - if (g_strcmp0 (username, "*guest") == 0) + if (username) { - user_tooltip = g_strdup (_("Guest Session")); - gtk_widget_hide (GTK_WIDGET (password_entry)); - gtk_widget_grab_focus (GTK_WIDGET (user_combo)); + set_login_button_label (ldm, username); + set_user_background (username); + set_user_image (username); } - - set_login_button_label (ldm, username); - set_user_background (username); - set_user_image (username); - user = lightdm_user_list_get_user_by_name (lightdm_user_list_get_instance (), username); + if (user) { set_language (lightdm_user_get_language (user)); @@ -2302,32 +2351,75 @@ set_displayed_user (LightDMGreeter *ldm, const gchar *username) set_language (lightdm_language_get_code (lightdm_get_language ())); set_session (lightdm_greeter_get_default_session_hint (ldm)); } + gtk_widget_set_tooltip_text (GTK_WIDGET (user_combo), user_tooltip); - start_authentication (username); g_free (user_tooltip); + + start_authentication (username); } -void user_combobox_active_changed_cb (GtkComboBox *widget, LightDMGreeter *greeter); -G_MODULE_EXPORT -void -user_combobox_active_changed_cb (GtkComboBox *widget, LightDMGreeter *ldm) +static gchar* +get_selected_user (void) { GtkTreeModel *model; GtkTreeIter iter; model = gtk_combo_box_get_model (user_combo); - if (gtk_combo_box_get_active_iter (user_combo, &iter)) { - gchar *user; + gchar *username; + + gtk_tree_model_get (GTK_TREE_MODEL (model), &iter, 0, &username, -1); + return g_strdup (username); + g_free (username); + } - gtk_tree_model_get (GTK_TREE_MODEL (model), &iter, 0, &user, -1); + return NULL; +} - set_displayed_user (ldm, user); +void user_combobox_active_changed_cb (GtkComboBox *widget, LightDMGreeter *greeter); +G_MODULE_EXPORT +void +user_combobox_active_changed_cb (GtkComboBox *widget, LightDMGreeter *ldm) +{ + clear_error (); - g_free (user); + gchar *username = get_selected_user (); + + if (username) + { + set_displayed_user (ldm, username); + g_free (username); + } +} + +static void +respond (void) +{ + clear_error (); + + if (lightdm_greeter_get_in_authentication (greeter)) + { + if (current_question) + switch (current_question->type.prompt) + { + case LIGHTDM_PROMPT_TYPE_SECRET: +#ifdef HAVE_LIBLIGHTDMGOBJECT_1_19_2 + lightdm_greeter_respond (greeter, gtk_entry_get_text (echo_off_entry), NULL); +#else + lightdm_greeter_respond (greeter, gtk_entry_get_text (echo_off_entry)); +#endif + break; + default: +#ifdef HAVE_LIBLIGHTDMGOBJECT_1_19_2 + lightdm_greeter_respond (greeter, gtk_entry_get_text (echo_on_entry), NULL); +#else + lightdm_greeter_respond (greeter, gtk_entry_get_text (echo_on_entry)); +#endif + } + if (pending_questions) + process_prompts (greeter); } - set_message_label (LIGHTDM_MESSAGE_TYPE_INFO, NULL); } void login_cb (GtkWidget *widget); @@ -2339,28 +2431,28 @@ login_cb (GtkWidget *widget) if (lightdm_greeter_get_lock_hint (greeter)) 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); - set_message_label (LIGHTDM_MESSAGE_TYPE_INFO, NULL); + gtk_widget_set_sensitive (GTK_WIDGET (echo_on_entry), FALSE); + gtk_widget_set_sensitive (GTK_WIDGET (echo_off_entry), FALSE); + gtk_widget_set_sensitive (GTK_WIDGET (login_button), FALSE); prompt_active = FALSE; if (lightdm_greeter_get_is_authenticated (greeter)) start_session (); - else if (lightdm_greeter_get_in_authentication (greeter)) + if (getting_username) { -#ifdef HAVE_LIBLIGHTDMGOBJECT_1_19_2 - lightdm_greeter_respond (greeter, gtk_entry_get_text (password_entry), NULL); -#else - lightdm_greeter_respond (greeter, gtk_entry_get_text (password_entry)); -#endif - /* If we have questions pending, then we continue processing - * those, until we are done. (Otherwise, authentication will - * not complete.) */ - if (pending_questions) - process_prompts (greeter); + getting_username = FALSE; + start_authentication (gtk_entry_get_text (echo_on_entry)); } + else if (lightdm_greeter_get_in_authentication (greeter)) + respond (); else - start_authentication (lightdm_greeter_get_authentication_user (greeter)); + { + clear_error (); + if (lightdm_greeter_get_hide_users_hint (greeter)) + start_authentication (NULL); + else + user_combobox_active_changed_cb (user_combo, greeter); + } } void cancel_cb (GtkWidget *widget); @@ -2368,6 +2460,7 @@ G_MODULE_EXPORT void cancel_cb (GtkWidget *widget) { + gtk_widget_set_sensitive (GTK_WIDGET (cancel_button), FALSE); cancel_authentication (); } @@ -2379,12 +2472,7 @@ user_combo_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_da { if (event->keyval == GDK_KEY_Return) { - if (gtk_widget_get_visible (GTK_WIDGET (username_entry))) - gtk_widget_grab_focus (GTK_WIDGET (username_entry)); - else if (gtk_widget_get_visible (GTK_WIDGET (password_entry))) - gtk_widget_grab_focus (GTK_WIDGET (password_entry)); - else - login_cb (GTK_WIDGET (login_button)); + login_cb (GTK_WIDGET (login_button)); return TRUE; } return FALSE; @@ -2409,17 +2497,7 @@ show_prompt_cb (LightDMGreeter *ldm, const gchar *text, LightDMPromptType type) static void show_message_cb (LightDMGreeter *ldm, const gchar *text, LightDMMessageType type) { - PAMConversationMessage *message_obj = g_new (PAMConversationMessage, 1); - if (message_obj) - { - message_obj->is_prompt = FALSE; - message_obj->type.message = type; - message_obj->text = g_strdup (text); - pending_questions = g_slist_append (pending_questions, message_obj); - } - - if (!prompt_active) - process_prompts (ldm); + set_message_label (type, text); } static void @@ -2462,51 +2540,130 @@ timed_autologin_cb (LightDMGreeter *ldm) static void authentication_complete_cb (LightDMGreeter *ldm) { - prompt_active = FALSE; - gtk_entry_set_text (password_entry, ""); + g_debug ("Authentication completed"); + + reset_widgets (); + + if (hide_cancel_noprompt) + gtk_widget_hide (GTK_WIDGET (cancel_button)); + + config_set_string (STATE_SECTION_GREETER, STATE_KEY_LAST_USER, + lightdm_greeter_get_authentication_user (ldm)); if (cancelling) { - cancel_authentication (); + cancelling = FALSE; + getting_username = FALSE; + clear_prompt (); + clear_error (); + reset_info (); + if (restart_on_cancel) + { + if (lightdm_greeter_get_hide_users_hint (ldm)) + start_authentication (NULL); + else + user_combobox_active_changed_cb (user_combo, ldm); + } + else + { + gtk_widget_set_sensitive (GTK_WIDGET (login_button), TRUE); + } return; } - if (pending_questions) + if (lightdm_greeter_get_is_authenticated (ldm)) + start_session (); + else if (prompted) { - g_slist_free_full (pending_questions, (GDestroyNotify) pam_message_finalize); - pending_questions = NULL; + if (!has_error && implicit_messages) + set_message_label (LIGHTDM_MESSAGE_TYPE_ERROR, _("Incorrect password, please try again")); + // TODO: Add a delay to give the user a chance to read the message! + start_authentication (lightdm_greeter_get_authentication_user (ldm)); } - - if (lightdm_greeter_get_is_authenticated (ldm)) + else { - if (prompted) - start_session (); - else + g_warning ("Failed to authenticate"); + if (!has_error && implicit_messages) + set_message_label (LIGHTDM_MESSAGE_TYPE_ERROR, _("Failed to authenticate")); + else if (has_new_errors) { - gtk_widget_hide (GTK_WIDGET (password_entry)); - gtk_widget_grab_focus (GTK_WIDGET (user_combo)); + gtk_widget_show (GTK_WIDGET (error_message)); } + clear_prompt (); + gtk_widget_set_sensitive (GTK_WIDGET (login_button), TRUE); } - else +} + +static void +switch_to_user (LightDMGreeter *greeter, const char *username) +{ + if (!username) return; + + if (!lightdm_greeter_get_hide_users_hint (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 = !message_label_is_empty () && - gtk_info_bar_get_message_type (info_bar) != GTK_MESSAGE_ERROR; - if (prompted) + GtkTreeModel *model; + model = gtk_combo_box_get_model (user_combo); + + GtkTreeIter active; + gchar *current = NULL; + if (gtk_combo_box_get_active_iter (user_combo, &active)) { - if (!have_pam_error) - set_message_label (LIGHTDM_MESSAGE_TYPE_ERROR, _("Incorrect password, please try again")); - start_authentication (lightdm_greeter_get_authentication_user (ldm)); + gtk_tree_model_get (model, &active, 0, ¤t, -1); } - else + + gboolean matched = FALSE; + gboolean other_found = FALSE; + gboolean unchanged = FALSE; + GtkTreeIter iter; + + if (gtk_tree_model_get_iter_first (model, &iter)) { - g_warning ("Failed to authenticate"); - if (!have_pam_error) - set_message_label (LIGHTDM_MESSAGE_TYPE_ERROR, _("Failed to authenticate")); + do + { + gchar *item; + gtk_tree_model_get (model, &iter, 0, &item, -1); + matched = g_strcmp0 (item, username) == 0; + unchanged = current && (g_strcmp0 (item, current) == 0); + g_free (item); + } while (!matched && gtk_tree_model_iter_next (model, &iter)); + } + + /* Switch to "Other..." if the name isn't in the list. */ + if (!matched && g_strcmp0 (username, "*other") != 0) + { + if (gtk_tree_model_get_iter_first (model, &iter)) + { + do + { + gchar *item; + gtk_tree_model_get (model, &iter, 0, &item, -1); + other_found = g_strcmp0 (item, "*other") == 0; + unchanged = current && (g_strcmp0 (item, current) == 0); + g_free (item); + } while (!other_found && gtk_tree_model_iter_next (model, &iter)); + } + } + + if (matched || other_found) + { + if (!unchanged) + { + /* set_displayed_user() and start_authentication() + are called automatically when the active item + is changed. + See user_combobox_active_changed_cb(). */ + gtk_combo_box_set_active_iter (user_combo, &iter); + return; + } + if (!current || unchanged) + { + user_combobox_active_changed_cb (user_combo, greeter); + return; + } } } + + start_authentication (username); } static void @@ -2593,9 +2750,6 @@ load_user_list (void) const GList *items; const GList *item; - - const gchar *selected_user; - gchar *last_user; gboolean logged_in = FALSE; g_signal_connect (lightdm_user_list_get_instance (), "user-added", G_CALLBACK (user_added_cb), greeter); @@ -2631,49 +2785,57 @@ load_user_list (void) 1, _("Other..."), 2, PANGO_WEIGHT_NORMAL, -1); +} - last_user = config_get_string (STATE_SECTION_GREETER, STATE_KEY_LAST_USER, NULL); +static void +start_initial_auth (void) +{ + gchar *_selected_user = NULL; + const gchar *selected_user; + reset_widgets (); + + gtk_widget_hide (GTK_WIDGET (error_message)); + if (lightdm_greeter_get_select_user_hint (greeter)) selected_user = lightdm_greeter_get_select_user_hint (greeter); else if (lightdm_greeter_get_select_guest_hint (greeter)) selected_user = "*guest"; - else if (last_user) - selected_user = last_user; else - selected_user = NULL; + { + selected_user = lightdm_greeter_get_authentication_user (greeter); + if (!selected_user) + if (!lightdm_greeter_get_hide_users_hint (greeter)) + { + _selected_user = get_selected_user (); + selected_user = _selected_user; + } + } - if (gtk_tree_model_get_iter_first (model, &iter)) + if (!selected_user && (!lightdm_greeter_get_hide_users_hint (greeter) || enter_username)) { - gchar *name; - gboolean matched = FALSE; + _selected_user = config_get_string (STATE_SECTION_GREETER, + STATE_KEY_LAST_USER, NULL); + if (_selected_user) + selected_user = _selected_user; + } - if (selected_user) - { - do - { - gtk_tree_model_get (model, &iter, 0, &name, -1); - matched = g_strcmp0 (name, selected_user) == 0; - g_free (name); - if (matched) - { - gtk_combo_box_set_active_iter (user_combo, &iter); - set_displayed_user (greeter, selected_user); - break; - } - } while (gtk_tree_model_iter_next (model, &iter)); - } - if (!matched) + if (selected_user) + { + if (enter_username) + gtk_entry_set_text (echo_on_entry, selected_user); + if (!lightdm_greeter_get_hide_users_hint (greeter)) { - 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); + switch_to_user (greeter, selected_user); + user_combobox_active_changed_cb (user_combo, greeter); } + else + start_authentication (NULL); } + else + start_authentication (NULL); - g_free (last_user); + g_free (_selected_user); } static GdkFilterReturn @@ -2955,12 +3117,18 @@ main (int argc, char **argv) /* Login window */ login_window = GTK_WIDGET (gtk_builder_get_object (builder, "login_window")); + info_message = GTK_LABEL (gtk_builder_get_object (builder, "info_message")); + info_comment = GTK_LABEL (gtk_builder_get_object (builder, "info_comment")); + user_selector = GTK_BOX (gtk_builder_get_object (builder, "user_selector")); 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")); - password_entry = GTK_ENTRY (gtk_builder_get_object (builder, "password_entry")); - info_bar = GTK_INFO_BAR (gtk_builder_get_object (builder, "greeter_infobar")); - message_label = GTK_LABEL (gtk_builder_get_object (builder, "message_label")); + prompt_box = GTK_BOX (gtk_builder_get_object (builder, "prompt_box")); + echo_on_box = GTK_BOX (gtk_builder_get_object (builder, "echo_on_box")); + echo_on_entry = GTK_ENTRY (gtk_builder_get_object (builder, "echo_on_entry")); + echo_off_box = GTK_BOX (gtk_builder_get_object (builder, "echo_off_box")); + echo_off_entry = GTK_ENTRY (gtk_builder_get_object (builder, "echo_off_entry")); + prompt_text = GTK_LABEL (gtk_builder_get_object (builder, "prompt_text")); + error_message = GTK_LABEL (gtk_builder_get_object (builder, "error_message")); cancel_button = GTK_BUTTON (gtk_builder_get_object (builder, "cancel_button")); login_button = GTK_BUTTON (gtk_builder_get_object (builder, "login_button")); @@ -3002,17 +3170,6 @@ main (int argc, char **argv) init_indicators (); - /* https://bugzilla.gnome.org/show_bug.cgi?id=710888 - > GtkInfoBar not shown after calling gtk_widget_show - Assume they will fix it someday. */ - if (gtk_get_major_version () == 3 && gtk_get_minor_version () < 18) - { - GList *children = gtk_container_get_children (GTK_CONTAINER (info_bar)); - if (g_list_length (children) == 1 && GTK_IS_REVEALER (children->data)) - g_signal_connect_after(children->data, "notify::child-revealed", (GCallback)infobar_revealed_cb_710888, NULL); - g_list_free (children); - } - /* Hide empty panel */ menubar_items = gtk_container_get_children (GTK_CONTAINER (menubar)); if (!menubar_items) @@ -3249,16 +3406,26 @@ main (int argc, char **argv) if (lightdm_greeter_get_hide_users_hint (greeter)) { + g_debug ("Start with user selector disabled"); set_user_image (NULL); - start_authentication ("*other"); + gtk_widget_hide (GTK_WIDGET (user_selector)); } else { + g_debug ("Start with user selector enabled"); + gtk_widget_show (GTK_WIDGET (user_selector)); load_user_list (); - gtk_widget_hide (GTK_WIDGET (cancel_button)); - gtk_widget_show (GTK_WIDGET (user_combo)); } + implicit_messages = config_get_bool (NULL, CONFIG_KEY_IMPLICIT_MESSAGES, TRUE); + restart_on_cancel = config_get_bool (NULL, CONFIG_KEY_RESTART_ON_CANCEL, FALSE); + hide_login_noprompt = config_get_bool (NULL, CONFIG_KEY_HIDE_LOGIN_NOPROMPT, FALSE); + hide_cancel_noprompt = config_get_bool (NULL, CONFIG_KEY_HIDE_CANCEL_NOPROMPT, TRUE); + + enter_username = config_get_bool (NULL, CONFIG_KEY_ENTER_USERNAME, FALSE); + + start_initial_auth (); + /* Windows positions */ value = config_get_string (NULL, CONFIG_KEY_POSITION, NULL); g_object_set_data_full (G_OBJECT (login_window), WINDOW_DATA_POSITION, str_to_position (value, &WINDOW_POS_CENTER), g_free); diff --git a/src/lightdm-gtk-greeter.glade b/src/lightdm-gtk-greeter.glade index 2a0bf02..3a873ba 100644 --- a/src/lightdm-gtk-greeter.glade +++ b/src/lightdm-gtk-greeter.glade @@ -1,10 +1,9 @@ - + - panel_window True @@ -182,6 +181,7 @@ + power_window False @@ -339,6 +339,9 @@ + + -1 + + + + False + True + 2 + + + + + False + True + 1 + + - 1 - 2 + False + True + 2 @@ -480,44 +615,36 @@ - - greeter_infobar + + True False - - - False - end - - - - - - False - False - -1 - - - - + 5 + 5 + True + 0 + none + + + True False + True + - - True + False - [message] + True + center + True + + - - True - True - 0 - - - False - True - -1 - + + + @@ -531,22 +658,26 @@ buttonbox_frame True False + end + 15 + 15 0 none True False - 24 - 24 - 24 + center + center + 24 Cancel cancel_button - True True False + center + center @@ -559,9 +690,10 @@ Log In login_button - True True False + center + center