diff options
author | Federico Mena Quintero <federico@ximian.com> | 2003-12-17 05:55:16 +0000 |
---|---|---|
committer | Federico Mena Quintero <federico@src.gnome.org> | 2003-12-17 05:55:16 +0000 |
commit | 8baf8571b52f21c0012420669483f4769cfa13ca (patch) | |
tree | 56b9ae2e89c29cd6647295ec52ef4cfc327f0487 /gtk | |
parent | 6b80f394a59244ab7a2e04fa6649728743469702 (diff) | |
download | gtk+-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.c | 475 | ||||
-rw-r--r-- | gtk/gtkfilesystem.c | 153 | ||||
-rw-r--r-- | gtk/gtkfilesystem.h | 51 | ||||
-rw-r--r-- | gtk/gtkfilesystemunix.c | 90 |
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, |