summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKristian Rietveld <kris@imendio.com>2006-05-01 21:41:12 +0000
committerKristian Rietveld <kristian@src.gnome.org>2006-05-01 21:41:12 +0000
commit2c97a8f6e8f260695515dabcb5185d0603dcd4f3 (patch)
tree68a070f95b168f8415fc6a438aa5436a9096716d
parent46789c877d6b4f73ca267bc78f31337be30ad889 (diff)
downloadgdk-pixbuf-AFTER_KRIS_ASYNC_BRANCH_MERGE.tar.gz
Merge of the GTK+ asynchronous file chooser branch. Please see theAFTER_KRIS_ASYNC_BRANCH_MERGE
2006-05-01 Kristian Rietveld <kris@imendio.com> Merge of the GTK+ asynchronous file chooser branch. Please see the kris-asynch-branch for more detailed ChangeLog entries. * configure.in: increase binary version to 2.9.0. * gtk.symbols: * gtkfilechooser.c: * gtkfilechooserbutton.c: * gtkfilechooserdefault.c: * gtkfilechooserdialog.c: * gtkfilechooserembed.c: * gtkfilechooserembed.h: * gtkfilechooserentry.c: * gtkfilechooserentry.h: * gtkfilechooserprivate.h: * gtkfilesystem.c: * gtkfilesystem.h: * gtkfilesystemmodel.c: * gtkfilesystemmodel.h: * gtkfilesystemunix.c: * gtkpathbar.c: * gtkpathbar.h: Merge from kris-async-branch.
-rw-r--r--ChangeLog26
-rw-r--r--ChangeLog.pre-2-1026
-rw-r--r--configure.in2
-rw-r--r--gtk/gtk.symbols7
-rw-r--r--gtk/gtkfilechooser.c3
-rw-r--r--gtk/gtkfilechooserbutton.c703
-rw-r--r--gtk/gtkfilechooserdefault.c1678
-rw-r--r--gtk/gtkfilechooserdialog.c43
-rw-r--r--gtk/gtkfilechooserembed.c18
-rw-r--r--gtk/gtkfilechooserembed.h1
-rw-r--r--gtk/gtkfilechooserentry.c134
-rw-r--r--gtk/gtkfilechooserentry.h2
-rw-r--r--gtk/gtkfilechooserprivate.h16
-rw-r--r--gtk/gtkfilesystem.c306
-rw-r--r--gtk/gtkfilesystem.h145
-rw-r--r--gtk/gtkfilesystemmodel.c610
-rw-r--r--gtk/gtkfilesystemmodel.h2
-rw-r--r--gtk/gtkfilesystemunix.c923
-rw-r--r--gtk/gtkpathbar.c387
-rw-r--r--gtk/gtkpathbar.h2
20 files changed, 3676 insertions, 1358 deletions
diff --git a/ChangeLog b/ChangeLog
index eabb68bae..d449ffc51 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,29 @@
+2006-05-01 Kristian Rietveld <kris@imendio.com>
+
+ Merge of the GTK+ asynchronous file chooser branch. Please see
+ the kris-asynch-branch for more detailed ChangeLog entries.
+
+ * configure.in: increase binary version to 2.9.0.
+
+ * gtk.symbols:
+ * gtkfilechooser.c:
+ * gtkfilechooserbutton.c:
+ * gtkfilechooserdefault.c:
+ * gtkfilechooserdialog.c:
+ * gtkfilechooserembed.c:
+ * gtkfilechooserembed.h:
+ * gtkfilechooserentry.c:
+ * gtkfilechooserentry.h:
+ * gtkfilechooserprivate.h:
+ * gtkfilesystem.c:
+ * gtkfilesystem.h:
+ * gtkfilesystemmodel.c:
+ * gtkfilesystemmodel.h:
+ * gtkfilesystemunix.c:
+ * gtkpathbar.c:
+ * gtkpathbar.h:
+ Merge from kris-async-branch.
+
2006-05-01 Matthias Clasen <mclasen@dhcp83-48.boston.redhat.com>
* NEWS: Updates
diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10
index eabb68bae..d449ffc51 100644
--- a/ChangeLog.pre-2-10
+++ b/ChangeLog.pre-2-10
@@ -1,3 +1,29 @@
+2006-05-01 Kristian Rietveld <kris@imendio.com>
+
+ Merge of the GTK+ asynchronous file chooser branch. Please see
+ the kris-asynch-branch for more detailed ChangeLog entries.
+
+ * configure.in: increase binary version to 2.9.0.
+
+ * gtk.symbols:
+ * gtkfilechooser.c:
+ * gtkfilechooserbutton.c:
+ * gtkfilechooserdefault.c:
+ * gtkfilechooserdialog.c:
+ * gtkfilechooserembed.c:
+ * gtkfilechooserembed.h:
+ * gtkfilechooserentry.c:
+ * gtkfilechooserentry.h:
+ * gtkfilechooserprivate.h:
+ * gtkfilesystem.c:
+ * gtkfilesystem.h:
+ * gtkfilesystemmodel.c:
+ * gtkfilesystemmodel.h:
+ * gtkfilesystemunix.c:
+ * gtkpathbar.c:
+ * gtkpathbar.h:
+ Merge from kris-async-branch.
+
2006-05-01 Matthias Clasen <mclasen@dhcp83-48.boston.redhat.com>
* NEWS: Updates
diff --git a/configure.in b/configure.in
index 857bf9d53..29f2d84fe 100644
--- a/configure.in
+++ b/configure.in
@@ -28,7 +28,7 @@ m4_define([gtk_api_version], [2.0])
# for GTK+.
#
#GTK_BINARY_VERSION=$GTK_MAJOR_VERSION.$GTK_MINOR_VERSION.$LT_CURRENT
-m4_define([gtk_binary_version], [2.4.0])
+m4_define([gtk_binary_version], [2.9.0])
# required versions of other packages
m4_define([glib_required_version], [2.10.1])
diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols
index e4fba9775..b55a6f9a3 100644
--- a/gtk/gtk.symbols
+++ b/gtk/gtk.symbols
@@ -1392,6 +1392,7 @@ gtk_file_info_copy
gtk_file_info_free
gtk_file_info_get_display_key
gtk_file_info_get_display_name
+gtk_file_info_get_icon_name
gtk_file_info_get_is_folder
gtk_file_info_get_is_hidden
gtk_file_info_get_mime_type
@@ -1399,7 +1400,9 @@ gtk_file_info_get_modification_time
gtk_file_info_get_size
gtk_file_info_get_type G_GNUC_CONST
gtk_file_info_new
+gtk_file_info_render_icon
gtk_file_info_set_display_name
+gtk_file_info_set_icon_name
gtk_file_info_set_is_folder
gtk_file_info_set_is_hidden
gtk_file_info_set_mime_type
@@ -1409,9 +1412,11 @@ gtk_file_path_get_type G_GNUC_CONST
gtk_file_paths_copy
gtk_file_paths_free
gtk_file_paths_sort
+gtk_file_system_cancel_operation
gtk_file_system_create_folder
gtk_file_system_error_quark
gtk_file_system_filename_to_path
+gtk_file_system_get_info
gtk_file_system_get_folder
gtk_file_system_get_parent
gtk_file_system_get_type G_GNUC_CONST
@@ -1425,11 +1430,11 @@ gtk_file_system_path_is_local
gtk_file_system_path_to_filename
gtk_file_system_path_to_uri
gtk_file_system_remove_bookmark
-gtk_file_system_render_icon
gtk_file_system_uri_to_path
gtk_file_system_volume_free
gtk_file_system_volume_get_base_path
gtk_file_system_volume_get_display_name
+gtk_file_system_volume_get_icon_name
gtk_file_system_volume_get_is_mounted
gtk_file_system_volume_mount
gtk_file_system_volume_render_icon
diff --git a/gtk/gtkfilechooser.c b/gtk/gtkfilechooser.c
index 3f9b943f8..55689952b 100644
--- a/gtk/gtkfilechooser.c
+++ b/gtk/gtkfilechooser.c
@@ -717,6 +717,9 @@ gtk_file_chooser_get_current_folder (GtkFileChooser *chooser)
file_system = _gtk_file_chooser_get_file_system (chooser);
path = _gtk_file_chooser_get_current_folder_path (chooser);
+ if (!path)
+ return NULL;
+
filename = gtk_file_system_path_to_filename (file_system, path);
gtk_file_path_free (path);
diff --git a/gtk/gtkfilechooserbutton.c b/gtk/gtkfilechooserbutton.c
index 390ded1b1..a3b202d0c 100644
--- a/gtk/gtkfilechooserbutton.c
+++ b/gtk/gtkfilechooserbutton.c
@@ -93,6 +93,8 @@ enum
DISPLAY_NAME_COLUMN,
TYPE_COLUMN,
DATA_COLUMN,
+ IS_FOLDER_COLUMN,
+ HANDLE_COLUMN,
NUM_COLUMNS
};
@@ -142,6 +144,10 @@ struct _GtkFileChooserButtonPrivate
gulong fs_volumes_changed_id;
gulong fs_bookmarks_changed_id;
+ GtkFileSystemHandle *dnd_select_folder_handle;
+ GtkFileSystemHandle *update_button_handle;
+ GSList *change_icon_theme_handles;
+
gint icon_size;
guint8 n_special;
@@ -229,8 +235,9 @@ static void gtk_file_chooser_button_screen_changed (GtkWidget *wi
/* Utility Functions */
static GtkIconTheme *get_icon_theme (GtkWidget *widget);
-static gchar *get_display_name_for_path (GtkFileSystem *fs,
- const GtkFilePath *path);
+static void set_info_for_path_at_iter (GtkFileChooserButton *fs,
+ const GtkFilePath *path,
+ GtkTreeIter *iter);
static gint model_get_type_position (GtkFileChooserButton *button,
RowType row_type);
@@ -451,7 +458,9 @@ gtk_file_chooser_button_init (GtkFileChooserButton *button)
GDK_TYPE_PIXBUF, /* Icon */
G_TYPE_STRING, /* Display Name */
G_TYPE_CHAR, /* Row Type */
- G_TYPE_POINTER /* Volume || Path */));
+ G_TYPE_POINTER /* Volume || Path */,
+ G_TYPE_BOOLEAN /* Is Folder? */,
+ G_TYPE_OBJECT /* handle */));
priv->combo_box = gtk_combo_box_new ();
priv->combo_box_changed_id =
@@ -519,30 +528,21 @@ gtk_file_chooser_button_add_shortcut_folder (GtkFileChooser *chooser,
GtkFileChooserButtonPrivate *priv = button->priv;
GtkTreeIter iter;
gint pos;
- GdkPixbuf *pixbuf;
- gchar *display_name;
pos = model_get_type_position (button, ROW_TYPE_SHORTCUT);
pos += priv->n_shortcuts;
- pixbuf = gtk_file_system_render_icon (priv->fs, path,
- GTK_WIDGET (chooser),
- priv->icon_size, NULL);
- display_name = get_display_name_for_path (priv->fs, path);
-
gtk_list_store_insert (GTK_LIST_STORE (priv->model), &iter, pos);
gtk_list_store_set (GTK_LIST_STORE (priv->model), &iter,
- ICON_COLUMN, pixbuf,
- DISPLAY_NAME_COLUMN, display_name,
+ ICON_COLUMN, NULL,
+ DISPLAY_NAME_COLUMN, _(FALLBACK_DISPLAY_NAME),
TYPE_COLUMN, ROW_TYPE_SHORTCUT,
DATA_COLUMN, gtk_file_path_copy (path),
+ IS_FOLDER_COLUMN, FALSE,
-1);
+ set_info_for_path_at_iter (button, path, &iter);
priv->n_shortcuts++;
- if (pixbuf)
- g_object_unref (pixbuf);
- g_free (display_name);
-
gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (priv->filter_model));
}
@@ -868,26 +868,10 @@ gtk_file_chooser_button_finalize (GObject *object)
{
GtkFileChooserButton *button = GTK_FILE_CHOOSER_BUTTON (object);
GtkFileChooserButtonPrivate *priv = button->priv;
- GtkTreeIter iter;
if (priv->old_path)
gtk_file_path_free (priv->old_path);
- gtk_tree_model_get_iter_first (priv->model, &iter);
-
- do
- {
- model_free_row_data (button, &iter);
- }
- while (gtk_tree_model_iter_next (priv->model, &iter));
-
- g_object_unref (priv->model);
- g_object_unref (priv->filter_model);
-
- g_signal_handler_disconnect (priv->fs, priv->fs_volumes_changed_id);
- g_signal_handler_disconnect (priv->fs, priv->fs_bookmarks_changed_id);
- g_object_unref (priv->fs);
-
if (G_OBJECT_CLASS (gtk_file_chooser_button_parent_class)->finalize != NULL)
(*G_OBJECT_CLASS (gtk_file_chooser_button_parent_class)->finalize) (object);
}
@@ -901,9 +885,65 @@ gtk_file_chooser_button_destroy (GtkObject *object)
{
GtkFileChooserButton *button = GTK_FILE_CHOOSER_BUTTON (object);
GtkFileChooserButtonPrivate *priv = button->priv;
+ GtkTreeIter iter;
+ GSList *l;
if (priv->dialog != NULL)
- gtk_widget_destroy (priv->dialog);
+ {
+ gtk_widget_destroy (priv->dialog);
+ priv->dialog = NULL;
+ }
+
+ gtk_tree_model_get_iter_first (priv->model, &iter);
+
+ do
+ {
+ model_free_row_data (button, &iter);
+ }
+ while (gtk_tree_model_iter_next (priv->model, &iter));
+
+ if (priv->dnd_select_folder_handle)
+ {
+ gtk_file_system_cancel_operation (priv->dnd_select_folder_handle);
+ priv->dnd_select_folder_handle = NULL;
+ }
+
+ if (priv->update_button_handle)
+ {
+ gtk_file_system_cancel_operation (priv->update_button_handle);
+ priv->update_button_handle = NULL;
+ }
+
+ if (priv->change_icon_theme_handles)
+ {
+ for (l = priv->change_icon_theme_handles; l; l = l->next)
+ {
+ GtkFileSystemHandle *handle = GTK_FILE_SYSTEM_HANDLE (l->data);
+ gtk_file_system_cancel_operation (handle);
+ }
+ g_slist_free (priv->change_icon_theme_handles);
+ priv->change_icon_theme_handles = NULL;
+ }
+
+ if (priv->model)
+ {
+ g_object_unref (priv->model);
+ priv->model = NULL;
+ }
+
+ if (priv->filter_model)
+ {
+ g_object_unref (priv->filter_model);
+ priv->filter_model = NULL;
+ }
+
+ if (priv->fs)
+ {
+ g_signal_handler_disconnect (priv->fs, priv->fs_volumes_changed_id);
+ g_signal_handler_disconnect (priv->fs, priv->fs_bookmarks_changed_id);
+ g_object_unref (priv->fs);
+ priv->fs = NULL;
+ }
if (GTK_OBJECT_CLASS (gtk_file_chooser_button_parent_class)->destroy != NULL)
(*GTK_OBJECT_CLASS (gtk_file_chooser_button_parent_class)->destroy) (object);
@@ -914,6 +954,76 @@ gtk_file_chooser_button_destroy (GtkObject *object)
* GtkWidget Functions *
* ********************* */
+struct DndSelectFolderData
+{
+ GtkFileChooserButton *button;
+ GtkFileChooserAction action;
+ GtkFilePath *path;
+ gchar **uris;
+ guint i;
+ gboolean selected;
+};
+
+static void
+dnd_select_folder_get_info_cb (GtkFileSystemHandle *handle,
+ const GtkFileInfo *info,
+ const GError *error,
+ gpointer user_data)
+{
+ gboolean cancelled = handle->cancelled;
+ struct DndSelectFolderData *data = user_data;
+
+ if (handle != data->button->priv->dnd_select_folder_handle)
+ {
+ g_object_unref (data->button);
+ gtk_file_path_free (data->path);
+ g_strfreev (data->uris);
+ g_free (data);
+
+ g_object_unref (handle);
+ return;
+ }
+
+ data->button->priv->dnd_select_folder_handle = NULL;
+
+ if (!cancelled && !error && info != NULL)
+ {
+ data->selected =
+ (((data->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER &&
+ gtk_file_info_get_is_folder (info)) ||
+ (data->action == GTK_FILE_CHOOSER_ACTION_OPEN &&
+ !gtk_file_info_get_is_folder (info))) &&
+ _gtk_file_chooser_select_path (GTK_FILE_CHOOSER (data->button->priv->dialog),
+ data->path, NULL));
+ }
+ else
+ data->selected = FALSE;
+
+ if (data->selected || data->uris[++data->i] == NULL)
+ {
+ g_object_unref (data->button);
+ gtk_file_path_free (data->path);
+ g_strfreev (data->uris);
+ g_free (data);
+
+ g_object_unref (handle);
+ return;
+ }
+
+ if (data->path)
+ gtk_file_path_free (data->path);
+
+ data->path = gtk_file_system_uri_to_path (handle->file_system,
+ data->uris[data->i]);
+
+ data->button->priv->dnd_select_folder_handle =
+ gtk_file_system_get_info (handle->file_system, data->path,
+ GTK_FILE_INFO_IS_FOLDER,
+ dnd_select_folder_get_info_cb, user_data);
+
+ g_object_unref (handle);
+}
+
static void
gtk_file_chooser_button_drag_data_received (GtkWidget *widget,
GdkDragContext *context,
@@ -943,59 +1053,30 @@ gtk_file_chooser_button_drag_data_received (GtkWidget *widget,
case TEXT_URI_LIST:
{
gchar **uris;
- GtkFilePath *base_path;
- guint i;
- gboolean selected;
+ struct DndSelectFolderData *info;
uris = gtk_selection_data_get_uris (data);
if (uris == NULL)
break;
- selected = FALSE;
- for (i = 0; !selected && uris[i] != NULL; i++)
- {
- path = gtk_file_system_uri_to_path (priv->fs, uris[i]);
-
- base_path = NULL;
- if (path != NULL &&
- gtk_file_system_get_parent (priv->fs, path, &base_path, NULL))
- {
- GtkFileFolder *folder;
- GtkFileInfo *info;
-
- folder = gtk_file_system_get_folder (priv->fs, base_path,
- GTK_FILE_INFO_IS_FOLDER,
- NULL);
-
- info = gtk_file_folder_get_info (folder, path, NULL);
-
- if (info != NULL)
- {
- GtkFileChooserAction action;
+ info = g_new0 (struct DndSelectFolderData, 1);
+ info->button = g_object_ref (button);
+ info->i = 0;
+ info->uris = uris;
+ info->selected = FALSE;
+ g_object_get (priv->dialog, "action", &info->action, NULL);
- g_object_get (priv->dialog, "action", &action, NULL);
-
- selected =
- (((action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER &&
- gtk_file_info_get_is_folder (info)) ||
- (action == GTK_FILE_CHOOSER_ACTION_OPEN &&
- !gtk_file_info_get_is_folder (info))) &&
- _gtk_file_chooser_select_path (GTK_FILE_CHOOSER (priv->dialog),
- path, NULL));
-
- gtk_file_info_free (info);
- }
- else
- selected = FALSE;
-
- gtk_file_path_free (base_path);
- }
+ info->path = gtk_file_system_uri_to_path (priv->fs,
+ info->uris[info->i]);
- gtk_file_path_free (path);
- }
+ if (priv->dnd_select_folder_handle)
+ gtk_file_system_cancel_operation (priv->dnd_select_folder_handle);
- g_strfreev (uris);
+ priv->dnd_select_folder_handle =
+ gtk_file_system_get_info (priv->fs, info->path,
+ GTK_FILE_INFO_IS_FOLDER,
+ dnd_select_folder_get_info_cb, info);
}
break;
@@ -1096,6 +1177,64 @@ gtk_file_chooser_button_mnemonic_activate (GtkWidget *widget,
}
/* Changes the icons wherever it is needed */
+struct ChangeIconThemeData
+{
+ GtkFileChooserButton *button;
+ GtkTreeRowReference *row_ref;
+};
+
+static void
+change_icon_theme_get_info_cb (GtkFileSystemHandle *handle,
+ const GtkFileInfo *info,
+ const GError *error,
+ gpointer user_data)
+{
+ gboolean cancelled = handle->cancelled;
+ GdkPixbuf *pixbuf;
+ struct ChangeIconThemeData *data = user_data;
+
+ if (!g_slist_find (data->button->priv->change_icon_theme_handles, handle))
+ goto out;
+
+ data->button->priv->change_icon_theme_handles =
+ g_slist_remove (data->button->priv->change_icon_theme_handles, handle);
+
+ if (cancelled || error)
+ goto out;
+
+ pixbuf = gtk_file_info_render_icon (info, GTK_WIDGET (data->button),
+ data->button->priv->icon_size, NULL);
+
+ if (pixbuf)
+ {
+ gint width = 0;
+ GtkTreeIter iter;
+ GtkTreePath *path;
+
+ width = MAX (width, gdk_pixbuf_get_width (pixbuf));
+
+ path = gtk_tree_row_reference_get_path (data->row_ref);
+ gtk_tree_model_get_iter (data->button->priv->model, &iter, path);
+ gtk_tree_path_free (path);
+
+ gtk_list_store_set (GTK_LIST_STORE (data->button->priv->model), &iter,
+ ICON_COLUMN, pixbuf,
+ -1);
+ g_object_unref (pixbuf);
+
+ g_object_set (data->button->priv->icon_cell,
+ "width", width,
+ NULL);
+ }
+
+out:
+ g_object_unref (data->button);
+ gtk_tree_row_reference_free (data->row_ref);
+ g_free (data);
+
+ g_object_unref (handle);
+}
+
static void
change_icon_theme (GtkFileChooserButton *button)
{
@@ -1103,7 +1242,16 @@ change_icon_theme (GtkFileChooserButton *button)
GtkSettings *settings;
GtkIconTheme *theme;
GtkTreeIter iter;
- gint width, height;
+ GSList *l;
+ gint width = 0, height = 0;
+
+ for (l = button->priv->change_icon_theme_handles; l; l = l->next)
+ {
+ GtkFileSystemHandle *handle = GTK_FILE_SYSTEM_HANDLE (l->data);
+ gtk_file_system_cancel_operation (handle);
+ }
+ g_slist_free (button->priv->change_icon_theme_handles);
+ button->priv->change_icon_theme_handles = NULL;
settings = gtk_settings_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (button)));
@@ -1138,9 +1286,25 @@ change_icon_theme (GtkFileChooserButton *button)
case ROW_TYPE_BOOKMARK:
case ROW_TYPE_CURRENT_FOLDER:
if (data)
- pixbuf = gtk_file_system_render_icon (priv->fs, data,
- GTK_WIDGET (button),
- priv->icon_size, NULL);
+ {
+ GtkTreePath *path;
+ GtkFileSystemHandle *handle;
+ struct ChangeIconThemeData *info;
+
+ info = g_new0 (struct ChangeIconThemeData, 1);
+ info->button = g_object_ref (button);
+ path = gtk_tree_model_get_path (priv->model, &iter);
+ info->row_ref = gtk_tree_row_reference_new (priv->model, path);
+ gtk_tree_path_free (path);
+
+ handle =
+ gtk_file_system_get_info (priv->fs, data, GTK_FILE_INFO_ICON,
+ change_icon_theme_get_info_cb,
+ info);
+ button->priv->change_icon_theme_handles =
+ g_slist_append (button->priv->change_icon_theme_handles, handle);
+ pixbuf = NULL;
+ }
else
pixbuf = gtk_icon_theme_load_icon (theme, FALLBACK_ICON_NAME,
priv->icon_size, 0, NULL);
@@ -1215,43 +1379,92 @@ get_icon_theme (GtkWidget *widget)
return gtk_icon_theme_get_default ();
}
-static gchar *
-get_display_name_for_path (GtkFileSystem *fs,
- const GtkFilePath *path)
+
+struct SetDisplayNameData
{
- GtkFilePath *parent_path;
- GtkFileFolder *folder;
- gchar *retval;
+ GtkFileChooserButton *button;
+ GtkTreeRowReference *row_ref;
+};
- parent_path = NULL;
- retval = NULL;
+static void
+set_info_get_info_cb (GtkFileSystemHandle *handle,
+ const GtkFileInfo *info,
+ const GError *error,
+ gpointer callback_data)
+{
+ gboolean cancelled = handle->cancelled;
+ GdkPixbuf *pixbuf;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ GtkFileSystemHandle *model_handle;
+ struct SetDisplayNameData *data = callback_data;
- gtk_file_system_get_parent (fs, path, &parent_path, NULL);
+ path = gtk_tree_row_reference_get_path (data->row_ref);
+ if (!path)
+ /* Handle doesn't exist anymore in the model */
+ goto out;
- folder = gtk_file_system_get_folder (fs, parent_path ? parent_path : path,
- GTK_FILE_INFO_DISPLAY_NAME, NULL);
+ gtk_tree_model_get_iter (data->button->priv->model, &iter, path);
+ gtk_tree_path_free (path);
- if (folder)
- {
- GtkFileInfo *info;
+ /* Validate the handle */
+ gtk_tree_model_get (data->button->priv->model, &iter,
+ HANDLE_COLUMN, &model_handle,
+ -1);
+ if (handle != model_handle)
+ goto out;
+
+ gtk_list_store_set (GTK_LIST_STORE (data->button->priv->model), &iter,
+ HANDLE_COLUMN, NULL,
+ -1);
- info = gtk_file_folder_get_info (folder, path, NULL);
- g_object_unref (folder);
+ if (cancelled || error)
+ /* There was an error, leave the fallback name in there */
+ goto out;
- if (info)
- {
- retval = g_strdup (gtk_file_info_get_display_name (info));
- gtk_file_info_free (info);
- }
- }
+ pixbuf = gtk_file_info_render_icon (info, GTK_WIDGET (data->button),
+ data->button->priv->icon_size, NULL);
- if (parent_path)
- gtk_file_path_free (parent_path);
+ gtk_list_store_set (GTK_LIST_STORE (data->button->priv->model), &iter,
+ ICON_COLUMN, pixbuf,
+ DISPLAY_NAME_COLUMN, gtk_file_info_get_display_name (info),
+ IS_FOLDER_COLUMN, gtk_file_info_get_is_folder (info),
+ -1);
+
+ if (pixbuf)
+ g_object_unref (pixbuf);
- if (!retval)
- retval = g_strdup (_(FALLBACK_DISPLAY_NAME));
+out:
+ g_object_unref (data->button);
+ gtk_tree_row_reference_free (data->row_ref);
+ g_free (data);
- return retval;
+ g_object_unref (handle);
+}
+
+static void
+set_info_for_path_at_iter (GtkFileChooserButton *button,
+ const GtkFilePath *path,
+ GtkTreeIter *iter)
+{
+ struct SetDisplayNameData *data;
+ GtkTreePath *tree_path;
+ GtkFileSystemHandle *handle;
+
+ data = g_new0 (struct SetDisplayNameData, 1);
+ data->button = g_object_ref (button);
+
+ tree_path = gtk_tree_model_get_path (button->priv->model, iter);
+ data->row_ref = gtk_tree_row_reference_new (button->priv->model, tree_path);
+ gtk_tree_path_free (tree_path);
+
+ handle = gtk_file_system_get_info (button->priv->fs, path,
+ GTK_FILE_INFO_DISPLAY_NAME | GTK_FILE_INFO_IS_FOLDER | GTK_FILE_INFO_ICON,
+ set_info_get_info_cb, data);
+
+ gtk_list_store_set (GTK_LIST_STORE (button->priv->model), iter,
+ HANDLE_COLUMN, handle,
+ -1);
}
/* Shortcuts Model */
@@ -1314,12 +1527,17 @@ model_free_row_data (GtkFileChooserButton *button,
{
gchar type;
gpointer data;
+ GtkFileSystemHandle *handle;
gtk_tree_model_get (button->priv->model, iter,
TYPE_COLUMN, &type,
DATA_COLUMN, &data,
+ HANDLE_COLUMN, &handle,
-1);
+ if (handle)
+ gtk_file_system_cancel_operation (handle);
+
switch (type)
{
case ROW_TYPE_SPECIAL:
@@ -1336,16 +1554,70 @@ model_free_row_data (GtkFileChooserButton *button,
}
}
+static void
+model_add_special_get_info_cb (GtkFileSystemHandle *handle,
+ const GtkFileInfo *info,
+ const GError *error,
+ gpointer user_data)
+{
+ gboolean cancelled = handle->cancelled;
+ GtkTreeIter iter;
+ GtkTreePath *path;
+ GdkPixbuf *pixbuf;
+ GtkFileSystemHandle *model_handle;
+ struct ChangeIconThemeData *data = user_data;
+
+ path = gtk_tree_row_reference_get_path (data->row_ref);
+ if (!path)
+ /* Handle doesn't exist anymore in the model */
+ goto out;
+
+ gtk_tree_model_get_iter (data->button->priv->model, &iter, path);
+ gtk_tree_path_free (path);
+
+ gtk_tree_model_get (data->button->priv->model, &iter,
+ HANDLE_COLUMN, &model_handle,
+ -1);
+ if (handle != model_handle)
+ goto out;
+
+ gtk_list_store_set (GTK_LIST_STORE (data->button->priv->model), &iter,
+ HANDLE_COLUMN, NULL,
+ -1);
+
+ if (cancelled || error)
+ goto out;
+
+ pixbuf = gtk_file_info_render_icon (info, GTK_WIDGET (data->button),
+ data->button->priv->icon_size, NULL);
+
+ if (pixbuf)
+ {
+ gtk_list_store_set (GTK_LIST_STORE (data->button->priv->model), &iter,
+ ICON_COLUMN, pixbuf,
+ -1);
+ g_object_unref (pixbuf);
+ }
+
+ gtk_list_store_set (GTK_LIST_STORE (data->button->priv->model), &iter,
+ DISPLAY_NAME_COLUMN, gtk_file_info_get_display_name (info),
+ -1);
+
+out:
+ gtk_tree_row_reference_free (data->row_ref);
+ g_free (data);
+
+ g_object_unref (handle);
+}
+
static inline void
model_add_special (GtkFileChooserButton *button)
{
const gchar *homedir;
- const gchar *display_name;
gchar *desktopdir = NULL;
GtkListStore *store;
GtkTreeIter iter;
GtkFilePath *path;
- GdkPixbuf *pixbuf;
gint pos;
store = GTK_LIST_STORE (button->priv->model);
@@ -1355,23 +1627,34 @@ model_add_special (GtkFileChooserButton *button)
if (homedir)
{
+ GtkTreePath *tree_path;
+ GtkFileSystemHandle *handle;
+ struct ChangeIconThemeData *info;
+
path = gtk_file_system_filename_to_path (button->priv->fs, homedir);
- display_name = get_display_name_for_path (button->priv->fs, path);
- pixbuf = gtk_file_system_render_icon (button->priv->fs, path,
- GTK_WIDGET (button),
- button->priv->icon_size, NULL);
gtk_list_store_insert (store, &iter, pos);
pos++;
+
+ info = g_new0 (struct ChangeIconThemeData, 1);
+ info->button = g_object_ref (button);
+ tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
+ info->row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (store),
+ tree_path);
+ gtk_tree_path_free (tree_path);
+
+ handle = gtk_file_system_get_info (button->priv->fs, path,
+ GTK_FILE_INFO_ICON,
+ model_add_special_get_info_cb, info);
+
gtk_list_store_set (store, &iter,
- ICON_COLUMN, pixbuf,
- DISPLAY_NAME_COLUMN, display_name,
+ ICON_COLUMN, NULL,
+ DISPLAY_NAME_COLUMN, NULL,
TYPE_COLUMN, ROW_TYPE_SPECIAL,
DATA_COLUMN, path,
+ IS_FOLDER_COLUMN, TRUE,
+ HANDLE_COLUMN, handle,
-1);
- if (pixbuf)
- g_object_unref (pixbuf);
- g_free (display_name);
button->priv->n_special++;
#ifndef G_OS_WIN32
@@ -1385,22 +1668,34 @@ model_add_special (GtkFileChooserButton *button)
if (desktopdir)
{
+ GtkTreePath *tree_path;
+ GtkFileSystemHandle *handle;
+ struct ChangeIconThemeData *info;
+
path = gtk_file_system_filename_to_path (button->priv->fs, desktopdir);
g_free (desktopdir);
- pixbuf = gtk_file_system_render_icon (button->priv->fs, path,
- GTK_WIDGET (button),
- button->priv->icon_size, NULL);
gtk_list_store_insert (store, &iter, pos);
pos++;
+
+ info = g_new0 (struct ChangeIconThemeData, 1);
+ info->button = g_object_ref (button);
+ tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
+ info->row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (store),
+ tree_path);
+ gtk_tree_path_free (tree_path);
+
+ handle = gtk_file_system_get_info (button->priv->fs, path,
+ GTK_FILE_INFO_ICON,
+ model_add_special_get_info_cb, info);
+
gtk_list_store_set (store, &iter,
TYPE_COLUMN, ROW_TYPE_SPECIAL,
- ICON_COLUMN, pixbuf,
+ ICON_COLUMN, NULL,
DISPLAY_NAME_COLUMN, _(DESKTOP_DISPLAY_NAME),
DATA_COLUMN, path,
+ IS_FOLDER_COLUMN, TRUE,
-1);
- if (pixbuf)
- g_object_unref (pixbuf);
button->priv->n_special++;
}
}
@@ -1438,6 +1733,7 @@ model_add_volumes (GtkFileChooserButton *button,
DISPLAY_NAME_COLUMN, display_name,
TYPE_COLUMN, ROW_TYPE_VOLUME,
DATA_COLUMN, volumes->data,
+ IS_FOLDER_COLUMN, TRUE,
-1);
if (pixbuf)
@@ -1473,32 +1769,24 @@ model_add_bookmarks (GtkFileChooserButton *button,
DISPLAY_NAME_COLUMN, NULL,
TYPE_COLUMN, ROW_TYPE_BOOKMARK_SEPARATOR,
DATA_COLUMN, NULL,
+ IS_FOLDER_COLUMN, FALSE,
-1);
button->priv->has_bookmark_separator = TRUE;
}
do
{
- GdkPixbuf *pixbuf;
- gchar *display_name;
-
pos++;
- pixbuf = gtk_file_system_render_icon (button->priv->fs, bookmarks->data,
- GTK_WIDGET (button),
- button->priv->icon_size, NULL);
- display_name = get_display_name_for_path (button->priv->fs,
- bookmarks->data);
gtk_list_store_insert (store, &iter, pos);
gtk_list_store_set (store, &iter,
- ICON_COLUMN, pixbuf,
- DISPLAY_NAME_COLUMN, display_name,
+ ICON_COLUMN, NULL,
+ DISPLAY_NAME_COLUMN, _(FALLBACK_DISPLAY_NAME),
TYPE_COLUMN, ROW_TYPE_BOOKMARK,
DATA_COLUMN, gtk_file_path_copy (bookmarks->data),
+ IS_FOLDER_COLUMN, FALSE,
-1);
- if (pixbuf)
- g_object_unref (pixbuf);
- g_free (display_name);
+ set_info_for_path_at_iter (button, bookmarks->data, &iter);
button->priv->n_bookmarks++;
bookmarks = bookmarks->next;
@@ -1513,8 +1801,6 @@ model_update_current_folder (GtkFileChooserButton *button,
GtkListStore *store;
GtkTreeIter iter;
gint pos;
- GdkPixbuf *pixbuf;
- gchar *display_name;
if (!path)
return;
@@ -1530,6 +1816,7 @@ model_update_current_folder (GtkFileChooserButton *button,
DISPLAY_NAME_COLUMN, NULL,
TYPE_COLUMN, ROW_TYPE_CURRENT_FOLDER_SEPARATOR,
DATA_COLUMN, NULL,
+ IS_FOLDER_COLUMN, FALSE,
-1);
button->priv->has_current_folder_separator = TRUE;
}
@@ -1546,19 +1833,14 @@ model_update_current_folder (GtkFileChooserButton *button,
model_free_row_data (button, &iter);
}
- pixbuf = gtk_file_system_render_icon (button->priv->fs, path,
- GTK_WIDGET (button),
- button->priv->icon_size, NULL);
- display_name = get_display_name_for_path (button->priv->fs, path);
gtk_list_store_set (store, &iter,
- ICON_COLUMN, pixbuf,
- DISPLAY_NAME_COLUMN, display_name,
+ ICON_COLUMN, NULL,
+ DISPLAY_NAME_COLUMN, _(FALLBACK_DISPLAY_NAME),
TYPE_COLUMN, ROW_TYPE_CURRENT_FOLDER,
DATA_COLUMN, gtk_file_path_copy (path),
+ IS_FOLDER_COLUMN, FALSE,
-1);
- if (pixbuf)
- g_object_unref (pixbuf);
- g_free (display_name);
+ set_info_for_path_at_iter (button, path, &iter);
}
static inline void
@@ -1577,6 +1859,7 @@ model_add_other (GtkFileChooserButton *button)
DISPLAY_NAME_COLUMN, NULL,
TYPE_COLUMN, ROW_TYPE_OTHER_SEPARATOR,
DATA_COLUMN, NULL,
+ IS_FOLDER_COLUMN, FALSE,
-1);
button->priv->has_other_separator = TRUE;
pos++;
@@ -1587,6 +1870,7 @@ model_add_other (GtkFileChooserButton *button)
DISPLAY_NAME_COLUMN, _("Other..."),
TYPE_COLUMN, ROW_TYPE_OTHER,
DATA_COLUMN, NULL,
+ IS_FOLDER_COLUMN, FALSE,
-1);
}
@@ -1620,42 +1904,17 @@ model_remove_rows (GtkFileChooserButton *button,
static inline gboolean
test_if_path_is_visible (GtkFileSystem *fs,
const GtkFilePath *path,
- gboolean local_only)
+ gboolean local_only,
+ gboolean is_folder)
{
- GtkFilePath *parent_path;
- GtkFileFolder *folder;
- GtkFileInfo *info;
-
if (!path)
return FALSE;
if (local_only && !gtk_file_system_path_is_local (fs, path))
return FALSE;
- parent_path = NULL;
- gtk_file_system_get_parent (fs, path, &parent_path, NULL);
-
- folder = gtk_file_system_get_folder (fs, parent_path ? parent_path : path,
- GTK_FILE_INFO_IS_FOLDER, NULL);
- gtk_file_path_free (parent_path);
-
- if (folder)
- {
- info = gtk_file_folder_get_info (folder, path, NULL);
- g_object_unref (folder);
- }
- else
- info = NULL;
-
- if (!info)
+ if (!is_folder)
return FALSE;
- else if (!gtk_file_info_get_is_folder (info))
- {
- gtk_file_info_free (info);
- return FALSE;
- }
-
- gtk_file_info_free (info);
return TRUE;
}
@@ -1669,7 +1928,7 @@ filter_model_visible_func (GtkTreeModel *model,
GtkFileChooserButtonPrivate *priv = button->priv;
gchar type;
gpointer data;
- gboolean local_only, retval;
+ gboolean local_only, retval, is_folder;
type = ROW_TYPE_INVALID;
data = NULL;
@@ -1678,6 +1937,7 @@ filter_model_visible_func (GtkTreeModel *model,
gtk_tree_model_get (model, iter,
TYPE_COLUMN, &type,
DATA_COLUMN, &data,
+ IS_FOLDER_COLUMN, &is_folder,
-1);
switch (type)
@@ -1688,7 +1948,7 @@ filter_model_visible_func (GtkTreeModel *model,
case ROW_TYPE_SPECIAL:
case ROW_TYPE_SHORTCUT:
case ROW_TYPE_BOOKMARK:
- retval = test_if_path_is_visible (priv->fs, data, local_only);
+ retval = test_if_path_is_visible (priv->fs, data, local_only, is_folder);
break;
case ROW_TYPE_VOLUME:
{
@@ -1837,6 +2097,43 @@ update_combo_box (GtkFileChooserButton *button)
/* Button */
static void
+update_label_get_info_cb (GtkFileSystemHandle *handle,
+ const GtkFileInfo *info,
+ const GError *error,
+ gpointer data)
+{
+ gboolean cancelled = handle->cancelled;
+ GdkPixbuf *pixbuf;
+ GtkFileChooserButton *button = data;
+ GtkFileChooserButtonPrivate *priv = button->priv;
+
+ if (handle != priv->update_button_handle)
+ goto out;
+
+ priv->update_button_handle = NULL;
+
+ if (cancelled || error)
+ goto out;
+
+ gtk_label_set_text (GTK_LABEL (priv->label), gtk_file_info_get_display_name (info));
+
+ pixbuf = gtk_file_info_render_icon (info, GTK_WIDGET (priv->image),
+ priv->icon_size, NULL);
+ if (!pixbuf)
+ pixbuf = gtk_icon_theme_load_icon (get_icon_theme (GTK_WIDGET (priv->image)),
+ FALLBACK_ICON_NAME,
+ priv->icon_size, 0, NULL);
+
+ gtk_image_set_from_pixbuf (GTK_IMAGE (priv->image), pixbuf);
+ if (pixbuf)
+ g_object_unref (pixbuf);
+
+out:
+ g_object_unref (button);
+ g_object_unref (handle);
+}
+
+static void
update_label_and_image (GtkFileChooserButton *button)
{
GtkFileChooserButtonPrivate *priv = button->priv;
@@ -1848,11 +2145,10 @@ update_label_and_image (GtkFileChooserButton *button)
label_text = NULL;
pixbuf = NULL;
- if (paths)
+ if (paths && paths->data)
{
- GtkFilePath *path, *parent_path;
- GtkFileSystemVolume *volume;
- GtkFileFolder *folder;
+ GtkFilePath *path;
+ GtkFileSystemVolume *volume = NULL;
path = paths->data;
@@ -1881,32 +2177,14 @@ update_label_and_image (GtkFileChooserButton *button)
goto out;
}
- if (!pixbuf)
- pixbuf = gtk_file_system_render_icon (priv->fs, path,
- GTK_WIDGET (button),
- priv->icon_size, NULL);
+ if (priv->update_button_handle)
+ gtk_file_system_cancel_operation (priv->update_button_handle);
- parent_path = NULL;
- gtk_file_system_get_parent (priv->fs, path, &parent_path, NULL);
-
- folder = gtk_file_system_get_folder (priv->fs,
- parent_path ? parent_path : path,
- GTK_FILE_INFO_DISPLAY_NAME, NULL);
- gtk_file_path_free (parent_path);
-
- if (folder)
- {
- GtkFileInfo *info;
-
- info = gtk_file_folder_get_info (folder, path, NULL);
- g_object_unref (folder);
-
- if (info)
- {
- label_text = g_strdup (gtk_file_info_get_display_name (info));
- gtk_file_info_free (info);
- }
- }
+ priv->update_button_handle =
+ gtk_file_system_get_info (priv->fs, path,
+ GTK_FILE_INFO_DISPLAY_NAME | GTK_FILE_INFO_ICON,
+ update_label_get_info_cb,
+ g_object_ref (button));
out:
gtk_file_paths_free (paths);
@@ -1919,15 +2197,6 @@ update_label_and_image (GtkFileChooserButton *button)
}
else
gtk_label_set_text (GTK_LABEL (priv->label), _(FALLBACK_DISPLAY_NAME));
-
- if (!pixbuf)
- pixbuf = gtk_icon_theme_load_icon (get_icon_theme (GTK_WIDGET (button)),
- FALLBACK_ICON_NAME,
- priv->icon_size, 0, NULL);
-
- gtk_image_set_from_pixbuf (GTK_IMAGE (priv->image), pixbuf);
- if (pixbuf)
- g_object_unref (pixbuf);
}
diff --git a/gtk/gtkfilechooserdefault.c b/gtk/gtkfilechooserdefault.c
index b78370a64..27a7df701 100644
--- a/gtk/gtkfilechooserdefault.c
+++ b/gtk/gtkfilechooserdefault.c
@@ -170,6 +170,7 @@ enum {
SHORTCUTS_COL_IS_VOLUME,
SHORTCUTS_COL_REMOVABLE,
SHORTCUTS_COL_PIXBUF_VISIBLE,
+ SHORTCUTS_COL_HANDLE,
SHORTCUTS_COL_NUM_COLUMNS
};
@@ -379,6 +380,8 @@ static void add_bookmark_button_clicked_cb (GtkButton *button,
GtkFileChooserDefault *impl);
static void remove_bookmark_button_clicked_cb (GtkButton *button,
GtkFileChooserDefault *impl);
+static void save_folder_combo_changed_cb (GtkComboBox *combo,
+ GtkFileChooserDefault *impl);
static void list_icon_data_func (GtkTreeViewColumn *tree_column,
GtkCellRenderer *cell,
@@ -699,11 +702,17 @@ shortcuts_free_row_data (GtkFileChooserDefault *impl,
{
gpointer col_data;
gboolean is_volume;
+ GtkFileSystemHandle *handle;
gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), iter,
SHORTCUTS_COL_DATA, &col_data,
SHORTCUTS_COL_IS_VOLUME, &is_volume,
+ SHORTCUTS_COL_HANDLE, &handle,
-1);
+
+ if (handle)
+ gtk_file_system_cancel_operation (handle);
+
if (!col_data)
return;
@@ -809,10 +818,6 @@ gtk_file_chooser_default_finalize (GObject *object)
shortcuts_free (impl);
- g_signal_handler_disconnect (impl->file_system, impl->volumes_changed_id);
- impl->volumes_changed_id = 0;
- g_signal_handler_disconnect (impl->file_system, impl->bookmarks_changed_id);
- impl->bookmarks_changed_id = 0;
g_object_unref (impl->file_system);
for (l = impl->filters; l; l = l->next)
@@ -836,8 +841,6 @@ gtk_file_chooser_default_finalize (GObject *object)
if (impl->preview_path)
gtk_file_path_free (impl->preview_path);
- pending_select_paths_free (impl);
-
load_remove_timer (impl);
/* Free all the Models we have */
@@ -1099,9 +1102,57 @@ set_preview_widget (GtkFileChooserDefault *impl,
}
/* Re-reads all the icons for the shortcuts, used when the theme changes */
+struct ReloadIconsData
+{
+ GtkFileChooserDefault *impl;
+ GtkTreeRowReference *row_ref;
+};
+
+static void
+shortcuts_reload_icons_get_info_cb (GtkFileSystemHandle *handle,
+ const GtkFileInfo *info,
+ const GError *error,
+ gpointer user_data)
+{
+ GdkPixbuf *pixbuf;
+ GtkTreeIter iter;
+ GtkTreePath *path;
+ gboolean cancelled = handle->cancelled;
+ struct ReloadIconsData *data = user_data;
+
+ if (!g_slist_find (data->impl->reload_icon_handles, handle))
+ goto out;
+
+ data->impl->reload_icon_handles = g_slist_remove (data->impl->reload_icon_handles, handle);
+
+ if (cancelled || error)
+ goto out;
+
+ pixbuf = gtk_file_info_render_icon (info, GTK_WIDGET (data->impl),
+ data->impl->icon_size, NULL);
+
+ path = gtk_tree_row_reference_get_path (data->row_ref);
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (data->impl->shortcuts_model), &iter, path);
+ gtk_list_store_set (data->impl->shortcuts_model, &iter,
+ SHORTCUTS_COL_PIXBUF, pixbuf,
+ -1);
+ gtk_tree_path_free (path);
+
+ if (pixbuf)
+ g_object_unref (pixbuf);
+
+out:
+ gtk_tree_row_reference_free (data->row_ref);
+ g_object_unref (data->impl);
+ g_free (data);
+
+ g_object_unref (handle);
+}
+
static void
shortcuts_reload_icons (GtkFileChooserDefault *impl)
{
+ GSList *l;
GtkTreeIter iter;
profile_start ("start", NULL);
@@ -1109,44 +1160,68 @@ shortcuts_reload_icons (GtkFileChooserDefault *impl)
if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (impl->shortcuts_model), &iter))
goto out;
- do {
- gpointer data;
- gboolean is_volume;
- gboolean pixbuf_visible;
- GdkPixbuf *pixbuf;
+ for (l = impl->reload_icon_handles; l; l = l->next)
+ {
+ GtkFileSystemHandle *handle = GTK_FILE_SYSTEM_HANDLE (l->data);
+ gtk_file_system_cancel_operation (handle);
+ }
+ g_slist_free (impl->reload_icon_handles);
+ impl->reload_icon_handles = NULL;
- gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
- SHORTCUTS_COL_DATA, &data,
- SHORTCUTS_COL_IS_VOLUME, &is_volume,
- SHORTCUTS_COL_PIXBUF_VISIBLE, &pixbuf_visible,
- -1);
+ do
+ {
+ gpointer data;
+ gboolean is_volume;
+ gboolean pixbuf_visible;
+ GdkPixbuf *pixbuf;
- if (pixbuf_visible && data)
- {
- if (is_volume)
- {
- GtkFileSystemVolume *volume;
+ gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
+ SHORTCUTS_COL_DATA, &data,
+ SHORTCUTS_COL_IS_VOLUME, &is_volume,
+ SHORTCUTS_COL_PIXBUF_VISIBLE, &pixbuf_visible,
+ -1);
- volume = data;
- pixbuf = gtk_file_system_volume_render_icon (impl->file_system, volume, GTK_WIDGET (impl),
- impl->icon_size, NULL);
- }
- else
- {
- const GtkFilePath *path;
+ if (pixbuf_visible && data)
+ {
+ if (is_volume)
+ {
+ GtkFileSystemVolume *volume;
- path = data;
- pixbuf = gtk_file_system_render_icon (impl->file_system, path, GTK_WIDGET (impl),
- impl->icon_size, NULL);
- }
+ volume = data;
+ pixbuf = gtk_file_system_volume_render_icon (impl->file_system, volume, GTK_WIDGET (impl),
+ impl->icon_size, NULL);
- gtk_list_store_set (impl->shortcuts_model, &iter,
- SHORTCUTS_COL_PIXBUF, pixbuf,
- -1);
- if (pixbuf)
- g_object_unref (pixbuf);
- }
- } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (impl->shortcuts_model),&iter));
+ gtk_list_store_set (impl->shortcuts_model, &iter,
+ SHORTCUTS_COL_PIXBUF, pixbuf,
+ -1);
+
+ if (pixbuf)
+ g_object_unref (pixbuf);
+ }
+ else
+ {
+ const GtkFilePath *path;
+ struct ReloadIconsData *info;
+ GtkTreePath *tree_path;
+ GtkFileSystemHandle *handle;
+
+ path = data;
+
+ info = g_new0 (struct ReloadIconsData, 1);
+ info->impl = g_object_ref (impl);
+ tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model), &iter);
+ info->row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (impl->shortcuts_model), tree_path);
+ gtk_tree_path_free (tree_path);
+
+ handle = gtk_file_system_get_info (impl->file_system, path,
+ GTK_FILE_INFO_ICON,
+ shortcuts_reload_icons_get_info_cb,
+ info);
+ impl->reload_icon_handles = g_slist_append (impl->reload_icon_handles, handle);
+ }
+ }
+ }
+ while (gtk_tree_model_iter_next (GTK_TREE_MODEL (impl->shortcuts_model),&iter));
out:
@@ -1183,83 +1258,203 @@ shortcuts_find_current_folder (GtkFileChooserDefault *impl)
shortcuts_find_folder (impl, impl->current_folder);
}
-/* Convenience function to get the display name and icon info for a path */
-static GtkFileInfo *
-get_file_info (GtkFileSystem *file_system,
- const GtkFilePath *path,
- gboolean name_only,
- GError **error)
+/* Removes the specified number of rows from the shortcuts list */
+static void
+shortcuts_remove_rows (GtkFileChooserDefault *impl,
+ int start_row,
+ int n_rows)
{
- GtkFilePath *parent_path;
- GtkFileFolder *parent_folder;
- GtkFileInfo *info;
- GError *tmp = NULL;
+ GtkTreePath *path;
- profile_start ("start", (char *) path);
+ path = gtk_tree_path_new_from_indices (start_row, -1);
+
+ for (; n_rows; n_rows--)
+ {
+ GtkTreeIter iter;
+
+ if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->shortcuts_model), &iter, path))
+ g_assert_not_reached ();
+
+ shortcuts_free_row_data (impl, &iter);
+ gtk_list_store_remove (impl->shortcuts_model, &iter);
+ }
+
+ gtk_tree_path_free (path);
+}
+
+static void
+shortcuts_update_count (GtkFileChooserDefault *impl,
+ ShortcutsIndex type,
+ gint value)
+{
+ switch (type)
+ {
+ case SHORTCUTS_HOME:
+ if (value < 0)
+ impl->has_home = FALSE;
+ else
+ impl->has_home = TRUE;
+ break;
+
+ case SHORTCUTS_DESKTOP:
+ if (value < 0)
+ impl->has_desktop = FALSE;
+ else
+ impl->has_desktop = TRUE;
+ break;
+
+ case SHORTCUTS_VOLUMES:
+ impl->num_volumes += value;
+ break;
+
+ case SHORTCUTS_SHORTCUTS:
+ impl->num_shortcuts += value;
+ break;
- parent_path = NULL;
- info = NULL;
+ case SHORTCUTS_BOOKMARKS:
+ impl->num_bookmarks += value;
+ break;
- if (!gtk_file_system_get_parent (file_system, path, &parent_path, &tmp))
+ case SHORTCUTS_CURRENT_FOLDER:
+ if (value < 0)
+ impl->shortcuts_current_folder_active = FALSE;
+ else
+ impl->shortcuts_current_folder_active = TRUE;
+ break;
+
+ default:
+ /* nothing */
+ break;
+ }
+}
+
+struct ShortcutsInsertRequest
+{
+ GtkFileChooserDefault *impl;
+ GtkFilePath *parent_path;
+ GtkFilePath *path;
+ int pos;
+ char *label_copy;
+ GtkTreeRowReference *row_ref;
+ ShortcutsIndex type;
+ gboolean name_only;
+ gboolean removable;
+};
+
+static void
+get_file_info_finished (GtkFileSystemHandle *handle,
+ const GtkFileInfo *info,
+ const GError *error,
+ gpointer data)
+{
+ gint pos = -1;
+ gboolean cancelled = handle->cancelled;
+ gboolean is_volume = FALSE;
+ GdkPixbuf *pixbuf;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ GtkFileSystemHandle *model_handle;
+ struct ShortcutsInsertRequest *request = data;
+
+ path = gtk_tree_row_reference_get_path (request->row_ref);
+ if (!path)
+ /* Handle doesn't exist anymore in the model */
goto out;
- parent_folder = gtk_file_system_get_folder (file_system, parent_path ? parent_path : path,
- GTK_FILE_INFO_DISPLAY_NAME
- | (name_only ? 0 : GTK_FILE_INFO_IS_FOLDER),
- &tmp);
- if (!parent_folder)
+ pos = gtk_tree_path_get_indices (path)[0];
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (request->impl->shortcuts_model),
+ &iter, path);
+ gtk_tree_path_free (path);
+
+ /* validate handle, else goto out */
+ gtk_tree_model_get (GTK_TREE_MODEL (request->impl->shortcuts_model), &iter,
+ SHORTCUTS_COL_HANDLE, &model_handle,
+ -1);
+ if (handle != model_handle)
goto out;
- info = gtk_file_folder_get_info (parent_folder, parent_path ? path : NULL, &tmp);
- g_object_unref (parent_folder);
+ /* set the handle to NULL in the model (we unref later on) */
+ gtk_list_store_set (request->impl->shortcuts_model, &iter,
+ SHORTCUTS_COL_HANDLE, NULL,
+ -1);
- out:
- if (parent_path)
- gtk_file_path_free (parent_path);
+ if (cancelled)
+ goto out;
- if (tmp)
+ if (!info)
{
- g_set_error (error,
- GTK_FILE_CHOOSER_ERROR,
- GTK_FILE_CHOOSER_ERROR_BAD_FILENAME,
- _("Could not get information about '%s': %s"),
- gtk_file_path_get_string (path),
- tmp->message);
- g_error_free (tmp);
- }
+ gtk_list_store_remove (request->impl->shortcuts_model, &iter);
+ shortcuts_update_count (request->impl, request->type, -1);
- profile_end ("end", (char *) path);
+ if (request->type == SHORTCUTS_HOME)
+ {
+ const char *home = g_get_home_dir ();
+ GtkFilePath *home_path;
- return info;
-}
+ home_path = gtk_file_system_filename_to_path (request->impl->file_system, home);
+ error_getting_info_dialog (request->impl, home_path, g_error_copy (error));
+ gtk_file_path_free (home_path);
+ }
+ else if (request->type == SHORTCUTS_CURRENT_FOLDER)
+ {
+ /* Remove the current folder separator */
+ gint separator_pos = shortcuts_get_index (request->impl, SHORTCUTS_CURRENT_FOLDER_SEPARATOR);
+ shortcuts_remove_rows (request->impl, separator_pos, 1);
+ }
-/* Returns whether a path is a folder */
-static gboolean
-check_is_folder (GtkFileSystem *file_system,
- const GtkFilePath *path,
- GError **error)
-{
- GtkFileFolder *folder;
+ goto out;
+ }
+
+ if (!request->label_copy)
+ request->label_copy = g_strdup (gtk_file_info_get_display_name (info));
+ pixbuf = gtk_file_info_render_icon (info, GTK_WIDGET (request->impl),
+ request->impl->icon_size, NULL);
- profile_start ("start", (char *) path);
+ gtk_list_store_set (request->impl->shortcuts_model, &iter,
+ SHORTCUTS_COL_PIXBUF, pixbuf,
+ SHORTCUTS_COL_PIXBUF_VISIBLE, TRUE,
+ SHORTCUTS_COL_NAME, request->label_copy,
+ SHORTCUTS_COL_IS_VOLUME, is_volume,
+ SHORTCUTS_COL_REMOVABLE, request->removable,
+ -1);
+
+ if (request->impl->shortcuts_filter_model)
+ gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (request->impl->shortcuts_filter_model));
- folder = gtk_file_system_get_folder (file_system, path, 0, error);
- if (!folder)
+ if (request->type == SHORTCUTS_CURRENT_FOLDER
+ && request->impl->save_folder_combo != NULL)
{
- profile_end ("end - is not folder", (char *) path);
- return FALSE;
+ /* The current folder is updated via _activate_iter(), don't
+ * have save_folder_combo_changed_cb() call _activate_iter()
+ * again.
+ */
+ g_signal_handlers_block_by_func (request->impl->save_folder_combo,
+ G_CALLBACK (save_folder_combo_changed_cb),
+ request->impl);
+ gtk_combo_box_set_active (GTK_COMBO_BOX (request->impl->save_folder_combo), pos);
+ g_signal_handlers_unblock_by_func (request->impl->save_folder_combo,
+ G_CALLBACK (save_folder_combo_changed_cb),
+ request->impl);
}
- g_object_unref (folder);
+ if (pixbuf)
+ g_object_unref (pixbuf);
- profile_end ("end", (char *) path);
- return TRUE;
+out:
+ g_object_unref (request->impl);
+ gtk_file_path_free (request->parent_path);
+ gtk_file_path_free (request->path);
+ gtk_tree_row_reference_free (request->row_ref);
+ g_free (request->label_copy);
+ g_free (request);
+
+ g_object_unref (handle);
}
/* Inserts a path in the shortcuts tree, making a copy of it; alternatively,
* inserts a volume. A position of -1 indicates the end of the tree.
*/
-static gboolean
+static void
shortcuts_insert_path (GtkFileChooserDefault *impl,
int pos,
gboolean is_volume,
@@ -1267,11 +1462,11 @@ shortcuts_insert_path (GtkFileChooserDefault *impl,
const GtkFilePath *path,
const char *label,
gboolean removable,
- GError **error)
+ ShortcutsIndex type)
{
char *label_copy;
- GdkPixbuf *pixbuf;
- gpointer data;
+ GdkPixbuf *pixbuf = NULL;
+ gpointer data = NULL;
GtkTreeIter iter;
profile_start ("start", is_volume ? "volume" : (char *) path);
@@ -1285,32 +1480,54 @@ shortcuts_insert_path (GtkFileChooserDefault *impl,
}
else
{
+ struct ShortcutsInsertRequest *request;
+ GtkFileSystemHandle *handle;
+ GtkTreePath *p;
+
+ request = g_new0 (struct ShortcutsInsertRequest, 1);
+ request->impl = g_object_ref (impl);
+ request->path = gtk_file_path_copy (path);
+ request->name_only = TRUE;
+ request->removable = removable;
+ request->pos = pos;
+ request->type = type;
if (label)
- label_copy = g_strdup (label);
+ request->label_copy = g_strdup (label);
+
+ if (pos == -1)
+ gtk_list_store_append (impl->shortcuts_model, &iter);
else
- {
- GtkFileInfo *info = get_file_info (impl->file_system, path, TRUE, error);
+ gtk_list_store_insert (impl->shortcuts_model, &iter, pos);
- if (!info)
- {
- profile_end ("end - could not get info", (char *) path);
- return FALSE;
- }
+ p = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model), &iter);
+ request->row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (impl->shortcuts_model), p);
+ gtk_tree_path_free (p);
- label_copy = g_strdup (gtk_file_info_get_display_name (info));
- gtk_file_info_free (info);
- }
+ handle = gtk_file_system_get_info (request->impl->file_system, request->path,
+ GTK_FILE_INFO_DISPLAY_NAME | GTK_FILE_INFO_IS_HIDDEN | GTK_FILE_INFO_ICON,
+ get_file_info_finished, request);
- data = gtk_file_path_copy (path);
- pixbuf = gtk_file_system_render_icon (impl->file_system, path, GTK_WIDGET (impl),
- impl->icon_size, NULL);
+ gtk_list_store_set (impl->shortcuts_model, &iter,
+ SHORTCUTS_COL_DATA, gtk_file_path_copy (path),
+ SHORTCUTS_COL_IS_VOLUME, is_volume,
+ SHORTCUTS_COL_HANDLE, handle,
+ -1);
+
+ shortcuts_update_count (impl, type, 1);
+
+ return;
}
+ if (!data)
+ data = gtk_file_path_copy (path);
+
if (pos == -1)
gtk_list_store_append (impl->shortcuts_model, &iter);
else
gtk_list_store_insert (impl->shortcuts_model, &iter, pos);
+ shortcuts_update_count (impl, type, 1);
+
gtk_list_store_set (impl->shortcuts_model, &iter,
SHORTCUTS_COL_PIXBUF, pixbuf,
SHORTCUTS_COL_PIXBUF_VISIBLE, TRUE,
@@ -1318,16 +1535,34 @@ shortcuts_insert_path (GtkFileChooserDefault *impl,
SHORTCUTS_COL_DATA, data,
SHORTCUTS_COL_IS_VOLUME, is_volume,
SHORTCUTS_COL_REMOVABLE, removable,
+ SHORTCUTS_COL_HANDLE, NULL,
-1);
+ if (impl->shortcuts_filter_model)
+ gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_filter_model));
+
+ if (type == SHORTCUTS_CURRENT_FOLDER && impl->save_folder_combo != NULL)
+ {
+ /* The current folder is updated via _activate_iter(), don't
+ * have save_folder_combo_changed_cb() call _activate_iter()
+ * again.
+ */
+ gint combo_pos = shortcuts_get_index (impl, SHORTCUTS_CURRENT_FOLDER);
+ g_signal_handlers_block_by_func (impl->save_folder_combo,
+ G_CALLBACK (save_folder_combo_changed_cb),
+ impl);
+ gtk_combo_box_set_active (GTK_COMBO_BOX (impl->save_folder_combo), combo_pos);
+ g_signal_handlers_unblock_by_func (impl->save_folder_combo,
+ G_CALLBACK (save_folder_combo_changed_cb),
+ impl);
+ }
+
g_free (label_copy);
if (pixbuf)
g_object_unref (pixbuf);
profile_end ("end", NULL);
-
- return TRUE;
}
/* Appends an item for the user's home directory to the shortcuts model */
@@ -1336,7 +1571,6 @@ shortcuts_append_home (GtkFileChooserDefault *impl)
{
const char *home;
GtkFilePath *home_path;
- GError *error;
profile_start ("start", NULL);
@@ -1349,10 +1583,7 @@ shortcuts_append_home (GtkFileChooserDefault *impl)
home_path = gtk_file_system_filename_to_path (impl->file_system, home);
- error = NULL;
- impl->has_home = shortcuts_insert_path (impl, -1, FALSE, NULL, home_path, NULL, FALSE, &error);
- if (!impl->has_home)
- error_getting_info_dialog (impl, home_path, error);
+ shortcuts_insert_path (impl, -1, FALSE, NULL, home_path, NULL, FALSE, SHORTCUTS_HOME);
gtk_file_path_free (home_path);
@@ -1385,7 +1616,7 @@ shortcuts_append_desktop (GtkFileChooserDefault *impl)
path = gtk_file_system_filename_to_path (impl->file_system, name);
g_free (name);
- impl->has_desktop = shortcuts_insert_path (impl, -1, FALSE, NULL, path, _("Desktop"), FALSE, NULL);
+ shortcuts_insert_path (impl, -1, FALSE, NULL, path, _("Desktop"), FALSE, SHORTCUTS_DESKTOP);
/* We do not actually pop up an error dialog if there is no desktop directory
* because some people may really not want to have one.
*/
@@ -1424,8 +1655,8 @@ shortcuts_append_paths (GtkFileChooserDefault *impl,
label = gtk_file_system_get_bookmark_label (impl->file_system, path);
/* NULL GError, but we don't really want to show error boxes here */
- if (shortcuts_insert_path (impl, start_row + num_inserted, FALSE, NULL, path, label, TRUE, NULL))
- num_inserted++;
+ shortcuts_insert_path (impl, start_row + num_inserted, FALSE, NULL, path, label, TRUE, SHORTCUTS_BOOKMARKS);
+ num_inserted++;
g_free (label);
}
@@ -1490,30 +1721,6 @@ shortcuts_get_index (GtkFileChooserDefault *impl,
return n;
}
-/* Removes the specified number of rows from the shortcuts list */
-static void
-shortcuts_remove_rows (GtkFileChooserDefault *impl,
- int start_row,
- int n_rows)
-{
- GtkTreePath *path;
-
- path = gtk_tree_path_new_from_indices (start_row, -1);
-
- for (; n_rows; n_rows--)
- {
- GtkTreeIter iter;
-
- if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->shortcuts_model), &iter, path))
- g_assert_not_reached ();
-
- shortcuts_free_row_data (impl, &iter);
- gtk_list_store_remove (impl->shortcuts_model, &iter);
- }
-
- gtk_tree_path_free (path);
-}
-
/* Adds all the file system volumes to the shortcuts model */
static void
shortcuts_add_volumes (GtkFileChooserDefault *impl)
@@ -1563,10 +1770,8 @@ shortcuts_add_volumes (GtkFileChooserDefault *impl)
}
}
- if (shortcuts_insert_path (impl, start_row + n, TRUE, volume, NULL, NULL, FALSE, NULL))
- n++;
- else
- gtk_file_system_volume_free (impl->file_system, volume);
+ shortcuts_insert_path (impl, start_row + n, TRUE, volume, NULL, NULL, FALSE, SHORTCUTS_VOLUMES);
+ n++;
}
impl->num_volumes = n;
@@ -1613,6 +1818,7 @@ shortcuts_add_bookmarks (GtkFileChooserDefault *impl)
profile_start ("start", NULL);
+
old_changing_folders = impl->changing_folder;
impl->changing_folder = TRUE;
@@ -1647,8 +1853,10 @@ shortcuts_add_bookmarks (GtkFileChooserDefault *impl)
shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS_SEPARATOR),
impl->num_bookmarks + 1);
+ impl->num_bookmarks = 0;
+
bookmarks = gtk_file_system_list_bookmarks (impl->file_system);
- impl->num_bookmarks = shortcuts_append_paths (impl, bookmarks);
+ shortcuts_append_paths (impl, bookmarks);
gtk_file_paths_free (bookmarks);
if (impl->num_bookmarks > 0)
@@ -1715,26 +1923,15 @@ shortcuts_add_current_folder (GtkFileChooserDefault *impl)
if (base_path &&
strcmp (gtk_file_path_get_string (base_path), gtk_file_path_get_string (impl->current_folder)) == 0)
{
- success = shortcuts_insert_path (impl, pos, TRUE, volume, NULL, NULL, FALSE, NULL);
- if (success)
- volume = NULL;
+ shortcuts_insert_path (impl, pos, TRUE, volume, NULL, NULL, FALSE, SHORTCUTS_CURRENT_FOLDER);
}
else
- success = shortcuts_insert_path (impl, pos, FALSE, NULL, impl->current_folder, NULL, FALSE, NULL);
-
- if (volume)
- gtk_file_system_volume_free (impl->file_system, volume);
+ shortcuts_insert_path (impl, pos, FALSE, NULL, impl->current_folder, NULL, FALSE, SHORTCUTS_CURRENT_FOLDER);
if (base_path)
gtk_file_path_free (base_path);
-
- if (!success)
- shortcuts_remove_rows (impl, pos - 1, 1); /* remove the separator */
-
- impl->shortcuts_current_folder_active = success;
}
-
- if (success && impl->save_folder_combo != NULL)
+ else if (impl->save_folder_combo != NULL)
gtk_combo_box_set_active (GTK_COMBO_BOX (impl->save_folder_combo), pos);
}
@@ -1788,7 +1985,8 @@ shortcuts_model_create (GtkFileChooserDefault *impl)
G_TYPE_POINTER, /* path or volume */
G_TYPE_BOOLEAN, /* is the previous column a volume? */
G_TYPE_BOOLEAN, /* removable */
- G_TYPE_BOOLEAN); /* pixbuf cell visibility */
+ G_TYPE_BOOLEAN, /* pixbuf cell visibility */
+ G_TYPE_OBJECT); /* GtkFileSystemHandle */
if (impl->file_system)
{
@@ -1837,6 +2035,33 @@ new_folder_button_clicked (GtkButton *button,
gtk_tree_path_free (path);
}
+static void
+edited_idle_create_folder_cb (GtkFileSystemHandle *handle,
+ const GtkFilePath *path,
+ const GError *error,
+ gpointer data)
+{
+ gboolean cancelled = handle->cancelled;
+ GtkFileChooserDefault *impl = data;
+
+ if (!g_slist_find (impl->pending_handles, handle))
+ goto out;
+
+ impl->pending_handles = g_slist_remove (impl->pending_handles, handle);
+
+ if (cancelled)
+ goto out;
+
+ if (!error)
+ change_folder_and_display_error (impl, path);
+ else
+ error_creating_folder_dialog (impl, path, g_error_copy (error));
+
+ out:
+ g_object_unref (impl);
+ g_object_unref (handle);
+}
+
/* Idle handler for creating a new folder after editing its name cell, or for
* canceling the editing.
*/
@@ -1859,15 +2084,18 @@ edited_idle_cb (GtkFileChooserDefault *impl)
GtkFilePath *file_path;
error = NULL;
- file_path = gtk_file_system_make_path (impl->file_system, impl->current_folder, impl->edited_new_text,
+ file_path = gtk_file_system_make_path (impl->file_system,
+ impl->current_folder,
+ impl->edited_new_text,
&error);
if (file_path)
{
- error = NULL;
- if (gtk_file_system_create_folder (impl->file_system, file_path, &error))
- change_folder_and_display_error (impl, file_path);
- else
- error_creating_folder_dialog (impl, file_path, error);
+ GtkFileSystemHandle *handle;
+
+ handle = gtk_file_system_create_folder (impl->file_system, file_path,
+ edited_idle_create_folder_cb,
+ g_object_ref (impl));
+ impl->pending_handles = g_slist_append (impl->pending_handles, handle);
gtk_file_path_free (file_path);
}
@@ -1981,6 +2209,12 @@ shortcut_find_position (GtkFileChooserDefault *impl,
current_folder_separator_idx = shortcuts_get_index (impl, SHORTCUTS_CURRENT_FOLDER_SEPARATOR);
+#if 0
+ /* FIXME: is this still needed? */
+ if (current_folder_separator_idx >= impl->shortcuts_model->length)
+ return -1;
+#endif
+
for (i = 0; i < current_folder_separator_idx; i++)
{
gpointer col_data;
@@ -3415,6 +3649,88 @@ error_selecting_dragged_file_dialog (GtkFileChooserDefault *impl,
}
static void
+file_list_drag_data_select_uris (GtkFileChooserDefault *impl,
+ gchar **uris)
+{
+ int i;
+ char *uri;
+ GtkFileChooser *chooser = GTK_FILE_CHOOSER (impl);
+
+ for (i = 1; uris[i]; i++)
+ {
+ GtkFilePath *path;
+
+ uri = uris[i];
+ path = gtk_file_system_uri_to_path (impl->file_system, uri);
+
+ if (path)
+ {
+ GError *error = NULL;
+
+ gtk_file_chooser_default_select_path (chooser, path, &error);
+ if (error)
+ error_selecting_dragged_file_dialog (impl, path, error);
+
+ gtk_file_path_free (path);
+ }
+ }
+}
+
+struct FileListDragData
+{
+ GtkFileChooserDefault *impl;
+ gchar **uris;
+ GtkFilePath *path;
+};
+
+static void
+file_list_drag_data_received_get_info_cb (GtkFileSystemHandle *handle,
+ const GtkFileInfo *info,
+ const GError *error,
+ gpointer user_data)
+{
+ gboolean cancelled = handle->cancelled;
+ struct FileListDragData *data = user_data;
+ GtkFileChooser *chooser = GTK_FILE_CHOOSER (data->impl);
+
+ if (handle != data->impl->file_list_drag_data_received_handle)
+ goto out;
+
+ data->impl->file_list_drag_data_received_handle = NULL;
+
+ if (cancelled || error)
+ goto out;
+
+ if ((data->impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
+ data->impl->action == GTK_FILE_CHOOSER_ACTION_SAVE) &&
+ data->uris[1] == 0 && !error &&
+ gtk_file_info_get_is_folder (info))
+ change_folder_and_display_error (data->impl, data->path);
+ else
+ {
+ GError *error = NULL;
+
+ gtk_file_chooser_default_unselect_all (chooser);
+ gtk_file_chooser_default_select_path (chooser, data->path, &error);
+ if (error)
+ error_selecting_dragged_file_dialog (data->impl, data->path, error);
+ else
+ browse_files_center_selected_row (data->impl);
+ }
+
+ if (data->impl->select_multiple)
+ file_list_drag_data_select_uris (data->impl, data->uris);
+
+out:
+ g_object_unref (data->impl);
+ g_strfreev (data->uris);
+ gtk_file_path_free (data->path);
+ g_free (data);
+
+ g_object_unref (handle);
+}
+
+static void
file_list_drag_data_received_cb (GtkWidget *widget,
GdkDragContext *context,
gint x,
@@ -3444,22 +3760,22 @@ file_list_drag_data_received_cb (GtkWidget *widget,
if (path)
{
- if ((impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
- impl->action == GTK_FILE_CHOOSER_ACTION_SAVE) &&
- uris[1] == 0 &&
- check_is_folder (impl->file_system, path, NULL))
- change_folder_and_display_error (impl, path);
- else
- {
- gtk_file_chooser_default_unselect_all (chooser);
- gtk_file_chooser_default_select_path (chooser, path, &error);
- if (error)
- error_selecting_dragged_file_dialog (impl, path, error);
- else
- browse_files_center_selected_row (impl);
- }
+ struct FileListDragData *data;
- gtk_file_path_free (path);
+ data = g_new0 (struct FileListDragData, 1);
+ data->impl = g_object_ref (impl);
+ data->uris = uris;
+ data->path = path;
+
+ if (impl->file_list_drag_data_received_handle)
+ gtk_file_system_cancel_operation (impl->file_list_drag_data_received_handle);
+
+ impl->file_list_drag_data_received_handle =
+ gtk_file_system_get_info (impl->file_system, path,
+ GTK_FILE_INFO_IS_FOLDER,
+ file_list_drag_data_received_get_info_cb,
+ data);
+ goto out;
}
else
{
@@ -3472,28 +3788,13 @@ file_list_drag_data_received_cb (GtkWidget *widget,
error_selecting_dragged_file_dialog (impl, NULL, error);
}
-
if (impl->select_multiple)
- {
- for (i = 1; uris[i]; i++)
- {
- uri = uris[i];
- path = gtk_file_system_uri_to_path (impl->file_system, uri);
-
- if (path)
- {
- gtk_file_chooser_default_select_path (chooser, path, &error);
- if (error)
- error_selecting_dragged_file_dialog (impl, path, error);
-
- gtk_file_path_free (path);
- }
- }
- }
+ file_list_drag_data_select_uris (impl, uris);
}
g_strfreev (uris);
+out:
g_signal_stop_emission_by_name (widget, "drag-data-received");
}
@@ -4518,6 +4819,7 @@ remove_settings_signal (GtkFileChooserDefault *impl,
static void
gtk_file_chooser_default_dispose (GObject *object)
{
+ GSList *l;
GtkFileChooserDefault *impl = (GtkFileChooserDefault *) object;
if (impl->extra_widget)
@@ -4526,6 +4828,90 @@ gtk_file_chooser_default_dispose (GObject *object)
impl->extra_widget = NULL;
}
+ if (impl->volumes_changed_id > 0)
+ {
+ g_signal_handler_disconnect (impl->file_system, impl->volumes_changed_id);
+ impl->volumes_changed_id = 0;
+ }
+
+ if (impl->bookmarks_changed_id > 0)
+ {
+ g_signal_handler_disconnect (impl->file_system, impl->bookmarks_changed_id);
+ impl->bookmarks_changed_id = 0;
+ }
+
+ pending_select_paths_free (impl);
+
+ /* cancel all pending operations */
+ if (impl->pending_handles)
+ {
+ for (l = impl->pending_handles; l; l = l->next)
+ {
+ GtkFileSystemHandle *handle =l->data;
+ gtk_file_system_cancel_operation (handle);
+ }
+ g_slist_free (impl->pending_handles);
+ impl->pending_handles = NULL;
+ }
+
+ if (impl->reload_icon_handles)
+ {
+ for (l = impl->reload_icon_handles; l; l = l->next)
+ {
+ GtkFileSystemHandle *handle =l->data;
+ gtk_file_system_cancel_operation (handle);
+ }
+ g_slist_free (impl->reload_icon_handles);
+ impl->reload_icon_handles = NULL;
+ }
+
+ if (impl->loading_shortcuts)
+ {
+ for (l = impl->loading_shortcuts; l; l = l->next)
+ {
+ GtkFileSystemHandle *handle =l->data;
+ gtk_file_system_cancel_operation (handle);
+ }
+ g_slist_free (impl->loading_shortcuts);
+ impl->loading_shortcuts = NULL;
+ }
+
+ if (impl->file_list_drag_data_received_handle)
+ {
+ gtk_file_system_cancel_operation (impl->file_list_drag_data_received_handle);
+ impl->file_list_drag_data_received_handle = NULL;
+ }
+
+ if (impl->update_current_folder_handle)
+ {
+ gtk_file_system_cancel_operation (impl->update_current_folder_handle);
+ impl->update_current_folder_handle = NULL;
+ }
+
+ if (impl->show_and_select_paths_handle)
+ {
+ gtk_file_system_cancel_operation (impl->show_and_select_paths_handle);
+ impl->show_and_select_paths_handle = NULL;
+ }
+
+ if (impl->should_respond_get_info_handle)
+ {
+ gtk_file_system_cancel_operation (impl->should_respond_get_info_handle);
+ impl->should_respond_get_info_handle = NULL;
+ }
+
+ if (impl->update_from_entry_handle)
+ {
+ gtk_file_system_cancel_operation (impl->update_from_entry_handle);
+ impl->update_from_entry_handle = NULL;
+ }
+
+ if (impl->shortcuts_activate_iter_handle)
+ {
+ gtk_file_system_cancel_operation (impl->shortcuts_activate_iter_handle);
+ impl->shortcuts_activate_iter_handle = NULL;
+ }
+
remove_settings_signal (impl, gtk_widget_get_screen (GTK_WIDGET (impl)));
G_OBJECT_CLASS (parent_class)->dispose (object);
@@ -4777,11 +5163,12 @@ gtk_file_chooser_default_map (GtkWidget *widget)
break;
case RELOAD_WAS_UNMAPPED:
- /* Just reload the current folder */
- g_assert (impl->current_folder != NULL);
-
- pending_select_paths_store_selection (impl);
- change_folder_and_display_error (impl, impl->current_folder);
+ /* Just reload the current folder; else continue the pending load. */
+ if (impl->current_folder)
+ {
+ pending_select_paths_store_selection (impl);
+ change_folder_and_display_error (impl, impl->current_folder);
+ }
break;
default:
@@ -5092,36 +5479,25 @@ browse_files_center_selected_row (GtkFileChooserDefault *impl)
gtk_tree_selection_selected_foreach (selection, center_selected_row_foreach_cb, &closure);
}
-static gboolean
-show_and_select_paths (GtkFileChooserDefault *impl,
- const GtkFilePath *parent_path,
- GSList *paths,
- GError **error)
+struct ShowAndSelectPathsData
+{
+ GtkFileChooserDefault *impl;
+ GSList *paths;
+};
+
+static void
+show_and_select_paths_finished_loading (GtkFileFolder *folder,
+ gpointer user_data)
{
- GtkFileFolder *folder;
gboolean have_hidden;
gboolean have_filtered;
GSList *l;
-
- profile_start ("start", NULL);
-
- if (!paths)
- {
- profile_end ("end", NULL);
- return TRUE;
- }
-
- folder = gtk_file_system_get_folder (impl->file_system, parent_path, GTK_FILE_INFO_IS_FOLDER | GTK_FILE_INFO_IS_HIDDEN, error);
- if (!folder)
- {
- profile_end ("end", NULL);
- return FALSE;
- }
+ struct ShowAndSelectPathsData *data = user_data;
have_hidden = FALSE;
have_filtered = FALSE;
- for (l = paths; l; l = l->next)
+ for (l = data->paths; l; l = l->next)
{
const GtkFilePath *path;
GtkFileInfo *info;
@@ -5136,7 +5512,7 @@ show_and_select_paths (GtkFileChooserDefault *impl,
have_hidden = gtk_file_info_get_is_hidden (info);
if (!have_filtered)
- have_filtered = !gtk_file_info_get_is_folder (info) && get_is_file_filtered (impl, path, info);
+ have_filtered = !gtk_file_info_get_is_folder (info) && get_is_file_filtered (data->impl, path, info);
gtk_file_info_free (info);
@@ -5145,22 +5521,95 @@ show_and_select_paths (GtkFileChooserDefault *impl,
}
}
+ g_signal_handlers_disconnect_by_func (folder,
+ show_and_select_paths_finished_loading,
+ user_data);
+
g_object_unref (folder);
if (have_hidden)
- g_object_set (impl, "show-hidden", TRUE, NULL);
+ g_object_set (data->impl, "show-hidden", TRUE, NULL);
if (have_filtered)
- set_current_filter (impl, NULL);
+ set_current_filter (data->impl, NULL);
- for (l = paths; l; l = l->next)
+ for (l = data->paths; l; l = l->next)
{
const GtkFilePath *path;
path = l->data;
- _gtk_file_system_model_path_do (impl->browse_files_model, path, select_func, impl);
+ _gtk_file_system_model_path_do (data->impl->browse_files_model, path,
+ select_func, data->impl);
+ }
+
+ gtk_file_paths_free (data->paths);
+ g_free (data);
+}
+
+static void
+show_and_select_paths_get_folder_cb (GtkFileSystemHandle *handle,
+ GtkFileFolder *folder,
+ const GError *error,
+ gpointer user_data)
+{
+ gboolean cancelled = handle->cancelled;
+ struct ShowAndSelectPathsData *data = user_data;
+
+ if (data->impl->show_and_select_paths_handle != handle)
+ goto out;
+
+ data->impl->show_and_select_paths_handle = NULL;
+
+ if (cancelled || error)
+ goto out;
+
+ g_object_unref (handle);
+
+ if (gtk_file_folder_is_finished_loading (folder))
+ show_and_select_paths_finished_loading (folder, user_data);
+ else
+ g_signal_connect (folder, "finished-loading",
+ G_CALLBACK (show_and_select_paths_finished_loading),
+ user_data);
+
+ return;
+
+out:
+ g_object_unref (data->impl);
+ gtk_file_paths_free (data->paths);
+ g_free (data);
+
+ g_object_unref (handle);
+}
+
+static gboolean
+show_and_select_paths (GtkFileChooserDefault *impl,
+ const GtkFilePath *parent_path,
+ GSList *paths,
+ GError **error)
+{
+ struct ShowAndSelectPathsData *info;
+
+ profile_start ("start", NULL);
+
+ if (!paths)
+ {
+ profile_end ("end", NULL);
+ return TRUE;
}
+ info = g_new (struct ShowAndSelectPathsData, 1);
+ info->impl = g_object_ref (impl);
+ info->paths = gtk_file_paths_copy (paths);
+
+ if (impl->show_and_select_paths_handle)
+ gtk_file_system_cancel_operation (impl->show_and_select_paths_handle);
+
+ impl->show_and_select_paths_handle =
+ gtk_file_system_get_folder (impl->file_system, parent_path,
+ GTK_FILE_INFO_IS_FOLDER | GTK_FILE_INFO_IS_HIDDEN,
+ show_and_select_paths_get_folder_cb, info);
+
profile_end ("end", NULL);
return TRUE;
}
@@ -5343,50 +5792,52 @@ gtk_file_chooser_default_set_current_folder (GtkFileChooser *chooser,
return gtk_file_chooser_default_update_current_folder (chooser, path, FALSE, error);
}
-static gboolean
-gtk_file_chooser_default_update_current_folder (GtkFileChooser *chooser,
- const GtkFilePath *path,
- gboolean keep_trail,
- GError **error)
+
+struct UpdateCurrentFolderData
{
- GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
- gboolean result;
+ GtkFileChooserDefault *impl;
+ GtkFilePath *path;
+ gboolean keep_trail;
+};
- profile_start ("start", (char *) path);
+static void
+update_current_folder_get_info_cb (GtkFileSystemHandle *handle,
+ const GtkFileInfo *info,
+ const GError *error,
+ gpointer user_data)
+{
+ gboolean cancelled = handle->cancelled;
+ struct UpdateCurrentFolderData *data = user_data;
+ GtkFileChooserDefault *impl = data->impl;
- g_assert (path != NULL);
+ if (handle != impl->update_current_folder_handle)
+ goto out;
- if (impl->local_only &&
- !gtk_file_system_path_is_local (impl->file_system, path))
- {
- g_set_error (error,
- GTK_FILE_CHOOSER_ERROR,
- GTK_FILE_CHOOSER_ERROR_BAD_FILENAME,
- _("Cannot change to folder because it is not local"));
+ impl->update_current_folder_handle = NULL;
- profile_end ("end - not local", (char *) path);
- return FALSE;
- }
+ set_busy_cursor (impl, FALSE);
- /* Test validity of path here. */
- if (!check_is_folder (impl->file_system, path, error))
- {
- profile_end ("end - not a folder", (char *) path);
- return FALSE;
- }
+ if (cancelled)
+ goto out;
- if (!_gtk_path_bar_set_path (GTK_PATH_BAR (impl->browse_path_bar), path, keep_trail, error))
+ if (error)
{
- profile_end ("end - could not set path bar", (char *) path);
- return FALSE;
+ error_changing_folder_dialog (impl, data->path, g_error_copy (error));
+ goto out;
}
- if (impl->current_folder != path)
+ if (!gtk_file_info_get_is_folder (info))
+ goto out;
+
+ if (!_gtk_path_bar_set_path (GTK_PATH_BAR (impl->browse_path_bar), data->path, data->keep_trail, NULL))
+ goto out;
+
+ if (impl->current_folder != data->path)
{
if (impl->current_folder)
gtk_file_path_free (impl->current_folder);
- impl->current_folder = gtk_file_path_copy (path);
+ impl->current_folder = gtk_file_path_copy (data->path);
impl->reload_state = RELOAD_HAS_FOLDER;
}
@@ -5412,7 +5863,7 @@ gtk_file_chooser_default_update_current_folder (GtkFileChooser *chooser,
* but perform more actions rather than returning immediately even if it
* generates an error.
*/
- result = set_list_model (impl, error);
+ set_list_model (impl, NULL);
/* Refresh controls */
@@ -5425,8 +5876,56 @@ gtk_file_chooser_default_update_current_folder (GtkFileChooser *chooser,
g_signal_emit_by_name (impl, "selection-changed", 0);
+out:
+ gtk_file_path_free (data->path);
+ g_free (data);
+
+ g_object_unref (handle);
+}
+
+static gboolean
+gtk_file_chooser_default_update_current_folder (GtkFileChooser *chooser,
+ const GtkFilePath *path,
+ gboolean keep_trail,
+ GError **error)
+{
+ GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
+ struct UpdateCurrentFolderData *data;
+
+ profile_start ("start", (char *) path);
+
+ g_assert (path != NULL);
+
+ if (impl->local_only &&
+ !gtk_file_system_path_is_local (impl->file_system, path))
+ {
+ g_set_error (error,
+ GTK_FILE_CHOOSER_ERROR,
+ GTK_FILE_CHOOSER_ERROR_BAD_FILENAME,
+ _("Cannot change to folder because it is not local"));
+
+ profile_end ("end - not local", (char *) path);
+ return FALSE;
+ }
+
+ if (impl->update_current_folder_handle)
+ gtk_file_system_cancel_operation (impl->update_current_folder_handle);
+
+ /* Test validity of path here. */
+ data = g_new0 (struct UpdateCurrentFolderData, 1);
+ data->impl = impl;
+ data->path = gtk_file_path_copy (path);
+ data->keep_trail = keep_trail;
+
+ impl->update_current_folder_handle =
+ gtk_file_system_get_info (impl->file_system, path, GTK_FILE_INFO_IS_FOLDER,
+ update_current_folder_get_info_cb,
+ data);
+
+ set_busy_cursor (impl, TRUE);
+
profile_end ("end", NULL);
- return result;
+ return TRUE;
}
static GtkFilePath *
@@ -5621,7 +6120,8 @@ check_save_entry (GtkFileChooserDefault *impl,
GtkFilePath **path_ret,
gboolean *is_well_formed_ret,
gboolean *is_empty_ret,
- gboolean *is_file_part_empty_ret)
+ gboolean *is_file_part_empty_ret,
+ gboolean *is_folder)
{
GtkFileChooserEntry *chooser_entry;
const GtkFilePath *current_folder;
@@ -5640,6 +6140,7 @@ check_save_entry (GtkFileChooserDefault *impl,
*is_well_formed_ret = TRUE;
*is_empty_ret = TRUE;
*is_file_part_empty_ret = TRUE;
+ *is_folder = FALSE;
return;
}
@@ -5654,6 +6155,7 @@ check_save_entry (GtkFileChooserDefault *impl,
*path_ret = gtk_file_path_copy (current_folder);
*is_well_formed_ret = TRUE;
*is_file_part_empty_ret = TRUE;
+ *is_folder = TRUE;
return;
}
@@ -5668,12 +6170,14 @@ check_save_entry (GtkFileChooserDefault *impl,
error_building_filename_dialog (impl, current_folder, file_part, error);
*path_ret = NULL;
*is_well_formed_ret = FALSE;
+ *is_folder = FALSE;
return;
}
*path_ret = path;
*is_well_formed_ret = TRUE;
+ *is_folder = _gtk_file_chooser_entry_get_is_folder (chooser_entry, path);
}
struct get_paths_closure {
@@ -5719,9 +6223,9 @@ gtk_file_chooser_default_get_paths (GtkFileChooser *chooser)
if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
|| impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
{
- gboolean is_well_formed, is_empty, is_file_part_empty;
+ gboolean is_well_formed, is_empty, is_file_part_empty, is_folder;
- check_save_entry (impl, &info.path_from_entry, &is_well_formed, &is_empty, &is_file_part_empty);
+ check_save_entry (impl, &info.path_from_entry, &is_well_formed, &is_empty, &is_file_part_empty, &is_folder);
if (!is_well_formed)
return NULL;
@@ -5872,19 +6376,53 @@ shortcuts_get_pos_for_shortcut_folder (GtkFileChooserDefault *impl,
return pos + shortcuts_get_index (impl, SHORTCUTS_SHORTCUTS);
}
+struct AddShortcutData
+{
+ GtkFileChooserDefault *impl;
+ GtkFilePath *path;
+};
+
+static void
+add_shortcut_get_info_cb (GtkFileSystemHandle *handle,
+ const GtkFileInfo *info,
+ const GError *error,
+ gpointer user_data)
+{
+ int pos;
+ gboolean cancelled = handle->cancelled;
+ struct AddShortcutData *data = user_data;
+
+ if (!g_slist_find (data->impl->loading_shortcuts, handle))
+ goto out;
+
+ data->impl->loading_shortcuts = g_slist_remove (data->impl->loading_shortcuts, handle);
+
+ if (cancelled || error || !gtk_file_info_get_is_folder (info))
+ goto out;
+
+ pos = shortcuts_get_pos_for_shortcut_folder (data->impl, data->impl->num_shortcuts);
+
+ shortcuts_insert_path (data->impl, pos, FALSE, NULL, data->path, NULL, FALSE, SHORTCUTS_SHORTCUTS);
+
+out:
+ g_object_unref (data->impl);
+ gtk_file_path_free (data->path);
+ g_free (data);
+
+ g_object_unref (handle);
+}
+
static gboolean
gtk_file_chooser_default_add_shortcut_folder (GtkFileChooser *chooser,
const GtkFilePath *path,
GError **error)
{
+ GtkFileSystemHandle *handle;
GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
- gboolean result;
+ struct AddShortcutData *data;
+ GSList *l;
int pos;
- /* Test validity of path here. */
- if (!check_is_folder (impl->file_system, path, error))
- return FALSE;
-
/* Avoid adding duplicates */
pos = shortcut_find_position (impl, path);
if (pos >= 0 && pos < shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS_SEPARATOR))
@@ -5902,17 +6440,43 @@ gtk_file_chooser_default_add_shortcut_folder (GtkFileChooser *chooser,
return FALSE;
}
- pos = shortcuts_get_pos_for_shortcut_folder (impl, impl->num_shortcuts);
+ for (l = impl->loading_shortcuts; l; l = l->next)
+ {
+ GtkFileSystemHandle *h = l->data;
+ GtkFilePath *p;
- result = shortcuts_insert_path (impl, pos, FALSE, NULL, path, NULL, FALSE, error);
+ p = g_object_get_data (G_OBJECT (h), "add-shortcut-path-key");
+ if (p && !gtk_file_path_compare (path, p))
+ {
+ gchar *uri;
- if (result)
- impl->num_shortcuts++;
+ uri = gtk_file_system_path_to_uri (impl->file_system, path);
+ g_set_error (error,
+ GTK_FILE_CHOOSER_ERROR,
+ GTK_FILE_CHOOSER_ERROR_ALREADY_EXISTS,
+ _("shortcut %s already exists"),
+ uri);
+ g_free (uri);
- if (impl->shortcuts_filter_model)
- gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_filter_model));
+ return FALSE;
+ }
+ }
- return result;
+ data = g_new0 (struct AddShortcutData, 1);
+ data->impl = g_object_ref (impl);
+ data->path = gtk_file_path_copy (path);
+
+ handle = gtk_file_system_get_info (impl->file_system, path,
+ GTK_FILE_INFO_IS_FOLDER,
+ add_shortcut_get_info_cb, data);
+
+ if (!handle)
+ return FALSE;
+
+ impl->loading_shortcuts = g_slist_append (impl->loading_shortcuts, handle);
+ g_object_set_data (G_OBJECT (handle), "add-shortcut-path-key", data->path);
+
+ return TRUE;
}
static gboolean
@@ -5923,9 +6487,24 @@ gtk_file_chooser_default_remove_shortcut_folder (GtkFileChooser *chooser,
GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
int pos;
GtkTreeIter iter;
+ GSList *l;
char *uri;
int i;
+ for (l = impl->loading_shortcuts; l; l = l->next)
+ {
+ GtkFileSystemHandle *h = l->data;
+ GtkFilePath *p;
+
+ p = g_object_get_data (G_OBJECT (h), "add-shortcut-path-key");
+ if (p && !gtk_file_path_compare (path, p))
+ {
+ impl->loading_shortcuts = g_slist_remove (impl->loading_shortcuts, h);
+ gtk_file_system_cancel_operation (h);
+ return TRUE;
+ }
+ }
+
if (impl->num_shortcuts == 0)
goto out;
@@ -6240,48 +6819,46 @@ confirm_dialog_should_accept_filename (GtkFileChooserDefault *impl,
return (response == GTK_RESPONSE_ACCEPT);
}
-static char *
-get_display_name_for_folder (GtkFileChooserDefault *impl,
- const GtkFilePath *path)
+struct GetDisplayNameData
{
- char *display_name;
- GtkFilePath *parent_path;
- GtkFileFolder *parent_folder;
- GtkFileInfo *info;
+ GtkFileChooserDefault *impl;
+ gchar *file_part;
+};
- display_name = NULL;
- parent_path = NULL;
- parent_folder = NULL;
- info = NULL;
+static void
+confirmation_confirm_get_info_cb (GtkFileSystemHandle *handle,
+ const GtkFileInfo *info,
+ const GError *error,
+ gpointer user_data)
+{
+ gboolean cancelled = handle->cancelled;
+ gboolean should_respond = FALSE;
+ struct GetDisplayNameData *data = user_data;
- if (!gtk_file_system_get_parent (impl->file_system, path, &parent_path, NULL))
+ if (handle != data->impl->should_respond_get_info_handle)
goto out;
- parent_folder = gtk_file_system_get_folder (impl->file_system,
- parent_path ? parent_path : path,
- GTK_FILE_INFO_DISPLAY_NAME,
- NULL);
- if (!parent_folder)
- goto out;
+ data->impl->should_respond_get_info_handle = NULL;
- info = gtk_file_folder_get_info (parent_folder, parent_path ? path : NULL, NULL);
- if (!info)
+ if (cancelled)
goto out;
- display_name = g_strdup (gtk_file_info_get_display_name (info));
-
- out:
-
- if (parent_path)
- gtk_file_path_free (parent_path);
+ if (error)
+ /* Huh? Did the folder disappear? Let the caller deal with it */
+ should_respond = TRUE;
+ else
+ should_respond = confirm_dialog_should_accept_filename (data->impl, data->file_part, gtk_file_info_get_display_name (info));
- if (parent_folder)
- g_object_unref (parent_folder);
+ set_busy_cursor (data->impl, FALSE);
+ if (should_respond)
+ g_signal_emit_by_name (data->impl, "response-requested");
- if (info)
- gtk_file_info_free (info);
+out:
+ g_object_unref (data->impl);
+ g_free (data->file_part);
+ g_free (data);
- return display_name;
+ g_object_unref (handle);
}
/* Does overwrite confirmation if appropriate, and returns whether the dialog
@@ -6305,18 +6882,24 @@ should_respond_after_confirm_overwrite (GtkFileChooserDefault *impl,
{
case GTK_FILE_CHOOSER_CONFIRMATION_CONFIRM:
{
- char *parent_display_name;
- gboolean retval;
+ struct GetDisplayNameData *data;
g_assert (file_part != NULL);
- parent_display_name = get_display_name_for_folder (impl, parent_path);
- if (!parent_display_name)
- return TRUE; /* Huh? Did the folder disappear? Let the caller deal with it */
+ data = g_new0 (struct GetDisplayNameData, 1);
+ data->impl = g_object_ref (impl);
+ data->file_part = g_strdup (file_part);
+
+ if (impl->should_respond_get_info_handle)
+ gtk_file_system_cancel_operation (impl->should_respond_get_info_handle);
- retval = confirm_dialog_should_accept_filename (impl, file_part, parent_display_name);
- g_free (parent_display_name);
- return retval;
+ impl->should_respond_get_info_handle =
+ gtk_file_system_get_info (impl->file_system, parent_path,
+ GTK_FILE_INFO_DISPLAY_NAME,
+ confirmation_confirm_get_info_cb,
+ data);
+ set_busy_cursor (data->impl, TRUE);
+ return FALSE;
}
case GTK_FILE_CHOOSER_CONFIRMATION_ACCEPT_FILENAME:
@@ -6331,6 +6914,114 @@ should_respond_after_confirm_overwrite (GtkFileChooserDefault *impl,
}
}
+static void
+action_create_folder_cb (GtkFileSystemHandle *handle,
+ const GtkFilePath *path,
+ const GError *error,
+ gpointer user_data)
+{
+ gboolean cancelled = handle->cancelled;
+ GtkFileChooserDefault *impl = user_data;
+
+ if (!g_slist_find (impl->pending_handles, handle))
+ goto out;
+
+ impl->pending_handles = g_slist_remove (impl->pending_handles, handle);
+
+ set_busy_cursor (impl, FALSE);
+
+ if (cancelled)
+ goto out;
+
+ if (error)
+ error_creating_folder_dialog (impl, path, g_error_copy (error));
+ else
+ g_signal_emit_by_name (impl, "response-requested");
+
+out:
+ g_object_unref (impl);
+ g_object_unref (handle);
+}
+
+struct SaveEntryData
+{
+ GtkFileChooserDefault *impl;
+ gboolean file_exists_and_is_not_folder;
+ GtkFilePath *parent_path;
+ GtkFilePath *path;
+};
+
+static void
+save_entry_get_info_cb (GtkFileSystemHandle *handle,
+ const GtkFileInfo *info,
+ const GError *error,
+ gpointer user_data)
+{
+ gboolean parent_is_folder;
+ gboolean cancelled = handle->cancelled;
+ struct SaveEntryData *data = user_data;
+
+ if (handle != data->impl->should_respond_get_info_handle)
+ goto out;
+
+ data->impl->should_respond_get_info_handle = NULL;
+
+ set_busy_cursor (data->impl, FALSE);
+
+ if (cancelled)
+ goto out;
+
+ if (!info)
+ parent_is_folder = FALSE;
+ else
+ parent_is_folder = gtk_file_info_get_is_folder (info);
+
+ if (parent_is_folder)
+ {
+ if (data->impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
+ {
+ if (data->file_exists_and_is_not_folder)
+ {
+ gboolean retval;
+ const char *file_part;
+
+ file_part = _gtk_file_chooser_entry_get_file_part (GTK_FILE_CHOOSER_ENTRY (data->impl->save_file_name_entry));
+ retval = should_respond_after_confirm_overwrite (data->impl, file_part, data->parent_path);
+
+ if (retval)
+ g_signal_emit_by_name (data->impl, "response-requested");
+ }
+ else
+ g_signal_emit_by_name (data->impl, "response-requested");
+ }
+ else /* GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER */
+ {
+ GtkFileSystemHandle *handle;
+
+ g_object_ref (data->impl);
+ handle = gtk_file_system_create_folder (data->impl->file_system,
+ data->path,
+ action_create_folder_cb,
+ data->impl);
+ data->impl->pending_handles = g_slist_append (data->impl->pending_handles, handle);
+ set_busy_cursor (data->impl, TRUE);
+ }
+ }
+ else
+ {
+ /* This will display an error, which is what we want */
+ change_folder_and_display_error (data->impl, data->parent_path);
+ }
+
+out:
+ g_object_unref (data->impl);
+ gtk_file_path_free (data->path);
+ gtk_file_path_free (data->parent_path);
+ g_free (data);
+
+ g_object_unref (handle);
+}
+
/* Implementation for GtkFileChooserEmbed::should_respond() */
static gboolean
gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed)
@@ -6437,7 +7128,7 @@ gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed)
|| impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER);
entry = GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry);
- check_save_entry (impl, &path, &is_well_formed, &is_empty, &is_file_part_empty);
+ check_save_entry (impl, &path, &is_well_formed, &is_empty, &is_file_part_empty, &is_folder);
if (is_empty || !is_well_formed)
return FALSE;
@@ -6445,7 +7136,6 @@ gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed)
g_assert (path != NULL);
error = NULL;
- is_folder = check_is_folder (impl->file_system, path, &error);
if (is_folder)
{
if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
@@ -6478,48 +7168,29 @@ gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed)
else
{
GtkFilePath *parent_path;
- gboolean parent_is_folder;
+ struct SaveEntryData *data;
/* check that everything up to the last component exists */
parent_path = gtk_file_path_copy (_gtk_file_chooser_entry_get_current_folder (entry));
- parent_is_folder = check_is_folder (impl->file_system, parent_path, NULL);
- if (parent_is_folder)
- {
- if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
- {
- if (file_exists_and_is_not_folder)
- {
- const char *file_part;
-
- file_part = _gtk_file_chooser_entry_get_file_part (GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry));
- retval = should_respond_after_confirm_overwrite (impl, file_part, parent_path);
- }
- else
- retval = TRUE;
- }
- else /* GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER */
- {
- GError *create_error;
-
- create_error = NULL;
- if (gtk_file_system_create_folder (impl->file_system, path, &create_error))
- retval = TRUE;
- else
- {
- error_creating_folder_dialog (impl, path, create_error);
- retval = FALSE;
- }
- }
- }
- else
- {
- /* This will display an error, which is what we want */
- change_folder_and_display_error (impl, parent_path);
- retval = FALSE;
- }
- gtk_file_path_free (parent_path);
+ data = g_new0 (struct SaveEntryData, 1);
+ data->impl = g_object_ref (impl);
+ data->file_exists_and_is_not_folder = file_exists_and_is_not_folder;
+ data->parent_path = parent_path; /* Takes ownership */
+ data->path = gtk_file_path_copy (path);
+
+ if (impl->should_respond_get_info_handle)
+ gtk_file_system_cancel_operation (impl->should_respond_get_info_handle);
+
+ impl->should_respond_get_info_handle =
+ gtk_file_system_get_info (impl->file_system, parent_path,
+ GTK_FILE_INFO_IS_FOLDER,
+ save_entry_get_info_cb,
+ data);
+ set_busy_cursor (impl, TRUE);
+
+ retval = FALSE;
}
if (error != NULL)
@@ -6691,6 +7362,51 @@ check_preview_change (GtkFileChooserDefault *impl)
}
}
+static void
+shortcuts_activate_volume_mount_cb (GtkFileSystemHandle *handle,
+ GtkFileSystemVolume *volume,
+ const GError *error,
+ gpointer data)
+{
+ GtkFilePath *path;
+ gboolean cancelled = handle->cancelled;
+ GtkFileChooserDefault *impl = data;
+
+ if (handle != impl->shortcuts_activate_iter_handle)
+ goto out;
+
+ impl->shortcuts_activate_iter_handle = NULL;
+
+ set_busy_cursor (impl, FALSE);
+
+ if (cancelled)
+ goto out;
+
+ if (error)
+ {
+ char *msg;
+
+ msg = g_strdup_printf (_("Could not mount %s"),
+ gtk_file_system_volume_get_display_name (impl->file_system, volume));
+ error_message (impl, msg, error->message);
+ g_free (msg);
+
+ goto out;
+ }
+
+ path = gtk_file_system_volume_get_base_path (impl->file_system, volume);
+ if (path != NULL)
+ {
+ change_folder_and_display_error (impl, path);
+ gtk_file_path_free (path);
+ }
+
+out:
+ g_object_unref (impl);
+ g_object_unref (handle);
+}
+
+
/* Activates a volume by mounting it if necessary and then switching to its
* base path.
*/
@@ -6707,44 +7423,63 @@ shortcuts_activate_volume (GtkFileChooserDefault *impl,
if (!gtk_file_system_volume_get_is_mounted (impl->file_system, volume))
{
- GError *error;
- gboolean result;
-
set_busy_cursor (impl, TRUE);
- error = NULL;
- result = gtk_file_system_volume_mount (impl->file_system, volume, &error);
+ impl->shortcuts_activate_iter_handle =
+ gtk_file_system_volume_mount (impl->file_system, volume,
+ shortcuts_activate_volume_mount_cb,
+ g_object_ref (impl));
+ }
+ else
+ {
+ path = gtk_file_system_volume_get_base_path (impl->file_system, volume);
+ if (path != NULL)
+ {
+ change_folder_and_display_error (impl, path);
+ gtk_file_path_free (path);
+ }
+ }
- if (!result)
- {
- char *msg;
+ g_object_unref (impl);
+}
- msg = g_strdup_printf (_("Could not mount %s"),
- gtk_file_system_volume_get_display_name (impl->file_system, volume));
- error_message (impl, msg, error->message);
- g_free (msg);
- g_error_free (error);
- }
+/* Opens the folder or volume at the specified iter in the shortcuts model */
+struct ShortcutsActivateData
+{
+ GtkFileChooserDefault *impl;
+ GtkFilePath *path;
+};
- set_busy_cursor (impl, FALSE);
+static void
+shortcuts_activate_get_info_cb (GtkFileSystemHandle *handle,
+ const GtkFileInfo *info,
+ const GError *error,
+ gpointer user_data)
+{
+ gboolean cancelled = handle->cancelled;
+ struct ShortcutsActivateData *data = user_data;
- if (!result)
- goto out;
- }
+ if (handle != data->impl->shortcuts_activate_iter_handle)
+ goto out;
- path = gtk_file_system_volume_get_base_path (impl->file_system, volume);
- if (path != NULL)
- {
- change_folder_and_display_error (impl, path);
- gtk_file_path_free (path);
- }
+ data->impl->shortcuts_activate_iter_handle = NULL;
- out:
+ if (cancelled)
+ goto out;
- g_object_unref (impl);
+ if (!error && gtk_file_info_get_is_folder (info))
+ change_folder_and_display_error (data->impl, data->path);
+ else
+ gtk_file_chooser_default_select_path (GTK_FILE_CHOOSER (data->impl), data->path, NULL);
+
+out:
+ g_object_unref (data->impl);
+ gtk_file_path_free (data->path);
+ g_free (data);
+
+ g_object_unref (handle);
}
-/* Opens the folder or volume at the specified iter in the shortcuts model */
static void
shortcuts_activate_iter (GtkFileChooserDefault *impl,
GtkTreeIter *iter)
@@ -6760,6 +7495,12 @@ shortcuts_activate_iter (GtkFileChooserDefault *impl,
if (!col_data)
return; /* We are on a separator */
+ if (impl->shortcuts_activate_iter_handle)
+ {
+ gtk_file_system_cancel_operation (impl->shortcuts_activate_iter_handle);
+ impl->shortcuts_activate_iter_handle = NULL;
+ }
+
if (is_volume)
{
GtkFileSystemVolume *volume;
@@ -6770,13 +7511,16 @@ shortcuts_activate_iter (GtkFileChooserDefault *impl,
}
else
{
- const GtkFilePath *file_path;
+ struct ShortcutsActivateData *data;
- file_path = col_data;
- if (check_is_folder (impl->file_system, file_path, NULL))
- change_folder_and_display_error (impl, file_path);
- else
- gtk_file_chooser_default_select_path (GTK_FILE_CHOOSER (impl), file_path, NULL);
+ data = g_new0 (struct ShortcutsActivateData, 1);
+ data->impl = g_object_ref (impl);
+ data->path = gtk_file_path_copy (col_data);
+
+ impl->shortcuts_activate_iter_handle =
+ gtk_file_system_get_info (impl->file_system, data->path,
+ GTK_FILE_INFO_IS_FOLDER,
+ shortcuts_activate_get_info_cb, data);
}
}
@@ -6989,9 +7733,14 @@ list_icon_data_func (GtkTreeViewColumn *tree_column,
if (path)
{
- /* FIXME: NULL GError */
- pixbuf = gtk_file_system_render_icon (impl->file_system, path, GTK_WIDGET (impl),
- impl->icon_size, NULL);
+ pixbuf = NULL;
+
+ if (info)
+ {
+ /* FIXME: NULL GError */
+ pixbuf = gtk_file_info_render_icon (info, GTK_WIDGET (impl),
+ impl->icon_size, NULL);
+ }
}
else
{
@@ -7199,6 +7948,75 @@ location_entry_create (GtkFileChooserDefault *impl,
return GTK_WIDGET (entry);
}
+struct UpdateFromEntryData
+{
+ GtkFileChooserDefault *impl;
+ GtkFilePath *subfolder_path;
+ GtkFilePath *folder_path;
+ char *file_part;
+};
+
+static void
+update_from_entry_get_info_cb (GtkFileSystemHandle *handle,
+ const GtkFileInfo *file_info,
+ const GError *error,
+ gpointer user_data)
+{
+ gboolean cancelled = handle->cancelled;
+ struct UpdateFromEntryData *data = user_data;
+
+ if (handle != data->impl->update_from_entry_handle)
+ goto out;
+
+ data->impl->update_from_entry_handle = NULL;
+
+ if (cancelled)
+ goto out;
+
+ if (!file_info)
+ {
+ if (data->impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
+ || data->impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+ {
+ if (!change_folder_and_display_error (data->impl, data->folder_path))
+ goto out;
+
+ gtk_file_chooser_default_set_current_name (GTK_FILE_CHOOSER (data->impl), data->file_part);
+ }
+ else
+ {
+ GError *err = g_error_copy (error);
+
+ error_getting_info_dialog (data->impl, data->subfolder_path, err);
+ }
+
+ goto out;
+ }
+
+ if (gtk_file_info_get_is_folder (file_info))
+ change_folder_and_display_error (data->impl, data->subfolder_path);
+ else
+ {
+ gboolean result;
+ GError *select_error = NULL;
+
+ result = _gtk_file_chooser_select_path (GTK_FILE_CHOOSER (data->impl), data->subfolder_path, &select_error);
+
+ if (!result)
+ error_dialog (data->impl, _("Could not select item"),
+ data->subfolder_path, select_error);
+ }
+
+out:
+ g_object_unref (data->impl);
+ gtk_file_path_free (data->subfolder_path);
+ gtk_file_path_free (data->folder_path);
+ g_free (data->file_part);
+ g_free (data);
+
+ g_object_unref (handle);
+}
+
static gboolean
update_from_entry (GtkFileChooserDefault *impl,
GtkWindow *parent,
@@ -7222,29 +8040,16 @@ update_from_entry (GtkFileChooserDefault *impl,
return change_folder_and_display_error (impl, folder_path);
else
{
- GtkFileFolder *folder = NULL;
GtkFilePath *subfolder_path = NULL;
- GtkFileInfo *info = NULL;
- GError *error;
- gboolean result;
-
- result = FALSE;
+ GError *error = NULL;
+ gboolean result = FALSE;
+ struct UpdateFromEntryData *data;
/* If the file part is non-empty, we need to figure out if it refers to a
* folder within folder. We could optimize the case here where the folder
* is already loaded for one of our tree models.
*/
- error = NULL;
- folder = gtk_file_system_get_folder (impl->file_system, folder_path, GTK_FILE_INFO_IS_FOLDER, &error);
-
- if (!folder)
- {
- error_getting_info_dialog (impl, folder_path, error);
- goto out;
- }
-
- error = NULL;
subfolder_path = gtk_file_system_make_path (impl->file_system, folder_path, file_part, &error);
if (!subfolder_path)
@@ -7256,54 +8061,29 @@ update_from_entry (GtkFileChooserDefault *impl,
msg = g_strdup_printf (_("Could not build file name from '%s' and '%s'"),
uri, file_part);
error_message (impl, msg, error->message);
+
g_free (uri);
g_free (msg);
- goto out;
- }
-
- error = NULL;
- info = gtk_file_folder_get_info (folder, subfolder_path, &error);
-
- if (!info)
- {
- if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
- || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
- {
- if (!change_folder_and_display_error (impl, folder_path))
- goto out;
-
- gtk_file_chooser_default_set_current_name (GTK_FILE_CHOOSER (impl), file_part);
- }
- else
- error_getting_info_dialog (impl, subfolder_path, error);
+ gtk_file_path_free (subfolder_path);
- goto out;
+ return result;
}
- if (gtk_file_info_get_is_folder (info))
- result = change_folder_and_display_error (impl, subfolder_path);
- else
- {
- GError *error;
-
- error = NULL;
- result = _gtk_file_chooser_select_path (GTK_FILE_CHOOSER (impl), subfolder_path, &error);
- if (!result)
- error_dialog (impl, _("Could not select item"),
- subfolder_path, error);
- }
+ data = g_new0 (struct UpdateFromEntryData, 1);
+ data->impl = g_object_ref (impl);
+ data->folder_path = gtk_file_path_copy (folder_path);
+ data->subfolder_path = subfolder_path;
+ data->file_part = g_strdup (file_part);
- out:
+ if (impl->update_from_entry_handle)
+ gtk_file_system_cancel_operation (impl->update_from_entry_handle);
- if (folder)
- g_object_unref (folder);
+ impl->update_from_entry_handle =
+ gtk_file_system_get_info (impl->file_system, subfolder_path,
+ GTK_FILE_INFO_IS_FOLDER,
+ update_from_entry_get_info_cb, data);
- gtk_file_path_free (subfolder_path);
-
- if (info)
- gtk_file_info_free (info);
-
- return result;
+ return TRUE;
}
g_assert_not_reached ();
diff --git a/gtk/gtkfilechooserdialog.c b/gtk/gtkfilechooserdialog.c
index 32a9fa9ce..9db98970a 100644
--- a/gtk/gtkfilechooserdialog.c
+++ b/gtk/gtkfilechooserdialog.c
@@ -129,6 +129,7 @@ gtk_file_chooser_dialog_init (GtkFileChooserDialog *dialog)
dialog->priv->default_height = -1;
dialog->priv->resize_horizontally = TRUE;
dialog->priv->resize_vertically = TRUE;
+ dialog->priv->response_requested = FALSE;
gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
@@ -355,6 +356,39 @@ file_chooser_widget_default_size_changed (GtkWidget *widget,
else
file_chooser_widget_default_unrealized_size_changed (widget, dialog);
}
+
+static void
+file_chooser_widget_response_requested (GtkWidget *widget,
+ GtkFileChooserDialog *dialog)
+{
+ GList *children, *l;
+
+ /* There probably isn't a default widget, so make things easier for the
+ * programmer by looking for a reasonable button on our own.
+ */
+
+ children = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
+
+ for (l = children; l; l = l->next)
+ {
+ GtkWidget *widget;
+ int response_id;
+
+ widget = GTK_WIDGET (l->data);
+ response_id = gtk_dialog_get_response_for_widget (GTK_DIALOG (dialog), widget);
+ if (response_id == GTK_RESPONSE_ACCEPT
+ || response_id == GTK_RESPONSE_OK
+ || response_id == GTK_RESPONSE_YES
+ || response_id == GTK_RESPONSE_APPLY)
+ {
+ dialog->priv->response_requested = TRUE;
+ gtk_widget_activate (widget); /* Should we gtk_dialog_response (dialog, response_id) instead? */
+ break;
+ }
+ }
+
+ g_list_free (children);
+}
static GObject*
gtk_file_chooser_dialog_constructor (GType type,
@@ -382,6 +416,8 @@ gtk_file_chooser_dialog_constructor (GType type,
G_CALLBACK (file_chooser_widget_file_activated), object);
g_signal_connect (priv->widget, "default-size-changed",
G_CALLBACK (file_chooser_widget_default_size_changed), object);
+ g_signal_connect (priv->widget, "response-requested",
+ G_CALLBACK (file_chooser_widget_response_requested), object);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (object)->vbox), priv->widget, TRUE, TRUE, 0);
@@ -550,8 +586,11 @@ response_cb (GtkDialog *dialog,
|| response_id == GTK_RESPONSE_APPLY))
return;
- if (!_gtk_file_chooser_embed_should_respond (GTK_FILE_CHOOSER_EMBED (priv->widget)))
- g_signal_stop_emission_by_name (dialog, "response");
+ if (!priv->response_requested && !_gtk_file_chooser_embed_should_respond (GTK_FILE_CHOOSER_EMBED (priv->widget)))
+ {
+ g_signal_stop_emission_by_name (dialog, "response");
+ priv->response_requested = FALSE;
+ }
}
static GtkWidget *
diff --git a/gtk/gtkfilechooserembed.c b/gtk/gtkfilechooserembed.c
index 1f584a3d8..8871fb7ad 100644
--- a/gtk/gtkfilechooserembed.c
+++ b/gtk/gtkfilechooserembed.c
@@ -35,6 +35,8 @@ static gboolean delegate_should_respond (GtkFileChooserEmbed *chooser_embe
static void delegate_initial_focus (GtkFileChooserEmbed *chooser_embed);
static void delegate_default_size_changed (GtkFileChooserEmbed *chooser_embed,
gpointer data);
+static void delegate_response_requested (GtkFileChooserEmbed *chooser_embed,
+ gpointer data);
static GtkFileChooserEmbed *
get_delegate (GtkFileChooserEmbed *receiver)
@@ -81,6 +83,8 @@ _gtk_file_chooser_embed_set_delegate (GtkFileChooserEmbed *receiver,
g_signal_connect (delegate, "default_size_changed",
G_CALLBACK (delegate_default_size_changed), receiver);
+ g_signal_connect (delegate, "response_requested",
+ G_CALLBACK (delegate_response_requested), receiver);
}
@@ -120,6 +124,13 @@ delegate_default_size_changed (GtkFileChooserEmbed *chooser_embed,
g_signal_emit_by_name (data, "default-size-changed");
}
+static void
+delegate_response_requested (GtkFileChooserEmbed *chooser_embed,
+ gpointer data)
+{
+ g_signal_emit_by_name (data, "response-requested");
+}
+
/* publicly callable functions */
@@ -160,6 +171,13 @@ gtk_file_chooser_embed_class_init (gpointer g_iface)
NULL, NULL,
_gtk_marshal_VOID__VOID,
G_TYPE_NONE, 0);
+ g_signal_new (_("response-requested"),
+ iface_type,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkFileChooserEmbedIface, response_requested),
+ NULL, NULL,
+ _gtk_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
}
void
diff --git a/gtk/gtkfilechooserembed.h b/gtk/gtkfilechooserembed.h
index 98b0ae54e..9477da068 100644
--- a/gtk/gtkfilechooserembed.h
+++ b/gtk/gtkfilechooserembed.h
@@ -53,6 +53,7 @@ struct _GtkFileChooserEmbedIface
/* Signals
*/
void (*default_size_changed) (GtkFileChooserEmbed *chooser_embed);
+ void (*response_requested) (GtkFileChooserEmbed *chooser_embed);
};
GType _gtk_file_chooser_embed_get_type (void) G_GNUC_CONST;
diff --git a/gtk/gtkfilechooserentry.c b/gtk/gtkfilechooserentry.c
index acbd1206c..cbae54c12 100644
--- a/gtk/gtkfilechooserentry.c
+++ b/gtk/gtkfilechooserentry.c
@@ -55,6 +55,7 @@ struct _GtkFileChooserEntry
GSource *load_directory_idle;
GtkFileFolder *current_folder;
+ GtkFileSystemHandle *load_folder_handle;
GtkListStore *completion_store;
@@ -75,6 +76,7 @@ static void gtk_file_chooser_entry_iface_init (GtkEditableClass *iface);
static void gtk_file_chooser_entry_init (GtkFileChooserEntry *chooser_entry);
static void gtk_file_chooser_entry_finalize (GObject *object);
+static void gtk_file_chooser_entry_dispose (GObject *object);
static gboolean gtk_file_chooser_entry_focus (GtkWidget *widget,
GtkDirectionType direction);
static void gtk_file_chooser_entry_activate (GtkEntry *entry);
@@ -156,6 +158,7 @@ gtk_file_chooser_entry_class_init (GtkFileChooserEntryClass *class)
parent_class = g_type_class_peek_parent (class);
gobject_class->finalize = gtk_file_chooser_entry_finalize;
+ gobject_class->dispose = gtk_file_chooser_entry_dispose;
widget_class->focus = gtk_file_chooser_entry_focus;
@@ -211,8 +214,29 @@ gtk_file_chooser_entry_finalize (GObject *object)
{
GtkFileChooserEntry *chooser_entry = GTK_FILE_CHOOSER_ENTRY (object);
+ gtk_file_path_free (chooser_entry->base_folder);
+ gtk_file_path_free (chooser_entry->current_folder_path);
+ g_free (chooser_entry->file_part);
+
+ parent_class->finalize (object);
+}
+
+static void
+gtk_file_chooser_entry_dispose (GObject *object)
+{
+ GtkFileChooserEntry *chooser_entry = GTK_FILE_CHOOSER_ENTRY (object);
+
if (chooser_entry->completion_store)
- g_object_unref (chooser_entry->completion_store);
+ {
+ g_object_unref (chooser_entry->completion_store);
+ chooser_entry->completion_store = NULL;
+ }
+
+ if (chooser_entry->load_folder_handle)
+ {
+ gtk_file_system_cancel_operation (chooser_entry->load_folder_handle);
+ chooser_entry->load_folder_handle = NULL;
+ }
if (chooser_entry->current_folder)
{
@@ -221,16 +245,16 @@ gtk_file_chooser_entry_finalize (GObject *object)
g_signal_handlers_disconnect_by_func (chooser_entry->current_folder,
G_CALLBACK (files_deleted_cb), chooser_entry);
g_object_unref (chooser_entry->current_folder);
+ chooser_entry->current_folder = NULL;
}
if (chooser_entry->file_system)
- g_object_unref (chooser_entry->file_system);
-
- gtk_file_path_free (chooser_entry->base_folder);
- gtk_file_path_free (chooser_entry->current_folder_path);
- g_free (chooser_entry->file_part);
+ {
+ g_object_unref (chooser_entry->file_system);
+ chooser_entry->file_system = NULL;
+ }
- parent_class->finalize (object);
+ parent_class->dispose (object);
}
/* Match functions for the GtkEntryCompletion */
@@ -601,6 +625,41 @@ files_deleted_cb (GtkFileSystem *file_system,
/* FIXME: gravy... */
}
+static void
+load_directory_get_folder_callback (GtkFileSystemHandle *handle,
+ GtkFileFolder *folder,
+ const GError *error,
+ gpointer data)
+{
+ gboolean cancelled = handle->cancelled;
+ GtkFileChooserEntry *chooser_entry = data;
+
+ if (handle != chooser_entry->load_folder_handle)
+ goto out;
+
+ chooser_entry->load_folder_handle = NULL;
+
+ if (cancelled || error)
+ goto out;
+
+ chooser_entry->current_folder = folder;
+ g_signal_connect (chooser_entry->current_folder, "files-added",
+ G_CALLBACK (files_added_cb), chooser_entry);
+ g_signal_connect (chooser_entry->current_folder, "files-removed",
+ G_CALLBACK (files_deleted_cb), chooser_entry);
+
+ chooser_entry->completion_store = gtk_list_store_new (N_COLUMNS,
+ G_TYPE_STRING,
+ GTK_TYPE_FILE_PATH);
+
+ gtk_entry_completion_set_model (gtk_entry_get_completion (GTK_ENTRY (chooser_entry)),
+ GTK_TREE_MODEL (chooser_entry->completion_store));
+
+out:
+ g_object_unref (chooser_entry);
+ g_object_unref (handle);
+}
+
static gboolean
load_directory_callback (GtkFileChooserEntry *chooser_entry)
{
@@ -623,38 +682,15 @@ load_directory_callback (GtkFileChooserEntry *chooser_entry)
g_assert (chooser_entry->completion_store == NULL);
/* Load the folder */
- chooser_entry->current_folder = gtk_file_system_get_folder (chooser_entry->file_system,
- chooser_entry->current_folder_path,
- GTK_FILE_INFO_DISPLAY_NAME | GTK_FILE_INFO_IS_FOLDER,
- NULL); /* NULL-GError */
-
- /* There is no folder by that name */
- if (!chooser_entry->current_folder)
- goto done;
- g_signal_connect (chooser_entry->current_folder, "files-added",
- G_CALLBACK (files_added_cb), chooser_entry);
- g_signal_connect (chooser_entry->current_folder, "files-removed",
- G_CALLBACK (files_deleted_cb), chooser_entry);
-
- chooser_entry->completion_store = gtk_list_store_new (N_COLUMNS,
- G_TYPE_STRING,
- GTK_TYPE_FILE_PATH);
+ if (chooser_entry->load_folder_handle)
+ gtk_file_system_cancel_operation (chooser_entry->load_folder_handle);
- if (chooser_entry->file_part_pos != -1)
- {
- gtk_file_folder_list_children (chooser_entry->current_folder,
- &child_paths,
- NULL); /* NULL-GError */
- if (child_paths)
- {
- update_current_folder_files (chooser_entry, child_paths);
- add_completion_idle (chooser_entry);
- gtk_file_paths_free (child_paths);
- }
- }
-
- gtk_entry_completion_set_model (gtk_entry_get_completion (GTK_ENTRY (chooser_entry)),
- GTK_TREE_MODEL (chooser_entry->completion_store));
+ chooser_entry->load_folder_handle =
+ gtk_file_system_get_folder (chooser_entry->file_system,
+ chooser_entry->current_folder_path,
+ GTK_FILE_INFO_DISPLAY_NAME | GTK_FILE_INFO_IS_FOLDER,
+ load_directory_get_folder_callback,
+ g_object_ref (chooser_entry));
done:
@@ -1041,5 +1077,27 @@ _gtk_file_chooser_entry_get_action (GtkFileChooserEntry *chooser_entry)
return chooser_entry->action;
}
+gboolean
+_gtk_file_chooser_entry_get_is_folder (GtkFileChooserEntry *chooser_entry,
+ const GtkFilePath *path)
+{
+ gboolean retval = FALSE;
+
+ if (chooser_entry->current_folder)
+ {
+ GtkFileInfo *file_info;
+
+ file_info = gtk_file_folder_get_info (chooser_entry->current_folder,
+ path, NULL);
+ if (file_info)
+ {
+ retval = gtk_file_info_get_is_folder (file_info);
+ gtk_file_info_free (file_info);
+ }
+ }
+
+ return retval;
+}
+
#define __GTK_FILE_CHOOSER_ENTRY_C__
#include "gtkaliasdef.c"
diff --git a/gtk/gtkfilechooserentry.h b/gtk/gtkfilechooserentry.h
index 04c70dd4d..19d06b87c 100644
--- a/gtk/gtkfilechooserentry.h
+++ b/gtk/gtkfilechooserentry.h
@@ -46,6 +46,8 @@ void _gtk_file_chooser_entry_set_file_part (GtkFileChooserEnt
const gchar *file_part);
const GtkFilePath *_gtk_file_chooser_entry_get_current_folder (GtkFileChooserEntry *chooser_entry);
const gchar * _gtk_file_chooser_entry_get_file_part (GtkFileChooserEntry *chooser_entry);
+gboolean _gtk_file_chooser_entry_get_is_folder (GtkFileChooserEntry *chooser_entry,
+ const GtkFilePath *path);
G_END_DECLS
diff --git a/gtk/gtkfilechooserprivate.h b/gtk/gtkfilechooserprivate.h
index e9d45aae8..34ad17b40 100644
--- a/gtk/gtkfilechooserprivate.h
+++ b/gtk/gtkfilechooserprivate.h
@@ -113,6 +113,7 @@ struct _GtkFileChooserDialogPrivate
gint default_height;
gboolean resize_horizontally;
gboolean resize_vertically;
+ gboolean response_requested;
};
@@ -187,6 +188,17 @@ struct _GtkFileChooserDefault
GtkTreeModelSort *sort_model;
+ /* Handles */
+ GSList *loading_shortcuts;
+ GSList *reload_icon_handles;
+ GtkFileSystemHandle *file_list_drag_data_received_handle;
+ GtkFileSystemHandle *update_current_folder_handle;
+ GtkFileSystemHandle *show_and_select_paths_handle;
+ GtkFileSystemHandle *should_respond_get_info_handle;
+ GtkFileSystemHandle *update_from_entry_handle;
+ GtkFileSystemHandle *shortcuts_activate_iter_handle;
+ GSList *pending_handles;
+
LoadState load_state;
ReloadState reload_state;
guint load_timeout_id;
@@ -267,9 +279,10 @@ struct _GtkFileSystemModel
GSList *idle_clears;
GSource *idle_clear_source;
- GSource *idle_finished_loading_source;
gushort max_depth;
+
+ GSList *pending_handles;
guint show_hidden : 1;
guint show_folders : 1;
@@ -300,6 +313,7 @@ struct _FileModelNode
guint is_visible : 1;
guint loaded : 1;
guint idle_clear : 1;
+ guint load_pending : 1;
};
diff --git a/gtk/gtkfilesystem.c b/gtk/gtkfilesystem.c
index 4ccc1cac1..d1af8fe93 100644
--- a/gtk/gtkfilesystem.c
+++ b/gtk/gtkfilesystem.c
@@ -25,6 +25,7 @@
#include "gtkmodules.h"
#include "gtkintl.h"
#include "gtkalias.h"
+#include "gtkstock.h"
#include <string.h>
@@ -35,6 +36,7 @@ struct _GtkFileInfo
gchar *display_name;
gchar *display_key;
gchar *mime_type;
+ gchar *icon_name;
guint is_folder : 1;
guint is_hidden : 1;
};
@@ -88,6 +90,10 @@ gtk_file_info_copy (GtkFileInfo *info)
new_info->display_key = g_strdup (new_info->display_key);
if (new_info->mime_type)
new_info->mime_type = g_strdup (new_info->mime_type);
+ if (new_info->icon_name)
+ new_info->icon_name = g_strdup (new_info->icon_name);
+ if (new_info->display_key)
+ new_info->display_key = g_strdup (new_info->display_key);
return new_info;
}
@@ -103,6 +109,8 @@ gtk_file_info_free (GtkFileInfo *info)
g_free (info->mime_type);
if (info->display_key)
g_free (info->display_key);
+ if (info->icon_name)
+ g_free (info->icon_name);
g_free (info);
}
@@ -250,6 +258,171 @@ gtk_file_info_set_size (GtkFileInfo *info,
info->size = size;
}
+void
+gtk_file_info_set_icon_name (GtkFileInfo *info,
+ const gchar *icon_name)
+{
+ g_return_if_fail (info != NULL);
+
+ if (info->icon_name)
+ g_free (info->icon_name);
+
+ info->icon_name = g_strdup (icon_name);
+}
+
+G_CONST_RETURN gchar *
+gtk_file_info_get_icon_name (const GtkFileInfo *info)
+{
+ g_return_val_if_fail (info != NULL, NULL);
+
+ return info->icon_name;
+}
+
+GdkPixbuf *
+gtk_file_info_render_icon (const GtkFileInfo *info,
+ GtkWidget *widget,
+ gint pixel_size,
+ GError **error)
+{
+ GdkPixbuf *pixbuf = NULL;
+
+ g_return_val_if_fail (info != NULL, NULL);
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
+
+ if (info->icon_name)
+ {
+ if (g_path_is_absolute (info->icon_name))
+ pixbuf = gdk_pixbuf_new_from_file_at_size (info->icon_name,
+ pixel_size,
+ pixel_size,
+ NULL);
+ else
+ {
+ GtkIconTheme *icon_theme;
+
+ icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (widget));
+ pixbuf = gtk_icon_theme_load_icon (icon_theme, info->icon_name,
+ pixel_size, 0, NULL);
+ }
+ }
+
+ if (!pixbuf)
+ {
+ /* load a fallback icon */
+ pixbuf = gtk_widget_render_icon (widget, GTK_STOCK_FILE, GTK_ICON_SIZE_SMALL_TOOLBAR, NULL);
+ if (!pixbuf && error)
+ g_set_error (error,
+ GTK_FILE_SYSTEM_ERROR,
+ GTK_FILE_SYSTEM_ERROR_FAILED,
+ _("Could not get a stock icon for %s\n"),
+ info->icon_name);
+ }
+
+ return pixbuf;
+}
+
+/*****************************************
+ * GtkFileSystemHandle *
+ *****************************************/
+
+static void gtk_file_system_handle_init (GtkFileSystemHandle *handle);
+static void gtk_file_system_handle_class_init (GtkFileSystemHandleClass *klass);
+
+enum
+{
+ PROP_0,
+ PROP_CANCELLED
+};
+
+GType
+gtk_file_system_handle_get_type (void)
+{
+ static GType file_system_handle_type = 0;
+
+ if (!file_system_handle_type)
+ {
+ static const GTypeInfo file_system_handle_info =
+ {
+ sizeof (GtkFileSystemHandleClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) gtk_file_system_handle_class_init,
+ NULL,
+ NULL,
+ sizeof (GtkFileSystemHandle),
+ 0,
+ (GInstanceInitFunc) gtk_file_system_handle_init,
+ };
+
+ file_system_handle_type = g_type_register_static (G_TYPE_OBJECT,
+ I_("GtkFileSystemHandle"),
+ &file_system_handle_info, 0);
+ }
+
+ return file_system_handle_type;
+}
+
+#if 0
+GtkFileSystemHandle *
+gtk_file_system_handle_new (void)
+{
+ return g_object_new (GTK_TYPE_FILE_SYSTEM_HANDLE, NULL);
+}
+#endif
+
+static void
+gtk_file_system_handle_init (GtkFileSystemHandle *handle)
+{
+ handle->file_system = NULL;
+ handle->cancelled = FALSE;
+}
+
+static void
+gtk_file_system_handle_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+}
+
+static void
+gtk_file_system_handle_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GtkFileSystemHandle *handle = GTK_FILE_SYSTEM_HANDLE (object);
+
+ switch (prop_id)
+ {
+ case PROP_CANCELLED:
+ g_value_set_boolean (value, handle->cancelled);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gtk_file_system_handle_class_init (GtkFileSystemHandleClass *klass)
+{
+ GObjectClass *o_class;
+
+ o_class = (GObjectClass *)klass;
+ o_class->set_property = gtk_file_system_handle_set_property;
+ o_class->get_property = gtk_file_system_handle_get_property;
+
+ g_object_class_install_property (o_class,
+ PROP_CANCELLED,
+ g_param_spec_boolean ("cancelled",
+ P_("Cancelled"),
+ P_("Whether or not the operation has been successfully cancelled"),
+ FALSE,
+ G_PARAM_READABLE));
+}
/*****************************************
* GtkFileSystem *
@@ -314,29 +487,53 @@ gtk_file_system_list_volumes (GtkFileSystem *file_system)
return GTK_FILE_SYSTEM_GET_IFACE (file_system)->list_volumes (file_system);
}
-GtkFileFolder *
-gtk_file_system_get_folder (GtkFileSystem *file_system,
- const GtkFilePath *path,
- GtkFileInfoType types,
- GError **error)
+GtkFileSystemHandle *
+gtk_file_system_get_folder (GtkFileSystem *file_system,
+ const GtkFilePath *path,
+ GtkFileInfoType types,
+ GtkFileSystemGetFolderCallback callback,
+ gpointer data)
{
g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
g_return_val_if_fail (path != NULL, NULL);
- g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+ g_return_val_if_fail (callback != NULL, NULL);
- return GTK_FILE_SYSTEM_GET_IFACE (file_system)->get_folder (file_system, path, types, error);
+ return GTK_FILE_SYSTEM_GET_IFACE (file_system)->get_folder (file_system, path, types, callback, data);
}
-gboolean
-gtk_file_system_create_folder(GtkFileSystem *file_system,
- const GtkFilePath *path,
- GError **error)
+GtkFileSystemHandle *
+gtk_file_system_get_info (GtkFileSystem *file_system,
+ const GtkFilePath *path,
+ GtkFileInfoType types,
+ GtkFileSystemGetInfoCallback callback,
+ gpointer data)
{
- g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), FALSE);
- g_return_val_if_fail (path != NULL, FALSE);
- g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+ g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
+ g_return_val_if_fail (path != NULL, NULL);
+ g_return_val_if_fail (callback != NULL, NULL);
+
+ return GTK_FILE_SYSTEM_GET_IFACE (file_system)->get_info (file_system, path, types, callback, data);
+}
+
+GtkFileSystemHandle *
+gtk_file_system_create_folder (GtkFileSystem *file_system,
+ const GtkFilePath *path,
+ GtkFileSystemCreateFolderCallback callback,
+ gpointer data)
+{
+ g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
+ g_return_val_if_fail (path != NULL, NULL);
+ g_return_val_if_fail (callback != NULL, NULL);
- return GTK_FILE_SYSTEM_GET_IFACE (file_system)->create_folder (file_system, path, error);
+ return GTK_FILE_SYSTEM_GET_IFACE (file_system)->create_folder (file_system, path, callback, data);
+}
+
+void
+gtk_file_system_cancel_operation (GtkFileSystemHandle *handle)
+{
+ g_return_if_fail (GTK_IS_FILE_SYSTEM_HANDLE (handle));
+
+ return GTK_FILE_SYSTEM_GET_IFACE (handle->file_system)->cancel_operation (handle);
}
/**
@@ -432,16 +629,18 @@ gtk_file_system_volume_get_is_mounted (GtkFileSystem *file_system,
*
* Return value: TRUE if the @volume was mounted successfully, FALSE otherwise.
**/
-gboolean
-gtk_file_system_volume_mount (GtkFileSystem *file_system,
- GtkFileSystemVolume *volume,
- GError **error)
+/* FIXME XXX: update documentation above */
+GtkFileSystemHandle *
+gtk_file_system_volume_mount (GtkFileSystem *file_system,
+ GtkFileSystemVolume *volume,
+ GtkFileSystemVolumeMountCallback callback,
+ gpointer data)
{
- g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), FALSE);
- g_return_val_if_fail (volume != NULL, FALSE);
- g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+ g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
+ g_return_val_if_fail (volume != NULL, NULL);
+ g_return_val_if_fail (callback != NULL, NULL);
- return GTK_FILE_SYSTEM_GET_IFACE (file_system)->volume_mount (file_system, volume, error);
+ return GTK_FILE_SYSTEM_GET_IFACE (file_system)->volume_mount (file_system, volume, callback, data);
}
/**
@@ -485,17 +684,53 @@ gtk_file_system_volume_render_icon (GtkFileSystem *file_system,
gint pixel_size,
GError **error)
{
+ gchar *icon_name;
+ GdkPixbuf *pixbuf;
+
g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
g_return_val_if_fail (volume != NULL, NULL);
g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
g_return_val_if_fail (pixel_size > 0, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
- return GTK_FILE_SYSTEM_GET_IFACE (file_system)->volume_render_icon (file_system,
- volume,
- widget,
- pixel_size,
- error);
+ icon_name = gtk_file_system_volume_get_icon_name (file_system, volume,
+ error);
+ if (!icon_name)
+ {
+ return NULL;
+ }
+
+ pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_for_screen (gtk_widget_get_screen (widget)),
+ icon_name, pixel_size, 0, NULL);
+ g_free (icon_name);
+
+ return pixbuf;
+}
+
+/**
+ * gtk_file_system_volume_get_icon_name:
+ * @file_system: a #GtkFileSystem
+ * @volume: a #GtkFileSystemVolume
+ * @error: location to store error, or %NULL
+ *
+ * Gets an icon name suitable for a #GtkFileSystemVolume.
+ *
+ * Return value: An icon name which can be used for rendering an icon for
+ * this volume, or %NULL if no icon name could be found. In the latter
+ * case, the @error value will be set as appropriate.
+ **/
+gchar *
+gtk_file_system_volume_get_icon_name (GtkFileSystem *file_system,
+ GtkFileSystemVolume *volume,
+ GError **error)
+{
+ g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
+ g_return_val_if_fail (volume != NULL, NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ return GTK_FILE_SYSTEM_GET_IFACE (file_system)->volume_get_icon_name (file_system,
+ volume,
+ error);
}
/**
@@ -682,21 +917,6 @@ gtk_file_system_path_is_local (GtkFileSystem *file_system,
return result;
}
-GdkPixbuf *
-gtk_file_system_render_icon (GtkFileSystem *file_system,
- const GtkFilePath *path,
- GtkWidget *widget,
- gint pixel_size,
- GError **error)
-{
- g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
- g_return_val_if_fail (path != NULL, NULL);
- g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
- g_return_val_if_fail (pixel_size > 0, NULL);
-
- return GTK_FILE_SYSTEM_GET_IFACE (file_system)->render_icon (file_system, path, widget, pixel_size, error);
-}
-
/**
* gtk_file_system_insert_bookmark:
* @file_system: a #GtkFileSystem
diff --git a/gtk/gtkfilesystem.h b/gtk/gtkfilesystem.h
index 6f038fdbc..57c458a02 100644
--- a/gtk/gtkfilesystem.h
+++ b/gtk/gtkfilesystem.h
@@ -55,7 +55,8 @@ typedef enum {
GTK_FILE_INFO_MIME_TYPE = 1 << 3,
GTK_FILE_INFO_MODIFICATION_TIME = 1 << 4,
GTK_FILE_INFO_SIZE = 1 << 5,
- GTK_FILE_INFO_ALL = (1 << 6) - 1
+ GTK_FILE_INFO_ICON = 1 << 6,
+ GTK_FILE_INFO_ALL = (1 << 7) - 1
} GtkFileInfoType;
/* GError enumeration for GtkFileSystem
@@ -106,6 +107,43 @@ gint64 gtk_file_info_get_size (const GtkFileInfo *in
void gtk_file_info_set_size (GtkFileInfo *info,
gint64 size);
+void gtk_file_info_set_icon_name (GtkFileInfo *info,
+ const gchar *con_name);
+G_CONST_RETURN gchar *gtk_file_info_get_icon_name (const GtkFileInfo *info);
+GdkPixbuf *gtk_file_info_render_icon (const GtkFileInfo *info,
+ GtkWidget *widget,
+ gint pixel_size,
+ GError **error);
+
+/* GtkFileSystemHandle
+ */
+
+#define GTK_TYPE_FILE_SYSTEM_HANDLE (gtk_file_system_handle_get_type ())
+#define GTK_FILE_SYSTEM_HANDLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_FILE_SYSTEM_HANDLE, GtkFileSystemHandle))
+#define GTK_IS_FILE_SYSTEM_HANDLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_FILE_SYSTEM_HANDLE))
+#define GTK_FILE_SYSTEM_HANDLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_SYSTEM_HANDLE, GtkFileSystemHandleUnixClass))
+#define GTK_IS_FILE_SYSTEM_HANDLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_SYSTEM_HANDLE))
+#define GTK_FILE_SYSTEM_HANDLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILE_SYSTEM_HANDLE, GtkFileSystemHandleClass))
+
+typedef struct _GtkFileSystemHandle GtkFileSystemHandle;
+typedef struct _GtkFileSystemHandleClass GtkFileSystemHandleClass;
+
+struct _GtkFileSystemHandle
+{
+ GObject parent_instance;
+
+ GtkFileSystem *file_system;
+
+ guint cancelled : 1;
+};
+
+struct _GtkFileSystemHandleClass
+{
+ GObjectClass parent_class;
+};
+
+GType gtk_file_system_handle_get_type (void);
+
/* The base GtkFileSystem interface
*/
#define GTK_TYPE_FILE_SYSTEM (gtk_file_system_get_type ())
@@ -113,6 +151,29 @@ void gtk_file_info_set_size (GtkFileInfo *in
#define GTK_IS_FILE_SYSTEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_FILE_SYSTEM))
#define GTK_FILE_SYSTEM_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GTK_TYPE_FILE_SYSTEM, GtkFileSystemIface))
+/* Callbacks for the asynchronous GtkFileSystem operations
+ */
+
+typedef void (* GtkFileSystemGetInfoCallback) (GtkFileSystemHandle *handle,
+ const GtkFileInfo *file_info,
+ const GError *error,
+ gpointer data);
+typedef void (* GtkFileSystemGetFolderCallback) (GtkFileSystemHandle *handle,
+ GtkFileFolder *folder,
+ const GError *error,
+ gpointer data);
+typedef void (* GtkFileSystemCreateFolderCallback) (GtkFileSystemHandle *handle,
+ const GtkFilePath *path,
+ const GError *error,
+ gpointer data);
+typedef void (* GtkFileSystemVolumeMountCallback) (GtkFileSystemHandle *handle,
+ GtkFileSystemVolume *volume,
+ const GError *error,
+ gpointer data);
+
+/*
+ */
+
struct _GtkFileSystemIface
{
GTypeInterface base_iface;
@@ -123,13 +184,22 @@ struct _GtkFileSystemIface
GtkFileSystemVolume * (*get_volume_for_path) (GtkFileSystem *file_system,
const GtkFilePath *path);
- GtkFileFolder * (*get_folder) (GtkFileSystem *file_system,
- const GtkFilePath *path,
- GtkFileInfoType types,
- GError **error);
- gboolean (*create_folder) (GtkFileSystem *file_system,
- const GtkFilePath *path,
- GError **error);
+ GtkFileSystemHandle * (*get_folder) (GtkFileSystem *file_system,
+ const GtkFilePath *path,
+ GtkFileInfoType types,
+ GtkFileSystemGetFolderCallback callback,
+ gpointer data);
+ GtkFileSystemHandle * (*get_info) (GtkFileSystem *file_system,
+ const GtkFilePath *path,
+ GtkFileInfoType types,
+ GtkFileSystemGetInfoCallback callback,
+ gpointer data);
+ GtkFileSystemHandle * (*create_folder) (GtkFileSystem *file_system,
+ const GtkFilePath *path,
+ GtkFileSystemCreateFolderCallback callback,
+ gpointer data);
+
+ void (*cancel_operation) (GtkFileSystemHandle *handle);
/* Volumes
*/
@@ -139,15 +209,14 @@ struct _GtkFileSystemIface
GtkFileSystemVolume *volume);
gboolean (*volume_get_is_mounted) (GtkFileSystem *file_system,
GtkFileSystemVolume *volume);
- gboolean (*volume_mount) (GtkFileSystem *file_system,
- GtkFileSystemVolume *volume,
- GError **error);
- char * (*volume_get_display_name) (GtkFileSystem *file_system,
+ GtkFileSystemHandle * (*volume_mount) (GtkFileSystem *file_system,
+ GtkFileSystemVolume *volume,
+ GtkFileSystemVolumeMountCallback callback,
+ gpointer data);
+ char * (*volume_get_display_name) (GtkFileSystem *file_system,
GtkFileSystemVolume *volume);
- GdkPixbuf * (*volume_render_icon) (GtkFileSystem *file_system,
+ gchar * (*volume_get_icon_name) (GtkFileSystem *file_system,
GtkFileSystemVolume *volume,
- GtkWidget *widget,
- gint pixel_size,
GError **error);
/* Path Manipulation
@@ -175,14 +244,6 @@ struct _GtkFileSystemIface
GtkFilePath *(*filename_to_path) (GtkFileSystem *file_system,
const gchar *path);
- /* Icons
- */
- GdkPixbuf * (*render_icon) (GtkFileSystem *file_system,
- const GtkFilePath *path,
- GtkWidget *widget,
- gint pixel_size,
- GError **error);
-
/* Bookmarks
*/
gboolean (*insert_bookmark) (GtkFileSystem *file_system,
@@ -221,9 +282,10 @@ GtkFilePath * gtk_file_system_volume_get_base_path (GtkFileSystem
GtkFileSystemVolume *volume);
gboolean gtk_file_system_volume_get_is_mounted (GtkFileSystem *file_system,
GtkFileSystemVolume *volume);
-gboolean gtk_file_system_volume_mount (GtkFileSystem *file_system,
- GtkFileSystemVolume *volume,
- GError **error);
+GtkFileSystemHandle *gtk_file_system_volume_mount (GtkFileSystem *file_system,
+ GtkFileSystemVolume *volume,
+ GtkFileSystemVolumeMountCallback callback,
+ gpointer data);
char * gtk_file_system_volume_get_display_name (GtkFileSystem *file_system,
GtkFileSystemVolume *volume);
GdkPixbuf * gtk_file_system_volume_render_icon (GtkFileSystem *file_system,
@@ -231,18 +293,29 @@ GdkPixbuf * gtk_file_system_volume_render_icon (GtkFileSystem
GtkWidget *widget,
gint pixel_size,
GError **error);
+gchar * gtk_file_system_volume_get_icon_name (GtkFileSystem *file_system,
+ GtkFileSystemVolume *volume,
+ GError **error);
gboolean gtk_file_system_get_parent (GtkFileSystem *file_system,
const GtkFilePath *path,
GtkFilePath **parent,
GError **error);
-GtkFileFolder *gtk_file_system_get_folder (GtkFileSystem *file_system,
- const GtkFilePath *path,
- GtkFileInfoType types,
- GError **error);
-gboolean gtk_file_system_create_folder (GtkFileSystem *file_system,
- const GtkFilePath *path,
- GError **error);
+GtkFileSystemHandle *gtk_file_system_get_folder (GtkFileSystem *file_system,
+ const GtkFilePath *path,
+ GtkFileInfoType types,
+ GtkFileSystemGetFolderCallback callback,
+ gpointer data);
+GtkFileSystemHandle *gtk_file_system_get_info (GtkFileSystem *file_system,
+ const GtkFilePath *path,
+ GtkFileInfoType types,
+ GtkFileSystemGetInfoCallback callback,
+ gpointer data);
+GtkFileSystemHandle *gtk_file_system_create_folder (GtkFileSystem *file_system,
+ const GtkFilePath *path,
+ GtkFileSystemCreateFolderCallback callback,
+ gpointer data);
+void gtk_file_system_cancel_operation (GtkFileSystemHandle *handle);
GtkFilePath * gtk_file_system_make_path (GtkFileSystem *file_system,
const GtkFilePath *base_path,
const gchar *display_name,
@@ -266,12 +339,6 @@ GtkFilePath *gtk_file_system_filename_to_path (GtkFileSystem *file_system,
gboolean gtk_file_system_path_is_local (GtkFileSystem *filesystem,
const GtkFilePath *path);
-GdkPixbuf *gtk_file_system_render_icon (GtkFileSystem *file_system,
- const GtkFilePath *path,
- GtkWidget *widget,
- gint pixel_size,
- GError **error);
-
gboolean gtk_file_system_insert_bookmark (GtkFileSystem *file_system,
const GtkFilePath *path,
gint position,
diff --git a/gtk/gtkfilesystemmodel.c b/gtk/gtkfilesystemmodel.c
index b2ad218ea..d365351ad 100644
--- a/gtk/gtkfilesystemmodel.c
+++ b/gtk/gtkfilesystemmodel.c
@@ -50,6 +50,7 @@ static void gtk_file_system_model_class_init (GtkFileSystemModelClass *class);
static void gtk_file_system_model_iface_init (GtkTreeModelIface *iface);
static void gtk_file_system_model_init (GtkFileSystemModel *model);
static void gtk_file_system_model_finalize (GObject *object);
+static void gtk_file_system_model_dispose (GObject *object);
static void drag_source_iface_init (GtkTreeDragSourceIface *iface);
@@ -205,6 +206,7 @@ gtk_file_system_model_class_init (GtkFileSystemModelClass *class)
parent_class = g_type_class_peek_parent (class);
gobject_class->finalize = gtk_file_system_model_finalize;
+ gobject_class->dispose = gtk_file_system_model_dispose;
file_system_model_signals[FINISHED_LOADING] =
g_signal_new (I_("finished-loading"),
@@ -258,9 +260,6 @@ gtk_file_system_model_finalize (GObject *object)
if (model->file_system)
g_object_unref (model->file_system);
- if (model->idle_finished_loading_source)
- g_source_destroy (model->idle_finished_loading_source);
-
children = model->roots;
while (children)
{
@@ -272,6 +271,25 @@ gtk_file_system_model_finalize (GObject *object)
G_OBJECT_CLASS (parent_class)->finalize (object);
}
+
+static void
+gtk_file_system_model_dispose (GObject *object)
+{
+ GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (object);
+
+ if (model->pending_handles)
+ {
+ GSList *l;
+
+ for (l = model->pending_handles; l; l = l->next)
+ gtk_file_system_cancel_operation (l->data);
+ g_slist_free (model->pending_handles);
+ model->pending_handles = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
static void
drag_source_iface_init (GtkTreeDragSourceIface *iface)
{
@@ -630,33 +648,75 @@ root_folder_finished_loading_cb (GtkFileFolder *folder,
g_signal_emit (model, file_system_model_signals[FINISHED_LOADING], 0);
}
-/* Emits the "finished-loading" signal as an idle handler; see the comment in
- * _gtk_file_system_model_new()
- */
-static gboolean
-idle_finished_loading_cb (GtkFileSystemModel *model)
+static void
+got_root_folder_cb (GtkFileSystemHandle *handle,
+ GtkFileFolder *folder,
+ const GError *error,
+ gpointer data)
{
- GDK_THREADS_ENTER ();
+ GSList *roots = NULL;
+ GSList *tmp_list;
+ gboolean cancelled = handle->cancelled;
+ GtkFileSystemModel *model = data;
- g_signal_emit (model, file_system_model_signals[FINISHED_LOADING], 0);
+ tmp_list = g_slist_find (model->pending_handles, handle);
+ if (!tmp_list)
+ goto out;
- g_source_destroy (model->idle_finished_loading_source);
- model->idle_finished_loading_source = NULL;
+ model->pending_handles = g_slist_remove_link (model->pending_handles,
+ tmp_list);
- GDK_THREADS_LEAVE ();
+ if (cancelled || !folder)
+ goto out;
- return FALSE;
-}
+ model->root_folder = folder;
-/* Queues an idle handler to emit the "finished-loading" signal */
-static void
-queue_finished_loading (GtkFileSystemModel *model)
-{
- model->idle_finished_loading_source = g_idle_source_new ();
- g_source_set_closure (model->idle_finished_loading_source,
- g_cclosure_new_object (G_CALLBACK (idle_finished_loading_cb),
- G_OBJECT (model)));
- g_source_attach (model->idle_finished_loading_source, NULL);
+ if (gtk_file_folder_is_finished_loading (model->root_folder))
+ g_signal_emit (model, file_system_model_signals[FINISHED_LOADING], 0);
+ else
+ g_signal_connect_object (model->root_folder, "finished-loading",
+ G_CALLBACK (root_folder_finished_loading_cb), model, 0);
+
+ gtk_file_folder_list_children (model->root_folder, &roots, NULL);
+
+ g_signal_connect_object (model->root_folder, "deleted",
+ G_CALLBACK (root_deleted_callback), model, 0);
+ g_signal_connect_object (model->root_folder, "files-added",
+ G_CALLBACK (root_files_added_callback), model, 0);
+ g_signal_connect_object (model->root_folder, "files-changed",
+ G_CALLBACK (root_files_changed_callback), model, 0);
+ g_signal_connect_object (model->root_folder, "files-removed",
+ G_CALLBACK (root_files_removed_callback), model, 0);
+
+ roots = gtk_file_paths_sort (roots);
+
+ for (tmp_list = roots; tmp_list; tmp_list = tmp_list->next)
+ {
+ FileModelNode *node = file_model_node_new (model, tmp_list->data);
+ gtk_file_path_free (tmp_list->data);
+ node->is_visible = file_model_node_is_visible (model, node);
+ node->next = model->roots;
+ node->depth = 0;
+ model->roots = node;
+
+ if (node->is_visible)
+ {
+ GtkTreeIter iter;
+ GtkTreePath *path;
+
+ iter.user_data = node;
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
+ gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, &iter);
+ gtk_tree_path_free (path);
+ }
+ }
+ g_slist_free (roots);
+
+ model->roots = (FileModelNode *) g_slist_reverse ((GSList *)model->roots);
+
+out:
+ g_object_unref (model);
+ g_object_unref (handle);
}
/**
@@ -691,28 +751,15 @@ _gtk_file_system_model_new (GtkFileSystem *file_system,
GError **error)
{
GtkFileSystemModel *model;
- GtkFileFolder *root_folder;
- GSList *roots;
- GSList *tmp_list;
+ GtkFileSystemHandle *handle;
g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
g_return_val_if_fail (root_path != NULL, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
- /* First, try to load the folder */
+ /* First, start loading the root folder */
types |= GTK_FILE_INFO_IS_FOLDER | GTK_FILE_INFO_IS_HIDDEN;
-
- root_folder = gtk_file_system_get_folder (file_system, root_path, types, error);
-
- if (!root_folder)
- return NULL;
-
- if (!gtk_file_folder_list_children (root_folder, &roots, error))
- {
- g_object_unref (root_folder);
- return NULL;
- }
/* Then, actually create the model and the root nodes */
@@ -724,39 +771,32 @@ _gtk_file_system_model_new (GtkFileSystem *file_system,
model->max_depth = MIN (max_depth, G_MAXUSHORT);
model->types = types;
- model->root_folder = root_folder;
+ model->root_folder = NULL;
model->root_path = gtk_file_path_copy (root_path);
- if (gtk_file_folder_is_finished_loading (model->root_folder))
- queue_finished_loading (model); /* done in an idle because we are being created */
- else
- g_signal_connect_object (model->root_folder, "finished-loading",
- G_CALLBACK (root_folder_finished_loading_cb), model, 0);
-
- g_signal_connect_object (model->root_folder, "deleted",
- G_CALLBACK (root_deleted_callback), model, 0);
- g_signal_connect_object (model->root_folder, "files-added",
- G_CALLBACK (root_files_added_callback), model, 0);
- g_signal_connect_object (model->root_folder, "files-changed",
- G_CALLBACK (root_files_changed_callback), model, 0);
- g_signal_connect_object (model->root_folder, "files-removed",
- G_CALLBACK (root_files_removed_callback), model, 0);
+ model->roots = NULL;
- roots = gtk_file_paths_sort (roots);
-
- for (tmp_list = roots; tmp_list; tmp_list = tmp_list->next)
+ handle = gtk_file_system_get_folder (file_system, root_path, types,
+ got_root_folder_cb,
+ g_object_ref (model));
+ if (!handle)
{
- FileModelNode *node = file_model_node_new (model, tmp_list->data);
- gtk_file_path_free (tmp_list->data);
- node->is_visible = file_model_node_is_visible (model, node);
- node->next = model->roots;
- node->depth = 0;
- model->roots = node;
+ /* In this case got_root_folder_cb() will never be called, so we
+ * need to unref model twice.
+ */
+ g_object_unref (model);
+ g_object_unref (model);
+
+ g_set_error (error,
+ GTK_FILE_CHOOSER_ERROR,
+ GTK_FILE_CHOOSER_ERROR_NONEXISTENT,
+ _("Could not obtain root folder"));
+
+ return NULL;
}
- g_slist_free (roots);
- model->roots = (FileModelNode *) g_slist_reverse ((GSList *)model->roots);
-
+ model->pending_handles = g_slist_append (model->pending_handles, handle);
+
return model;
}
@@ -988,58 +1028,6 @@ find_child_node (GtkFileSystemModel *model,
return NULL;
}
-
-
-static FileModelNode *
-find_and_ref_path (GtkFileSystemModel *model,
- const GtkFilePath *path,
- GSList **cleanups)
-{
- GtkFilePath *parent_path;
- FileModelNode *parent_node;
- FileModelNode *child_node;
- GtkFileFolder *folder;
-
- if (gtk_file_path_compare (path, model->root_path) == 0
- || !gtk_file_system_get_parent (model->file_system, path, &parent_path, NULL))
- return NULL;
-
- if (parent_path)
- {
- parent_node = find_and_ref_path (model, parent_path, cleanups);
- gtk_file_path_free (parent_path);
- }
- else
- parent_node = NULL;
-
- child_node = find_child_node (model, parent_node, path);
- if (child_node)
- {
- file_model_node_ref (child_node);
- return child_node;
- }
-
- folder = gtk_file_system_get_folder (model->file_system,
- path,
- model->types,
- NULL); /* NULL-GError */
- if (folder)
- {
- *cleanups = g_slist_prepend (*cleanups, folder);
-
- child_node = find_child_node (model, parent_node, path);
- if (child_node)
- {
- file_model_node_ref (child_node);
- return child_node;
- }
- }
-
- if (parent_node)
- unref_node_and_parents (model, parent_node);
-
- return NULL;
-}
/**
* _gtk_file_system_model_set_filter:
@@ -1064,6 +1052,126 @@ _gtk_file_system_model_set_filter (GtkFileSystemModel *model,
model_refilter_all (model);
}
+
+struct RefPathData
+{
+ GtkFileSystemModel *model;
+ FileModelNode *node;
+ FileModelNode *parent_node;
+ GSList *paths;
+ GSList *cleanups;
+ GtkFileSystemModelPathFunc func;
+ gpointer user_data;
+};
+
+/* FIXME: maybe we have to wait on finished-loading? */
+static void
+ref_path_cb (GtkFileSystemHandle *handle,
+ GtkFileFolder *folder,
+ const GError *error,
+ gpointer data)
+{
+ struct RefPathData *info = data;
+ gboolean cancelled = handle->cancelled;
+
+ if (!g_slist_find (info->model->pending_handles, handle))
+ goto out;
+
+ info->model->pending_handles = g_slist_remove (info->model->pending_handles, handle);
+
+ /* Note that !folder means that the child node was already
+ * found, without using get_folder.
+ */
+ if (cancelled || error)
+ goto out;
+
+ if (folder)
+ info->cleanups = g_slist_prepend (info->cleanups, folder);
+ else if (g_slist_length (info->paths) == 1
+ && gtk_file_path_compare (info->node->path, info->paths->data) == 0)
+ {
+ /* Done, now call the function */
+ if (info->node)
+ {
+ GtkTreeIter iter;
+ GtkTreePath *path;
+
+ iter.user_data = info->node;
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (info->model), &iter);
+
+ (* info->func) (info->model, path, &iter, info->user_data);
+
+ gtk_tree_path_free (path);
+ }
+
+ goto out;
+ }
+
+ info->node = find_child_node (info->model, info->parent_node, info->paths->data);
+ if (info->node)
+ file_model_node_ref (info->node);
+ else
+ {
+ goto out;
+ }
+
+ gtk_file_path_free (info->paths->data);
+ info->paths = g_slist_remove (info->paths, info->paths->data);
+
+ if (g_slist_length (info->paths) < 1)
+ {
+ /* Done, now call the function */
+ if (info->node)
+ {
+ GtkTreeIter iter;
+ GtkTreePath *path;
+
+ iter.user_data = info->node;
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (info->model), &iter);
+
+ (* info->func) (info->model, path, &iter, info->user_data);
+
+ gtk_tree_path_free (path);
+ }
+
+ goto out;
+ }
+ else
+ {
+ info->parent_node = info->node;
+
+ if (info->parent_node->loaded)
+ {
+ info->node = find_child_node (info->model, info->parent_node, info->paths->data);
+ ref_path_cb (NULL, NULL, NULL, info);
+ }
+ else
+ {
+ GtkFileSystemHandle *handle;
+
+ handle = gtk_file_system_get_folder (info->model->file_system,
+ info->paths->data,
+ info->model->types,
+ ref_path_cb, data);
+ info->model->pending_handles =
+ g_slist_append (info->model->pending_handles, handle);
+ }
+
+ return;
+ }
+
+out:
+ if (info->node)
+ unref_node_and_parents (info->model, info->node);
+ gtk_file_paths_free (info->paths);
+ g_slist_foreach (info->cleanups, (GFunc)g_object_unref, NULL);
+ g_slist_free (info->cleanups);
+ g_object_unref (info->model);
+ g_free (info);
+
+ g_object_unref (handle);
+}
+
/**
* _gtk_file_system_model_path_do:
* @model: a #GtkFileSystemModel
@@ -1090,33 +1198,90 @@ _gtk_file_system_model_set_filter (GtkFileSystemModel *model,
* Return value: %TRUE if the path was successfully
* found in @model and @func was called.
**/
-gboolean
-_gtk_file_system_model_path_do (GtkFileSystemModel *model,
- const GtkFilePath *path,
- GtkFileSystemModelPathFunc func,
- gpointer user_data)
+void
+_gtk_file_system_model_path_do (GtkFileSystemModel *model,
+ const GtkFilePath *path,
+ GtkFileSystemModelPathFunc func,
+ gpointer user_data)
{
- GSList *cleanups = NULL;
- FileModelNode *node = find_and_ref_path (model, path, &cleanups);
+ GtkFilePath *parent_path;
+ GSList *paths = NULL;
+ FileModelNode *node;
+ struct RefPathData *info;
- if (node)
- {
- GtkTreeIter iter;
- GtkTreePath *path;
+ if (gtk_file_path_compare (path, model->root_path) == 0
+ || !gtk_file_system_get_parent (model->file_system, path, &parent_path, NULL))
+ return;
- iter.user_data = node;
- path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
+ paths = g_slist_prepend (paths, gtk_file_path_copy (path));
+ while (gtk_file_path_compare (parent_path, model->root_path) != 0)
+ {
+ paths = g_slist_prepend (paths, parent_path);
+ if (!gtk_file_system_get_parent (model->file_system, parent_path, &parent_path, NULL))
+ {
+ gtk_file_paths_free (paths);
+ return;
+ }
+ }
- (*func) (model, path, &iter, user_data);
+ if (g_slist_length (paths) < 1)
+ return;
- gtk_tree_path_free (path);
- unref_node_and_parents (model, node);
+ /* Now we have all paths, except the root path */
+ node = find_child_node (model, NULL, paths->data);
+ if (!node)
+ {
+ gtk_file_paths_free (paths);
+ return;
}
- g_slist_foreach (cleanups, (GFunc)g_object_unref, NULL);
- g_slist_free (cleanups);
+ file_model_node_ref (node);
- return node != NULL;
+ gtk_file_path_free (paths->data);
+ paths = g_slist_remove (paths, paths->data);
+
+ if (g_slist_length (paths) < 1)
+ {
+ /* Done, now call the function */
+ if (node)
+ {
+ GtkTreeIter iter;
+ GtkTreePath *path;
+
+ iter.user_data = node;
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
+
+ (* func) (model, path, &iter, user_data);
+
+ gtk_tree_path_free (path);
+ unref_node_and_parents (model, node);
+ }
+ }
+ else
+ {
+ info = g_new0 (struct RefPathData, 1);
+ info->paths = paths;
+ info->model = g_object_ref (model);
+ info->func = func;
+ info->user_data = user_data;
+ info->node = node;
+
+ if (info->node->loaded)
+ {
+ info->parent_node = info->node;
+ info->node = find_child_node (model, info->parent_node, info->paths->data);
+ ref_path_cb (NULL, NULL, NULL, info);
+ }
+ else
+ {
+ GtkFileSystemHandle *handle;
+
+ handle = gtk_file_system_get_folder (model->file_system,
+ paths->data, model->types,
+ ref_path_cb, info);
+ model->pending_handles = g_slist_append (model->pending_handles, handle);
+ }
+ }
}
/**
@@ -1389,6 +1554,114 @@ file_model_node_child_unref (FileModelNode *parent)
file_model_node_idle_clear (parent);
}
+struct GetChildrenData
+{
+ GtkFileSystemModel *model;
+ FileModelNode *node;
+};
+
+static void
+get_children_get_folder_cb (GtkFileSystemHandle *handle,
+ GtkFileFolder *folder,
+ const GError *error,
+ gpointer callback_data)
+{
+ GSList *child_paths, *tmp_list;
+ gboolean has_children = FALSE;
+ gboolean cancelled = handle->cancelled;
+ struct GetChildrenData *data = callback_data;
+
+ tmp_list = g_slist_find (data->model->pending_handles, handle);
+
+ if (!tmp_list)
+ goto out;
+
+ data->model->pending_handles = g_slist_remove_link (data->model->pending_handles, tmp_list);
+
+ if (cancelled || !folder)
+ {
+ /* error, no folder, remove dummy child */
+ if (data->node->parent && data->node->parent->has_dummy)
+ {
+ data->node->parent->children = NULL;
+ data->node->parent->has_dummy = FALSE;
+ }
+
+ file_model_node_free (data->node);
+
+ goto out;
+ }
+
+ data->node->folder = folder;
+ data->node->load_pending = FALSE;
+
+ if (gtk_file_folder_list_children (folder, &child_paths, NULL)) /* NULL-GError */
+ {
+ child_paths = gtk_file_paths_sort (child_paths);
+
+ for (tmp_list = child_paths; tmp_list; tmp_list = tmp_list->next)
+ {
+ FileModelNode *child_node = file_model_node_new (data->model, tmp_list->data);
+ gtk_file_path_free (tmp_list->data);
+ child_node->next = data->node->children;
+ child_node->parent = data->node;
+ child_node->depth = data->node->depth + 1;
+ child_node->is_visible = file_model_node_is_visible (data->model, child_node);
+
+ if (child_node->is_visible)
+ {
+ GtkTreeIter iter;
+ GtkTreePath *path;
+
+ has_children = TRUE;
+
+ iter.user_data = child_node;
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (data->model), &iter);
+ gtk_tree_model_row_inserted (GTK_TREE_MODEL (data->model), path, &iter);
+ gtk_tree_path_free (path);
+ }
+
+ data->node->children = child_node;
+ }
+ g_slist_free (child_paths);
+ }
+
+ data->node->children = (FileModelNode *)g_slist_reverse ((GSList *)data->node->children);
+
+ g_signal_connect (data->node->folder, "deleted",
+ G_CALLBACK (deleted_callback), data->node);
+ g_signal_connect (data->node->folder, "files-added",
+ G_CALLBACK (files_added_callback), data->node);
+ g_signal_connect (data->node->folder, "files-changed",
+ G_CALLBACK (files_changed_callback), data->node);
+ g_signal_connect (data->node->folder, "files-removed",
+ G_CALLBACK (files_removed_callback), data->node);
+
+ data->node->loaded = TRUE;
+
+ if (!has_children)
+ {
+ /* The hard case ... we claimed this folder had children, but actually
+ * it didn't. We have to add a dummy child, possibly to remove later.
+ */
+ FileModelNode *child_node = file_model_node_new (data->model, NULL);
+ child_node->is_visible = TRUE;
+ child_node->parent = data->node;
+ child_node->is_dummy = TRUE;
+
+ data->node->children = child_node;
+ data->node->has_dummy = TRUE;
+ }
+
+ g_object_set_data (G_OBJECT (data->node->folder), I_("model-node"), data->node);
+
+out:
+ g_object_unref (data->model);
+ g_free (data);
+
+ g_object_unref (handle);
+}
+
static FileModelNode *
file_model_node_get_children (GtkFileSystemModel *model,
FileModelNode *node)
@@ -1396,7 +1669,7 @@ file_model_node_get_children (GtkFileSystemModel *model,
if (node->ref_count == 0)
return NULL;
- if (!node->loaded)
+ if (!node->loaded && !node->load_pending)
{
const GtkFileInfo *info = file_model_node_get_info (model, node);
gboolean has_children = FALSE;
@@ -1405,48 +1678,25 @@ file_model_node_get_children (GtkFileSystemModel *model,
file_model_node_idle_clear_cancel (node);
if (is_folder)
- node->folder = gtk_file_system_get_folder (model->file_system,
- node->path,
- model->types,
- NULL); /* NULL-GError */
-
- if (node->folder)
- {
- GSList *child_paths, *tmp_list;
-
- if (gtk_file_folder_list_children (node->folder, &child_paths, NULL)) /* NULL-GError */
- {
- child_paths = gtk_file_paths_sort (child_paths);
-
- for (tmp_list = child_paths; tmp_list; tmp_list = tmp_list->next)
- {
- FileModelNode *child_node = file_model_node_new (model, tmp_list->data);
- gtk_file_path_free (tmp_list->data);
- child_node->next = node->children;
- child_node->parent = node;
- child_node->depth = node->depth + 1;
- child_node->is_visible = file_model_node_is_visible (model, child_node);
- if (child_node->is_visible)
- has_children = TRUE;
- node->children = child_node;
- }
- g_slist_free (child_paths);
- }
-
- node->children = (FileModelNode *)g_slist_reverse ((GSList *)node->children);
-
- g_signal_connect (node->folder, "deleted",
- G_CALLBACK (deleted_callback), node);
- g_signal_connect (node->folder, "files-added",
- G_CALLBACK (files_added_callback), node);
- g_signal_connect (node->folder, "files-changed",
- G_CALLBACK (files_changed_callback), node);
- g_signal_connect (node->folder, "files-removed",
- G_CALLBACK (files_removed_callback), node);
-
- g_object_set_data (G_OBJECT (node->folder), I_("model-node"), node);
+ {
+ struct GetChildrenData *data;
+ GtkFileSystemHandle *handle;
+
+ data = g_new (struct GetChildrenData, 1);
+ data->model = g_object_ref (model);
+ data->node = node;
+
+ handle =
+ gtk_file_system_get_folder (model->file_system,
+ node->path,
+ model->types,
+ get_children_get_folder_cb,
+ data);
+
+ model->pending_handles = g_slist_append (model->pending_handles, handle);
+ node->load_pending = TRUE;
}
-
+
if (is_folder && !has_children)
{
/* The hard case ... we claimed this folder had children, but actually
@@ -1460,8 +1710,6 @@ file_model_node_get_children (GtkFileSystemModel *model,
node->children = child_node;
node->has_dummy = TRUE;
}
-
- node->loaded = TRUE;
}
return node->children;
diff --git a/gtk/gtkfilesystemmodel.h b/gtk/gtkfilesystemmodel.h
index 2057a142e..c2fa493db 100644
--- a/gtk/gtkfilesystemmodel.h
+++ b/gtk/gtkfilesystemmodel.h
@@ -71,7 +71,7 @@ typedef void (*GtkFileSystemModelPathFunc) (GtkFileSystemModel *model,
GtkTreeIter *iter,
gpointer user_data);
-gboolean _gtk_file_system_model_path_do (GtkFileSystemModel *model,
+void _gtk_file_system_model_path_do (GtkFileSystemModel *model,
const GtkFilePath *path,
GtkFileSystemModelPathFunc func,
gpointer user_data);
diff --git a/gtk/gtkfilesystemunix.c b/gtk/gtkfilesystemunix.c
index 0dfdcd078..39f98a1ab 100644
--- a/gtk/gtkfilesystemunix.c
+++ b/gtk/gtkfilesystemunix.c
@@ -111,10 +111,12 @@ struct _GtkFileFolderUnix
GtkFileInfoType types;
gchar *filename;
GHashTable *stat_info;
+ guint load_folder_id;
guint have_stat : 1;
guint have_mime_type : 1;
guint is_network_dir : 1;
guint have_hidden : 1;
+ guint is_finished_loading : 1;
time_t asof;
};
@@ -127,7 +129,8 @@ struct stat_info_entry {
static const GtkFileInfoType STAT_NEEDED_MASK = (GTK_FILE_INFO_IS_FOLDER |
GTK_FILE_INFO_MODIFICATION_TIME |
- GTK_FILE_INFO_SIZE);
+ GTK_FILE_INFO_SIZE |
+ GTK_FILE_INFO_ICON);
static GObjectClass *system_parent_class;
static GObjectClass *folder_parent_class;
@@ -141,13 +144,21 @@ static GSList * gtk_file_system_unix_list_volumes (GtkFileSys
static GtkFileSystemVolume *gtk_file_system_unix_get_volume_for_path (GtkFileSystem *file_system,
const GtkFilePath *path);
-static GtkFileFolder *gtk_file_system_unix_get_folder (GtkFileSystem *file_system,
- const GtkFilePath *path,
- GtkFileInfoType types,
- GError **error);
-static gboolean gtk_file_system_unix_create_folder (GtkFileSystem *file_system,
- const GtkFilePath *path,
- GError **error);
+static GtkFileSystemHandle *gtk_file_system_unix_get_folder (GtkFileSystem *file_system,
+ const GtkFilePath *path,
+ GtkFileInfoType types,
+ GtkFileSystemGetFolderCallback callback,
+ gpointer data);
+static GtkFileSystemHandle *gtk_file_system_unix_get_info (GtkFileSystem *file_system,
+ const GtkFilePath *path,
+ GtkFileInfoType types,
+ GtkFileSystemGetInfoCallback callback,
+ gpointer data);
+static GtkFileSystemHandle *gtk_file_system_unix_create_folder (GtkFileSystem *file_system,
+ const GtkFilePath *path,
+ GtkFileSystemCreateFolderCallback callback,
+ gpointer data);
+static void gtk_file_system_unix_cancel_operation (GtkFileSystemHandle *handle);
static void gtk_file_system_unix_volume_free (GtkFileSystem *file_system,
GtkFileSystemVolume *volume);
@@ -155,15 +166,14 @@ static GtkFilePath *gtk_file_system_unix_volume_get_base_path (GtkFileSystem
GtkFileSystemVolume *volume);
static gboolean gtk_file_system_unix_volume_get_is_mounted (GtkFileSystem *file_system,
GtkFileSystemVolume *volume);
-static gboolean gtk_file_system_unix_volume_mount (GtkFileSystem *file_system,
+static GtkFileSystemHandle *gtk_file_system_unix_volume_mount (GtkFileSystem *file_system,
GtkFileSystemVolume *volume,
- GError **error);
+ GtkFileSystemVolumeMountCallback callback,
+ gpointer data);
static gchar * gtk_file_system_unix_volume_get_display_name (GtkFileSystem *file_system,
GtkFileSystemVolume *volume);
-static GdkPixbuf * gtk_file_system_unix_volume_render_icon (GtkFileSystem *file_system,
+static gchar * gtk_file_system_unix_volume_get_icon_name (GtkFileSystem *file_system,
GtkFileSystemVolume *volume,
- GtkWidget *widget,
- gint pixel_size,
GError **error);
static gboolean gtk_file_system_unix_get_parent (GtkFileSystem *file_system,
@@ -190,11 +200,6 @@ static GtkFilePath *gtk_file_system_unix_uri_to_path (GtkFileSystem *fi
static GtkFilePath *gtk_file_system_unix_filename_to_path (GtkFileSystem *file_system,
const gchar *filename);
-static GdkPixbuf *gtk_file_system_unix_render_icon (GtkFileSystem *file_system,
- const GtkFilePath *path,
- GtkWidget *widget,
- gint pixel_size,
- GError **error);
static gboolean gtk_file_system_unix_insert_bookmark (GtkFileSystem *file_system,
const GtkFilePath *path,
@@ -229,13 +234,35 @@ static GtkFilePath *filename_to_path (const gchar *filename);
static gboolean filename_is_root (const char *filename);
+static gboolean get_is_hidden_for_file (const char *filename,
+ const char *basename);
static gboolean file_is_hidden (GtkFileFolderUnix *folder_unix,
const char *basename);
-static gboolean fill_in_names (GtkFileFolderUnix *folder_unix, GError **error);
-static void fill_in_stats (GtkFileFolderUnix *folder_unix);
-static void fill_in_mime_type (GtkFileFolderUnix *folder_unix);
-static void fill_in_hidden (GtkFileFolderUnix *folder_unix);
+static GtkFileInfo *file_info_for_root_with_error (const char *root_name,
+ GError **error);
+static gboolean stat_with_error (const char *filename,
+ struct stat *statbuf,
+ GError **error);
+static GtkFileInfo *create_file_info (GtkFileFolderUnix *folder_unix,
+ const char *filename,
+ const char *basename,
+ GtkFileInfoType types,
+ struct stat *statbuf,
+ const char *mime_type);
+
+static gboolean fill_in_names (GtkFileFolderUnix *folder_unix,
+ GError **error);
+static void fill_in_stats (GtkFileFolderUnix *folder_unix);
+static void fill_in_mime_type (GtkFileFolderUnix *folder_unix);
+static void fill_in_hidden (GtkFileFolderUnix *folder_unix);
+
+static gboolean cb_fill_in_stats (gpointer key,
+ gpointer value,
+ gpointer user_data);
+static gboolean cb_fill_in_mime_type (gpointer key,
+ gpointer value,
+ gpointer user_data);
static char * get_parent_dir (const char *filename);
@@ -311,13 +338,15 @@ gtk_file_system_unix_iface_init (GtkFileSystemIface *iface)
iface->list_volumes = gtk_file_system_unix_list_volumes;
iface->get_volume_for_path = gtk_file_system_unix_get_volume_for_path;
iface->get_folder = gtk_file_system_unix_get_folder;
+ iface->get_info = gtk_file_system_unix_get_info;
iface->create_folder = gtk_file_system_unix_create_folder;
+ iface->cancel_operation = gtk_file_system_unix_cancel_operation;
iface->volume_free = gtk_file_system_unix_volume_free;
iface->volume_get_base_path = gtk_file_system_unix_volume_get_base_path;
iface->volume_get_is_mounted = gtk_file_system_unix_volume_get_is_mounted;
iface->volume_mount = gtk_file_system_unix_volume_mount;
iface->volume_get_display_name = gtk_file_system_unix_volume_get_display_name;
- iface->volume_render_icon = gtk_file_system_unix_volume_render_icon;
+ iface->volume_get_icon_name = gtk_file_system_unix_volume_get_icon_name;
iface->get_parent = gtk_file_system_unix_get_parent;
iface->make_path = gtk_file_system_unix_make_path;
iface->parse = gtk_file_system_unix_parse;
@@ -325,7 +354,6 @@ gtk_file_system_unix_iface_init (GtkFileSystemIface *iface)
iface->path_to_filename = gtk_file_system_unix_path_to_filename;
iface->uri_to_path = gtk_file_system_unix_uri_to_path;
iface->filename_to_path = gtk_file_system_unix_filename_to_path;
- iface->render_icon = gtk_file_system_unix_render_icon;
iface->insert_bookmark = gtk_file_system_unix_insert_bookmark;
iface->remove_bookmark = gtk_file_system_unix_remove_bookmark;
iface->list_bookmarks = gtk_file_system_unix_list_bookmarks;
@@ -395,14 +423,386 @@ remove_trailing_slash (const char *filename)
return g_memdup (filename, len + 1);
}
-static GtkFileFolder *
-gtk_file_system_unix_get_folder (GtkFileSystem *file_system,
- const GtkFilePath *path,
- GtkFileInfoType types,
- GError **error)
+/* Delay callback dispatching
+ */
+
+enum callback_types
+{
+ CALLBACK_GET_INFO,
+ CALLBACK_GET_FOLDER,
+ CALLBACK_CREATE_FOLDER,
+ CALLBACK_VOLUME_MOUNT
+};
+
+static void queue_callback (enum callback_types type, gpointer data);
+
+struct get_info_callback
+{
+ GtkFileSystemGetInfoCallback callback;
+ GtkFileSystemHandle *handle;
+ GtkFileInfo *file_info;
+ GError *error;
+ gpointer data;
+};
+
+static inline void
+dispatch_get_info_callback (struct get_info_callback *info)
+{
+ (* info->callback) (info->handle, info->file_info, info->error, info->data);
+
+ if (info->file_info)
+ gtk_file_info_free (info->file_info);
+
+ if (info->error)
+ g_error_free (info->error);
+
+ g_object_unref (info->handle);
+
+ g_free (info);
+}
+
+static inline void
+queue_get_info_callback (GtkFileSystemGetInfoCallback callback,
+ GtkFileSystemHandle *handle,
+ GtkFileInfo *file_info,
+ GError *error,
+ gpointer data)
+{
+ struct get_info_callback *info;
+
+ info = g_new (struct get_info_callback, 1);
+ info->callback = callback;
+ info->handle = handle;
+ info->file_info = file_info;
+ info->error = error;
+ info->data = data;
+
+ queue_callback (CALLBACK_GET_INFO, info);
+}
+
+
+struct get_folder_callback
+{
+ GtkFileSystemGetFolderCallback callback;
+ GtkFileSystemHandle *handle;
+ GtkFileFolder *folder;
+ GError *error;
+ gpointer data;
+};
+
+static inline void
+dispatch_get_folder_callback (struct get_folder_callback *info)
+{
+ (* info->callback) (info->handle, info->folder, info->error, info->data);
+
+ if (info->error)
+ g_error_free (info->error);
+
+ g_object_unref (info->handle);
+
+ g_free (info);
+}
+
+static inline void
+queue_get_folder_callback (GtkFileSystemGetFolderCallback callback,
+ GtkFileSystemHandle *handle,
+ GtkFileFolder *folder,
+ GError *error,
+ gpointer data)
+{
+ struct get_folder_callback *info;
+
+ info = g_new (struct get_folder_callback, 1);
+ info->callback = callback;
+ info->handle = handle;
+ info->folder = folder;
+ info->error = error;
+ info->data = data;
+
+ queue_callback (CALLBACK_GET_FOLDER, info);
+}
+
+
+struct create_folder_callback
{
+ GtkFileSystemCreateFolderCallback callback;
+ GtkFileSystemHandle *handle;
+ GtkFilePath *path;
+ GError *error;
+ gpointer data;
+};
+
+static inline void
+dispatch_create_folder_callback (struct create_folder_callback *info)
+{
+ (* info->callback) (info->handle, info->path, info->error, info->data);
+
+ if (info->error)
+ g_error_free (info->error);
+
+ if (info->path)
+ gtk_file_path_free (info->path);
+
+ g_object_unref (info->handle);
+
+ g_free (info);
+}
+
+static inline void
+queue_create_folder_callback (GtkFileSystemCreateFolderCallback callback,
+ GtkFileSystemHandle *handle,
+ const GtkFilePath *path,
+ GError *error,
+ gpointer data)
+{
+ struct create_folder_callback *info;
+
+ info = g_new (struct create_folder_callback, 1);
+ info->callback = callback;
+ info->handle = handle;
+ info->path = gtk_file_path_copy (path);
+ info->error = error;
+ info->data = data;
+
+ queue_callback (CALLBACK_CREATE_FOLDER, info);
+}
+
+
+struct volume_mount_callback
+{
+ GtkFileSystemVolumeMountCallback callback;
+ GtkFileSystemHandle *handle;
+ GtkFileSystemVolume *volume;
+ GError *error;
+ gpointer data;
+};
+
+static inline void
+dispatch_volume_mount_callback (struct volume_mount_callback *info)
+{
+ (* info->callback) (info->handle, info->volume, info->error, info->data);
+
+ if (info->error)
+ g_error_free (info->error);
+
+ g_object_unref (info->handle);
+
+ g_free (info);
+}
+
+static inline void
+queue_volume_mount_callback (GtkFileSystemVolumeMountCallback callback,
+ GtkFileSystemHandle *handle,
+ GtkFileSystemVolume *volume,
+ GError *error,
+ gpointer data)
+{
+ struct volume_mount_callback *info;
+
+ info = g_new (struct volume_mount_callback, 1);
+ info->callback = callback;
+ info->handle = handle;
+ info->volume = volume;
+ info->error = error;
+ info->data = data;
+
+ queue_callback (CALLBACK_VOLUME_MOUNT, info);
+}
+
+
+struct callback_info
+{
+ enum callback_types type;
+
+ union
+ {
+ struct get_info_callback *get_info;
+ struct get_folder_callback *get_folder;
+ struct create_folder_callback *create_folder;
+ struct volume_mount_callback *volume_mount;
+ } info;
+};
+
+
+static guint execute_callbacks_idle_id = 0;
+static GSList *callbacks = NULL;
+
+static gboolean
+execute_callbacks_idle (gpointer data)
+{
+ GSList *l;
+
+ GDK_THREADS_ENTER ();
+
+ for (l = callbacks; l; l = l->next)
+ {
+ struct callback_info *info = l->data;
+
+ switch (info->type)
+ {
+ case CALLBACK_GET_INFO:
+ dispatch_get_info_callback (info->info.get_info);
+ break;
+
+ case CALLBACK_GET_FOLDER:
+ dispatch_get_folder_callback (info->info.get_folder);
+ break;
+
+ case CALLBACK_CREATE_FOLDER:
+ dispatch_create_folder_callback (info->info.create_folder);
+ break;
+
+ case CALLBACK_VOLUME_MOUNT:
+ dispatch_volume_mount_callback (info->info.volume_mount);
+ break;
+ }
+
+ g_free (info);
+ }
+
+ g_slist_free (callbacks);
+ callbacks = NULL;
+
+ execute_callbacks_idle_id = 0;
+
+ GDK_THREADS_LEAVE ();
+
+ return FALSE;
+}
+
+static void
+queue_callback (enum callback_types type, gpointer data)
+{
+ struct callback_info *info;
+
+ info = g_new (struct callback_info, 1);
+ info->type = type;
+
+ switch (type)
+ {
+ case CALLBACK_GET_INFO:
+ info->info.get_info = data;
+ break;
+
+ case CALLBACK_GET_FOLDER:
+ info->info.get_folder = data;
+ break;
+
+ case CALLBACK_CREATE_FOLDER:
+ info->info.create_folder = data;
+ break;
+
+ case CALLBACK_VOLUME_MOUNT:
+ info->info.volume_mount = data;
+ break;
+ }
+
+ callbacks = g_slist_append (callbacks, info);
+
+ if (!execute_callbacks_idle_id)
+ execute_callbacks_idle_id = g_idle_add (execute_callbacks_idle, NULL);
+}
+
+static GtkFileSystemHandle *
+create_handle (GtkFileSystem *file_system)
+{
+ GtkFileSystemHandle *handle;
+
+ handle = g_object_new (GTK_TYPE_FILE_SYSTEM_HANDLE, NULL);
+ handle->file_system = file_system;
+
+ return handle;
+}
+
+
+
+static GtkFileSystemHandle *
+gtk_file_system_unix_get_info (GtkFileSystem *file_system,
+ const GtkFilePath *path,
+ GtkFileInfoType types,
+ GtkFileSystemGetInfoCallback callback,
+ gpointer data)
+{
+ GError *error = NULL;
+ GtkFileSystemUnix *system_unix;
+ GtkFileSystemHandle *handle;
+ const char *filename;
+ GtkFileInfo *info;
+ gchar *basename;
+ struct stat statbuf;
+ const char *mime_type;
+
+ system_unix = GTK_FILE_SYSTEM_UNIX (file_system);
+ handle = create_handle (file_system);
+
+ filename = gtk_file_path_get_string (path);
+ g_return_val_if_fail (filename != NULL, FALSE);
+ g_return_val_if_fail (g_path_is_absolute (filename), FALSE);
+
+ if (!stat_with_error (filename, &statbuf, &error))
+ {
+ g_object_ref (handle);
+ queue_get_info_callback (callback, handle, NULL, error, data);
+ return handle;
+ }
+
+ if ((types & GTK_FILE_INFO_MIME_TYPE) != 0)
+ mime_type = xdg_mime_get_mime_type_for_file (filename, &statbuf);
+ else
+ mime_type = NULL;
+
+ basename = g_path_get_basename (filename);
+
+ info = create_file_info (NULL, filename, basename, types, &statbuf,
+ mime_type);
+ g_free (basename);
+ g_object_ref (handle);
+ queue_get_info_callback (callback, handle, info, NULL, data);
+
+ return handle;
+}
+
+static gboolean
+load_folder (gpointer data)
+{
+ GtkFileFolderUnix *folder_unix = data;
+ GSList *children;
+
+ GDK_THREADS_ENTER ();
+
+ if ((folder_unix->types & STAT_NEEDED_MASK) != 0)
+ fill_in_stats (folder_unix);
+
+ if ((folder_unix->types & GTK_FILE_INFO_MIME_TYPE) != 0)
+ fill_in_mime_type (folder_unix);
+
+ if (gtk_file_folder_unix_list_children (GTK_FILE_FOLDER (folder_unix), &children, NULL))
+ {
+ folder_unix->is_finished_loading = TRUE;
+ g_signal_emit_by_name (folder_unix, "files-added", children);
+ gtk_file_paths_free (children);
+ }
+
+ folder_unix->load_folder_id = 0;
+
+ g_signal_emit_by_name (folder_unix, "finished-loading", 0);
+
+ GDK_THREADS_LEAVE ();
+
+ return FALSE;
+}
+
+static GtkFileSystemHandle *
+gtk_file_system_unix_get_folder (GtkFileSystem *file_system,
+ const GtkFilePath *path,
+ GtkFileInfoType types,
+ GtkFileSystemGetFolderCallback callback,
+ gpointer data)
+{
+ GError *error = NULL;
GtkFileSystemUnix *system_unix;
GtkFileFolderUnix *folder_unix;
+ GtkFileSystemHandle *handle;
const char *filename;
char *filename_copy;
gboolean set_asof = FALSE;
@@ -413,6 +813,8 @@ gtk_file_system_unix_get_folder (GtkFileSystem *file_system,
g_return_val_if_fail (filename != NULL, NULL);
g_return_val_if_fail (g_path_is_absolute (filename), NULL);
+ handle = create_handle (file_system);
+
filename_copy = remove_trailing_slash (filename);
folder_unix = g_hash_table_lookup (system_unix->folder_hash, filename_copy);
@@ -470,16 +872,19 @@ gtk_file_system_unix_get_folder (GtkFileSystem *file_system,
if (result != 0)
{
gchar *display_name = g_filename_display_name (filename);
- g_set_error (error,
+ g_set_error (&error,
GTK_FILE_SYSTEM_ERROR,
code,
_("Error getting information for '%s': %s"),
display_name,
g_strerror (my_errno));
+ g_object_ref (handle);
+ queue_get_folder_callback (callback, handle, NULL, error, data);
+
g_free (display_name);
g_free (filename_copy);
- return NULL;
+ return handle;
}
folder_unix = g_object_new (GTK_TYPE_FILE_FOLDER_UNIX, NULL);
@@ -487,9 +892,11 @@ gtk_file_system_unix_get_folder (GtkFileSystem *file_system,
folder_unix->filename = filename_copy;
folder_unix->types = types;
folder_unix->stat_info = NULL;
+ folder_unix->load_folder_id = 0;
folder_unix->have_mime_type = FALSE;
folder_unix->have_stat = FALSE;
folder_unix->have_hidden = FALSE;
+ folder_unix->is_finished_loading = FALSE;
set_asof = TRUE;
if ((system_unix->have_afs &&
@@ -507,24 +914,28 @@ gtk_file_system_unix_get_folder (GtkFileSystem *file_system,
folder_unix);
}
- if ((types & STAT_NEEDED_MASK) != 0)
- fill_in_stats (folder_unix);
-
- if ((types & GTK_FILE_INFO_MIME_TYPE) != 0)
- fill_in_mime_type (folder_unix);
-
if (set_asof)
folder_unix->asof = time (NULL);
- return GTK_FILE_FOLDER (folder_unix);
+ g_object_ref (handle);
+ queue_get_folder_callback (callback, handle, GTK_FILE_FOLDER (folder_unix), NULL, data);
+
+ /* Start loading the folder contents in an idle */
+ folder_unix->load_folder_id =
+ g_idle_add ((GSourceFunc) load_folder, folder_unix);
+
+ return handle;
}
-static gboolean
-gtk_file_system_unix_create_folder (GtkFileSystem *file_system,
- const GtkFilePath *path,
- GError **error)
+static GtkFileSystemHandle *
+gtk_file_system_unix_create_folder (GtkFileSystem *file_system,
+ const GtkFilePath *path,
+ GtkFileSystemCreateFolderCallback callback,
+ gpointer data)
{
+ GError *error = NULL;
GtkFileSystemUnix *system_unix;
+ GtkFileSystemHandle *handle;
const char *filename;
gboolean result;
char *parent, *tmp;
@@ -536,6 +947,8 @@ gtk_file_system_unix_create_folder (GtkFileSystem *file_system,
g_return_val_if_fail (filename != NULL, FALSE);
g_return_val_if_fail (g_path_is_absolute (filename), FALSE);
+ handle = create_handle (file_system);
+
tmp = remove_trailing_slash (filename);
errno = 0;
result = mkdir (tmp, 0777) == 0;
@@ -545,18 +958,22 @@ gtk_file_system_unix_create_folder (GtkFileSystem *file_system,
if (!result)
{
gchar *display_name = g_filename_display_name (filename);
- g_set_error (error,
+ g_set_error (&error,
GTK_FILE_SYSTEM_ERROR,
GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
_("Error creating directory '%s': %s"),
display_name,
g_strerror (save_errno));
+
+ g_object_ref (handle);
+ queue_create_folder_callback (callback, handle, path, error, data);
+
g_free (display_name);
- return FALSE;
+ return handle;
}
- if (filename_is_root (filename))
- return TRUE; /* hmmm, but with no notification */
+ g_object_ref (handle);
+ queue_create_folder_callback (callback, handle, path, NULL, data);
parent = get_parent_dir (filename);
if (parent)
@@ -566,34 +983,52 @@ gtk_file_system_unix_create_folder (GtkFileSystem *file_system,
folder_unix = g_hash_table_lookup (system_unix->folder_hash, parent);
if (folder_unix)
{
- GtkFileInfoType types;
- GtkFilePath *parent_path;
GSList *paths;
- GtkFileFolder *folder;
+ char *basename;
+ struct stat_info_entry *entry;
- /* This is sort of a hack. We re-get the folder, to ensure that the
- * newly-created directory gets read into the folder's info hash table.
- */
-
- types = folder_unix->types;
+ /* Make sure the new folder exists in the parent's folder */
+ entry = g_new0 (struct stat_info_entry, 1);
+ if (folder_unix->is_network_dir)
+ {
+ entry->statbuf.st_mode = S_IFDIR;
+ entry->mime_type = g_strdup ("x-directory/normal");
+ }
- parent_path = gtk_file_path_new_dup (parent);
- folder = gtk_file_system_get_folder (file_system, parent_path, types, NULL);
- gtk_file_path_free (parent_path);
+ basename = g_path_get_basename (filename);
+ g_hash_table_insert (folder_unix->stat_info,
+ basename,
+ entry);
- if (folder)
+ if (folder_unix->have_stat)
{
- paths = g_slist_append (NULL, (GtkFilePath *) path);
- g_signal_emit_by_name (folder, "files-added", paths);
- g_slist_free (paths);
- g_object_unref (folder);
+ /* Cheating */
+ if ((folder_unix->types & STAT_NEEDED_MASK) != 0)
+ cb_fill_in_stats (basename, entry, folder_unix);
+
+ if ((folder_unix->types & GTK_FILE_INFO_MIME_TYPE) != 0)
+ cb_fill_in_mime_type (basename, entry, folder_unix);
}
+
+ paths = g_slist_append (NULL, (GtkFilePath *) path);
+ g_signal_emit_by_name (folder_unix, "files-added", paths);
+ g_slist_free (paths);
}
g_free (parent);
}
- return TRUE;
+ return handle;
+}
+
+static void
+gtk_file_system_unix_cancel_operation (GtkFileSystemHandle *handle)
+{
+ /* We don't set "cancelled" to TRUE here, since the actual operation
+ * is executed in the function itself and not in a callback. So
+ * the operations can never be cancelled (since they will be already
+ * completed at this point.
+ */
}
static void
@@ -620,16 +1055,24 @@ gtk_file_system_unix_volume_get_is_mounted (GtkFileSystem *file_system,
return TRUE;
}
-static gboolean
-gtk_file_system_unix_volume_mount (GtkFileSystem *file_system,
- GtkFileSystemVolume *volume,
- GError **error)
+static GtkFileSystemHandle *
+gtk_file_system_unix_volume_mount (GtkFileSystem *file_system,
+ GtkFileSystemVolume *volume,
+ GtkFileSystemVolumeMountCallback callback,
+ gpointer data)
{
- g_set_error (error,
+ GError *error = NULL;
+ GtkFileSystemHandle *handle = create_handle (file_system);
+
+ g_set_error (&error,
GTK_FILE_SYSTEM_ERROR,
GTK_FILE_SYSTEM_ERROR_FAILED,
_("This file system does not support mounting"));
- return FALSE;
+
+ g_object_ref (handle);
+ queue_volume_mount_callback (callback, handle, volume, error, data);
+
+ return handle;
}
static gchar *
@@ -691,83 +1134,11 @@ get_icon_type (const char *filename,
return get_icon_type_from_stat (&statbuf);
}
-typedef struct
-{
- gint size;
- GdkPixbuf *pixbuf;
-} IconCacheElement;
-
-static void
-icon_cache_element_free (IconCacheElement *element)
-{
- if (element->pixbuf)
- g_object_unref (element->pixbuf);
- g_slice_free (IconCacheElement, element);
-}
-
-static void
-icon_theme_changed (GtkIconTheme *icon_theme)
-{
- GHashTable *cache;
-
- /* Difference from the initial creation is that we don't
- * reconnect the signal
- */
- cache = g_hash_table_new_full (g_str_hash, g_str_equal,
- (GDestroyNotify)g_free,
- (GDestroyNotify)icon_cache_element_free);
- g_object_set_data_full (G_OBJECT (icon_theme), I_("gtk-file-icon-cache"),
- cache, (GDestroyNotify)g_hash_table_destroy);
-}
-
-static GdkPixbuf *
-get_cached_icon (GtkWidget *widget,
- const gchar *name,
- gint pixel_size)
-{
- GtkIconTheme *icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (widget));
- GHashTable *cache = g_object_get_data (G_OBJECT (icon_theme), "gtk-file-icon-cache");
- IconCacheElement *element;
-
- if (!cache)
- {
- cache = g_hash_table_new_full (g_str_hash, g_str_equal,
- (GDestroyNotify)g_free,
- (GDestroyNotify)icon_cache_element_free);
-
- g_object_set_data_full (G_OBJECT (icon_theme), I_("gtk-file-icon-cache"),
- cache, (GDestroyNotify)g_hash_table_destroy);
- g_signal_connect (icon_theme, "changed",
- G_CALLBACK (icon_theme_changed), NULL);
- }
-
- element = g_hash_table_lookup (cache, name);
- if (!element)
- {
- element = g_slice_new0 (IconCacheElement);
- g_hash_table_insert (cache, g_strdup (name), element);
- }
-
- if (element->size != pixel_size)
- {
- if (element->pixbuf)
- g_object_unref (element->pixbuf);
- element->size = pixel_size;
- element->pixbuf = gtk_icon_theme_load_icon (icon_theme, name,
- pixel_size, 0, NULL);
- }
-
- return element->pixbuf ? g_object_ref (element->pixbuf) : NULL;
-}
-
/* Renders a fallback icon from the stock system */
-static GdkPixbuf *
-get_fallback_icon (GtkWidget *widget,
- IconType icon_type,
- GError **error)
+static const gchar *
+get_fallback_icon_name (IconType icon_type)
{
const char *stock_name;
- GdkPixbuf *pixbuf;
switch (icon_type)
{
@@ -788,38 +1159,18 @@ get_fallback_icon (GtkWidget *widget,
break;
}
- pixbuf = gtk_widget_render_icon (widget, stock_name, GTK_ICON_SIZE_SMALL_TOOLBAR, NULL);
- if (!pixbuf)
- g_set_error (error,
- GTK_FILE_SYSTEM_ERROR,
- GTK_FILE_SYSTEM_ERROR_FAILED,
- _("Could not get a stock icon for %s"),
- stock_name);
-
- return pixbuf;
+ return stock_name;
}
-static GdkPixbuf *
-gtk_file_system_unix_volume_render_icon (GtkFileSystem *file_system,
- GtkFileSystemVolume *volume,
- GtkWidget *widget,
- gint pixel_size,
- GError **error)
+static gchar *
+gtk_file_system_unix_volume_get_icon_name (GtkFileSystem *file_system,
+ GtkFileSystemVolume *volume,
+ GError **error)
{
- GdkPixbuf *pixbuf;
-
- pixbuf = get_cached_icon (widget, "drive-harddisk", pixel_size);
- if (pixbuf)
- return pixbuf;
-
- pixbuf = get_cached_icon (widget, "gnome-dev-harddisk", pixel_size);
- if (pixbuf)
- return pixbuf;
-
- pixbuf = get_fallback_icon (widget, ICON_BLOCK_DEVICE, error);
- g_assert (pixbuf != NULL);
-
- return pixbuf;
+ /* FIXME: maybe we just always want to return GTK_STOCK_HARDDISK here?
+ * or the new tango icon name?
+ */
+ return g_strdup ("gnome-dev-harddisk");
}
static char *
@@ -1176,26 +1527,21 @@ get_icon_name_for_directory (const char *path)
return "gnome-fs-desktop";
else
return "gnome-fs-directory";
+
+ return NULL;
}
/* Computes our internal icon type based on a path name; also returns the MIME
* type in case we come up with ICON_REGULAR.
*/
static IconType
-get_icon_type_from_path (GtkFileSystemUnix *system_unix,
- const GtkFilePath *path,
+get_icon_type_from_path (GtkFileFolderUnix *folder_unix,
+ struct stat *statbuf,
+ const char *filename,
const char **mime_type)
{
- const char *filename;
- char *dirname;
- GtkFileFolderUnix *folder_unix;
IconType icon_type;
- filename = gtk_file_path_get_string (path);
- dirname = g_path_get_dirname (filename);
- folder_unix = g_hash_table_lookup (system_unix->folder_hash, dirname);
- g_free (dirname);
-
*mime_type = NULL;
if (folder_unix && folder_unix->have_stat)
@@ -1226,6 +1572,9 @@ get_icon_type_from_path (GtkFileSystemUnix *system_unix,
}
}
+ if (statbuf)
+ return get_icon_type_from_stat (statbuf);
+
icon_type = get_icon_type (filename, NULL);
if (icon_type == ICON_REGULAR)
*mime_type = xdg_mime_get_mime_type_for_file (filename, NULL);
@@ -1234,11 +1583,9 @@ get_icon_type_from_path (GtkFileSystemUnix *system_unix,
}
/* Renders an icon for a non-ICON_REGULAR file */
-static GdkPixbuf *
-get_special_icon (IconType icon_type,
- const GtkFilePath *path,
- GtkWidget *widget,
- gint pixel_size)
+static const gchar *
+get_special_icon_name (IconType icon_type,
+ const gchar *filename)
{
const char *name;
@@ -1255,13 +1602,9 @@ get_special_icon (IconType icon_type,
case ICON_CHARACTER_DEVICE:
name = "gnome-fs-chardev";
break;
- case ICON_DIRECTORY: {
- const char *filename;
-
- filename = gtk_file_path_get_string (path);
- name = get_icon_name_for_directory (filename);
- break;
- }
+ case ICON_DIRECTORY:
+ /* get_icon_name_for_directory() returns a dupped string */
+ return get_icon_name_for_directory (filename);
case ICON_EXECUTABLE:
name ="gnome-fs-executable";
break;
@@ -1276,17 +1619,15 @@ get_special_icon (IconType icon_type,
return NULL;
}
- return get_cached_icon (widget, name, pixel_size);
+ return name;
}
-static GdkPixbuf *
-get_icon_for_mime_type (GtkWidget *widget,
- const char *mime_type,
- gint pixel_size)
+static gchar *
+get_icon_name_for_mime_type (const char *mime_type)
{
+ char *name;
const char *separator;
GString *icon_name;
- GdkPixbuf *pixbuf;
if (!mime_type)
return NULL;
@@ -1295,6 +1636,10 @@ get_icon_for_mime_type (GtkWidget *widget,
if (!separator)
return NULL; /* maybe we should return a GError with "invalid MIME-type" */
+ /* FIXME: we default to the gnome icon naming for now. Some question
+ * as below, how are we going to handle a second attempt?
+ */
+#if 0
icon_name = g_string_new ("");
g_string_append_len (icon_name, mime_type, separator - mime_type);
g_string_append_c (icon_name, '-');
@@ -1311,13 +1656,19 @@ get_icon_for_mime_type (GtkWidget *widget,
g_string_free (icon_name, TRUE);
if (pixbuf)
return pixbuf;
+#endif
icon_name = g_string_new ("gnome-mime-");
g_string_append_len (icon_name, mime_type, separator - mime_type);
g_string_append_c (icon_name, '-');
g_string_append (icon_name, separator + 1);
- pixbuf = get_cached_icon (widget, icon_name->str, pixel_size);
- g_string_free (icon_name, TRUE);
+ name = icon_name->str;
+ g_string_free (icon_name, FALSE);
+
+ return name;
+
+ /* FIXME: how are we going to implement a second attempt? */
+#if 0
if (pixbuf)
return pixbuf;
@@ -1327,50 +1678,7 @@ get_icon_for_mime_type (GtkWidget *widget,
g_string_free (icon_name, TRUE);
return pixbuf;
-}
-
-static GdkPixbuf *
-gtk_file_system_unix_render_icon (GtkFileSystem *file_system,
- const GtkFilePath *path,
- GtkWidget *widget,
- gint pixel_size,
- GError **error)
-{
- GtkFileSystemUnix *system_unix;
- IconType icon_type;
- const char *mime_type;
- GdkPixbuf *pixbuf;
-
- system_unix = GTK_FILE_SYSTEM_UNIX (file_system);
-
- icon_type = get_icon_type_from_path (system_unix, path, &mime_type);
-
- switch (icon_type) {
- case ICON_NONE:
- goto fallback;
-
- case ICON_REGULAR:
- pixbuf = get_icon_for_mime_type (widget, mime_type, pixel_size);
- break;
-
- default:
- pixbuf = get_special_icon (icon_type, path, widget, pixel_size);
- }
-
- if (pixbuf)
- goto out;
-
- fallback:
-
- pixbuf = get_cached_icon (widget, "gnome-fs-regular", pixel_size);
- if (pixbuf)
- goto out;
-
- pixbuf = get_fallback_icon (widget, icon_type, error);
-
- out:
-
- return pixbuf;
+#endif
}
static void
@@ -1808,6 +2116,12 @@ gtk_file_folder_unix_finalize (GObject *object)
{
GtkFileFolderUnix *folder_unix = GTK_FILE_FOLDER_UNIX (object);
+ if (folder_unix->load_folder_id)
+ {
+ g_source_remove (folder_unix->load_folder_id);
+ folder_unix->load_folder_id = 0;
+ }
+
g_hash_table_remove (folder_unix->system_unix->folder_hash, folder_unix->filename);
if (folder_unix->stat_info)
@@ -1912,8 +2226,16 @@ create_file_info (GtkFileFolderUnix *folder_unix,
if (types & GTK_FILE_INFO_IS_HIDDEN)
{
- if (file_is_hidden (folder_unix, basename))
- gtk_file_info_set_is_hidden (info, TRUE);
+ if (folder_unix)
+ {
+ if (file_is_hidden (folder_unix, basename))
+ gtk_file_info_set_is_hidden (info, TRUE);
+ }
+ else
+ {
+ if (get_is_hidden_for_file (filename, basename))
+ gtk_file_info_set_is_hidden (info, TRUE);
+ }
}
if (types & GTK_FILE_INFO_IS_FOLDER)
@@ -1928,6 +2250,40 @@ create_file_info (GtkFileFolderUnix *folder_unix,
if (types & GTK_FILE_INFO_SIZE)
gtk_file_info_set_size (info, (gint64) statbuf->st_size);
+ if (types & GTK_FILE_INFO_ICON)
+ {
+ IconType icon_type;
+ gboolean free_icon_name = FALSE;
+ const char *icon_name;
+ const char *icon_mime_type;
+
+ icon_type = get_icon_type_from_path (folder_unix, statbuf, filename, &icon_mime_type);
+
+ switch (icon_type)
+ {
+ case ICON_NONE:
+ icon_name = get_fallback_icon_name (icon_type);
+ break;
+
+ case ICON_REGULAR:
+ free_icon_name = TRUE;
+ if (icon_mime_type)
+ icon_name = get_icon_name_for_mime_type (icon_mime_type);
+ else
+ icon_name = get_icon_name_for_mime_type (mime_type);
+ break;
+
+ default:
+ icon_name = get_special_icon_name (icon_type, filename);
+ break;
+ }
+
+ gtk_file_info_set_icon_name (info, icon_name);
+
+ if (free_icon_name)
+ g_free ((char *) icon_name);
+ }
+
return info;
}
@@ -2052,13 +2408,11 @@ gtk_file_folder_unix_list_children (GtkFileFolder *folder,
GtkFileFolderUnix *folder_unix = GTK_FILE_FOLDER_UNIX (folder);
GSList *l;
- if (!fill_in_names (folder_unix, error))
- return FALSE;
-
*children = NULL;
/* Get the list of basenames. */
- g_hash_table_foreach (folder_unix->stat_info, cb_list_children, children);
+ if (folder_unix->stat_info)
+ g_hash_table_foreach (folder_unix->stat_info, cb_list_children, children);
/* Turn basenames into GFilePaths. */
for (l = *children; l; l = l->next)
@@ -2075,8 +2429,7 @@ gtk_file_folder_unix_list_children (GtkFileFolder *folder,
static gboolean
gtk_file_folder_unix_is_finished_loading (GtkFileFolder *folder)
{
- /* Since we don't do asynchronous loads, we are always finished loading */
- return TRUE;
+ return GTK_FILE_FOLDER_UNIX (folder)->is_finished_loading;
}
static void
@@ -2207,23 +2560,40 @@ fill_in_mime_type (GtkFileFolderUnix *folder_unix)
folder_unix->have_mime_type = TRUE;
}
+static gchar **
+read_hidden_file (const char *dirname)
+{
+ gchar **lines = NULL;
+ gchar *contents;
+ gchar *hidden_file;
+
+ hidden_file = g_build_filename (dirname, HIDDEN_FILENAME, NULL);
+
+ if (g_file_get_contents (hidden_file, &contents, NULL, NULL))
+ {
+ lines = g_strsplit (contents, "\n", -1);
+ g_free (contents);
+ }
+
+ g_free (hidden_file);
+
+ return lines;
+}
+
static void
fill_in_hidden (GtkFileFolderUnix *folder_unix)
{
- gchar *hidden_file;
- gchar *contents;
+ gchar **lines;
if (folder_unix->have_hidden)
return;
- hidden_file = g_build_filename (folder_unix->filename, HIDDEN_FILENAME, NULL);
+ lines = read_hidden_file (folder_unix->filename);
- if (g_file_get_contents (hidden_file, &contents, NULL, NULL))
+ if (lines)
{
- gchar **lines;
int i;
- lines = g_strsplit (contents, "\n", -1);
for (i = 0; lines[i]; i++)
{
if (lines[i][0])
@@ -2237,10 +2607,8 @@ fill_in_hidden (GtkFileFolderUnix *folder_unix)
}
g_strfreev (lines);
- g_free (contents);
}
- g_free (hidden_file);
folder_unix->have_hidden = TRUE;
}
@@ -2264,6 +2632,37 @@ filename_is_root (const char *filename)
}
static gboolean
+get_is_hidden_for_file (const char *filename,
+ const char *basename)
+{
+ gchar *dirname;
+ gchar **lines;
+ gboolean hidden = FALSE;
+
+ dirname = g_path_get_dirname (filename);
+ lines = read_hidden_file (dirname);
+ g_free (dirname);
+
+ if (lines)
+ {
+ int i;
+
+ for (i = 0; lines[i]; i++)
+ {
+ if (lines[i][0] && strcmp (lines[i], basename) == 0)
+ {
+ hidden = TRUE;
+ break;
+ }
+ }
+
+ g_strfreev (lines);
+ }
+
+ return hidden;
+}
+
+static gboolean
file_is_hidden (GtkFileFolderUnix *folder_unix,
const char *basename)
{
diff --git a/gtk/gtkpathbar.c b/gtk/gtkpathbar.c
index ec62d32d3..2688c1ee3 100644
--- a/gtk/gtkpathbar.c
+++ b/gtk/gtkpathbar.c
@@ -65,6 +65,7 @@ struct _ButtonData
GtkFilePath *path;
GtkWidget *image;
GtkWidget *label;
+ GtkFileSystemHandle *handle;
guint ignore_changes : 1;
guint file_is_hidden : 1;
};
@@ -140,6 +141,8 @@ gtk_path_bar_init (GtkPathBar *path_bar)
GTK_WIDGET_SET_FLAGS (path_bar, GTK_NO_WINDOW);
gtk_widget_set_redraw_on_allocate (GTK_WIDGET (path_bar), FALSE);
+ path_bar->set_path_handle = NULL;
+
path_bar->spacing = 3;
path_bar->up_slider_button = get_slider_button (path_bar, GTK_ARROW_LEFT);
path_bar->down_slider_button = get_slider_button (path_bar, GTK_ARROW_RIGHT);
@@ -247,8 +250,13 @@ remove_settings_signal (GtkPathBar *path_bar,
static void
gtk_path_bar_dispose (GObject *object)
{
- remove_settings_signal (GTK_PATH_BAR (object),
- gtk_widget_get_screen (GTK_WIDGET (object)));
+ GtkPathBar *path_bar = GTK_PATH_BAR (object);
+
+ remove_settings_signal (path_bar, gtk_widget_get_screen (GTK_WIDGET (object)));
+
+ if (path_bar->set_path_handle)
+ gtk_file_system_cancel_operation (path_bar->set_path_handle);
+ path_bar->set_path_handle = NULL;
G_OBJECT_CLASS (gtk_path_bar_parent_class)->dispose (object);
}
@@ -957,7 +965,11 @@ button_clicked_cb (GtkWidget *button,
button_list = g_list_find (path_bar->button_list, button_data);
g_assert (button_list != NULL);
+ g_signal_handlers_block_by_func (button,
+ G_CALLBACK (button_clicked_cb), data);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
+ g_signal_handlers_unblock_by_func (button,
+ G_CALLBACK (button_clicked_cb), data);
if (button_list->prev)
{
@@ -977,22 +989,79 @@ button_clicked_cb (GtkWidget *button,
button_data->path, child_path, child_is_hidden);
}
-static GdkPixbuf *
-get_button_image (GtkPathBar *path_bar,
- ButtonType button_type)
+struct SetButtonImageData
+{
+ GtkPathBar *path_bar;
+ ButtonData *button_data;
+};
+
+static void
+set_button_image_get_info_cb (GtkFileSystemHandle *handle,
+ const GtkFileInfo *info,
+ const GError *error,
+ gpointer user_data)
+{
+ gboolean cancelled = handle->cancelled;
+ GdkPixbuf *pixbuf;
+ struct SetButtonImageData *data = user_data;
+
+ if (handle != data->button_data->handle)
+ goto out;
+
+ data->button_data->handle = NULL;
+
+ if (cancelled || error)
+ goto out;
+
+ pixbuf = gtk_file_info_render_icon (info, GTK_WIDGET (data->path_bar),
+ data->path_bar->icon_size, NULL);
+ gtk_image_set_from_pixbuf (GTK_IMAGE (data->button_data->image), pixbuf);
+
+ switch (data->button_data->type)
+ {
+ case HOME_BUTTON:
+ if (data->path_bar->home_icon)
+ g_object_unref (pixbuf);
+ else
+ data->path_bar->home_icon = pixbuf;
+ break;
+
+ case DESKTOP_BUTTON:
+ if (data->path_bar->desktop_icon)
+ g_object_unref (pixbuf);
+ else
+ data->path_bar->desktop_icon = pixbuf;
+ break;
+
+ default:
+ break;
+ };
+
+out:
+ g_free (data);
+ g_object_unref (handle);
+}
+
+static void
+set_button_image (GtkPathBar *path_bar,
+ ButtonData *button_data)
{
GtkFileSystemVolume *volume;
+ struct SetButtonImageData *data;
- switch (button_type)
+ switch (button_data->type)
{
case ROOT_BUTTON:
if (path_bar->root_icon != NULL)
- return path_bar->root_icon;
+ {
+ gtk_image_set_from_pixbuf (GTK_IMAGE (button_data->image), path_bar->root_icon);
+ break;
+ }
volume = gtk_file_system_get_volume_for_path (path_bar->file_system, path_bar->root_path);
if (volume == NULL)
- return NULL;
+ return;
path_bar->root_icon = gtk_file_system_volume_render_icon (path_bar->file_system,
volume,
@@ -1001,37 +1070,63 @@ get_button_image (GtkPathBar *path_bar,
NULL);
gtk_file_system_volume_free (path_bar->file_system, volume);
- return path_bar->root_icon;
+ gtk_image_set_from_pixbuf (GTK_IMAGE (button_data->image), path_bar->root_icon);
+ break;
+
case HOME_BUTTON:
if (path_bar->home_icon != NULL)
- return path_bar->home_icon;
-
- path_bar->home_icon = gtk_file_system_render_icon (path_bar->file_system,
- path_bar->home_path,
- GTK_WIDGET (path_bar),
- path_bar->icon_size,
- NULL);
- return path_bar->home_icon;
+ {
+ gtk_image_set_from_pixbuf (GTK_IMAGE (button_data->image), path_bar->home_icon);
+ break;
+ }
+
+ data = g_new0 (struct SetButtonImageData, 1);
+ data->path_bar = path_bar;
+ data->button_data = button_data;
+
+ if (button_data->handle)
+ gtk_file_system_cancel_operation (button_data->handle);
+
+ button_data->handle =
+ gtk_file_system_get_info (path_bar->file_system,
+ path_bar->home_path,
+ GTK_FILE_INFO_ICON,
+ set_button_image_get_info_cb,
+ data);
+ break;
+
case DESKTOP_BUTTON:
if (path_bar->desktop_icon != NULL)
- return path_bar->desktop_icon;
-
- path_bar->desktop_icon = gtk_file_system_render_icon (path_bar->file_system,
- path_bar->desktop_path,
- GTK_WIDGET (path_bar),
- path_bar->icon_size,
- NULL);
- return path_bar->desktop_icon;
+ {
+ gtk_image_set_from_pixbuf (GTK_IMAGE (button_data->image), path_bar->desktop_icon);
+ break;
+ }
+
+ data = g_new0 (struct SetButtonImageData, 1);
+ data->path_bar = path_bar;
+ data->button_data = button_data;
+
+ if (button_data->handle)
+ gtk_file_system_cancel_operation (button_data->handle);
+
+ button_data->handle =
+ gtk_file_system_get_info (path_bar->file_system,
+ path_bar->desktop_path,
+ GTK_FILE_INFO_ICON,
+ set_button_image_get_info_cb,
+ data);
+ break;
default:
- return NULL;
+ break;
}
-
- return NULL;
}
static void
button_data_free (ButtonData *button_data)
{
+ if (button_data->handle)
+ gtk_file_system_cancel_operation (button_data->handle);
+
gtk_file_path_free (button_data->path);
g_free (button_data->dir_name);
g_free (button_data);
@@ -1094,9 +1189,7 @@ gtk_path_bar_update_button_appearance (GtkPathBar *path_bar,
if (button_data->image != NULL)
{
- GdkPixbuf *pixbuf;
- pixbuf = get_button_image (path_bar, button_data->type);
- gtk_image_set_from_pixbuf (GTK_IMAGE (button_data->image), pixbuf);
+ set_button_image (path_bar, button_data);
}
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button_data->button)) != current_dir)
@@ -1294,126 +1387,174 @@ gtk_path_bar_check_parent_path (GtkPathBar *path_bar,
return FALSE;
}
-gboolean
-_gtk_path_bar_set_path (GtkPathBar *path_bar,
- const GtkFilePath *file_path,
- const gboolean keep_trail,
- GError **error)
+
+struct SetPathInfo
{
GtkFilePath *path;
- gboolean first_directory = TRUE;
- gboolean result;
- GList *new_buttons = NULL;
- GList *fake_root = NULL;
-
- g_return_val_if_fail (GTK_IS_PATH_BAR (path_bar), FALSE);
- g_return_val_if_fail (file_path != NULL, FALSE);
-
- result = TRUE;
-
- /* Check whether the new path is already present in the pathbar as buttons.
- * This could be a parent directory or a previous selected subdirectory.
- */
- if (keep_trail &&
- gtk_path_bar_check_parent_path (path_bar, file_path, path_bar->file_system))
- return TRUE;
+ GtkFilePath *parent_path;
+ GtkPathBar *path_bar;
+ GList *new_buttons;
+ GList *fake_root;
+ gboolean first_directory;
+};
- path = gtk_file_path_copy (file_path);
+static void
+gtk_path_bar_set_path_finish (struct SetPathInfo *info,
+ gboolean result)
+{
+ if (result)
+ {
+ GList *l;
- gtk_widget_push_composite_child ();
+ gtk_path_bar_clear_buttons (info->path_bar);
+ info->path_bar->button_list = g_list_reverse (info->new_buttons);
+ info->path_bar->fake_root = info->fake_root;
- while (path != NULL)
- {
- GtkFilePath *parent_path = NULL;
- ButtonData *button_data;
- const gchar *display_name;
- gboolean is_hidden;
- GtkFileFolder *file_folder;
- GtkFileInfo *file_info;
- gboolean valid;
-
- valid = gtk_file_system_get_parent (path_bar->file_system,
- path,
- &parent_path,
- error);
- if (!valid)
+ for (l = info->path_bar->button_list; l; l = l->next)
{
- result = FALSE;
- gtk_file_path_free (path);
- break;
+ GtkWidget *button = BUTTON_DATA (l->data)->button;
+ gtk_container_add (GTK_CONTAINER (info->path_bar), button);
}
+ }
+ else
+ {
+ GList *l;
- file_folder = gtk_file_system_get_folder (path_bar->file_system,
- parent_path ? parent_path : path,
- GTK_FILE_INFO_DISPLAY_NAME | GTK_FILE_INFO_IS_HIDDEN,
- NULL);
- if (!file_folder)
+ for (l = info->new_buttons; l; l = l->next)
{
- result = FALSE;
- gtk_file_path_free (parent_path);
- gtk_file_path_free (path);
- break;
- }
-
- file_info = gtk_file_folder_get_info (file_folder, parent_path ? path : NULL, error);
- g_object_unref (file_folder);
+ ButtonData *button_data;
- if (!file_info)
- {
- result = FALSE;
- gtk_file_path_free (parent_path);
- gtk_file_path_free (path);
- break;
+ button_data = BUTTON_DATA (l->data);
+ gtk_widget_destroy (button_data->button);
}
- display_name = gtk_file_info_get_display_name (file_info);
- is_hidden = gtk_file_info_get_is_hidden (file_info);
-
- button_data = make_directory_button (path_bar, display_name, path, first_directory, is_hidden);
- gtk_file_info_free (file_info);
- gtk_file_path_free (path);
+ g_list_free (info->new_buttons);
+ }
- new_buttons = g_list_prepend (new_buttons, button_data);
+ if (info->path)
+ gtk_file_path_free (info->path);
+ if (info->parent_path)
+ gtk_file_path_free (info->parent_path);
+ g_free (info);
+}
- if (BUTTON_IS_FAKE_ROOT (button_data))
- fake_root = new_buttons;
+static void
+gtk_path_bar_get_info_callback (GtkFileSystemHandle *handle,
+ const GtkFileInfo *file_info,
+ const GError *error,
+ gpointer data)
+{
+ gboolean cancelled = handle->cancelled;
+ struct SetPathInfo *path_info = data;
+ ButtonData *button_data;
+ const gchar *display_name;
+ gboolean is_hidden;
+ gboolean valid;
- path = parent_path;
- first_directory = FALSE;
+ if (handle != path_info->path_bar->set_path_handle)
+ {
+ gtk_path_bar_set_path_finish (path_info, FALSE);
+ g_object_unref (handle);
+ return;
}
- if (result)
+ g_object_unref (handle);
+ path_info->path_bar->set_path_handle = NULL;
+
+ if (cancelled || !file_info)
{
- GList *l;
+ gtk_path_bar_set_path_finish (path_info, FALSE);
+ return;
+ }
- gtk_path_bar_clear_buttons (path_bar);
- path_bar->button_list = g_list_reverse (new_buttons);
- path_bar->fake_root = fake_root;
+ display_name = gtk_file_info_get_display_name (file_info);
+ is_hidden = gtk_file_info_get_is_hidden (file_info);
- for (l = path_bar->button_list; l; l = l->next)
- {
- GtkWidget *button = BUTTON_DATA (l->data)->button;
- gtk_container_add (GTK_CONTAINER (path_bar), button);
- }
+ gtk_widget_push_composite_child ();
+ button_data = make_directory_button (path_info->path_bar, display_name,
+ path_info->path,
+ path_info->first_directory, is_hidden);
+ gtk_widget_pop_composite_child ();
+ gtk_file_path_free (path_info->path);
+
+ path_info->new_buttons = g_list_prepend (path_info->new_buttons, button_data);
+
+ if (BUTTON_IS_FAKE_ROOT (button_data))
+ path_info->fake_root = path_info->new_buttons;
+
+ path_info->path = path_info->parent_path;
+ path_info->first_directory = FALSE;
+
+ if (!path_info->path)
+ {
+ gtk_path_bar_set_path_finish (path_info, TRUE);
+ return;
}
- else
+
+ valid = gtk_file_system_get_parent (path_info->path_bar->file_system,
+ path_info->path,
+ &path_info->parent_path,
+ NULL);
+ if (!valid)
{
- GList *l;
+ gtk_path_bar_set_path_finish (path_info, FALSE);
+ return;
+ }
- for (l = new_buttons; l; l = l->next)
- {
- ButtonData *button_data;
+ path_info->path_bar->set_path_handle =
+ gtk_file_system_get_info (handle->file_system,
+ path_info->path,
+ GTK_FILE_INFO_DISPLAY_NAME | GTK_FILE_INFO_IS_HIDDEN,
+ gtk_path_bar_get_info_callback,
+ path_info);
+}
- button_data = BUTTON_DATA (l->data);
- gtk_widget_destroy (button_data->button);
- }
+gboolean
+_gtk_path_bar_set_path (GtkPathBar *path_bar,
+ const GtkFilePath *file_path,
+ const gboolean keep_trail,
+ GError **error)
+{
+ struct SetPathInfo *info;
+ gboolean result;
+
+ g_return_val_if_fail (GTK_IS_PATH_BAR (path_bar), FALSE);
+ g_return_val_if_fail (file_path != NULL, FALSE);
+
+ result = TRUE;
+
+ /* Check whether the new path is already present in the pathbar as buttons.
+ * This could be a parent directory or a previous selected subdirectory.
+ */
+ if (keep_trail &&
+ gtk_path_bar_check_parent_path (path_bar, file_path, path_bar->file_system))
+ return TRUE;
- g_list_free (new_buttons);
+ info = g_new0 (struct SetPathInfo, 1);
+ info->path = gtk_file_path_copy (file_path);
+ info->path_bar = path_bar;
+ info->first_directory = TRUE;
+
+ result = gtk_file_system_get_parent (path_bar->file_system,
+ info->path, &info->parent_path, error);
+ if (!result)
+ {
+ gtk_file_path_free (info->path);
+ g_free (info);
+ return result;
}
- gtk_widget_pop_composite_child ();
+ if (path_bar->set_path_handle)
+ gtk_file_system_cancel_operation (path_bar->set_path_handle);
+
+ path_bar->set_path_handle =
+ gtk_file_system_get_info (path_bar->file_system,
+ info->path,
+ GTK_FILE_INFO_DISPLAY_NAME | GTK_FILE_INFO_IS_HIDDEN,
+ gtk_path_bar_get_info_callback,
+ info);
- return result;
+ return TRUE;
}
/* FIXME: This should be a construct-only property */
diff --git a/gtk/gtkpathbar.h b/gtk/gtkpathbar.h
index e395ccc0b..9474427b5 100644
--- a/gtk/gtkpathbar.h
+++ b/gtk/gtkpathbar.h
@@ -45,6 +45,8 @@ struct _GtkPathBar
GtkFilePath *home_path;
GtkFilePath *desktop_path;
+ GtkFileSystemHandle *set_path_handle;
+
GdkPixbuf *root_icon;
GdkPixbuf *home_icon;
GdkPixbuf *desktop_icon;