diff options
Diffstat (limited to 'src/nautilus-canvas-view.c')
-rw-r--r-- | src/nautilus-canvas-view.c | 1647 |
1 files changed, 1647 insertions, 0 deletions
diff --git a/src/nautilus-canvas-view.c b/src/nautilus-canvas-view.c new file mode 100644 index 0000000..4b3197b --- /dev/null +++ b/src/nautilus-canvas-view.c @@ -0,0 +1,1647 @@ +/* fm-canvas-view.c - implementation of canvas view of directory. + * + * Copyright (C) 2000, 2001 Eazel, Inc. + * + * The Gnome Library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * The Gnome Library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with the Gnome Library; see the file COPYING.LIB. If not, + * see <http://www.gnu.org/licenses/>. + * + * Authors: John Sullivan <sullivan@eazel.com> + */ + +#include <config.h> + +#include "nautilus-canvas-view.h" + +#include "nautilus-canvas-view-container.h" +#include "nautilus-error-reporting.h" +#include "nautilus-files-view-dnd.h" +#include "nautilus-toolbar.h" +#include "nautilus-view.h" + +#include <stdlib.h> +#include <errno.h> +#include <fcntl.h> +#include <gtk/gtk.h> +#include <glib/gi18n.h> +#include <gio/gio.h> +#include "nautilus-directory.h" +#include "nautilus-dnd.h" +#include "nautilus-file-utilities.h" +#include "nautilus-ui-utilities.h" +#include "nautilus-global-preferences.h" +#include "nautilus-canvas-container.h" +#include "nautilus-canvas-dnd.h" +#include "nautilus-metadata.h" +#include "nautilus-clipboard.h" + +#define DEBUG_FLAG NAUTILUS_DEBUG_CANVAS_VIEW +#include "nautilus-debug.h" + +#include <locale.h> +#include <signal.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> + +typedef gboolean (*SortCriterionMatchFunc) (NautilusFile *file); + +typedef struct +{ + const NautilusFileSortType sort_type; + const char *metadata_text; + const char *action_target_name; + const gboolean reverse_order; + SortCriterionMatchFunc match_func; +} SortCriterion; + +typedef enum +{ + MENU_ITEM_TYPE_STANDARD, + MENU_ITEM_TYPE_CHECK, + MENU_ITEM_TYPE_RADIO, + MENU_ITEM_TYPE_TREE +} MenuItemType; + +struct _NautilusCanvasView +{ + NautilusFilesView parent_instance; + + GList *icons_not_positioned; + + guint react_to_canvas_change_idle_id; + + const SortCriterion *sort; + + GtkWidget *canvas_container; + + /* FIXME: Needed for async operations. Suposedly we would use cancellable and gtask, + * sadly gtkclipboard doesn't support that. + * We follow this pattern for checking validity of the object in the views. + * Ideally we would connect to a weak reference and do a cancellable. + */ + gboolean destroyed; +}; + +/* Note that the first item in this list is the default sort, + * and that the items show up in the menu in the order they + * appear in this list. + */ +static const SortCriterion sort_criteria[] = +{ + { + NAUTILUS_FILE_SORT_BY_DISPLAY_NAME, + "name", + "name", + FALSE + }, + { + NAUTILUS_FILE_SORT_BY_DISPLAY_NAME, + "name", + "name-desc", + TRUE + }, + { + NAUTILUS_FILE_SORT_BY_SIZE, + "size", + "size", + TRUE + }, + { + NAUTILUS_FILE_SORT_BY_TYPE, + "type", + "type", + FALSE + }, + { + NAUTILUS_FILE_SORT_BY_MTIME, + "modification date", + "modification-date", + FALSE + }, + { + NAUTILUS_FILE_SORT_BY_MTIME, + "modification date", + "modification-date-desc", + TRUE + }, + { + NAUTILUS_FILE_SORT_BY_ATIME, + "access date", + "access-date", + FALSE + }, + { + NAUTILUS_FILE_SORT_BY_ATIME, + "access date", + "access-date-desc", + TRUE + }, + { + NAUTILUS_FILE_SORT_BY_TRASHED_TIME, + "trashed", + "trash-time", + TRUE, + nautilus_file_is_in_trash + }, + { + NAUTILUS_FILE_SORT_BY_SEARCH_RELEVANCE, + NULL, + "search-relevance", + TRUE, + nautilus_file_is_in_search + }, + { + NAUTILUS_FILE_SORT_BY_RECENCY, + NULL, + "recency", + TRUE, + nautilus_file_is_in_recent + } +}; + +G_DEFINE_TYPE (NautilusCanvasView, nautilus_canvas_view, NAUTILUS_TYPE_FILES_VIEW); + +static void nautilus_canvas_view_set_directory_sort_by (NautilusCanvasView *canvas_view, + NautilusFile *file, + const SortCriterion *sort); +static void nautilus_canvas_view_update_click_mode (NautilusCanvasView *canvas_view); +static void nautilus_canvas_view_reveal_selection (NautilusFilesView *view); +static const SortCriterion *get_sort_criterion_by_metadata_text (const char *metadata_text, + gboolean reversed); +static const SortCriterion *get_sort_criterion_by_sort_type (NautilusFileSortType sort_type, + gboolean reversed); +static const SortCriterion *get_default_sort_order (NautilusFile *file); +static void nautilus_canvas_view_clear (NautilusFilesView *view); +static void on_clipboard_owner_changed (GtkClipboard *clipboard, + GdkEvent *event, + gpointer user_data); + +static void +nautilus_canvas_view_destroy (GtkWidget *object) +{ + NautilusCanvasView *canvas_view; + GtkClipboard *clipboard; + + canvas_view = NAUTILUS_CANVAS_VIEW (object); + + nautilus_canvas_view_clear (NAUTILUS_FILES_VIEW (object)); + + if (canvas_view->react_to_canvas_change_idle_id != 0) + { + g_source_remove (canvas_view->react_to_canvas_change_idle_id); + canvas_view->react_to_canvas_change_idle_id = 0; + } + + clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); + g_signal_handlers_disconnect_by_func (clipboard, + on_clipboard_owner_changed, + canvas_view); + + if (canvas_view->icons_not_positioned) + { + nautilus_file_list_free (canvas_view->icons_not_positioned); + canvas_view->icons_not_positioned = NULL; + } + + GTK_WIDGET_CLASS (nautilus_canvas_view_parent_class)->destroy (object); +} + +static NautilusCanvasContainer * +get_canvas_container (NautilusCanvasView *canvas_view) +{ + return NAUTILUS_CANVAS_CONTAINER (canvas_view->canvas_container); +} + +NautilusCanvasContainer * +nautilus_canvas_view_get_canvas_container (NautilusCanvasView *canvas_view) +{ + return get_canvas_container (canvas_view); +} + +static void +update_sort_criterion (NautilusCanvasView *canvas_view, + const SortCriterion *sort, + gboolean set_metadata) +{ + NautilusFile *file; + const SortCriterion *overrided_sort_criterion; + + file = nautilus_files_view_get_directory_as_file (NAUTILUS_FILES_VIEW (canvas_view)); + + /* Make sure we use the default one and not one that the user used previously + * of the change to not allow sorting on search and recent, or the + * case that the user or some app modified directly the metadata */ + if (nautilus_file_is_in_search (file) || nautilus_file_is_in_recent (file)) + { + overrided_sort_criterion = get_default_sort_order (file); + } + else if (sort != NULL && canvas_view->sort != sort) + { + overrided_sort_criterion = sort; + if (set_metadata) + { + /* Store the new sort setting. */ + nautilus_canvas_view_set_directory_sort_by (canvas_view, + file, + sort); + } + } + else + { + return; + } + + canvas_view->sort = overrided_sort_criterion; +} + +static void +list_covers (NautilusCanvasIconData *data, + gpointer callback_data) +{ + GSList **file_list; + + file_list = callback_data; + + *file_list = g_slist_prepend (*file_list, data); +} + +static void +unref_cover (NautilusCanvasIconData *data, + gpointer callback_data) +{ + nautilus_file_unref (NAUTILUS_FILE (data)); +} + +static void +nautilus_canvas_view_clear (NautilusFilesView *view) +{ + NautilusCanvasContainer *canvas_container; + GSList *file_list; + + g_return_if_fail (NAUTILUS_IS_CANVAS_VIEW (view)); + + canvas_container = get_canvas_container (NAUTILUS_CANVAS_VIEW (view)); + if (!canvas_container) + { + return; + } + + /* Clear away the existing icons. */ + file_list = NULL; + nautilus_canvas_container_for_each (canvas_container, list_covers, &file_list); + nautilus_canvas_container_clear (canvas_container); + g_slist_foreach (file_list, (GFunc) unref_cover, NULL); + g_slist_free (file_list); +} + +static void +nautilus_canvas_view_remove_file (NautilusFilesView *view, + NautilusFile *file, + NautilusDirectory *directory) +{ + NautilusCanvasView *canvas_view; + + /* This used to assert that 'directory == nautilus_files_view_get_model (view)', but that + * resulted in a lot of crash reports (bug #352592). I don't see how that trace happens. + * It seems that somehow we get a files_changed event sent to the view from a directory + * that isn't the model, but the code disables the monitor and signal callback handlers when + * changing directories. Maybe we can get some more information when this happens. + * Further discussion in bug #368178. + */ + if (directory != nautilus_files_view_get_model (view)) + { + char *file_uri, *dir_uri, *model_uri; + file_uri = nautilus_file_get_uri (file); + dir_uri = nautilus_directory_get_uri (directory); + model_uri = nautilus_directory_get_uri (nautilus_files_view_get_model (view)); + g_warning ("nautilus_canvas_view_remove_file() - directory not canvas view model, shouldn't happen.\n" + "file: %p:%s, dir: %p:%s, model: %p:%s, view loading: %d\n" + "If you see this, please add this info to http://bugzilla.gnome.org/show_bug.cgi?id=368178", + file, file_uri, directory, dir_uri, nautilus_files_view_get_model (view), model_uri, nautilus_files_view_get_loading (view)); + g_free (file_uri); + g_free (dir_uri); + g_free (model_uri); + } + + canvas_view = NAUTILUS_CANVAS_VIEW (view); + + if (nautilus_canvas_container_remove (get_canvas_container (canvas_view), + NAUTILUS_CANVAS_ICON_DATA (file))) + { + nautilus_file_unref (file); + } +} + +static void +nautilus_canvas_view_add_files (NautilusFilesView *view, + GList *files) +{ + NautilusCanvasView *canvas_view; + NautilusCanvasContainer *canvas_container; + GList *l; + + canvas_view = NAUTILUS_CANVAS_VIEW (view); + canvas_container = get_canvas_container (canvas_view); + + for (l = files; l != NULL; l = l->next) + { + if (nautilus_canvas_container_add (canvas_container, + NAUTILUS_CANVAS_ICON_DATA (l->data))) + { + nautilus_file_ref (NAUTILUS_FILE (l->data)); + } + } +} + +static void +nautilus_canvas_view_file_changed (NautilusFilesView *view, + NautilusFile *file, + NautilusDirectory *directory) +{ + NautilusCanvasView *canvas_view; + + g_assert (directory == nautilus_files_view_get_model (view)); + + g_return_if_fail (view != NULL); + canvas_view = NAUTILUS_CANVAS_VIEW (view); + + nautilus_canvas_container_request_update + (get_canvas_container (canvas_view), + NAUTILUS_CANVAS_ICON_DATA (file)); +} + +static const SortCriterion * +nautilus_canvas_view_get_directory_sort_by (NautilusCanvasView *canvas_view, + NautilusFile *file) +{ + const SortCriterion *default_sort; + g_autofree char *sort_by = NULL; + gboolean reversed; + + default_sort = get_default_sort_order (file); + g_return_val_if_fail (default_sort != NULL, NULL); + + sort_by = nautilus_file_get_metadata (file, + NAUTILUS_METADATA_KEY_ICON_VIEW_SORT_BY, + default_sort->metadata_text); + + reversed = nautilus_file_get_boolean_metadata (file, + NAUTILUS_METADATA_KEY_ICON_VIEW_SORT_REVERSED, + default_sort->reverse_order); + + return get_sort_criterion_by_metadata_text (sort_by, reversed); +} + +static const SortCriterion * +get_default_sort_order (NautilusFile *file) +{ + NautilusFileSortType sort_type; + gboolean reversed; + + sort_type = nautilus_file_get_default_sort_type (file, &reversed); + + return get_sort_criterion_by_sort_type (sort_type, reversed); +} + +static void +nautilus_canvas_view_set_directory_sort_by (NautilusCanvasView *canvas_view, + NautilusFile *file, + const SortCriterion *sort) +{ + const SortCriterion *default_sort_criterion; + + default_sort_criterion = get_default_sort_order (file); + g_return_if_fail (default_sort_criterion != NULL); + + nautilus_file_set_metadata + (file, NAUTILUS_METADATA_KEY_ICON_VIEW_SORT_BY, + default_sort_criterion->metadata_text, + sort->metadata_text); + nautilus_file_set_boolean_metadata (file, + NAUTILUS_METADATA_KEY_ICON_VIEW_SORT_REVERSED, + default_sort_criterion->reverse_order, + sort->reverse_order); +} + +static const SortCriterion * +get_sort_criterion_by_metadata_text (const char *metadata_text, + gboolean reversed) +{ + guint i; + + /* Figure out what the new sort setting should be. */ + for (i = 0; i < G_N_ELEMENTS (sort_criteria); i++) + { + if (g_strcmp0 (sort_criteria[i].metadata_text, metadata_text) == 0 + && reversed == sort_criteria[i].reverse_order) + { + return &sort_criteria[i]; + } + } + return &sort_criteria[0]; +} + +static const SortCriterion * +get_sort_criterion_by_action_target_name (const char *action_target_name) +{ + guint i; + /* Figure out what the new sort setting should be. */ + for (i = 0; i < G_N_ELEMENTS (sort_criteria); i++) + { + if (g_strcmp0 (sort_criteria[i].action_target_name, action_target_name) == 0) + { + return &sort_criteria[i]; + } + } + return NULL; +} + +static const SortCriterion * +get_sort_criterion_by_sort_type (NautilusFileSortType sort_type, + gboolean reversed) +{ + guint i; + + /* Figure out what the new sort setting should be. */ + for (i = 0; i < G_N_ELEMENTS (sort_criteria); i++) + { + if (sort_type == sort_criteria[i].sort_type + && reversed == sort_criteria[i].reverse_order) + { + return &sort_criteria[i]; + } + } + + return &sort_criteria[0]; +} + +static NautilusCanvasZoomLevel +get_default_zoom_level (NautilusCanvasView *canvas_view) +{ + NautilusCanvasZoomLevel default_zoom_level; + + default_zoom_level = g_settings_get_enum (nautilus_icon_view_preferences, + NAUTILUS_PREFERENCES_ICON_VIEW_DEFAULT_ZOOM_LEVEL); + + return CLAMP (default_zoom_level, NAUTILUS_CANVAS_ZOOM_LEVEL_SMALL, NAUTILUS_CANVAS_ZOOM_LEVEL_LARGER); +} + +static void +nautilus_canvas_view_begin_loading (NautilusFilesView *view) +{ + NautilusCanvasView *canvas_view; + NautilusFile *file; + char *uri; + const SortCriterion *sort; + + g_return_if_fail (NAUTILUS_IS_CANVAS_VIEW (view)); + + canvas_view = NAUTILUS_CANVAS_VIEW (view); + file = nautilus_files_view_get_directory_as_file (view); + uri = nautilus_file_get_uri (file); + + g_free (uri); + + /* Set the sort mode. + * It's OK not to resort the icons because the + * container doesn't have any icons at this point. + */ + sort = nautilus_canvas_view_get_directory_sort_by (canvas_view, file); + update_sort_criterion (canvas_view, sort, FALSE); + + /* We could have changed to the trash directory or to searching, and then + * we need to update the menus */ + nautilus_files_view_update_context_menus (view); + nautilus_files_view_update_toolbar_menus (view); +} + +static void +on_clipboard_contents_received (GtkClipboard *clipboard, + const gchar *selection_data, + gpointer user_data) +{ + NautilusCanvasView *canvas_view; + + canvas_view = NAUTILUS_CANVAS_VIEW (user_data); + + if (canvas_view->destroyed) + { + /* We've been destroyed since call */ + g_object_unref (canvas_view); + return; + } + + if (nautilus_clipboard_is_cut_from_selection_data (selection_data)) + { + GList *uris; + GList *files; + + uris = nautilus_clipboard_get_uri_list_from_selection_data (selection_data); + files = nautilus_file_list_from_uri_list (uris); + nautilus_canvas_container_set_highlighted_for_clipboard (get_canvas_container (canvas_view), + files); + + nautilus_file_list_free (files); + g_list_free_full (uris, g_free); + } + else + { + nautilus_canvas_container_set_highlighted_for_clipboard (get_canvas_container (canvas_view), + NULL); + } + + g_object_unref (canvas_view); +} + +static void +update_clipboard_status (NautilusCanvasView *view) +{ + g_object_ref (view); /* Need to keep the object alive until we get the reply */ + gtk_clipboard_request_text (nautilus_clipboard_get (GTK_WIDGET (view)), + on_clipboard_contents_received, + view); +} + +static void +on_clipboard_owner_changed (GtkClipboard *clipboard, + GdkEvent *event, + gpointer user_data) +{ + update_clipboard_status (NAUTILUS_CANVAS_VIEW (user_data)); +} + +static void +nautilus_canvas_view_end_loading (NautilusFilesView *view, + gboolean all_files_seen) +{ + NautilusCanvasView *canvas_view; + + canvas_view = NAUTILUS_CANVAS_VIEW (view); + update_clipboard_status (canvas_view); +} + +static NautilusCanvasZoomLevel +nautilus_canvas_view_get_zoom_level (NautilusFilesView *view) +{ + g_return_val_if_fail (NAUTILUS_IS_CANVAS_VIEW (view), NAUTILUS_CANVAS_ZOOM_LEVEL_LARGE); + + return nautilus_canvas_container_get_zoom_level (get_canvas_container (NAUTILUS_CANVAS_VIEW (view))); +} + +static void +nautilus_canvas_view_zoom_to_level (NautilusFilesView *view, + gint new_level) +{ + NautilusCanvasView *canvas_view; + NautilusCanvasContainer *canvas_container; + + g_return_if_fail (NAUTILUS_IS_CANVAS_VIEW (view)); + g_return_if_fail (new_level >= NAUTILUS_CANVAS_ZOOM_LEVEL_SMALL && + new_level <= NAUTILUS_CANVAS_ZOOM_LEVEL_LARGER); + + canvas_view = NAUTILUS_CANVAS_VIEW (view); + canvas_container = get_canvas_container (canvas_view); + if (nautilus_canvas_container_get_zoom_level (canvas_container) == new_level) + { + return; + } + + nautilus_canvas_container_set_zoom_level (canvas_container, new_level); + g_action_group_change_action_state (nautilus_files_view_get_action_group (view), + "zoom-to-level", g_variant_new_int32 (new_level)); + + nautilus_files_view_update_toolbar_menus (view); +} + +static void +nautilus_canvas_view_bump_zoom_level (NautilusFilesView *view, + int zoom_increment) +{ + NautilusCanvasZoomLevel new_level; + + g_return_if_fail (NAUTILUS_IS_CANVAS_VIEW (view)); + if (!nautilus_files_view_supports_zooming (view)) + { + return; + } + + new_level = nautilus_canvas_view_get_zoom_level (view) + zoom_increment; + + if (new_level >= NAUTILUS_CANVAS_ZOOM_LEVEL_SMALL && + new_level <= NAUTILUS_CANVAS_ZOOM_LEVEL_LARGER) + { + nautilus_canvas_view_zoom_to_level (view, new_level); + } +} + +static void +nautilus_canvas_view_restore_standard_zoom_level (NautilusFilesView *view) +{ + nautilus_canvas_view_zoom_to_level (view, NAUTILUS_CANVAS_ZOOM_LEVEL_LARGE); +} + +static gboolean +nautilus_canvas_view_can_zoom_in (NautilusFilesView *view) +{ + g_return_val_if_fail (NAUTILUS_IS_CANVAS_VIEW (view), FALSE); + + return nautilus_canvas_view_get_zoom_level (view) + < NAUTILUS_CANVAS_ZOOM_LEVEL_LARGER; +} + +static gboolean +nautilus_canvas_view_can_zoom_out (NautilusFilesView *view) +{ + g_return_val_if_fail (NAUTILUS_IS_CANVAS_VIEW (view), FALSE); + + return nautilus_canvas_view_get_zoom_level (view) + > NAUTILUS_CANVAS_ZOOM_LEVEL_SMALL; +} + +static gfloat +nautilus_canvas_view_get_zoom_level_percentage (NautilusFilesView *view) +{ + guint icon_size; + NautilusCanvasZoomLevel zoom_level; + + zoom_level = nautilus_canvas_view_get_zoom_level (view); + icon_size = nautilus_canvas_container_get_icon_size_for_zoom_level (zoom_level); + + return (gfloat) icon_size / NAUTILUS_CANVAS_ICON_SIZE_LARGE; +} + +static gboolean +nautilus_canvas_view_is_zoom_level_default (NautilusFilesView *view) +{ + guint icon_size; + NautilusCanvasZoomLevel zoom_level; + + zoom_level = nautilus_canvas_view_get_zoom_level (view); + icon_size = nautilus_canvas_container_get_icon_size_for_zoom_level (zoom_level); + + return icon_size == NAUTILUS_CANVAS_ICON_SIZE_LARGE; +} + +static gboolean +nautilus_canvas_view_is_empty (NautilusFilesView *view) +{ + g_assert (NAUTILUS_IS_CANVAS_VIEW (view)); + + return nautilus_canvas_container_is_empty + (get_canvas_container (NAUTILUS_CANVAS_VIEW (view))); +} + +static GList * +nautilus_canvas_view_get_selection (NautilusFilesView *view) +{ + GList *list; + + g_return_val_if_fail (NAUTILUS_IS_CANVAS_VIEW (view), NULL); + + list = nautilus_canvas_container_get_selection + (get_canvas_container (NAUTILUS_CANVAS_VIEW (view))); + nautilus_file_list_ref (list); + return list; +} + +static void +action_sort_order_changed (GSimpleAction *action, + GVariant *value, + gpointer user_data) +{ + const gchar *target_name; + const SortCriterion *sort_criterion; + + g_assert (NAUTILUS_IS_CANVAS_VIEW (user_data)); + + target_name = g_variant_get_string (value, NULL); + sort_criterion = get_sort_criterion_by_action_target_name (target_name); + + g_assert (sort_criterion != NULL); + + update_sort_criterion (user_data, sort_criterion, TRUE); + + nautilus_canvas_container_sort (get_canvas_container (user_data)); + nautilus_canvas_view_reveal_selection (NAUTILUS_FILES_VIEW (user_data)); + + g_simple_action_set_state (action, value); +} + +static void +action_zoom_to_level (GSimpleAction *action, + GVariant *state, + gpointer user_data) +{ + NautilusFilesView *view; + NautilusCanvasZoomLevel zoom_level; + + g_assert (NAUTILUS_IS_FILES_VIEW (user_data)); + + view = NAUTILUS_FILES_VIEW (user_data); + zoom_level = g_variant_get_int32 (state); + nautilus_canvas_view_zoom_to_level (view, zoom_level); + + g_simple_action_set_state (G_SIMPLE_ACTION (action), state); + if (g_settings_get_enum (nautilus_icon_view_preferences, + NAUTILUS_PREFERENCES_ICON_VIEW_DEFAULT_ZOOM_LEVEL) != zoom_level) + { + g_settings_set_enum (nautilus_icon_view_preferences, + NAUTILUS_PREFERENCES_ICON_VIEW_DEFAULT_ZOOM_LEVEL, + zoom_level); + } +} + +const GActionEntry canvas_view_entries[] = +{ + { "sort", NULL, "s", "'name'", action_sort_order_changed }, + { "zoom-to-level", NULL, NULL, "1", action_zoom_to_level } +}; + +static void +update_sort_action_state_hint (NautilusCanvasView *canvas_view) +{ + NautilusFile *file; + GVariantBuilder builder; + GActionGroup *action_group; + GAction *action; + GVariant *state_hint; + gint idx; + + file = nautilus_files_view_get_directory_as_file (NAUTILUS_FILES_VIEW (canvas_view)); + g_variant_builder_init (&builder, G_VARIANT_TYPE ("as")); + + for (idx = 0; idx < G_N_ELEMENTS (sort_criteria); idx++) + { + if (sort_criteria[idx].match_func == NULL || + (file != NULL && sort_criteria[idx].match_func (file))) + { + g_variant_builder_add (&builder, "s", sort_criteria[idx].action_target_name); + } + } + + state_hint = g_variant_builder_end (&builder); + + action_group = nautilus_files_view_get_action_group (NAUTILUS_FILES_VIEW (canvas_view)); + action = g_action_map_lookup_action (G_ACTION_MAP (action_group), "sort"); + g_simple_action_set_state_hint (G_SIMPLE_ACTION (action), state_hint); + + g_variant_unref (state_hint); +} + +static gboolean +showing_recent_directory (NautilusFilesView *view) +{ + NautilusFile *file; + + file = nautilus_files_view_get_directory_as_file (view); + if (file != NULL) + { + return nautilus_file_is_in_recent (file); + } + return FALSE; +} + +static gboolean +showing_search_directory (NautilusFilesView *view) +{ + NautilusFile *file; + + file = nautilus_files_view_get_directory_as_file (view); + if (file != NULL) + { + return nautilus_file_is_in_search (file); + } + return FALSE; +} + +static void +nautilus_canvas_view_update_actions_state (NautilusFilesView *view) +{ + GActionGroup *view_action_group; + GVariant *sort_state; + GAction *action; + NautilusCanvasView *canvas_view; + + canvas_view = NAUTILUS_CANVAS_VIEW (view); + + NAUTILUS_FILES_VIEW_CLASS (nautilus_canvas_view_parent_class)->update_actions_state (view); + + view_action_group = nautilus_files_view_get_action_group (view); + + /* When we change the sort action state, even using the same value, it triggers + * the sort action changed handler, which reveals the selection, since we expect + * the selection to be visible when the user changes the sort order. But we may + * need to update the actions state for others reason than an actual sort change, + * so we need to prevent to trigger the sort action changed handler for those cases. + * To achieve this, check if the action state value actually changed before setting + * it + */ + sort_state = g_action_group_get_action_state (view_action_group, "sort"); + + if (g_strcmp0 (g_variant_get_string (sort_state, NULL), + canvas_view->sort->action_target_name) != 0) + { + g_action_group_change_action_state (view_action_group, + "sort", + g_variant_new_string (canvas_view->sort->action_target_name)); + } + + action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), "sort"); + g_simple_action_set_enabled (G_SIMPLE_ACTION (action), + !showing_recent_directory (view) && + !showing_search_directory (view)); + + update_sort_action_state_hint (canvas_view); + + g_variant_unref (sort_state); +} + +static void +nautilus_canvas_view_select_all (NautilusFilesView *view) +{ + NautilusCanvasContainer *canvas_container; + + g_return_if_fail (NAUTILUS_IS_CANVAS_VIEW (view)); + + canvas_container = get_canvas_container (NAUTILUS_CANVAS_VIEW (view)); + nautilus_canvas_container_select_all (canvas_container); +} + +static void +nautilus_canvas_view_select_first (NautilusFilesView *view) +{ + NautilusCanvasContainer *canvas_container; + + g_return_if_fail (NAUTILUS_IS_CANVAS_VIEW (view)); + + canvas_container = get_canvas_container (NAUTILUS_CANVAS_VIEW (view)); + nautilus_canvas_container_select_first (canvas_container); +} + +static void +nautilus_canvas_view_reveal_selection (NautilusFilesView *view) +{ + g_autolist (NautilusFile) selection = NULL; + + g_return_if_fail (NAUTILUS_IS_CANVAS_VIEW (view)); + + selection = nautilus_view_get_selection (NAUTILUS_VIEW (view)); + + /* Make sure at least one of the selected items is scrolled into view */ + if (selection != NULL) + { + /* Update the icon ordering to reveal the rigth selection */ + nautilus_canvas_container_layout_now (get_canvas_container (NAUTILUS_CANVAS_VIEW (view))); + nautilus_canvas_container_reveal + (get_canvas_container (NAUTILUS_CANVAS_VIEW (view)), + selection->data); + } +} + +static GdkRectangle * +get_rectangle_for_data (NautilusFilesView *view, + NautilusCanvasIconData *data) +{ + NautilusCanvasContainer *container; + GdkRectangle *rectangle; + + container = get_canvas_container (NAUTILUS_CANVAS_VIEW (view)); + rectangle = nautilus_canvas_container_get_icon_bounding_box (container, data); + if (rectangle != NULL) + { + GtkWidget *context_widget; + GtkAdjustment *vadjustment; + GtkAdjustment *hadjustment; + + context_widget = nautilus_files_view_get_content_widget (view); + vadjustment = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (context_widget)); + hadjustment = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (context_widget)); + + rectangle->x -= gtk_adjustment_get_value (hadjustment); + rectangle->y -= gtk_adjustment_get_value (vadjustment); + } + return rectangle; +} + +static GdkRectangle * +nautilus_canvas_view_compute_rename_popover_pointing_to (NautilusFilesView *view) +{ + g_autolist (NautilusFile) selection = NULL; + NautilusCanvasIconData *data; + + g_return_val_if_fail (NAUTILUS_IS_CANVAS_VIEW (view), NULL); + + selection = nautilus_view_get_selection (NAUTILUS_VIEW (view)); + g_return_val_if_fail (selection != NULL, NULL); + + /* We only allow renaming one item at once */ + data = NAUTILUS_CANVAS_ICON_DATA (selection->data); + + return get_rectangle_for_data (view, data); +} + +static GdkRectangle * +nautilus_canvas_view_reveal_for_selection_context_menu (NautilusFilesView *view) +{ + g_autolist (NautilusFile) selection = NULL; + NautilusCanvasContainer *container; + NautilusCanvasIconData *data; + + g_return_val_if_fail (NAUTILUS_IS_CANVAS_VIEW (view), NULL); + + selection = nautilus_view_get_selection (NAUTILUS_VIEW (view)); + g_return_val_if_fail (selection != NULL, NULL); + + container = get_canvas_container (NAUTILUS_CANVAS_VIEW (view)); + + /* Update the icon ordering to reveal the rigth selection */ + nautilus_canvas_container_layout_now (container); + + /* Get the data of the focused item, if selected. Otherwise, get the + * data of the last selected item.*/ + data = nautilus_canvas_container_get_focused_icon (container); + if (data == NULL || g_list_find (selection, NAUTILUS_FILE (data)) == NULL) + { + selection = g_list_last (selection); + data = NAUTILUS_CANVAS_ICON_DATA (selection->data); + } + + nautilus_canvas_container_reveal (container, data); + + return get_rectangle_for_data (view, data); +} + +static void +nautilus_canvas_view_set_selection (NautilusFilesView *view, + GList *selection) +{ + g_return_if_fail (NAUTILUS_IS_CANVAS_VIEW (view)); + + nautilus_canvas_container_set_selection + (get_canvas_container (NAUTILUS_CANVAS_VIEW (view)), selection); +} + +static void +nautilus_canvas_view_invert_selection (NautilusFilesView *view) +{ + g_return_if_fail (NAUTILUS_IS_CANVAS_VIEW (view)); + + nautilus_canvas_container_invert_selection + (get_canvas_container (NAUTILUS_CANVAS_VIEW (view))); +} + +static void +nautilus_canvas_view_widget_to_file_operation_position (NautilusFilesView *view, + GdkPoint *position) +{ + g_assert (NAUTILUS_IS_CANVAS_VIEW (view)); + + nautilus_canvas_container_widget_to_file_operation_position + (get_canvas_container (NAUTILUS_CANVAS_VIEW (view)), position); +} + +static void +canvas_container_activate_callback (NautilusCanvasContainer *container, + GList *file_list, + NautilusCanvasView *canvas_view) +{ + g_assert (NAUTILUS_IS_CANVAS_VIEW (canvas_view)); + g_assert (container == get_canvas_container (canvas_view)); + + nautilus_files_view_activate_files (NAUTILUS_FILES_VIEW (canvas_view), + file_list, + 0, TRUE); +} + +static void +canvas_container_activate_previewer_callback (NautilusCanvasContainer *container, + GList *file_list, + GArray *locations, + NautilusCanvasView *canvas_view) +{ + g_assert (NAUTILUS_IS_CANVAS_VIEW (canvas_view)); + g_assert (container == get_canvas_container (canvas_view)); + + nautilus_files_view_preview_files (NAUTILUS_FILES_VIEW (canvas_view), + file_list, locations); +} + +/* this is called in one of these cases: + * - we activate with enter holding shift + * - we activate with space holding shift + * - we double click an canvas holding shift + * - we middle click an canvas + * + * If we don't open in new windows by default, the behavior should be + * - middle click, shift + activate -> open in new tab + * - shift + double click -> open in new window + * + * If we open in new windows by default, the behaviour should be + * - middle click, or shift + activate, or shift + double-click -> close parent + */ +static void +canvas_container_activate_alternate_callback (NautilusCanvasContainer *container, + GList *file_list, + NautilusCanvasView *canvas_view) +{ + GdkEvent *event; + GdkEventButton *button_event; + GdkEventKey *key_event; + gboolean open_in_tab, open_in_window; + NautilusWindowOpenFlags flags; + + g_assert (NAUTILUS_IS_CANVAS_VIEW (canvas_view)); + g_assert (container == get_canvas_container (canvas_view)); + + flags = 0; + event = gtk_get_current_event (); + open_in_tab = FALSE; + open_in_window = FALSE; + + if (event->type == GDK_BUTTON_PRESS || + event->type == GDK_BUTTON_RELEASE || + event->type == GDK_2BUTTON_PRESS || + event->type == GDK_3BUTTON_PRESS) + { + button_event = (GdkEventButton *) event; + open_in_window = ((button_event->state & GDK_SHIFT_MASK) != 0); + open_in_tab = !open_in_window; + } + else if (event->type == GDK_KEY_PRESS || + event->type == GDK_KEY_RELEASE) + { + key_event = (GdkEventKey *) event; + open_in_tab = ((key_event->state & GDK_SHIFT_MASK) != 0); + } + + if (open_in_tab) + { + flags |= NAUTILUS_WINDOW_OPEN_FLAG_NEW_TAB; + flags |= NAUTILUS_WINDOW_OPEN_FLAG_DONT_MAKE_ACTIVE; + } + + if (open_in_window) + { + flags |= NAUTILUS_WINDOW_OPEN_FLAG_NEW_WINDOW; + } + + DEBUG ("Activate alternate, open in tab %d, new window %d\n", + open_in_tab, open_in_window); + + nautilus_files_view_activate_files (NAUTILUS_FILES_VIEW (canvas_view), + file_list, + flags, + TRUE); +} + +static void +band_select_started_callback (NautilusCanvasContainer *container, + NautilusCanvasView *canvas_view) +{ + g_assert (NAUTILUS_IS_CANVAS_VIEW (canvas_view)); + g_assert (container == get_canvas_container (canvas_view)); + + nautilus_files_view_start_batching_selection_changes (NAUTILUS_FILES_VIEW (canvas_view)); +} + +static void +band_select_ended_callback (NautilusCanvasContainer *container, + NautilusCanvasView *canvas_view) +{ + g_assert (NAUTILUS_IS_CANVAS_VIEW (canvas_view)); + g_assert (container == get_canvas_container (canvas_view)); + + nautilus_files_view_stop_batching_selection_changes (NAUTILUS_FILES_VIEW (canvas_view)); +} + +int +nautilus_canvas_view_compare_files (NautilusCanvasView *canvas_view, + NautilusFile *a, + NautilusFile *b) +{ + return nautilus_file_compare_for_sort + (a, b, canvas_view->sort->sort_type, + /* Use type-unsafe cast for performance */ + nautilus_files_view_should_sort_directories_first ((NautilusFilesView *) canvas_view), + canvas_view->sort->reverse_order); +} + +static int +compare_files (NautilusFilesView *canvas_view, + NautilusFile *a, + NautilusFile *b) +{ + return nautilus_canvas_view_compare_files ((NautilusCanvasView *) canvas_view, a, b); +} + +static void +selection_changed_callback (NautilusCanvasContainer *container, + NautilusCanvasView *canvas_view) +{ + g_assert (NAUTILUS_IS_CANVAS_VIEW (canvas_view)); + g_assert (container == get_canvas_container (canvas_view)); + + nautilus_files_view_notify_selection_changed (NAUTILUS_FILES_VIEW (canvas_view)); +} + +static void +canvas_container_context_click_selection_callback (NautilusCanvasContainer *container, + const GdkEvent *event, + NautilusCanvasView *canvas_view) +{ + g_assert (NAUTILUS_IS_CANVAS_CONTAINER (container)); + g_assert (NAUTILUS_IS_CANVAS_VIEW (canvas_view)); + + nautilus_files_view_pop_up_selection_context_menu (NAUTILUS_FILES_VIEW (canvas_view), + event); +} + +static void +canvas_container_context_click_background_callback (NautilusCanvasContainer *container, + const GdkEvent *event, + NautilusCanvasView *canvas_view) +{ + g_assert (NAUTILUS_IS_CANVAS_CONTAINER (container)); + g_assert (NAUTILUS_IS_CANVAS_VIEW (canvas_view)); + + nautilus_files_view_pop_up_background_context_menu (NAUTILUS_FILES_VIEW (canvas_view), + event); +} + +static char * +get_icon_uri_callback (NautilusCanvasContainer *container, + NautilusFile *file, + NautilusCanvasView *canvas_view) +{ + g_assert (NAUTILUS_IS_CANVAS_CONTAINER (container)); + g_assert (NAUTILUS_IS_FILE (file)); + g_assert (NAUTILUS_IS_CANVAS_VIEW (canvas_view)); + + return nautilus_file_get_uri (file); +} + +static char * +get_icon_activation_uri_callback (NautilusCanvasContainer *container, + NautilusFile *file, + NautilusCanvasView *canvas_view) +{ + g_assert (NAUTILUS_IS_CANVAS_CONTAINER (container)); + g_assert (NAUTILUS_IS_FILE (file)); + g_assert (NAUTILUS_IS_CANVAS_VIEW (canvas_view)); + + return nautilus_file_get_activation_uri (file); +} + +static char * +get_icon_drop_target_uri_callback (NautilusCanvasContainer *container, + NautilusFile *file, + NautilusCanvasView *canvas_view) +{ + g_return_val_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container), NULL); + g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL); + g_return_val_if_fail (NAUTILUS_IS_CANVAS_VIEW (canvas_view), NULL); + + return nautilus_file_get_uri (file); +} + +/* Preferences changed callbacks */ +static void +nautilus_canvas_view_click_policy_changed (NautilusFilesView *directory_view) +{ + g_assert (NAUTILUS_IS_CANVAS_VIEW (directory_view)); + + nautilus_canvas_view_update_click_mode (NAUTILUS_CANVAS_VIEW (directory_view)); +} + +static void +image_display_policy_changed_callback (gpointer callback_data) +{ + NautilusCanvasView *canvas_view; + + canvas_view = NAUTILUS_CANVAS_VIEW (callback_data); + + nautilus_canvas_container_request_update_all (get_canvas_container (canvas_view)); +} + +static void +text_attribute_names_changed_callback (gpointer callback_data) +{ + NautilusCanvasView *canvas_view; + + canvas_view = NAUTILUS_CANVAS_VIEW (callback_data); + + nautilus_canvas_container_request_update_all (get_canvas_container (canvas_view)); +} + +static void +default_sort_order_changed_callback (gpointer callback_data) +{ + NautilusCanvasView *canvas_view; + NautilusFile *file; + const SortCriterion *sort; + NautilusCanvasContainer *canvas_container; + + g_return_if_fail (NAUTILUS_IS_CANVAS_VIEW (callback_data)); + + canvas_view = NAUTILUS_CANVAS_VIEW (callback_data); + + file = nautilus_files_view_get_directory_as_file (NAUTILUS_FILES_VIEW (canvas_view)); + sort = nautilus_canvas_view_get_directory_sort_by (canvas_view, file); + update_sort_criterion (canvas_view, sort, FALSE); + + canvas_container = get_canvas_container (canvas_view); + g_return_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (canvas_container)); + + nautilus_canvas_container_request_update_all (canvas_container); +} + +static void +nautilus_canvas_view_sort_directories_first_changed (NautilusFilesView *directory_view) +{ + NautilusCanvasView *canvas_view; + + canvas_view = NAUTILUS_CANVAS_VIEW (directory_view); + + nautilus_canvas_container_sort (get_canvas_container (canvas_view)); +} + +static void +nautilus_canvas_view_preview_selection_event (NautilusFilesView *directory_view, + GtkDirectionType direction) +{ + NautilusCanvasView *canvas_view; + + canvas_view = NAUTILUS_CANVAS_VIEW (directory_view); + + nautilus_canvas_container_preview_selection_event (get_canvas_container (canvas_view), + direction); +} + +static char * +canvas_view_get_container_uri (NautilusCanvasContainer *container, + NautilusFilesView *view) +{ + return nautilus_files_view_get_uri (view); +} + +static void +canvas_view_move_copy_items (NautilusCanvasContainer *container, + const GList *item_uris, + const char *target_dir, + int copy_action, + NautilusFilesView *view) +{ + nautilus_clipboard_clear_if_colliding_uris (GTK_WIDGET (view), + item_uris); + nautilus_files_view_move_copy_items (view, item_uris, target_dir, + copy_action); +} + +static void +nautilus_canvas_view_update_click_mode (NautilusCanvasView *canvas_view) +{ + NautilusCanvasContainer *canvas_container; + int click_mode; + + canvas_container = get_canvas_container (canvas_view); + g_assert (canvas_container != NULL); + + click_mode = g_settings_get_enum (nautilus_preferences, NAUTILUS_PREFERENCES_CLICK_POLICY); + + nautilus_canvas_container_set_single_click_mode (canvas_container, + click_mode == NAUTILUS_CLICK_POLICY_SINGLE); +} + +static void +canvas_container_longpress_gesture_pressed_callback (GtkGestureLongPress *gesture, + gdouble x, + gdouble y, + gpointer user_data) +{ + GdkEventSequence *event_sequence; + const GdkEvent *event; + NautilusCanvasView *view = NAUTILUS_CANVAS_VIEW (user_data); + + event_sequence = gtk_gesture_get_last_updated_sequence (GTK_GESTURE (gesture)); + event = gtk_gesture_get_last_event (GTK_GESTURE (gesture), event_sequence); + + if (nautilus_view_get_selection (NAUTILUS_VIEW (view))) + { + nautilus_files_view_pop_up_selection_context_menu (NAUTILUS_FILES_VIEW (view), + event); + } + else + { + nautilus_files_view_pop_up_background_context_menu (NAUTILUS_FILES_VIEW (view), + event); + } +} + +static void +initialize_canvas_container (NautilusCanvasView *canvas_view, + NautilusCanvasContainer *canvas_container) +{ + GtkWidget *content_widget; + GtkGesture *longpress_gesture; + + content_widget = nautilus_files_view_get_content_widget (NAUTILUS_FILES_VIEW (canvas_view)); + canvas_view->canvas_container = GTK_WIDGET (canvas_container); + g_object_add_weak_pointer (G_OBJECT (canvas_container), + (gpointer *) &canvas_view->canvas_container); + + longpress_gesture = gtk_gesture_long_press_new (GTK_WIDGET (content_widget)); + gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (longpress_gesture), + GTK_PHASE_CAPTURE); + gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (longpress_gesture), + TRUE); + g_signal_connect (longpress_gesture, "pressed", + (GCallback) canvas_container_longpress_gesture_pressed_callback, + canvas_view); + + gtk_widget_set_can_focus (GTK_WIDGET (canvas_container), TRUE); + + g_signal_connect_object (canvas_container, "activate", + G_CALLBACK (canvas_container_activate_callback), canvas_view, 0); + g_signal_connect_object (canvas_container, "activate-alternate", + G_CALLBACK (canvas_container_activate_alternate_callback), canvas_view, 0); + g_signal_connect_object (canvas_container, "activate-previewer", + G_CALLBACK (canvas_container_activate_previewer_callback), canvas_view, 0); + g_signal_connect_object (canvas_container, "band-select-started", + G_CALLBACK (band_select_started_callback), canvas_view, 0); + g_signal_connect_object (canvas_container, "band-select-ended", + G_CALLBACK (band_select_ended_callback), canvas_view, 0); + g_signal_connect_object (canvas_container, "context-click-selection", + G_CALLBACK (canvas_container_context_click_selection_callback), canvas_view, 0); + g_signal_connect_object (canvas_container, "context-click-background", + G_CALLBACK (canvas_container_context_click_background_callback), canvas_view, 0); + g_signal_connect_object (canvas_container, "selection-changed", + G_CALLBACK (selection_changed_callback), canvas_view, 0); + /* FIXME: many of these should move into fm-canvas-container as virtual methods */ + g_signal_connect_object (canvas_container, "get-icon-uri", + G_CALLBACK (get_icon_uri_callback), canvas_view, 0); + g_signal_connect_object (canvas_container, "get-icon-activation-uri", + G_CALLBACK (get_icon_activation_uri_callback), canvas_view, 0); + g_signal_connect_object (canvas_container, "get-icon-drop-target-uri", + G_CALLBACK (get_icon_drop_target_uri_callback), canvas_view, 0); + g_signal_connect_object (canvas_container, "move-copy-items", + G_CALLBACK (canvas_view_move_copy_items), canvas_view, 0); + g_signal_connect_object (canvas_container, "get-container-uri", + G_CALLBACK (canvas_view_get_container_uri), canvas_view, 0); + + gtk_container_add (GTK_CONTAINER (content_widget), + GTK_WIDGET (canvas_container)); + + nautilus_canvas_view_update_click_mode (canvas_view); + nautilus_canvas_container_set_zoom_level (canvas_container, + get_default_zoom_level (canvas_view)); + + gtk_widget_show (GTK_WIDGET (canvas_container)); +} + +static void +canvas_view_handle_uri_list (NautilusCanvasContainer *container, + const char *item_uris, + const char *target_uri, + GdkDragAction action, + NautilusCanvasView *view) +{ + nautilus_files_view_handle_uri_list_drop (NAUTILUS_FILES_VIEW (view), + item_uris, target_uri, action); +} + +/* Handles an URL received from Mozilla */ +static void +canvas_view_handle_netscape_url (NautilusCanvasContainer *container, + const char *encoded_url, + const char *target_uri, + GdkDragAction action, + NautilusCanvasView *view) +{ + nautilus_files_view_handle_netscape_url_drop (NAUTILUS_FILES_VIEW (view), + encoded_url, target_uri, action); +} + +static void +canvas_view_handle_text (NautilusCanvasContainer *container, + const char *text, + const char *target_uri, + GdkDragAction action, + NautilusCanvasView *view) +{ + nautilus_files_view_handle_text_drop (NAUTILUS_FILES_VIEW (view), + text, target_uri, action); +} + +static void +canvas_view_handle_raw (NautilusCanvasContainer *container, + const char *raw_data, + int length, + const char *target_uri, + const char *direct_save_uri, + GdkDragAction action, + NautilusCanvasView *view) +{ + nautilus_files_view_handle_raw_drop (NAUTILUS_FILES_VIEW (view), + raw_data, length, target_uri, direct_save_uri, action); +} + +static void +canvas_view_handle_hover (NautilusCanvasContainer *container, + const char *target_uri, + NautilusCanvasView *view) +{ + nautilus_files_view_handle_hover (NAUTILUS_FILES_VIEW (view), target_uri); +} + +static char * +canvas_view_get_first_visible_file (NautilusFilesView *view) +{ + NautilusFile *file; + NautilusCanvasView *canvas_view; + + canvas_view = NAUTILUS_CANVAS_VIEW (view); + + file = NAUTILUS_FILE (nautilus_canvas_container_get_first_visible_icon (get_canvas_container (canvas_view))); + + if (file) + { + return nautilus_file_get_uri (file); + } + + return NULL; +} + +static void +canvas_view_scroll_to_file (NautilusFilesView *view, + const char *uri) +{ + NautilusFile *file; + NautilusCanvasView *canvas_view; + + canvas_view = NAUTILUS_CANVAS_VIEW (view); + + if (uri != NULL) + { + /* Only if existing, since we don't want to add the file to + * the directory if it has been removed since then */ + file = nautilus_file_get_existing_by_uri (uri); + if (file != NULL) + { + nautilus_canvas_container_scroll_to_canvas (get_canvas_container (canvas_view), + NAUTILUS_CANVAS_ICON_DATA (file)); + nautilus_file_unref (file); + } + } +} + +static guint +nautilus_canvas_view_get_id (NautilusFilesView *view) +{ + return NAUTILUS_VIEW_GRID_ID; +} + +static void +nautilus_canvas_view_dispose (GObject *object) +{ + NautilusCanvasView *canvas_view; + + canvas_view = NAUTILUS_CANVAS_VIEW (object); + canvas_view->destroyed = TRUE; + + g_signal_handlers_disconnect_by_func (nautilus_preferences, + default_sort_order_changed_callback, + canvas_view); + g_signal_handlers_disconnect_by_func (nautilus_preferences, + image_display_policy_changed_callback, + canvas_view); + + g_signal_handlers_disconnect_by_func (nautilus_icon_view_preferences, + text_attribute_names_changed_callback, + canvas_view); + + + G_OBJECT_CLASS (nautilus_canvas_view_parent_class)->dispose (object); +} + +static void +nautilus_canvas_view_class_init (NautilusCanvasViewClass *klass) +{ + NautilusFilesViewClass *nautilus_files_view_class; + GObjectClass *oclass; + + nautilus_files_view_class = NAUTILUS_FILES_VIEW_CLASS (klass); + oclass = G_OBJECT_CLASS (klass); + + oclass->dispose = nautilus_canvas_view_dispose; + + GTK_WIDGET_CLASS (klass)->destroy = nautilus_canvas_view_destroy; + + nautilus_files_view_class->add_files = nautilus_canvas_view_add_files; + nautilus_files_view_class->begin_loading = nautilus_canvas_view_begin_loading; + nautilus_files_view_class->bump_zoom_level = nautilus_canvas_view_bump_zoom_level; + nautilus_files_view_class->can_zoom_in = nautilus_canvas_view_can_zoom_in; + nautilus_files_view_class->can_zoom_out = nautilus_canvas_view_can_zoom_out; + nautilus_files_view_class->get_zoom_level_percentage = nautilus_canvas_view_get_zoom_level_percentage; + nautilus_files_view_class->is_zoom_level_default = nautilus_canvas_view_is_zoom_level_default; + nautilus_files_view_class->clear = nautilus_canvas_view_clear; + nautilus_files_view_class->end_loading = nautilus_canvas_view_end_loading; + nautilus_files_view_class->file_changed = nautilus_canvas_view_file_changed; + nautilus_files_view_class->compute_rename_popover_pointing_to = nautilus_canvas_view_compute_rename_popover_pointing_to; + nautilus_files_view_class->get_selection = nautilus_canvas_view_get_selection; + nautilus_files_view_class->get_selection_for_file_transfer = nautilus_canvas_view_get_selection; + nautilus_files_view_class->is_empty = nautilus_canvas_view_is_empty; + nautilus_files_view_class->remove_file = nautilus_canvas_view_remove_file; + nautilus_files_view_class->restore_standard_zoom_level = nautilus_canvas_view_restore_standard_zoom_level; + nautilus_files_view_class->reveal_selection = nautilus_canvas_view_reveal_selection; + nautilus_files_view_class->select_all = nautilus_canvas_view_select_all; + nautilus_files_view_class->select_first = nautilus_canvas_view_select_first; + nautilus_files_view_class->set_selection = nautilus_canvas_view_set_selection; + nautilus_files_view_class->invert_selection = nautilus_canvas_view_invert_selection; + nautilus_files_view_class->compare_files = compare_files; + nautilus_files_view_class->click_policy_changed = nautilus_canvas_view_click_policy_changed; + nautilus_files_view_class->update_actions_state = nautilus_canvas_view_update_actions_state; + nautilus_files_view_class->sort_directories_first_changed = nautilus_canvas_view_sort_directories_first_changed; + nautilus_files_view_class->widget_to_file_operation_position = nautilus_canvas_view_widget_to_file_operation_position; + nautilus_files_view_class->get_view_id = nautilus_canvas_view_get_id; + nautilus_files_view_class->get_first_visible_file = canvas_view_get_first_visible_file; + nautilus_files_view_class->scroll_to_file = canvas_view_scroll_to_file; + nautilus_files_view_class->reveal_for_selection_context_menu = nautilus_canvas_view_reveal_for_selection_context_menu; + nautilus_files_view_class->preview_selection_event = nautilus_canvas_view_preview_selection_event; +} + +static void +nautilus_canvas_view_init (NautilusCanvasView *canvas_view) +{ + NautilusCanvasContainer *canvas_container; + GActionGroup *view_action_group; + GtkClipboard *clipboard; + + canvas_view->sort = &sort_criteria[0]; + canvas_view->destroyed = FALSE; + + canvas_container = nautilus_canvas_view_container_new (canvas_view); + initialize_canvas_container (canvas_view, canvas_container); + + g_signal_connect_swapped (nautilus_preferences, + "changed::" NAUTILUS_PREFERENCES_DEFAULT_SORT_ORDER, + G_CALLBACK (default_sort_order_changed_callback), + canvas_view); + g_signal_connect_swapped (nautilus_preferences, + "changed::" NAUTILUS_PREFERENCES_DEFAULT_SORT_IN_REVERSE_ORDER, + G_CALLBACK (default_sort_order_changed_callback), + canvas_view); + g_signal_connect_swapped (nautilus_preferences, + "changed::" NAUTILUS_PREFERENCES_SHOW_FILE_THUMBNAILS, + G_CALLBACK (image_display_policy_changed_callback), + canvas_view); + + g_signal_connect_swapped (nautilus_icon_view_preferences, + "changed::" NAUTILUS_PREFERENCES_ICON_VIEW_CAPTIONS, + G_CALLBACK (text_attribute_names_changed_callback), + canvas_view); + + g_signal_connect_object (canvas_container, "handle-uri-list", + G_CALLBACK (canvas_view_handle_uri_list), canvas_view, 0); + g_signal_connect_object (canvas_container, "handle-netscape-url", + G_CALLBACK (canvas_view_handle_netscape_url), canvas_view, 0); + g_signal_connect_object (canvas_container, "handle-text", + G_CALLBACK (canvas_view_handle_text), canvas_view, 0); + g_signal_connect_object (canvas_container, "handle-raw", + G_CALLBACK (canvas_view_handle_raw), canvas_view, 0); + g_signal_connect_object (canvas_container, "handle-hover", + G_CALLBACK (canvas_view_handle_hover), canvas_view, 0); + + /* React to clipboard changes */ + clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); + g_signal_connect (clipboard, "owner-change", + G_CALLBACK (on_clipboard_owner_changed), canvas_view); + + view_action_group = nautilus_files_view_get_action_group (NAUTILUS_FILES_VIEW (canvas_view)); + g_action_map_add_action_entries (G_ACTION_MAP (view_action_group), + canvas_view_entries, + G_N_ELEMENTS (canvas_view_entries), + canvas_view); + /* Keep the action synced with the actual value, so the toolbar can poll it */ + g_action_group_change_action_state (nautilus_files_view_get_action_group (NAUTILUS_FILES_VIEW (canvas_view)), + "zoom-to-level", g_variant_new_int32 (get_default_zoom_level (canvas_view))); +} + +NautilusFilesView * +nautilus_canvas_view_new (NautilusWindowSlot *slot) +{ + return g_object_new (NAUTILUS_TYPE_CANVAS_VIEW, + "window-slot", slot, + NULL); +} |