summaryrefslogtreecommitdiff
path: root/gtk
diff options
context:
space:
mode:
authorFederico Mena Quintero <federico@ximian.com>2003-12-17 05:55:16 +0000
committerFederico Mena Quintero <federico@src.gnome.org>2003-12-17 05:55:16 +0000
commit8baf8571b52f21c0012420669483f4769cfa13ca (patch)
tree56b9ae2e89c29cd6647295ec52ef4cfc327f0487 /gtk
parent6b80f394a59244ab7a2e04fa6649728743469702 (diff)
downloadgtk+-8baf8571b52f21c0012420669483f4769cfa13ca.tar.gz
Added a "volumes-changed" signal. Added the following methods:
2003-12-16 Federico Mena Quintero <federico@ximian.com> * gtk/gtkfilesystem.h (struct _GtkFileSystemIface): Added a "volumes-changed" signal. Added the following methods: list_volumes volume_free volume_get_base_path volume_get_is_mounted volume_mount volume_get_display_name volume_render_icon * gtk/gtkfilesystem.c (gtk_file_system_base_init): Create the "volumes-changed" signal. (gtk_file_system_list_volumes): New function. (gtk_file_system_volume_free): New function. (gtk_file_system_volume_get_base_path): New function. (gtk_file_system_volume_get_is_mounted): New function. (gtk_file_system_volume_mount): New function. (gtk_file_system_volume_get_display_name): New function. (gtk_file_system_volume_render_icon): New function. * gtk/gtkfilesystemunix.c (gtk_file_system_unix_volume_free): Implement. (gtk_file_system_unix_volume_get_base_path): Implement. (gtk_file_system_unix_volume_get_is_mounted): Implement. (gtk_file_system_unix_volume_mount): Implement. (gtk_file_system_unix_volume_get_display_name): Implement. (gtk_file_system_unix_volume_render_icon): Implement. * gtk/gtkfilechooserdefault.c (struct _GtkFileChooserDefault): Added a field for the "volumes-changed" signal connection. (gtk_file_chooser_default_set_property): Connect to "volumes-changed" on the file system. (gtk_file_chooser_default_finalize): Disconnect from "volumes-changed". * gtk/gtkfilechooserdefault.c (shortcuts_remove_rows): New helper function. (shortcuts_get_index): New helper function. (shortcuts_insert_path): Can now insert volumes as well as paths. (shortcuts_append_paths): Don't take is_file_system_root. (shortcuts_add_volumes): New function. (shortcuts_append_file_system_roots): Removed. (create_shortcuts_model): Use shortcuts_add_volumes(). (remove_bookmark_button_clicked_cb): Check that the index is within range. (bookmarks_check_add_sensitivity): Take volumes into account. (shortcuts_get_selected_index): New helper function. (remove_bookmark_button_clicked_cb): Use shortcuts_get_selected_index(). (bookmarks_check_remove_sensitivity): Likewise. (shortcuts_select_func): Likewise. (shortcuts_row_activated_cb): Handle volumes as well as normal paths. (shortcuts_activate_volume): New function. (struct _GtkFileChooserDefault): Removed the bookmarks_set and bookmarks_iter fields. (shortcuts_append_bookmarks): Use shortcuts_remove_rows(). (bookmarks_changed_cb): Use shortcuts_add_bookmarks(). (remove_bookmark_rows): Removed. (shortcuts_add_bookmarks): New function; moved most of the code over from shortcuts_append_bookmarks(). (shortcuts_append_bookmarks): Add the separator node here, and then call shortcuts_add_bookmarks().
Diffstat (limited to 'gtk')
-rw-r--r--gtk/gtkfilechooserdefault.c475
-rw-r--r--gtk/gtkfilesystem.c153
-rw-r--r--gtk/gtkfilesystem.h51
-rw-r--r--gtk/gtkfilesystemunix.c90
4 files changed, 631 insertions, 138 deletions
diff --git a/gtk/gtkfilechooserdefault.c b/gtk/gtkfilechooserdefault.c
index 86aec4c320..0b037895cc 100644
--- a/gtk/gtkfilechooserdefault.c
+++ b/gtk/gtkfilechooserdefault.c
@@ -85,12 +85,14 @@ struct _GtkFileChooserDefault
gboolean has_home;
gboolean has_desktop;
- int num_roots;
+
+ int num_volumes;
int num_shortcuts;
int num_bookmarks;
+ guint volumes_changed_id;
+
guint bookmarks_changed_id;
- GtkTreeIter bookmarks_iter;
GtkFilePath *current_folder;
GtkFilePath *preview_path;
@@ -122,7 +124,6 @@ struct _GtkFileChooserDefault
guint select_multiple : 1;
guint show_hidden : 1;
guint list_sort_ascending : 1;
- guint bookmarks_set : 1;
guint changing_folder : 1;
};
@@ -154,6 +155,16 @@ static GtkTargetEntry shortcuts_targets[] = {
static const int num_shortcuts_targets = sizeof (shortcuts_targets) / sizeof (shortcuts_targets[0]);
+/* Interesting places in the shortcuts bar */
+typedef enum {
+ SHORTCUTS_HOME,
+ SHORTCUTS_DESKTOP,
+ SHORTCUTS_VOLUMES,
+ SHORTCUTS_SHORTCUTS,
+ SHORTCUTS_SEPARATOR,
+ SHORTCUTS_BOOKMARKS
+} ShortcutsIndex;
+
/* Standard icon size */
/* FIXME: maybe this should correspond to the font size in the tree views... */
#define ICON_SIZE 20
@@ -354,6 +365,8 @@ gtk_file_chooser_default_finalize (GObject *object)
{
GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (object);
+ 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);
@@ -494,60 +507,62 @@ get_file_info (GtkFileSystem *file_system, const GtkFilePath *path, GError **err
return info;
}
-/* Inserts a path in the shortcuts tree, making a copy of it. A position of -1
- * indicates the end of the tree. If the label is NULL, then the display name
- * of a GtkFileInfo is used.
+/* 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
shortcuts_insert_path (GtkFileChooserDefault *impl,
int pos,
+ gboolean is_volume,
+ GtkFileSystemVolume *volume,
const GtkFilePath *path,
- gboolean is_root,
const char *label,
GError **error)
{
- GtkFileInfo *info;
- GtkFilePath *path_copy;
+ char *label_copy;
GdkPixbuf *pixbuf;
+ gpointer data;
GtkTreeIter iter;
- /* FIXME: what if someone adds a shortcut to a root? get_file_info() will not
- * work in that case, I think...
- */
-
- if (is_root)
- info = gtk_file_system_get_root_info (impl->file_system,
- path,
-#if 0
- GTK_FILE_INFO_DISPLAY_NAME | GTK_FILE_INFO_ICON,
-#else
- GTK_FILE_INFO_DISPLAY_NAME,
-#endif
- error);
+ if (is_volume)
+ {
+ data = volume;
+ label_copy = gtk_file_system_volume_get_display_name (impl->file_system, volume);
+ pixbuf = gtk_file_system_volume_render_icon (impl->file_system,
+ volume,
+ GTK_WIDGET (impl),
+ ICON_SIZE,
+ NULL);
+ }
else
- info = get_file_info (impl->file_system, path, error);
+ {
+ GtkFileInfo *info;
- if (!info)
- return FALSE;
-#if 0
- pixbuf = gtk_file_info_render_icon (info, impl->shortcuts_tree, ICON_SIZE);
-#endif
- /* FIXME: NULL GError */
- pixbuf = gtk_file_system_render_icon (impl->file_system, path, GTK_WIDGET (impl), ICON_SIZE, NULL);
+ info = get_file_info (impl->file_system, path, error);
+ if (!info)
+ return FALSE;
- gtk_tree_store_insert (impl->shortcuts_model, &iter, NULL, pos);
- path_copy = gtk_file_path_copy (path);
+ data = gtk_file_path_copy (path);
+
+ if (label)
+ label_copy = g_strdup (label);
+ else
+ label_copy = g_strdup (gtk_file_info_get_display_name (info));
+
+ pixbuf = gtk_file_system_render_icon (impl->file_system, path, GTK_WIDGET (impl), ICON_SIZE, NULL);
+
+ gtk_file_info_free (info);
+ }
- if (!label)
- label = gtk_file_info_get_display_name (info);
+ gtk_tree_store_insert (impl->shortcuts_model, &iter, NULL, pos);
gtk_tree_store_set (impl->shortcuts_model, &iter,
SHORTCUTS_COL_PIXBUF, pixbuf,
- SHORTCUTS_COL_NAME, label,
- SHORTCUTS_COL_PATH, path_copy,
+ SHORTCUTS_COL_NAME, label_copy,
+ SHORTCUTS_COL_PATH, data,
-1);
- gtk_file_info_free (info);
+ g_free (label_copy);
if (pixbuf)
g_object_unref (pixbuf);
@@ -567,7 +582,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, home_path, FALSE, _("Home"), &error);
+ impl->has_home = shortcuts_insert_path (impl, -1, FALSE, NULL, home_path, _("Home"), &error);
if (!impl->has_home)
error_getting_info_dialog (impl, home_path, error);
@@ -587,7 +602,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, path, FALSE, NULL, NULL);
+ impl->has_desktop = shortcuts_insert_path (impl, -1, FALSE, NULL, path, NULL, NULL);
/* 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.
*/
@@ -598,8 +613,7 @@ shortcuts_append_desktop (GtkFileChooserDefault *impl)
/* Appends a list of GtkFilePath to the shortcuts model; returns how many were inserted */
static int
shortcuts_append_paths (GtkFileChooserDefault *impl,
- GSList *paths,
- gboolean is_file_system_root)
+ GSList *paths)
{
int num_inserted;
@@ -613,7 +627,7 @@ shortcuts_append_paths (GtkFileChooserDefault *impl,
path = paths->data;
error = NULL;
- if (shortcuts_insert_path (impl, -1, path, is_file_system_root, NULL, &error))
+ if (shortcuts_insert_path (impl, -1, FALSE, NULL, path, NULL, &error))
num_inserted++;
else
error_getting_info_dialog (impl, path, error);
@@ -622,62 +636,160 @@ shortcuts_append_paths (GtkFileChooserDefault *impl,
return num_inserted;
}
-/* Appends all the file system roots to the shortcuts model */
-static void
-shortcuts_append_file_system_roots (GtkFileChooserDefault *impl)
+/* Returns the index for the corresponding item in the shortcuts bar */
+static int
+shortcuts_get_index (GtkFileChooserDefault *impl,
+ ShortcutsIndex where)
{
- GSList *roots;
+ int n;
- roots = gtk_file_system_list_roots (impl->file_system);
- /* FIXME: handle the roots-changed signal on the file system */
+ n = 0;
+
+ if (where == SHORTCUTS_HOME)
+ goto out;
+
+ n += impl->has_home ? 1 : 0;
+
+ if (where == SHORTCUTS_DESKTOP)
+ goto out;
+
+ n += impl->has_desktop ? 1 : 0;
+
+ if (where == SHORTCUTS_VOLUMES)
+ goto out;
+
+ n += impl->num_volumes;
+
+ if (where == SHORTCUTS_SHORTCUTS)
+ goto out;
- impl->num_roots = shortcuts_append_paths (impl, roots, TRUE);
- gtk_file_paths_free (roots);
+ n += impl->num_shortcuts;
+
+ if (where == SHORTCUTS_SEPARATOR)
+ goto out;
+
+ n += 1;
+
+ if (where == SHORTCUTS_BOOKMARKS)
+ goto out;
+
+ g_assert_not_reached ();
+
+ out:
+
+ return n;
}
-/* Removes the bookmarks separator node and all the bookmarks from the tree
- * model.
- */
+typedef void (* RemoveFunc) (GtkFileChooserDefault *impl, gpointer data);
+
+/* Removes the specified number of rows from the shortcuts list */
static void
-remove_bookmark_rows (GtkFileChooserDefault *impl)
+shortcuts_remove_rows (GtkFileChooserDefault *impl,
+ int start_row,
+ int n_rows,
+ RemoveFunc remove_fn)
{
GtkTreePath *path;
- GtkTreeIter iter;
- if (!impl->bookmarks_set)
- return;
+ path = gtk_tree_path_new_from_indices (start_row, -1);
- /* Ugh. Is there a better way to do this? */
+ for (; n_rows; n_rows--)
+ {
+ GtkTreeIter iter;
+ gpointer data;
- path = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model), &impl->bookmarks_iter);
+ if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->shortcuts_model), &iter, path))
+ g_assert_not_reached ();
- while (gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->shortcuts_model), &iter, path))
- gtk_tree_store_remove (impl->shortcuts_model, &impl->bookmarks_iter);
+ if (remove_fn)
+ {
+ gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter, SHORTCUTS_COL_PATH, &data, -1);
+ (* remove_fn) (impl, data);
+ }
- impl->bookmarks_set = FALSE;
+ gtk_tree_store_remove (impl->shortcuts_model, &iter);
+ }
+
+ gtk_tree_path_free (path);
}
-/* Appends the bookmarks separator node and the bookmarks from the file system. */
+/* Used from shortcuts_remove_rows() */
static void
-shortcuts_append_bookmarks (GtkFileChooserDefault *impl)
+volume_remove_cb (GtkFileChooserDefault *impl, gpointer data)
+{
+ GtkFileSystemVolume *volume;
+
+ volume = data;
+ gtk_file_system_volume_free (impl->file_system, volume);
+}
+
+/* Adds all the file system volumes to the shortcuts model */
+static void
+shortcuts_add_volumes (GtkFileChooserDefault *impl)
+{
+ int start_row;
+ GSList *list, *l;
+ int n;
+
+ start_row = shortcuts_get_index (impl, SHORTCUTS_VOLUMES);
+ shortcuts_remove_rows (impl, start_row, impl->num_volumes, volume_remove_cb);
+ impl->num_volumes = 0;
+
+ list = gtk_file_system_list_volumes (impl->file_system);
+
+ n = 0;
+
+ for (l = list; l; l = l->next)
+ {
+ GtkFileSystemVolume *volume;
+
+ volume = l->data;
+
+ shortcuts_insert_path (impl, start_row + n, TRUE, volume, NULL, NULL, NULL);
+ n++;
+ }
+
+ impl->num_volumes = n;
+}
+
+/* Used from shortcuts_remove_rows() */
+static void
+remove_bookmark_cb (GtkFileChooserDefault *impl, gpointer data)
+{
+ GtkFilePath *path;
+
+ path = data;
+ gtk_file_path_free (path);
+}
+
+/* Updates the list of bookmarks */
+static void
+shortcuts_add_bookmarks (GtkFileChooserDefault *impl)
{
GSList *bookmarks;
- remove_bookmark_rows (impl);
+ shortcuts_remove_rows (impl,
+ shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS),
+ impl->num_bookmarks,
+ remove_bookmark_cb);
+
+ bookmarks = gtk_file_system_list_bookmarks (impl->file_system);
+ impl->num_bookmarks = shortcuts_append_paths (impl, bookmarks);
+ gtk_file_paths_free (bookmarks);
+}
+
+/* Appends the bookmarks separator node and the bookmarks from the file system. */
+static void
+shortcuts_append_bookmarks (GtkFileChooserDefault *impl)
+{
+ GtkTreeIter iter;
- gtk_tree_store_append (impl->shortcuts_model, &impl->bookmarks_iter, NULL);
- gtk_tree_store_set (impl->shortcuts_model, &impl->bookmarks_iter,
+ gtk_tree_store_append (impl->shortcuts_model, &iter, NULL);
+ gtk_tree_store_set (impl->shortcuts_model, &iter,
SHORTCUTS_COL_PIXBUF, NULL,
SHORTCUTS_COL_NAME, NULL,
SHORTCUTS_COL_PATH, NULL,
-1);
- impl->bookmarks_set = TRUE;
-
- bookmarks = gtk_file_system_list_bookmarks (impl->file_system);
-
- /* FIXME: How do we know if a bookmark is a file system root? */
- impl->num_bookmarks = shortcuts_append_paths (impl, bookmarks, FALSE);
- gtk_file_paths_free (bookmarks);
}
/* Creates the GtkTreeStore used as the shortcuts model */
@@ -691,13 +803,13 @@ create_shortcuts_model (GtkFileChooserDefault *impl)
impl->shortcuts_model = gtk_tree_store_new (SHORTCUTS_COL_NUM_COLUMNS,
GDK_TYPE_PIXBUF, /* pixbuf */
G_TYPE_STRING, /* name */
- G_TYPE_POINTER); /* path */
+ G_TYPE_POINTER); /* path or volume */
if (impl->file_system)
{
shortcuts_append_home (impl);
shortcuts_append_desktop (impl);
- shortcuts_append_file_system_roots (impl);
+ shortcuts_add_volumes (impl);
shortcuts_append_bookmarks (impl);
}
@@ -904,20 +1016,51 @@ add_bookmark_button_clicked_cb (GtkButton *button,
shortcuts_add_bookmark_from_path (impl, impl->current_folder);
}
+/* Returns the index of the selected row in the shortcuts list, or -1 if nothing
+ * is selected.
+ */
+static int
+shortcuts_get_selected_index (GtkFileChooserDefault *impl)
+{
+ GtkTreeSelection *selection;
+ GtkTreeIter iter;
+ GtkTreePath *path;
+ int *indices;
+ int idx;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->shortcuts_tree));
+
+ if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
+ return -1;
+
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model), &iter);
+ g_assert (path != NULL);
+
+ indices = gtk_tree_path_get_indices (path);
+ g_assert (gtk_tree_path_get_depth (path) == 1);
+
+ idx = *indices;
+
+ gtk_tree_path_free (path);
+
+ return idx;
+}
+
/* Callback used when the "Remove bookmark" button is clicked */
static void
remove_bookmark_button_clicked_cb (GtkButton *button,
GtkFileChooserDefault *impl)
{
- GtkTreeSelection *selection;
GtkTreeIter iter;
GtkFilePath *path;
+ int selected, start_row;
GError *error;
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->shortcuts_tree));
+ selected = shortcuts_get_selected_index (impl);
- if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
- return;
+ start_row = shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS);
+ if (selected < start_row || selected >= start_row + impl->num_bookmarks)
+ g_assert_not_reached ();
gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter, SHORTCUTS_COL_PATH, &path, -1);
@@ -937,23 +1080,59 @@ bookmarks_check_add_sensitivity (GtkFileChooserDefault *impl)
{
GtkTreeIter iter;
gboolean exists;
+ int volumes_idx;
+ int separator_idx;
exists = FALSE;
if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (impl->shortcuts_model), &iter))
- do
- {
- GtkFilePath *path;
+ {
+ int i;
- gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter, SHORTCUTS_COL_PATH, &path, -1);
+ separator_idx = shortcuts_get_index (impl, SHORTCUTS_SEPARATOR);
+ volumes_idx = shortcuts_get_index (impl, SHORTCUTS_VOLUMES);
- if (path && gtk_file_path_compare (path, impl->current_folder) == 0)
- {
- exists = TRUE;
- break;
- }
- }
- while (gtk_tree_model_iter_next (GTK_TREE_MODEL (impl->shortcuts_model), &iter));
+ i = 0;
+
+ do
+ {
+ gpointer data;
+
+ if (i == separator_idx)
+ continue;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter, SHORTCUTS_COL_PATH, &data, -1);
+
+ if (i >= volumes_idx && i < volumes_idx + impl->num_volumes)
+ {
+ GtkFileSystemVolume *volume;
+ GtkFilePath *base_path;
+
+ volume = data;
+ base_path = gtk_file_system_volume_get_base_path (impl->file_system, volume);
+
+ exists = strcmp (gtk_file_path_get_string (impl->current_folder),
+ gtk_file_path_get_string (base_path)) == 0;
+ g_free (base_path);
+
+ if (exists)
+ break;
+ }
+ else
+ {
+ GtkFilePath *path;
+
+ path = data;
+
+ if (path && gtk_file_path_compare (path, impl->current_folder) == 0)
+ {
+ exists = TRUE;
+ break;
+ }
+ }
+ }
+ while (gtk_tree_model_iter_next (GTK_TREE_MODEL (impl->shortcuts_model), &iter));
+ }
gtk_widget_set_sensitive (impl->add_bookmark_button, !exists);
}
@@ -964,28 +1143,13 @@ bookmarks_check_add_sensitivity (GtkFileChooserDefault *impl)
static void
bookmarks_check_remove_sensitivity (GtkFileChooserDefault *impl)
{
- GtkTreeSelection *selection;
- GtkTreeIter iter;
+ int selected, start_row;
gboolean is_bookmark;
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->shortcuts_tree));
+ selected = shortcuts_get_selected_index (impl);
+ start_row = shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS);
- if (gtk_tree_selection_get_selected (selection, NULL, &iter))
- {
- GtkTreePath *bookmarks_path;
- GtkTreePath *sel_path;
-
- bookmarks_path = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model),
- &impl->bookmarks_iter);
- sel_path = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model), &iter);
-
- is_bookmark = (gtk_tree_path_compare (bookmarks_path, sel_path) < 0);
-
- gtk_tree_path_free (bookmarks_path);
- gtk_tree_path_free (sel_path);
- }
- else
- is_bookmark = FALSE;
+ is_bookmark = (selected >= start_row) && (selected < start_row + impl->num_bookmarks);
gtk_widget_set_sensitive (impl->remove_bookmark_button, is_bookmark);
}
@@ -1435,12 +1599,19 @@ set_extra_widget (GtkFileChooserDefault *impl,
}
}
+static void
+volumes_changed_cb (GtkFileSystem *file_system,
+ GtkFileChooserDefault *impl)
+{
+ shortcuts_add_volumes (impl);
+}
+
/* Callback used when the set of bookmarks changes in the file system */
static void
bookmarks_changed_cb (GtkFileSystem *file_system,
GtkFileChooserDefault *impl)
{
- shortcuts_append_bookmarks (impl);
+ shortcuts_add_bookmarks (impl);
bookmarks_check_add_sensitivity (impl);
bookmarks_check_remove_sensitivity (impl);
@@ -1467,6 +1638,8 @@ gtk_file_chooser_default_set_property (GObject *object,
{
if (impl->file_system)
{
+ 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);
@@ -1475,6 +1648,9 @@ gtk_file_chooser_default_set_property (GObject *object,
if (impl->file_system)
{
g_object_ref (impl->file_system);
+ impl->volumes_changed_id = g_signal_connect (impl->file_system, "volumes-changed",
+ G_CALLBACK (volumes_changed_cb),
+ impl);
impl->bookmarks_changed_id = g_signal_connect (impl->file_system, "bookmarks-changed",
G_CALLBACK (bookmarks_changed_cb),
impl);
@@ -2173,9 +2349,7 @@ static int
shortcuts_get_pos_for_shortcut_folder (GtkFileChooserDefault *impl,
int pos)
{
- return pos + ((impl->has_home ? 1 : 0)
- + (impl->has_desktop ? 1 : 0)
- + impl->num_roots);
+ return pos + shortcuts_get_index (impl, SHORTCUTS_SHORTCUTS);
}
static gboolean
@@ -2189,8 +2363,7 @@ gtk_file_chooser_default_add_shortcut_folder (GtkFileChooser *chooser,
pos = shortcuts_get_pos_for_shortcut_folder (impl, impl->num_shortcuts);
- /* FIXME: how do we know if the path is a file system root? */
- result = shortcuts_insert_path (impl, pos, path, FALSE, NULL, error);
+ result = shortcuts_insert_path (impl, pos, FALSE, NULL, path, NULL, error);
if (result)
impl->num_shortcuts++;
@@ -2446,6 +2619,40 @@ tree_selection_changed (GtkTreeSelection *selection,
_gtk_file_chooser_set_current_folder_path (GTK_FILE_CHOOSER (impl), file_path);
}
+/* Activates a volume by mounting it if necessary and then switching to its
+ * base path.
+ */
+static void
+shortcuts_activate_volume (GtkFileChooserDefault *impl,
+ GtkFileSystemVolume *volume)
+{
+ GtkFilePath *path;
+
+ if (!gtk_file_system_volume_get_is_mounted (impl->file_system, volume))
+ {
+ GError *error;
+
+ error = NULL;
+ if (!gtk_file_system_volume_mount (impl->file_system, volume, &error))
+ {
+ char *msg;
+
+ msg = g_strdup_printf ("Could not mount %s:\n%s",
+ gtk_file_system_volume_get_display_name (impl->file_system, volume),
+ error->message);
+ error_message (impl, msg);
+ g_free (msg);
+ g_error_free (error);
+
+ return;
+ }
+ }
+
+ path = gtk_file_system_volume_get_base_path (impl->file_system, volume);
+ _gtk_file_chooser_set_current_folder_path (GTK_FILE_CHOOSER (impl), path);
+ gtk_file_path_free (path);
+}
+
/* Callback used when a row in the shortcuts list is activated */
static void
shortcuts_row_activated_cb (GtkTreeView *tree_view,
@@ -2454,22 +2661,34 @@ shortcuts_row_activated_cb (GtkTreeView *tree_view,
GtkFileChooserDefault *impl)
{
GtkTreeIter iter;
- GtkFilePath *model_path;
+ int selected, start_row;
+ gpointer data;
if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->shortcuts_model), &iter, path))
return;
- /* Set the current folder */
+ selected = *gtk_tree_path_get_indices (path);
- gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter, SHORTCUTS_COL_PATH, &model_path, -1);
+ if (selected == shortcuts_get_index (impl, SHORTCUTS_SEPARATOR))
+ return;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter, SHORTCUTS_COL_PATH, &data, -1);
- if (!model_path)
+ start_row = shortcuts_get_index (impl, SHORTCUTS_VOLUMES);
+ if (selected >= start_row && selected < start_row + impl->num_volumes)
{
- /* We are on the bookmarks separator node, so do nothing */
- return;
+ GtkFileSystemVolume *volume;
+
+ volume = data;
+ shortcuts_activate_volume (impl, volume);
}
+ else
+ {
+ GtkFilePath *file_path;
- _gtk_file_chooser_set_current_folder_path (GTK_FILE_CHOOSER (impl), model_path);
+ file_path = data;
+ _gtk_file_chooser_set_current_folder_path (GTK_FILE_CHOOSER (impl), file_path);
+ }
}
static gboolean
@@ -2480,16 +2699,8 @@ shortcuts_select_func (GtkTreeSelection *selection,
gpointer data)
{
GtkFileChooserDefault *impl = data;
- GtkTreeIter iter;
- GtkFilePath *model_path;
-
- if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->shortcuts_model), &iter, path))
- return FALSE;
-
- gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter, SHORTCUTS_COL_PATH, &model_path, -1);
- /* Don't allow the separator node to be selected */
- return model_path != NULL;
+ return (*gtk_tree_path_get_indices (path) != shortcuts_get_index (impl, SHORTCUTS_SEPARATOR));
}
static void
diff --git a/gtk/gtkfilesystem.c b/gtk/gtkfilesystem.c
index c927029d06..691941b42a 100644
--- a/gtk/gtkfilesystem.c
+++ b/gtk/gtkfilesystem.c
@@ -447,6 +447,13 @@ gtk_file_system_base_init (gpointer g_class)
{
GType iface_type = G_TYPE_FROM_INTERFACE (g_class);
+ g_signal_new ("volumes-changed",
+ iface_type,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkFileSystemIface, volumes_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
g_signal_new ("roots-changed",
iface_type,
G_SIGNAL_RUN_LAST,
@@ -467,6 +474,14 @@ gtk_file_system_base_init (gpointer g_class)
}
GSList *
+gtk_file_system_list_volumes (GtkFileSystem *file_system)
+{
+ g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
+
+ return GTK_FILE_SYSTEM_GET_IFACE (file_system)->list_volumes (file_system);
+}
+
+GSList *
gtk_file_system_list_roots (GtkFileSystem *file_system)
{
g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
@@ -513,6 +528,142 @@ gtk_file_system_create_folder(GtkFileSystem *file_system,
}
/**
+ * gtk_file_system_volume_free:
+ * @file_system: a #GtkFileSystem
+ * @volume: a #GtkFileSystemVolume
+ *
+ * Frees a #GtkFileSystemVolume structure as returned by
+ * gtk_file_system_list_volumes().
+ **/
+void
+gtk_file_system_volume_free (GtkFileSystem *file_system,
+ GtkFileSystemVolume *volume)
+{
+ g_return_if_fail (GTK_IS_FILE_SYSTEM (file_system));
+ g_return_if_fail (volume != NULL);
+
+ GTK_FILE_SYSTEM_GET_IFACE (file_system)->volume_free (file_system, volume);
+}
+
+/**
+ * gtk_file_system_volume_get_base_path:
+ * @file_system: a #GtkFileSystem
+ * @volume: a #GtkFileSystemVolume
+ *
+ * Queries the base path for a volume. For example, a CD-ROM device may yield a
+ * path of "/mnt/cdrom".
+ *
+ * Return value: a #GtkFilePath with the base mount path of the specified
+ * @volume.
+ **/
+GtkFilePath *
+gtk_file_system_volume_get_base_path (GtkFileSystem *file_system,
+ GtkFileSystemVolume *volume)
+{
+ g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
+ g_return_val_if_fail (volume != NULL, NULL);
+
+ return GTK_FILE_SYSTEM_GET_IFACE (file_system)->volume_get_base_path (file_system, volume);
+}
+
+/**
+ * gtk_file_system_volume_get_is_mounted:
+ * @file_system: a #GtkFileSystem
+ * @volume: a #GtkFileSystemVolume
+ *
+ * Queries whether a #GtkFileSystemVolume is mounted or not. If it is not, it
+ * can be mounted with gtk_file_system_volume_mount().
+ *
+ * Return value: TRUE if the @volume is mounted, FALSE otherwise.
+ **/
+gboolean
+gtk_file_system_volume_get_is_mounted (GtkFileSystem *file_system,
+ GtkFileSystemVolume *volume)
+{
+ g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), FALSE);
+ g_return_val_if_fail (volume != NULL, FALSE);
+
+ return GTK_FILE_SYSTEM_GET_IFACE (file_system)->volume_get_is_mounted (file_system, volume);
+}
+
+/**
+ * gtk_file_system_volume_mount:
+ * @file_system: a #GtkFileSystem
+ * @volume: a #GtkFileSystemVolume
+ * @error: location to store error, or %NULL
+ *
+ * Tries to mount an unmounted volume. This may cause the "volumes-changed"
+ * signal in the @file_system to be emitted.
+ *
+ * Return value: TRUE if the @volume was mounted successfully, FALSE otherwise.
+ **/
+gboolean
+gtk_file_system_volume_mount (GtkFileSystem *file_system,
+ GtkFileSystemVolume *volume,
+ GError **error)
+{
+ 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);
+
+ return GTK_FILE_SYSTEM_GET_IFACE (file_system)->volume_mount (file_system, volume, error);
+}
+
+/**
+ * gtk_file_system_volume_get_display_name:
+ * @file_system: a #GtkFileSystem
+ * @volume: a #GtkFileSystemVolume
+ *
+ * Queries the human-readable name for a @volume. This string can be displayed
+ * in a list of volumes that can be accessed, for example.
+ *
+ * Return value: A string with the human-readable name for a #GtkFileSystemVolume.
+ **/
+char *
+gtk_file_system_volume_get_display_name (GtkFileSystem *file_system,
+ GtkFileSystemVolume *volume)
+{
+ g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
+ g_return_val_if_fail (volume != NULL, NULL);
+
+ return GTK_FILE_SYSTEM_GET_IFACE (file_system)->volume_get_display_name (file_system, volume);
+}
+
+/**
+ * gtk_file_system_volume_render_icon:
+ * @file_system: a #GtkFileSystem
+ * @volume: a #GtkFileSystemVolume
+ * @widget: Reference widget to render icons.
+ * @pixel_size: Size of the icon.
+ * @error: location to store error, or %NULL
+ *
+ * Renders an icon suitable for a file #GtkFileSystemVolume.
+ *
+ * Return value: A #GdkPixbuf containing an icon, or NULL if the icon could not
+ * be rendered. In the latter case, the @error value will be set as
+ * appropriate.
+ **/
+GdkPixbuf *
+gtk_file_system_volume_render_icon (GtkFileSystem *file_system,
+ GtkFileSystemVolume *volume,
+ GtkWidget *widget,
+ gint pixel_size,
+ 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 (GTK_IS_WIDGET (widget), NULL);
+ g_return_val_if_fail (pixel_size > 0, NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ return GTK_FILE_SYSTEM_GET_IFACE (file_system)->volume_render_icon (file_system,
+ volume,
+ widget,
+ pixel_size,
+ error);
+}
+
+/**
* gtk_file_system_get_parent:
* @file_system: a #GtkFileSystem
* @path: base path name
@@ -680,7 +831,7 @@ gtk_file_system_render_icon (GtkFileSystem *file_system,
{
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 (widget != 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);
diff --git a/gtk/gtkfilesystem.h b/gtk/gtkfilesystem.h
index e3c061870d..3949388645 100644
--- a/gtk/gtkfilesystem.h
+++ b/gtk/gtkfilesystem.h
@@ -36,11 +36,12 @@ G_BEGIN_DECLS
typedef gint64 GtkFileTime;
-typedef struct _GtkFileFolder GtkFileFolder;
-typedef struct _GtkFileFolderIface GtkFileFolderIface;
-typedef struct _GtkFileInfo GtkFileInfo;
-typedef struct _GtkFileSystem GtkFileSystem;
-typedef struct _GtkFileSystemIface GtkFileSystemIface;
+typedef struct _GtkFileFolder GtkFileFolder;
+typedef struct _GtkFileFolderIface GtkFileFolderIface;
+typedef struct _GtkFileInfo GtkFileInfo;
+typedef struct _GtkFileSystem GtkFileSystem;
+typedef struct _GtkFileSystemIface GtkFileSystemIface;
+typedef struct _GtkFileSystemVolume GtkFileSystemVolume;
typedef struct _GtkFilePath GtkFilePath;
@@ -143,6 +144,7 @@ struct _GtkFileSystemIface
/* Methods
*/
+ GSList * (*list_volumes) (GtkFileSystem *file_system);
GSList * (*list_roots) (GtkFileSystem *file_system);
GtkFileInfo * (*get_root_info) (GtkFileSystem *file_system,
@@ -158,6 +160,26 @@ struct _GtkFileSystemIface
const GtkFilePath *path,
GError **error);
+ /* Volumes
+ */
+
+ void (*volume_free) (GtkFileSystem *file_system,
+ GtkFileSystemVolume *volume);
+ GtkFilePath * (*volume_get_base_path) (GtkFileSystem *file_system,
+ 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,
+ GtkFileSystemVolume *volume);
+ GdkPixbuf * (*volume_render_icon) (GtkFileSystem *file_system,
+ GtkFileSystemVolume *volume,
+ GtkWidget *widget,
+ gint pixel_size,
+ GError **error);
+
/* Path Manipulation
*/
gboolean (*get_parent) (GtkFileSystem *file_system,
@@ -203,18 +225,37 @@ struct _GtkFileSystemIface
/* Signals
*/
+ void (*volumes_changed) (GtkFileSystem *file_system);
void (*roots_changed) (GtkFileSystem *file_system);
void (*bookmarks_changed) (GtkFileSystem *file_system);
};
GType gtk_file_system_get_type (void);
+GSList * gtk_file_system_list_volumes (GtkFileSystem *file_system);
GSList * gtk_file_system_list_roots (GtkFileSystem *file_system);
GtkFileInfo * gtk_file_system_get_root_info (GtkFileSystem *file_system,
const GtkFilePath *path,
GtkFileInfoType types,
GError **error);
+void gtk_file_system_volume_free (GtkFileSystem *file_system,
+ GtkFileSystemVolume *volume);
+GtkFilePath * gtk_file_system_volume_get_base_path (GtkFileSystem *file_system,
+ 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);
+char * gtk_file_system_volume_get_display_name (GtkFileSystem *file_system,
+ GtkFileSystemVolume *volume);
+GdkPixbuf * gtk_file_system_volume_render_icon (GtkFileSystem *file_system,
+ GtkFileSystemVolume *volume,
+ GtkWidget *widget,
+ gint pixel_size,
+ GError **error);
+
gboolean gtk_file_system_get_parent (GtkFileSystem *file_system,
const GtkFilePath *path,
GtkFilePath **parent,
diff --git a/gtk/gtkfilesystemunix.c b/gtk/gtkfilesystemunix.c
index d0a1924c46..2eb9744d70 100644
--- a/gtk/gtkfilesystemunix.c
+++ b/gtk/gtkfilesystemunix.c
@@ -47,6 +47,11 @@ struct _GtkFileSystemUnix
GObject parent_instance;
};
+/* Simple stub for our returned volumes */
+typedef struct {
+ int dummy;
+} Volume;
+
#define GTK_TYPE_FILE_FOLDER_UNIX (gtk_file_folder_unix_get_type ())
#define GTK_FILE_FOLDER_UNIX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_FILE_FOLDER_UNIX, GtkFileFolderUnix))
#define GTK_IS_FILE_FOLDER_UNIX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_FILE_FOLDER_UNIX))
@@ -78,6 +83,7 @@ static void gtk_file_system_unix_iface_init (GtkFileSystemIface *iface);
static void gtk_file_system_unix_init (GtkFileSystemUnix *impl);
static void gtk_file_system_unix_finalize (GObject *object);
+static GSList * gtk_file_system_unix_list_volumes (GtkFileSystem *file_system);
static GSList * gtk_file_system_unix_list_roots (GtkFileSystem *file_system);
static GtkFileInfo * gtk_file_system_unix_get_root_info (GtkFileSystem *file_system,
const GtkFilePath *path,
@@ -90,6 +96,24 @@ static GtkFileFolder *gtk_file_system_unix_get_folder (GtkFileSystem *fi
static gboolean gtk_file_system_unix_create_folder (GtkFileSystem *file_system,
const GtkFilePath *path,
GError **error);
+
+static void gtk_file_system_unix_volume_free (GtkFileSystem *file_system,
+ GtkFileSystemVolume *volume);
+static GtkFilePath *gtk_file_system_unix_volume_get_base_path (GtkFileSystem *file_system,
+ 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,
+ GtkFileSystemVolume *volume,
+ GError **error);
+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,
+ GtkFileSystemVolume *volume,
+ GtkWidget *widget,
+ gint pixel_size,
+ GError **error);
+
static gboolean gtk_file_system_unix_get_parent (GtkFileSystem *file_system,
const GtkFilePath *path,
GtkFilePath **parent,
@@ -218,10 +242,17 @@ gtk_file_system_unix_class_init (GtkFileSystemUnixClass *class)
static void
gtk_file_system_unix_iface_init (GtkFileSystemIface *iface)
{
+ iface->list_volumes = gtk_file_system_unix_list_volumes;
iface->list_roots = gtk_file_system_unix_list_roots;
iface->get_folder = gtk_file_system_unix_get_folder;
iface->get_root_info = gtk_file_system_unix_get_root_info;
iface->create_folder = gtk_file_system_unix_create_folder;
+ 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->get_parent = gtk_file_system_unix_get_parent;
iface->make_path = gtk_file_system_unix_make_path;
iface->parse = gtk_file_system_unix_parse;
@@ -247,6 +278,12 @@ gtk_file_system_unix_finalize (GObject *object)
}
static GSList *
+gtk_file_system_unix_list_volumes (GtkFileSystem *file_system)
+{
+ return g_slist_append (NULL, gtk_file_path_new_dup ("/"));
+}
+
+static GSList *
gtk_file_system_unix_list_roots (GtkFileSystem *file_system)
{
return g_slist_append (NULL, gtk_file_path_new_dup ("/"));
@@ -314,6 +351,59 @@ gtk_file_system_unix_create_folder (GtkFileSystem *file_system,
return result;
}
+static void
+gtk_file_system_unix_volume_free (GtkFileSystem *file_system,
+ GtkFileSystemVolume *volume)
+{
+ GtkFilePath *path;
+
+ path = (GtkFilePath *) volume;
+ gtk_file_path_free (path);
+}
+
+static GtkFilePath *
+gtk_file_system_unix_volume_get_base_path (GtkFileSystem *file_system,
+ GtkFileSystemVolume *volume)
+{
+ return gtk_file_path_new_dup ("/");
+}
+
+static gboolean
+gtk_file_system_unix_volume_get_is_mounted (GtkFileSystem *file_system,
+ GtkFileSystemVolume *volume)
+{
+ return TRUE;
+}
+
+static gboolean
+gtk_file_system_unix_volume_mount (GtkFileSystem *file_system,
+ GtkFileSystemVolume *volume,
+ GError **error)
+{
+ g_set_error (error,
+ GTK_FILE_SYSTEM_ERROR,
+ GTK_FILE_SYSTEM_ERROR_FAILED,
+ _("This file system does not support mounting"));
+ return FALSE;
+}
+
+static gchar *
+gtk_file_system_unix_volume_get_display_name (GtkFileSystem *file_system,
+ GtkFileSystemVolume *volume)
+{
+ return g_strdup (_("Filesystem")); /* Same as Nautilus */
+}
+
+static GdkPixbuf *
+gtk_file_system_unix_volume_render_icon (GtkFileSystem *file_system,
+ GtkFileSystemVolume *volume,
+ GtkWidget *widget,
+ gint pixel_size,
+ GError **error)
+{
+ return NULL; /* FIXME: We need a hard disk icon or something */
+}
+
static gboolean
gtk_file_system_unix_get_parent (GtkFileSystem *file_system,
const GtkFilePath *path,