← Back to team overview

lightdm-gtk-greeter-team team mailing list archive

[Merge] lp:~kalgasnik/lightdm-gtk-greeter/lp-1445420-greeter-show-manual-login-fixed into lp:lightdm-gtk-greeter

 

Andrew P. has proposed merging lp:~kalgasnik/lightdm-gtk-greeter/lp-1445420-greeter-show-manual-login-fixed into lp:lightdm-gtk-greeter.

Requested reviews:
  LightDM Gtk+ Greeter Development Team (lightdm-gtk-greeter-team)
Related bugs:
  Bug #1445420 in LightDM GTK+ Greeter: "greeter-show-manual-login=false ignored in lightdm.conf"
  https://bugs.launchpad.net/lightdm-gtk-greeter/+bug/1445420

For more details, see:
https://code.launchpad.net/~kalgasnik/lightdm-gtk-greeter/lp-1445420-greeter-show-manual-login-fixed/+merge/263830

1. Support of "greeter-show-manual-login" option.
2. "Other" item is displayed dynamically.
3. Replacing literals with named constants (other, guest, model columns).
4. New column in users model - type. Will be used later for #1379710.
-- 
Your team LightDM Gtk+ Greeter Development Team is requested to review the proposed merge of lp:~kalgasnik/lightdm-gtk-greeter/lp-1445420-greeter-show-manual-login-fixed into lp:lightdm-gtk-greeter.
=== modified file 'src/greeterbackground.c'
--- src/greeterbackground.c	2015-06-26 06:00:10 +0000
+++ src/greeterbackground.c	2015-07-04 17:20:19 +0000
@@ -299,7 +299,7 @@
 
 /* Implemented in lightdm-gtk-greeter.c */
 gpointer greeter_save_focus(GtkWidget* widget);
-void greeter_restore_focus(const gpointer saved_data);
+void greeter_restore_focus(gpointer* saved_data);
 
 static const MonitorConfig DEFAULT_MONITOR_CONFIG =
 {
@@ -650,11 +650,7 @@
     if(!priv->active_monitor)
         greeter_background_set_active_monitor(background, NULL);
 
-    if(saved_focus)
-    {
-        greeter_restore_focus(saved_focus);
-        g_free(saved_focus);
-    }
+    greeter_restore_focus(&saved_focus);
 
     priv->screen_monitors_changed_handler_id = g_signal_connect(G_OBJECT(screen), "monitors-changed",
                                                                 G_CALLBACK(greeter_background_monitors_changed_cb),
@@ -802,8 +798,7 @@
             gtk_container_add(GTK_CONTAINER(active->window), priv->child);
 
         gtk_window_present(active->window);
-        greeter_restore_focus(focus);
-        g_free(focus);
+        greeter_restore_focus(&focus);
     }
     else
         g_warning("[Background] Child widget is destroyed or not defined");

=== modified file 'src/lightdm-gtk-greeter.c'
--- src/lightdm-gtk-greeter.c	2015-05-18 03:25:42 +0000
+++ src/lightdm-gtk-greeter.c	2015-07-04 17:20:19 +0000
@@ -214,6 +214,27 @@
 static void process_prompts (LightDMGreeter *greeter);
 static void show_prompt_cb (LightDMGreeter *greeter, const gchar *text, LightDMPromptType type);
 
+/* Users list */
+
+typedef enum
+{
+    USERS_MODEL_TYPE,
+    USERS_MODEL_NAME,
+    USERS_MODEL_DISPLAY_NAME,
+    USERS_MODEL_FONT_WEIGHT
+} UsersModelColumn;
+
+typedef enum
+{
+    USER_TYPE_REGULAR,
+    USER_TYPE_GUEST,
+    USER_TYPE_OTHER,
+    USER_TYPE_INVALID
+} UserType;
+
+static const gchar *OTHER_USER_NAME = "*other";
+static const gchar *GUEST_USER_NAME = "*guest";
+
 /* Panel and indicators */
 
 typedef enum
@@ -290,14 +311,28 @@
 
 static void read_monitor_configuration (const gchar *group, const gchar *name);
 
-struct SavedFocusData
+static gboolean get_iter_by_str (GtkTreeModel *model, GtkTreeIter *iter, gint column, const gchar *value);
+static gint get_iter_by_intr (GtkTreeModel *model, GtkTreeIter *iter, gint column, gint value, gint search_length);
+
+typedef struct
 {
     GtkWidget *widget;
     gint editable_pos;
-};
-
-gpointer greeter_save_focus(GtkWidget* widget);
-void greeter_restore_focus(const gpointer saved_data);
+} SavedFocusData;
+
+SavedFocusData* greeter_save_focus (GtkWidget* widget);
+/* Restore focus, "focus" will be freed */
+void greeter_restore_focus (SavedFocusData** focus);
+
+typedef struct
+{
+    GtkTreePath *path;
+    UserType type;
+} SavedUserSelectionData;
+
+static SavedUserSelectionData* save_user_selection (void);
+/* Restore saved user selection, saved_data will be freed */
+static void restore_user_selection (SavedUserSelectionData** saved_data, gboolean override_current);
 
 
 static void
@@ -318,31 +353,127 @@
     g_free (background);
 }
 
-gpointer
-greeter_save_focus(GtkWidget* widget)
-{
-    GtkWidget *window = gtk_widget_get_toplevel(widget);
-    if (!GTK_IS_WINDOW (window))
+
+static gboolean
+get_iter_by_str (GtkTreeModel *model, GtkTreeIter *iter, gint column, const gchar *value)
+{
+    if (gtk_tree_model_get_iter_first (model, iter))
+        do
+        {
+            gchar *iter_value;
+            gboolean matched;
+
+            gtk_tree_model_get (model, iter, column, &iter_value, -1);
+            matched = g_strcmp0 (iter_value, value) == 0;
+            g_free (iter_value);
+            if (matched)
+                return TRUE;
+        } while (gtk_tree_model_iter_next (model, iter));
+
+    return FALSE;
+}
+
+static gint
+get_iter_by_intr (GtkTreeModel *model, GtkTreeIter *iter, gint column, gint value, gint search_length)
+{
+    gint length = gtk_tree_model_iter_n_children (model, NULL);
+    GtkTreePath *path = length ? gtk_tree_path_new_from_indices (length - 1, -1) : NULL;
+    gboolean found = FALSE;
+    gint iter_value;
+
+    if (path && gtk_tree_model_get_iter (model, iter, path))
+    {
+        do
+        {
+            gtk_tree_model_get (model, iter, column, &iter_value, -1);
+            found = iter_value == value;
+        } while (!found && --search_length != 0 && gtk_tree_model_iter_previous (model, iter));
+    }
+
+    if (path)
+        gtk_tree_path_free (path);
+    return found;
+}
+
+SavedFocusData*
+greeter_save_focus (GtkWidget *widget)
+{
+    GtkWidget *window = gtk_widget_get_toplevel (widget);
+    if(!GTK_IS_WINDOW (window))
         return NULL;
-
-    struct SavedFocusData *data = g_new0 (struct SavedFocusData, 1);
-    data->widget = gtk_window_get_focus (GTK_WINDOW (window));
-    data->editable_pos = GTK_IS_EDITABLE(data->widget) ? gtk_editable_get_position (GTK_EDITABLE (data->widget)) : -1;
+    SavedFocusData* focus = g_new0 (SavedFocusData, 1);
+    focus->widget = gtk_window_get_focus (GTK_WINDOW (window));
+    focus->editable_pos = GTK_IS_EDITABLE (focus->widget) ? gtk_editable_get_position (GTK_EDITABLE (focus->widget)) : -1;
+    return focus;
+}
+
+void
+greeter_restore_focus (SavedFocusData** pfocus)
+{
+    g_return_if_fail (pfocus != NULL);
+
+    SavedFocusData *focus = *pfocus;
+    if(focus && GTK_IS_WIDGET (focus->widget))
+    {
+        gtk_widget_grab_focus (focus->widget);
+        if (GTK_IS_EDITABLE (focus->widget) && focus->editable_pos > -1)
+            gtk_editable_set_position (GTK_EDITABLE (focus->widget), focus->editable_pos);
+    }
+    g_free (focus);
+    *pfocus = NULL;
+}
+
+static SavedUserSelectionData*
+save_user_selection (void)
+{
+    SavedUserSelectionData *data = g_new0 (SavedUserSelectionData, 1);
+
+    GtkTreeIter active_iter;
+    if (gtk_combo_box_get_active_iter (user_combo, &active_iter))
+    {
+        GtkTreeModel *model = gtk_combo_box_get_model (user_combo);
+        data->path = gtk_tree_model_get_path (model, &active_iter);
+        gtk_tree_model_get (model, &active_iter, USERS_MODEL_TYPE, &data->type, -1);
+    }
 
     return data;
 }
 
-void
-greeter_restore_focus(const gpointer saved_data)
+static void
+restore_user_selection (SavedUserSelectionData** pdata, gboolean override_current)
 {
-    struct SavedFocusData *data = saved_data;
-
-    if (!saved_data || !GTK_IS_WIDGET (data->widget))
-        return;
-
-    gtk_widget_grab_focus (data->widget);
-    if (GTK_IS_EDITABLE(data->widget) && data->editable_pos > -1)
-        gtk_editable_set_position(GTK_EDITABLE(data->widget), data->editable_pos);
+    g_return_if_fail(pdata != NULL);
+
+    SavedUserSelectionData* data = *pdata;
+    GtkTreeIter active_iter;
+
+    if (override_current || !gtk_combo_box_get_active_iter (user_combo, &active_iter))
+    {
+        GtkTreeModel *model = gtk_combo_box_get_model (user_combo);
+        UserType new_active_type;
+        gboolean iter_is_valid = FALSE;
+
+        if (data->path)
+        {
+            iter_is_valid = gtk_tree_model_get_iter (model, &active_iter, data->path);
+            if (iter_is_valid)
+                gtk_tree_model_get (model, &active_iter, USERS_MODEL_TYPE, &new_active_type, -1);
+
+            GtkTreeIter iter;
+            if ((!iter_is_valid || data->type != new_active_type) &&
+                get_iter_by_intr (model, &iter, USERS_MODEL_TYPE, data->type, 2))
+            {
+                iter_is_valid = TRUE;
+                active_iter = iter;
+            }
+        }
+
+        if (iter_is_valid || gtk_tree_model_get_iter_first (model, &active_iter))
+            gtk_combo_box_set_active_iter (user_combo, &active_iter);
+    }
+
+    gtk_tree_path_free (data->path);
+    g_clear_pointer (pdata, g_free);
 }
 
 static void
@@ -1856,24 +1987,6 @@
         lightdm_shutdown (NULL);
 }
 
-static void
-set_login_button_label (LightDMGreeter *greeter, const gchar *username)
-{
-    LightDMUser *user;
-    gboolean logged_in = FALSE;
-
-    user = lightdm_user_list_get_user_by_name (lightdm_user_list_get_instance (), username);
-    if (user)
-        logged_in = lightdm_user_get_logged_in (user);
-    if (logged_in)
-        gtk_button_set_label (login_button, _("Unlock"));
-    else
-        gtk_button_set_label (login_button, _("Log In"));
-    /* and disable the session and language widgets */
-    gtk_widget_set_sensitive (GTK_WIDGET (session_menuitem), !logged_in);
-    gtk_widget_set_sensitive (GTK_WIDGET (language_menuitem), !logged_in);
-}
-
 static guint set_user_background_delayed_id = 0;
 
 static gboolean
@@ -1928,13 +2041,13 @@
 
     config_set_string (STATE_SECTION_GREETER, STATE_KEY_LAST_USER, username);
 
-    if (g_strcmp0 (username, "*other") == 0)
+    if (g_strcmp0 (username, OTHER_USER_NAME) == 0)
     {
         gtk_widget_show (GTK_WIDGET (username_entry));
         gtk_widget_show (GTK_WIDGET (cancel_button));
         lightdm_greeter_authenticate (greeter, NULL);
     }
-    else if (g_strcmp0 (username, "*guest") == 0)
+    else if (g_strcmp0 (username, GUEST_USER_NAME) == 0)
     {
         lightdm_greeter_authenticate_as_guest (greeter);
     }
@@ -1963,10 +2076,6 @@
 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);
@@ -1974,10 +2083,9 @@
     }
 
     /* If in authentication then stop that first */
-    cancelling = FALSE;
-    if (lightdm_greeter_get_in_authentication (greeter))
+    cancelling = lightdm_greeter_get_in_authentication (greeter);
+    if (cancelling)
     {
-        cancelling = TRUE;
         lightdm_greeter_cancel_authentication (greeter);
         set_message_label (LIGHTDM_MESSAGE_TYPE_INFO, NULL);
     }
@@ -1985,22 +2093,19 @@
     /* 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))
+    UserType user_type = gtk_widget_get_visible (GTK_WIDGET (user_combo)) ? USER_TYPE_INVALID : USER_TYPE_OTHER;
+    if (user_type == USER_TYPE_INVALID)
     {
-        gchar *user;
-
-        gtk_tree_model_get (GTK_TREE_MODEL (model), &iter, 0, &user, -1);
-        other = (g_strcmp0 (user, "*other") == 0);
-        g_free (user);
+        GtkTreeIter iter;
+        if (gtk_combo_box_get_active_iter (user_combo, &iter))
+            gtk_tree_model_get (gtk_combo_box_get_model (user_combo), &iter, USERS_MODEL_TYPE, &user_type, -1);
     }
 
-    /* Start a new login or return to the user list */
-    if (other || lightdm_greeter_get_hide_users_hint (greeter))
-        start_authentication ("*other");
+    if (user_type == USER_TYPE_OTHER)
+        /* Force refreshing the prompt_box for "Other" */
+        start_authentication (OTHER_USER_NAME);
     else
+        /* Return to the user list */
         gtk_widget_grab_focus (GTK_WIDGET (user_combo));
 }
 
@@ -2145,51 +2250,51 @@
 }
 
 static void
-set_displayed_user (LightDMGreeter *greeter, const gchar *username)
+set_displayed_user (LightDMGreeter *greeter, const gchar *user_name)
 {
-    gchar *user_tooltip;
-    LightDMUser *user;
-
-    if (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
-    {
-        gtk_widget_hide (GTK_WIDGET (username_entry));
-        gtk_widget_hide (GTK_WIDGET (cancel_button));
-        user_tooltip = g_strdup (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)
-    {
-        user_tooltip = g_strdup (_("Guest Session"));
+    UserType user_type = g_strcmp0 (user_name, OTHER_USER_NAME) == 0 ? USER_TYPE_OTHER :
+                         g_strcmp0 (user_name, GUEST_USER_NAME) == 0 ? USER_TYPE_GUEST : USER_TYPE_REGULAR;
+    LightDMUser *user = NULL;
+    const gchar *user_tooltip = user_name;
+    gboolean logged_in = FALSE;
+
+    gtk_widget_set_visible (GTK_WIDGET (username_entry), user_type == USER_TYPE_OTHER);
+    gtk_widget_set_visible (GTK_WIDGET (cancel_button), user_type == USER_TYPE_OTHER);
+
+    if (user_type == USER_TYPE_REGULAR)
+        user = lightdm_user_list_get_user_by_name (lightdm_user_list_get_instance (), user_name);
+    else if (user_type == USER_TYPE_OTHER)
+        user_tooltip = _("Other");
+    else if (user_type == USER_TYPE_GUEST)
+    {
+        user_tooltip = _("Guest Session");
+        /* 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 */
         gtk_widget_hide (GTK_WIDGET (password_entry));
         gtk_widget_grab_focus (GTK_WIDGET (user_combo));
     }
 
-    set_login_button_label (greeter, 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)
     {
+        logged_in = lightdm_user_get_logged_in (user);
         set_language (lightdm_user_get_language (user));
         set_session (lightdm_user_get_session (user));
     }
     else
         set_language (lightdm_language_get_code (lightdm_get_language ()));
+
     gtk_widget_set_tooltip_text (GTK_WIDGET (user_combo), user_tooltip);
-    start_authentication (username);
-    g_free (user_tooltip);
+    gtk_widget_set_sensitive (GTK_WIDGET (session_menuitem), !logged_in);
+    gtk_widget_set_sensitive (GTK_WIDGET (language_menuitem), !logged_in);
+    gtk_button_set_label (login_button, logged_in ? _("Unlock") : _("Log In"));
+
+    set_user_background (user_name);
+    set_user_image (user_name);
+
+    start_authentication (user_name);
 }
 
 void user_combobox_active_changed_cb (GtkComboBox *widget, LightDMGreeter *greeter);
@@ -2197,19 +2302,14 @@
 void
 user_combobox_active_changed_cb (GtkComboBox *widget, LightDMGreeter *greeter)
 {
-    GtkTreeModel *model;
+    GtkTreeModel *model = gtk_combo_box_get_model (user_combo);
     GtkTreeIter iter;
 
-    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);
-
+        gtk_tree_model_get (GTK_TREE_MODEL (model), &iter, USERS_MODEL_NAME, &user, -1);
         set_displayed_user (greeter, user);
-
         g_free (user);
     }
     set_message_label (LIGHTDM_MESSAGE_TYPE_INFO, NULL);
@@ -2380,164 +2480,185 @@
     }
 }
 
-static void
-user_added_cb (LightDMUserList *user_list, LightDMUser *user, LightDMGreeter *greeter)
-{
-    GtkTreeModel *model;
-    GtkTreeIter iter;
-    gboolean logged_in = FALSE;
-
-    model = gtk_combo_box_get_model (user_combo);
-
-    logged_in = lightdm_user_get_logged_in (user);
-
-    gtk_list_store_append (GTK_LIST_STORE (model), &iter);
+/* Controls visibility of "other" user.
+   Must be called after any change of users list. */
+static void
+update_manual_login_item (void)
+{
+    GtkTreeModel *model = gtk_combo_box_get_model (user_combo);
+    GtkTreeIter other_iter;
+    /* "other" user must be the last, no need to check more than one */
+    gboolean other_iter_is_valid = get_iter_by_intr (model, &other_iter, USERS_MODEL_TYPE, USER_TYPE_OTHER, 1);
+
+    gboolean show_manual_login = lightdm_greeter_get_show_manual_login_hint (greeter);
+    if (!show_manual_login)
+    {
+        GtkTreeIter iter = other_iter;
+        if (other_iter_is_valid)
+            /* Force to show if "Other" is the only entry we have */
+            show_manual_login = !gtk_tree_model_iter_previous (model, &iter);
+        else
+            /* Or there are no other entries */
+            show_manual_login = !gtk_tree_model_get_iter_first (model, &iter);
+    }
+
+    if (show_manual_login && !other_iter_is_valid)
+    {
+        gtk_list_store_append (GTK_LIST_STORE (model), &other_iter);
+        gtk_list_store_set (GTK_LIST_STORE (model), &other_iter,
+                            USERS_MODEL_TYPE, USER_TYPE_OTHER,
+                            USERS_MODEL_NAME, OTHER_USER_NAME,
+                            USERS_MODEL_DISPLAY_NAME, _("Other..."),
+                            USERS_MODEL_FONT_WEIGHT, PANGO_WEIGHT_NORMAL,
+                            -1);
+    }
+    else if (!show_manual_login && other_iter_is_valid)
+    {
+        gtk_list_store_remove (GTK_LIST_STORE (model), &other_iter);
+    }
+}
+
+static void
+user_added_cb (LightDMUserList *user_list, LightDMUser *user)
+{
+    if (!gtk_widget_get_visible (GTK_WIDGET (user_combo)))
+        return;
+
+    GtkTreeModel *model = gtk_combo_box_get_model (user_combo);
+    GtkTreeIter iter, last_user_iter;
+    gboolean logged_in = lightdm_user_get_logged_in (user);
+
+    /* Insert item before "guest" and "other" accounts */
+    if (get_iter_by_intr (model, &last_user_iter, USERS_MODEL_TYPE, USER_TYPE_REGULAR, -1))
+        gtk_list_store_insert_after (GTK_LIST_STORE (model), &iter, &last_user_iter);
+    else
+        gtk_list_store_insert_after (GTK_LIST_STORE (model), &iter, NULL);
+
+    SavedUserSelectionData* user_selection = save_user_selection ();
     gtk_list_store_set (GTK_LIST_STORE (model), &iter,
-                        0, lightdm_user_get_name (user),
-                        1, lightdm_user_get_display_name (user),
-                        2, logged_in ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL,
+                        USERS_MODEL_TYPE, USER_TYPE_REGULAR,
+                        USERS_MODEL_NAME, lightdm_user_get_name (user),
+                        USERS_MODEL_DISPLAY_NAME, lightdm_user_get_display_name (user),
+                        USERS_MODEL_FONT_WEIGHT, logged_in ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL,
                         -1);
-}
-
-static gboolean
-get_user_iter (const gchar *username, GtkTreeIter *iter)
-{
-    GtkTreeModel *model;
-
-    model = gtk_combo_box_get_model (user_combo);
-
-    if (!gtk_tree_model_get_iter_first (model, iter))
-        return FALSE;
-    do
-    {
-        gchar *name;
-        gboolean matched;
-
-        gtk_tree_model_get (model, iter, 0, &name, -1);
-        matched = g_strcmp0 (name, username) == 0;
-        g_free (name);
-        if (matched)
-            return TRUE;
-    } while (gtk_tree_model_iter_next (model, iter));
-
-    return FALSE;
+    update_manual_login_item ();
+    restore_user_selection (&user_selection, TRUE);
 }
 
 static void
-user_changed_cb (LightDMUserList *user_list, LightDMUser *user, LightDMGreeter *greeter)
+user_changed_cb (LightDMUserList *user_list, LightDMUser *user)
 {
-    GtkTreeModel *model;
+    if (!gtk_widget_get_visible (GTK_WIDGET (user_combo)))
+        return;
+
+    const gchar *name = lightdm_user_get_name (user);
+    GtkTreeModel *model = gtk_combo_box_get_model (user_combo);
     GtkTreeIter iter;
-    gboolean logged_in = FALSE;
 
-    if (!get_user_iter (lightdm_user_get_name (user), &iter))
+    if (!get_iter_by_str (model, &iter, USERS_MODEL_NAME, name))
+    {
+        g_warning ("%s: model doesn't contain user '%s'", G_STRFUNC, name);
         return;
-    logged_in = lightdm_user_get_logged_in (user);
-
-    model = gtk_combo_box_get_model (user_combo);
-
+    }
+
+    gboolean logged_in = lightdm_user_get_logged_in (user);
     gtk_list_store_set (GTK_LIST_STORE (model), &iter,
-                        0, lightdm_user_get_name (user),
-                        1, lightdm_user_get_display_name (user),
-                        2, logged_in ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL,
+                        USERS_MODEL_DISPLAY_NAME, lightdm_user_get_display_name (user),
+                        USERS_MODEL_FONT_WEIGHT, logged_in ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL,
                         -1);
 }
 
 static void
 user_removed_cb (LightDMUserList *user_list, LightDMUser *user)
 {
-    GtkTreeModel *model;
+    if (!gtk_widget_get_visible (GTK_WIDGET (user_combo)))
+        return;
+
+    const gchar *name = lightdm_user_get_name (user);
+    GtkTreeModel *model = gtk_combo_box_get_model (user_combo);
     GtkTreeIter iter;
 
-    if (!get_user_iter (lightdm_user_get_name (user), &iter))
+    if (!get_iter_by_str (model, &iter, USERS_MODEL_NAME, name))
+    {
+        g_warning ("%s: model doesn't contain user '%s'", G_STRFUNC, name);
         return;
+    }
 
-    model = gtk_combo_box_get_model (user_combo);
+    SavedUserSelectionData* user_selection = save_user_selection ();
     gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
+    update_manual_login_item ();
+    restore_user_selection (&user_selection, TRUE);
 }
 
 static void
 load_user_list (void)
 {
-    const GList *items, *item;
-    GtkTreeModel *model;
-    GtkTreeIter iter;
+    LightDMUserList *lightdm_users = lightdm_user_list_get_instance ();
+
+    g_signal_connect (lightdm_users, "user-added", G_CALLBACK (user_added_cb), NULL);
+    g_signal_connect (lightdm_users, "user-changed", G_CALLBACK (user_changed_cb), NULL);
+    g_signal_connect (lightdm_users, "user-removed", G_CALLBACK (user_removed_cb), NULL);
+
+    if (!gtk_widget_get_visible (GTK_WIDGET (user_combo)))
+        return;
+
+    const GList *users = lightdm_user_list_get_users (lightdm_users);
+    const GList *users_iter;
+    GtkTreeModel *model = gtk_combo_box_get_model (user_combo);
+    GtkTreeIter model_iter;
+
+    for (users_iter = users; users_iter; users_iter = users_iter->next)
+    {
+        LightDMUser *user = users_iter->data;
+        gboolean logged_in = lightdm_user_get_logged_in (user);
+
+        gtk_list_store_append (GTK_LIST_STORE (model), &model_iter);
+        gtk_list_store_set (GTK_LIST_STORE (model), &model_iter,
+                            USERS_MODEL_TYPE, USER_TYPE_REGULAR,
+                            USERS_MODEL_NAME, lightdm_user_get_name (user),
+                            USERS_MODEL_DISPLAY_NAME, lightdm_user_get_display_name (user),
+                            USERS_MODEL_FONT_WEIGHT, logged_in ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL,
+                            -1);
+    }
+
+    if (lightdm_greeter_get_has_guest_account_hint (greeter))
+    {
+        gtk_list_store_append (GTK_LIST_STORE (model), &model_iter);
+        gtk_list_store_set (GTK_LIST_STORE (model), &model_iter,
+                            USERS_MODEL_TYPE, USER_TYPE_GUEST,
+                            USERS_MODEL_NAME, GUEST_USER_NAME,
+                            USERS_MODEL_DISPLAY_NAME, _("Guest Session"),
+                            USERS_MODEL_FONT_WEIGHT, PANGO_WEIGHT_NORMAL,
+                            -1);
+    }
+
+    update_manual_login_item ();
+
+    /* Initial user selection */
     const gchar *selected_user;
-    gboolean logged_in = FALSE;
-
-    g_signal_connect (lightdm_user_list_get_instance (), "user-added", G_CALLBACK (user_added_cb), greeter);
-    g_signal_connect (lightdm_user_list_get_instance (), "user-changed", G_CALLBACK (user_changed_cb), greeter);
-    g_signal_connect (lightdm_user_list_get_instance (), "user-removed", G_CALLBACK (user_removed_cb), NULL);
-    model = gtk_combo_box_get_model (user_combo);
-    items = lightdm_user_list_get_users (lightdm_user_list_get_instance ());
-    for (item = items; item; item = item->next)
-    {
-        LightDMUser *user = item->data;
-        logged_in = lightdm_user_get_logged_in (user);
-
-        gtk_list_store_append (GTK_LIST_STORE (model), &iter);
-        gtk_list_store_set (GTK_LIST_STORE (model), &iter,
-                            0, lightdm_user_get_name (user),
-                            1, lightdm_user_get_display_name (user),
-                            2, logged_in ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL,
-                            -1);
-    }
-    if (lightdm_greeter_get_has_guest_account_hint (greeter))
-    {
-        gtk_list_store_append (GTK_LIST_STORE (model), &iter);
-        gtk_list_store_set (GTK_LIST_STORE (model), &iter,
-                            0, "*guest",
-                            1, _("Guest Session"),
-                            2, PANGO_WEIGHT_NORMAL,
-                            -1);
-    }
-
-    gtk_list_store_append (GTK_LIST_STORE (model), &iter);
-    gtk_list_store_set (GTK_LIST_STORE (model), &iter,
-                        0, "*other",
-                        1, _("Other..."),
-                        2, PANGO_WEIGHT_NORMAL,
-                        -1);
-
     gchar *last_user = config_get_string (STATE_SECTION_GREETER, STATE_KEY_LAST_USER, NULL);
 
     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";
+        selected_user = GUEST_USER_NAME;
     else if (last_user)
         selected_user = last_user;
     else
         selected_user = NULL;
 
-    if (gtk_tree_model_get_iter_first (model, &iter))
+    if (selected_user && get_iter_by_str (model, &model_iter, USERS_MODEL_NAME, selected_user))
+    {
+        gtk_combo_box_set_active_iter (user_combo, &model_iter);
+        set_displayed_user (greeter, selected_user);
+    }
+    else if (gtk_tree_model_get_iter_first (model, &model_iter))
     {
         gchar *name;
-        gboolean matched = FALSE;
-
-        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)
-        {
-            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);
-        }
+        gtk_tree_model_get (model, &model_iter, USERS_MODEL_NAME, &name, -1);
+        gtk_combo_box_set_active_iter (user_combo, &model_iter);
+        set_displayed_user (greeter, name);
+        g_free (name);
     }
 
     g_free (last_user);
@@ -3059,7 +3180,7 @@
     if (lightdm_greeter_get_hide_users_hint (greeter))
     {
         set_user_image (NULL);
-        start_authentication ("*other");
+        start_authentication (OTHER_USER_NAME);
     }
     else
     {

=== modified file 'src/lightdm-gtk-greeter.glade'
--- src/lightdm-gtk-greeter.glade	2015-06-29 15:11:04 +0000
+++ src/lightdm-gtk-greeter.glade	2015-07-04 17:20:19 +0000
@@ -343,11 +343,13 @@
   </object>
   <object class="GtkListStore" id="user_liststore">
     <columns>
-      <!-- column-name username -->
-      <column type="gchararray"/>
-      <!-- column-name label -->
-      <column type="gchararray"/>
-      <!-- column-name weight -->
+      <!-- column-name type -->
+      <column type="gint"/>
+      <!-- column-name name -->
+      <column type="gchararray"/>
+      <!-- column-name display-name -->
+      <column type="gchararray"/>
+      <!-- column-name font-weight -->
       <column type="gint"/>
     </columns>
   </object>
@@ -418,8 +420,8 @@
                     <child>
                       <object class="GtkCellRendererText" id="cellrenderertext1"/>
                       <attributes>
-                        <attribute name="text">1</attribute>
-                        <attribute name="weight">2</attribute>
+                        <attribute name="text">2</attribute>
+                        <attribute name="weight">3</attribute>
                       </attributes>
                     </child>
                   </object>


Follow ups