Merge of the GTK+ asynchronous file chooser branch. Please see the

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.
This commit is contained in:
Kristian Rietveld 2006-05-01 21:41:12 +00:00 committed by Kristian Rietveld
parent 46789c877d
commit 2c97a8f6e8
20 changed files with 3691 additions and 1373 deletions

View File

@ -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

View File

@ -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

View File

@ -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])

View File

@ -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

View File

@ -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);

View File

@ -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]);
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);
base_path = NULL;
if (path != NULL &&
gtk_file_system_get_parent (priv->fs, path, &base_path, NULL))
{
GtkFileFolder *folder;
GtkFileInfo *info;
info->path = gtk_file_system_uri_to_path (priv->fs,
info->uris[info->i]);
folder = gtk_file_system_get_folder (priv->fs, base_path,
GTK_FILE_INFO_IS_FOLDER,
NULL);
if (priv->dnd_select_folder_handle)
gtk_file_system_cancel_operation (priv->dnd_select_folder_handle);
info = gtk_file_folder_get_info (folder, path, NULL);
if (info != NULL)
{
GtkFileChooserAction action;
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);
}
gtk_file_path_free (path);
}
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;
info = gtk_file_folder_get_info (folder, path, NULL);
g_object_unref (folder);
gtk_list_store_set (GTK_LIST_STORE (data->button->priv->model), &iter,
HANDLE_COLUMN, NULL,
-1);
if (info)
{
retval = g_strdup (gtk_file_info_get_display_name (info));
gtk_file_info_free (info);
}
}
if (cancelled || error)
/* There was an error, leave the fallback name in there */
goto out;
if (parent_path)
gtk_file_path_free (parent_path);
pixbuf = gtk_file_info_render_icon (info, GTK_WIDGET (data->button),
data->button->priv->icon_size, NULL);
if (!retval)
retval = g_strdup (_(FALLBACK_DISPLAY_NAME));
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);
return retval;
if (pixbuf)
g_object_unref (pixbuf);
out:
g_object_unref (data->button);
gtk_tree_row_reference_free (data->row_ref);
g_free (data);
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:
{
@ -1836,6 +2096,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)
{
@ -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);
}

File diff suppressed because it is too large Load Diff

View File

@ -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 *

View File

@ -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

View File

@ -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;

View File

@ -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);
{
g_object_unref (chooser_entry->file_system);
chooser_entry->file_system = NULL;
}
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);
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 */
if (chooser_entry->load_folder_handle)
gtk_file_system_cancel_operation (chooser_entry->load_folder_handle);
/* 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->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"

View File

@ -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

View File

@ -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;
};

View File

@ -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)->create_folder (file_system, path, error);
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, 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

View File

@ -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,

View File

@ -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)
{
GDK_THREADS_ENTER ();
g_signal_emit (model, file_system_model_signals[FINISHED_LOADING], 0);
g_source_destroy (model->idle_finished_loading_source);
model->idle_finished_loading_source = NULL;
GDK_THREADS_LEAVE ();
return FALSE;
}
/* Queues an idle handler to emit the "finished-loading" signal */
static void
queue_finished_loading (GtkFileSystemModel *model)
got_root_folder_cb (GtkFileSystemHandle *handle,
GtkFileFolder *folder,
const GError *error,
gpointer data)
{
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);
GSList *roots = NULL;
GSList *tmp_list;
gboolean cancelled = handle->cancelled;
GtkFileSystemModel *model = data;
tmp_list = g_slist_find (model->pending_handles, handle);
if (!tmp_list)
goto out;
model->pending_handles = g_slist_remove_link (model->pending_handles,
tmp_list);
if (cancelled || !folder)
goto out;
model->root_folder = folder;
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);
model->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)
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;
}
g_slist_free (roots);
/* 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;
}
model->pending_handles = g_slist_append (model->pending_handles, handle);
model->roots = (FileModelNode *) g_slist_reverse ((GSList *)model->roots);
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)
if (gtk_file_path_compare (path, model->root_path) == 0
|| !gtk_file_system_get_parent (model->file_system, path, &parent_path, NULL))
return;
paths = g_slist_prepend (paths, gtk_file_path_copy (path));
while (gtk_file_path_compare (parent_path, model->root_path) != 0)
{
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);
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;
}
}
g_slist_foreach (cleanups, (GFunc)g_object_unref, NULL);
g_slist_free (cleanups);
if (g_slist_length (paths) < 1)
return;
return node != NULL;
/* 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;
}
file_model_node_ref (node);
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 */
{
struct GetChildrenData *data;
GtkFileSystemHandle *handle;
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);
data = g_new (struct GetChildrenData, 1);
data->model = g_object_ref (model);
data->node = node;
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);
}
handle =
gtk_file_system_get_folder (model->file_system,
node->path,
model->types,
get_children_get_folder_cb,
data);
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);
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;

View File

@ -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);

File diff suppressed because it is too large Load Diff

View File

@ -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;
{
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;
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;
case DESKTOP_BUTTON:
if (path_bar->desktop_icon != NULL)
return path_bar->desktop_icon;
{
gtk_image_set_from_pixbuf (GTK_IMAGE (button_data->image), path_bar->desktop_icon);
break;
}
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;
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,17 +1387,136 @@ gtk_path_bar_check_parent_path (GtkPathBar *path_bar,
return FALSE;
}
struct SetPathInfo
{
GtkFilePath *path;
GtkFilePath *parent_path;
GtkPathBar *path_bar;
GList *new_buttons;
GList *fake_root;
gboolean first_directory;
};
static void
gtk_path_bar_set_path_finish (struct SetPathInfo *info,
gboolean result)
{
if (result)
{
GList *l;
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;
for (l = info->path_bar->button_list; l; l = l->next)
{
GtkWidget *button = BUTTON_DATA (l->data)->button;
gtk_container_add (GTK_CONTAINER (info->path_bar), button);
}
}
else
{
GList *l;
for (l = info->new_buttons; l; l = l->next)
{
ButtonData *button_data;
button_data = BUTTON_DATA (l->data);
gtk_widget_destroy (button_data->button);
}
g_list_free (info->new_buttons);
}
if (info->path)
gtk_file_path_free (info->path);
if (info->parent_path)
gtk_file_path_free (info->parent_path);
g_free (info);
}
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;
if (handle != path_info->path_bar->set_path_handle)
{
gtk_path_bar_set_path_finish (path_info, FALSE);
g_object_unref (handle);
return;
}
g_object_unref (handle);
path_info->path_bar->set_path_handle = NULL;
if (cancelled || !file_info)
{
gtk_path_bar_set_path_finish (path_info, FALSE);
return;
}
display_name = gtk_file_info_get_display_name (file_info);
is_hidden = gtk_file_info_get_is_hidden (file_info);
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;
}
valid = gtk_file_system_get_parent (path_info->path_bar->file_system,
path_info->path,
&path_info->parent_path,
NULL);
if (!valid)
{
gtk_path_bar_set_path_finish (path_info, FALSE);
return;
}
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);
}
gboolean
_gtk_path_bar_set_path (GtkPathBar *path_bar,
const GtkFilePath *file_path,
const gboolean keep_trail,
GError **error)
{
GtkFilePath *path;
gboolean first_directory = TRUE;
struct SetPathInfo *info;
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);
@ -1318,102 +1530,31 @@ _gtk_path_bar_set_path (GtkPathBar *path_bar,
gtk_path_bar_check_parent_path (path_bar, file_path, path_bar->file_system))
return TRUE;
path = gtk_file_path_copy (file_path);
info = g_new0 (struct SetPathInfo, 1);
info->path = gtk_file_path_copy (file_path);
info->path_bar = path_bar;
info->first_directory = TRUE;
gtk_widget_push_composite_child ();
while (path != NULL)
result = gtk_file_system_get_parent (path_bar->file_system,
info->path, &info->parent_path, error);
if (!result)
{
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)
{
result = FALSE;
gtk_file_path_free (path);
break;
}
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)
{
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);
if (!file_info)
{
result = FALSE;
gtk_file_path_free (parent_path);
gtk_file_path_free (path);
break;
}
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);
new_buttons = g_list_prepend (new_buttons, button_data);
if (BUTTON_IS_FAKE_ROOT (button_data))
fake_root = new_buttons;
path = parent_path;
first_directory = FALSE;
gtk_file_path_free (info->path);
g_free (info);
return result;
}
if (result)
{
GList *l;
if (path_bar->set_path_handle)
gtk_file_system_cancel_operation (path_bar->set_path_handle);
gtk_path_bar_clear_buttons (path_bar);
path_bar->button_list = g_list_reverse (new_buttons);
path_bar->fake_root = fake_root;
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);
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);
}
}
else
{
GList *l;
for (l = new_buttons; l; l = l->next)
{
ButtonData *button_data;
button_data = BUTTON_DATA (l->data);
gtk_widget_destroy (button_data->button);
}
g_list_free (new_buttons);
}
gtk_widget_pop_composite_child ();
return result;
return TRUE;
}
/* FIXME: This should be a construct-only property */

View File

@ -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;