+ if (cmpl_is_directory (poss))
+ {
+ if (strcmp (filename, "." G_DIR_SEPARATOR_S) != 0 &&
+ strcmp (filename, ".." G_DIR_SEPARATOR_S) != 0)
+ {
+ gtk_list_store_append (dir_model, &iter);
+ gtk_list_store_set (dir_model, &iter, DIR_COLUMN, filename, -1);
+ }
+ }
+ else
+ {
+ gtk_list_store_append (file_model, &iter);
+ gtk_list_store_set (file_model, &iter, DIR_COLUMN, filename, -1);
+ }
+ }
+
+ poss = cmpl_next_completion (cmpl_state);
+ }
+
+#ifdef G_PLATFORM_WIN32
+ /* For Windows, add drives as potential selections */
+ win32_gtk_add_drives_to_dir_list (dir_model);
+#endif
+
+ /* File lists are set. */
+
+ g_assert (cmpl_state->reference_dir);
+
+ if (try_complete)
+ {
+
+ /* User is trying to complete filenames, so advance the user's input
+ * string to the updated_text, which is the common leading substring
+ * of all possible completions, and if its a directory attempt
+ * attempt completions in it. */
+
+ if (cmpl_updated_text (cmpl_state)[0])
+ {
+
+ if (cmpl_updated_dir (cmpl_state))
+ {
+ gchar* dir_name = g_strdup (cmpl_updated_text (cmpl_state));
+
+ did_recurse = TRUE;
+
+ gtk_file_selection_populate (fs, dir_name, TRUE, TRUE);
+
+ g_free (dir_name);
+ }
+ else
+ {
+ if (fs->selection_entry)
+ gtk_entry_set_text (GTK_ENTRY (fs->selection_entry),
+ cmpl_updated_text (cmpl_state));
+ }
+ }
+ else
+ {
+ if (fs->selection_entry)
+ gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), rem_path);
+ }
+ }
+ else if (reset_entry)
+ {
+ if (fs->selection_entry)
+ gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), "");
+ }
+
+ if (!did_recurse)
+ {
+ if (fs->selection_entry && try_complete)
+ gtk_editable_set_position (GTK_EDITABLE (fs->selection_entry), -1);
+
+ if (fs->selection_entry)
+ {
+ char *escaped = escape_underscores (cmpl_reference_position (cmpl_state));
+ sel_text = g_strconcat (_("_Selection: "), escaped, NULL);
+ g_free (escaped);
+
+ gtk_label_set_text_with_mnemonic (GTK_LABEL (fs->selection_text), sel_text);
+ g_free (sel_text);
+ }
+
+ if (fs->history_pulldown)
+ {
+ gtk_file_selection_update_history_menu (fs, cmpl_reference_position (cmpl_state));
+ }
+
+ }
+}
+
+static void
+gtk_file_selection_abort (GtkFileSelection *fs)
+{
+ gchar err_buf[256];
+
+ g_snprintf (err_buf, sizeof (err_buf), _("Folder unreadable: %s"), cmpl_strerror (cmpl_errno));
+
+ /* BEEP gdk_beep(); */
+
+ if (fs->selection_entry)
+ gtk_label_set_text (GTK_LABEL (fs->selection_text), err_buf);
+}
+
+/**
+ * gtk_file_selection_set_select_multiple:
+ * @filesel: a #GtkFileSelection
+ * @select_multiple: whether or not the user is allowed to select multiple
+ * files in the file list.
+ *
+ * Sets whether the user is allowed to select multiple files in the file list.
+ * Use gtk_file_selection_get_selections () to get the list of selected files.
+ **/
+void
+gtk_file_selection_set_select_multiple (GtkFileSelection *filesel,
+ gboolean select_multiple)
+{
+ GtkTreeSelection *sel;
+ GtkSelectionMode mode;
+
+ g_return_if_fail (GTK_IS_FILE_SELECTION (filesel));
+
+ sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (filesel->file_list));
+
+ mode = select_multiple ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_SINGLE;
+
+ if (mode != gtk_tree_selection_get_mode (sel))
+ {
+ gtk_tree_selection_set_mode (sel, mode);
+
+ g_object_notify (G_OBJECT (filesel), "select-multiple");
+ }
+}
+
+/**
+ * gtk_file_selection_get_select_multiple:
+ * @filesel: a #GtkFileSelection
+ *
+ * Determines whether or not the user is allowed to select multiple files in
+ * the file list. See gtk_file_selection_set_select_multiple().
+ *
+ * Return value: %TRUE if the user is allowed to select multiple files in the
+ * file list
+ **/
+gboolean
+gtk_file_selection_get_select_multiple (GtkFileSelection *filesel)
+{
+ GtkTreeSelection *sel;
+
+ g_return_val_if_fail (GTK_IS_FILE_SELECTION (filesel), FALSE);
+
+ sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (filesel->file_list));
+ return (gtk_tree_selection_get_mode (sel) == GTK_SELECTION_MULTIPLE);
+}
+
+static void
+multiple_changed_foreach (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ GPtrArray *names = data;
+ gchar *filename;
+
+ gtk_tree_model_get (model, iter, FILE_COLUMN, &filename, -1);
+
+ g_ptr_array_add (names, filename);
+}
+
+static void
+free_selected_names (GPtrArray *names)
+{
+ gint i;
+
+ for (i = 0; i < names->len; i++)
+ g_free (g_ptr_array_index (names, i));
+
+ g_ptr_array_free (names, TRUE);
+}
+
+static void
+gtk_file_selection_file_changed (GtkTreeSelection *selection,
+ gpointer user_data)
+{
+ GtkFileSelection *fs = GTK_FILE_SELECTION (user_data);
+ GPtrArray *new_names;
+ gchar *filename;
+ const gchar *entry;
+ gint index = -1;
+
+ new_names = g_ptr_array_sized_new (8);
+
+ gtk_tree_selection_selected_foreach (selection,
+ multiple_changed_foreach,
+ new_names);
+
+ /* nothing selected */
+ if (new_names->len == 0)
+ {
+ g_ptr_array_free (new_names, TRUE);
+
+ if (fs->selected_names != NULL)
+ {
+ free_selected_names (fs->selected_names);
+ fs->selected_names = NULL;
+ }
+
+ goto maybe_clear_entry;
+ }
+
+ if (new_names->len != 1)
+ {
+ GPtrArray *old_names = fs->selected_names;
+
+ if (old_names != NULL)
+ {
+ /* A common case is selecting a range of files from top to bottom,
+ * so quickly check for that to avoid looping over the entire list
+ */
+ if (compare_utf8_filenames (g_ptr_array_index (old_names, old_names->len - 1),
+ g_ptr_array_index (new_names, new_names->len - 1)) != 0)
+ index = new_names->len - 1;
+ else
+ {
+ gint i = 0, j = 0, cmp;
+
+ /* do a quick diff, stopping at the first file not in the
+ * old list
+ */
+ while (i < old_names->len && j < new_names->len)