diff options
Diffstat (limited to 'src/file-manager/fm-icon-view.c')
-rw-r--r-- | src/file-manager/fm-icon-view.c | 3439 |
1 files changed, 3439 insertions, 0 deletions
diff --git a/src/file-manager/fm-icon-view.c b/src/file-manager/fm-icon-view.c new file mode 100644 index 00000000..7d8687a2 --- /dev/null +++ b/src/file-manager/fm-icon-view.c @@ -0,0 +1,3439 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* fm-icon-view.c - implementation of icon view of directory. + + Copyright (C) 2000, 2001 Eazel, Inc. + + The Mate 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 Mate 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 Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: John Sullivan <[email protected]> +*/ + +#include <config.h> +#include "fm-icon-view.h" + +#include "fm-actions.h" +#include "fm-icon-container.h" +#include "fm-desktop-icon-view.h" +#include "fm-error-reporting.h" +#include <stdlib.h> +#include <eel/eel-background.h> +#include <eel/eel-glib-extensions.h> +#include <eel/eel-gtk-extensions.h> +#include <eel/eel-gtk-macros.h> +#include <eel/eel-stock-dialogs.h> +#include <eel/eel-string.h> +#include <eel/eel-vfs-extensions.h> +#include <errno.h> +#include <fcntl.h> +#include <gtk/gtk.h> +#include <glib/gi18n.h> +#include <gio/gio.h> +#include <libcaja-private/caja-clipboard-monitor.h> +#include <libcaja-private/caja-directory-background.h> +#include <libcaja-private/caja-directory.h> +#include <libcaja-private/caja-dnd.h> +#include <libcaja-private/caja-file-utilities.h> +#include <libcaja-private/caja-ui-utilities.h> +#include <libcaja-private/caja-global-preferences.h> +#include <libcaja-private/caja-icon-container.h> +#include <libcaja-private/caja-icon-dnd.h> +#include <libcaja-private/caja-link.h> +#include <libcaja-private/caja-metadata.h> +#include <libcaja-private/caja-view-factory.h> +#include <libcaja-private/caja-clipboard.h> +#include <libcaja-private/caja-desktop-icon-file.h> +#include <locale.h> +#include <signal.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> + +#include "caja-audio-mime-types.h" + +#define POPUP_PATH_ICON_APPEARANCE "/selection/Icon Appearance Items" + +enum +{ + PROP_0, + PROP_COMPACT +}; + +typedef struct +{ + const CajaFileSortType sort_type; + const char *metadata_text; + const char *action; + const char *menu_label; + const char *menu_hint; +} SortCriterion; + +typedef enum +{ + MENU_ITEM_TYPE_STANDARD, + MENU_ITEM_TYPE_CHECK, + MENU_ITEM_TYPE_RADIO, + MENU_ITEM_TYPE_TREE +} MenuItemType; + +struct FMIconViewDetails +{ + GList *icons_not_positioned; + + guint react_to_icon_change_idle_id; + + const SortCriterion *sort; + gboolean sort_reversed; + + GtkActionGroup *icon_action_group; + guint icon_merge_id; + + int audio_preview_timeout; + CajaFile *audio_preview_file; + int audio_preview_child_watch; + GPid audio_preview_child_pid; + + gboolean filter_by_screen; + int num_screens; + + gboolean compact; + + gulong clipboard_handler_id; +}; + + +/* 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[] = +{ + { + CAJA_FILE_SORT_BY_DISPLAY_NAME, + "name", + "Sort by Name", + N_("by _Name"), + N_("Keep icons sorted by name in rows") + }, + { + CAJA_FILE_SORT_BY_SIZE, + "size", + "Sort by Size", + N_("by _Size"), + N_("Keep icons sorted by size in rows") + }, + { + CAJA_FILE_SORT_BY_TYPE, + "type", + "Sort by Type", + N_("by _Type"), + N_("Keep icons sorted by type in rows") + }, + { + CAJA_FILE_SORT_BY_MTIME, + "modification date", + "Sort by Modification Date", + N_("by Modification _Date"), + N_("Keep icons sorted by modification date in rows") + }, + { + CAJA_FILE_SORT_BY_EMBLEMS, + "emblems", + "Sort by Emblems", + N_("by _Emblems"), + N_("Keep icons sorted by emblems in rows") + }, + { + CAJA_FILE_SORT_BY_TRASHED_TIME, + "trashed", + "Sort by Trash Time", + N_("by T_rash Time"), + N_("Keep icons sorted by trash time in rows") + } +}; + +static gboolean default_sort_in_reverse_order = FALSE; +static int preview_sound_auto_value; + +static void fm_icon_view_set_directory_sort_by (FMIconView *icon_view, + CajaFile *file, + const char *sort_by); +static void fm_icon_view_set_zoom_level (FMIconView *view, + CajaZoomLevel new_level, + gboolean always_emit); +static void fm_icon_view_update_click_mode (FMIconView *icon_view); +static void fm_icon_view_set_directory_tighter_layout (FMIconView *icon_view, + CajaFile *file, + gboolean tighter_layout); +static gboolean fm_icon_view_supports_manual_layout (FMIconView *icon_view); +static gboolean fm_icon_view_supports_scaling (FMIconView *icon_view); +static void fm_icon_view_reveal_selection (FMDirectoryView *view); +static const SortCriterion *get_sort_criterion_by_sort_type (CajaFileSortType sort_type); +static void set_sort_criterion_by_sort_type (FMIconView *icon_view, + CajaFileSortType sort_type); +static gboolean set_sort_reversed (FMIconView *icon_view, + gboolean new_value); +static void switch_to_manual_layout (FMIconView *view); +static void preview_audio (FMIconView *icon_view, + CajaFile *file, + gboolean start_flag); +static void update_layout_menus (FMIconView *view); +static CajaFileSortType get_default_sort_order (CajaFile *file, + gboolean *reversed); + + +static void fm_icon_view_iface_init (CajaViewIface *iface); + +G_DEFINE_TYPE_WITH_CODE (FMIconView, fm_icon_view, FM_TYPE_DIRECTORY_VIEW, + G_IMPLEMENT_INTERFACE (CAJA_TYPE_VIEW, + fm_icon_view_iface_init)); + +static void +fm_icon_view_destroy (GtkObject *object) +{ + FMIconView *icon_view; + + icon_view = FM_ICON_VIEW (object); + + if (icon_view->details->react_to_icon_change_idle_id != 0) + { + g_source_remove (icon_view->details->react_to_icon_change_idle_id); + icon_view->details->react_to_icon_change_idle_id = 0; + } + + if (icon_view->details->clipboard_handler_id != 0) + { + g_signal_handler_disconnect (caja_clipboard_monitor_get (), + icon_view->details->clipboard_handler_id); + icon_view->details->clipboard_handler_id = 0; + } + + /* kill any sound preview process that is ongoing */ + preview_audio (icon_view, NULL, FALSE); + + if (icon_view->details->icons_not_positioned) + { + caja_file_list_free (icon_view->details->icons_not_positioned); + icon_view->details->icons_not_positioned = NULL; + } + + GTK_OBJECT_CLASS (fm_icon_view_parent_class)->destroy (object); +} + + +static void +fm_icon_view_finalize (GObject *object) +{ + FMIconView *icon_view; + + icon_view = FM_ICON_VIEW (object); + + g_free (icon_view->details); + + G_OBJECT_CLASS (fm_icon_view_parent_class)->finalize (object); +} + +static CajaIconContainer * +get_icon_container (FMIconView *icon_view) +{ + return CAJA_ICON_CONTAINER (gtk_bin_get_child (GTK_BIN (icon_view))); +} + +static gboolean +get_stored_icon_position_callback (CajaIconContainer *container, + CajaFile *file, + CajaIconPosition *position, + FMIconView *icon_view) +{ + char *position_string, *scale_string; + gboolean position_good; + char c; + + g_assert (CAJA_IS_ICON_CONTAINER (container)); + g_assert (CAJA_IS_FILE (file)); + g_assert (position != NULL); + g_assert (FM_IS_ICON_VIEW (icon_view)); + + if (!fm_icon_view_supports_manual_layout (icon_view)) + { + return FALSE; + } + + /* Get the current position of this icon from the metadata. */ + position_string = caja_file_get_metadata + (file, CAJA_METADATA_KEY_ICON_POSITION, ""); + position_good = sscanf + (position_string, " %d , %d %c", + &position->x, &position->y, &c) == 2; + g_free (position_string); + + /* If it is the desktop directory, maybe the mate-libs metadata has information about it */ + + /* Disable scaling if not on the desktop */ + if (fm_icon_view_supports_scaling (icon_view)) + { + /* Get the scale of the icon from the metadata. */ + scale_string = caja_file_get_metadata + (file, CAJA_METADATA_KEY_ICON_SCALE, "1"); + position->scale = g_ascii_strtod (scale_string, NULL); + if (errno != 0) + { + position->scale = 1.0; + } + + g_free (scale_string); + } + else + { + position->scale = 1.0; + } + + return position_good; +} + +static void +real_set_sort_criterion (FMIconView *icon_view, + const SortCriterion *sort, + gboolean clear) +{ + CajaFile *file; + + file = fm_directory_view_get_directory_as_file (FM_DIRECTORY_VIEW (icon_view)); + + if (clear) + { + caja_file_set_metadata (file, + CAJA_METADATA_KEY_ICON_VIEW_SORT_BY, NULL, NULL); + caja_file_set_metadata (file, + CAJA_METADATA_KEY_ICON_VIEW_SORT_REVERSED, NULL, NULL); + icon_view->details->sort = + get_sort_criterion_by_sort_type (get_default_sort_order + (file, &icon_view->details->sort_reversed)); + } + else + { + /* Store the new sort setting. */ + fm_icon_view_set_directory_sort_by (icon_view, + file, + sort->metadata_text); + } + + /* Update the layout menus to match the new sort setting. */ + update_layout_menus (icon_view); +} + +static void +set_sort_criterion (FMIconView *icon_view, const SortCriterion *sort) +{ + if (sort == NULL || + icon_view->details->sort == sort) + { + return; + } + + icon_view->details->sort = sort; + + real_set_sort_criterion (icon_view, sort, FALSE); +} + +static void +clear_sort_criterion (FMIconView *icon_view) +{ + real_set_sort_criterion (icon_view, NULL, TRUE); +} + +static void +action_stretch_callback (GtkAction *action, + gpointer callback_data) +{ + g_assert (FM_IS_ICON_VIEW (callback_data)); + + caja_icon_container_show_stretch_handles + (get_icon_container (FM_ICON_VIEW (callback_data))); +} + +static void +action_unstretch_callback (GtkAction *action, + gpointer callback_data) +{ + g_assert (FM_IS_ICON_VIEW (callback_data)); + + caja_icon_container_unstretch + (get_icon_container (FM_ICON_VIEW (callback_data))); +} + +static void +fm_icon_view_clean_up (FMIconView *icon_view) +{ + EEL_CALL_METHOD (FM_ICON_VIEW_CLASS, icon_view, clean_up, (icon_view)); +} + +static void +fm_icon_view_real_clean_up (FMIconView *icon_view) +{ + CajaIconContainer *icon_container; + gboolean saved_sort_reversed; + + icon_container = get_icon_container (icon_view); + + /* Hardwire Clean Up to always be by name, in forward order */ + saved_sort_reversed = icon_view->details->sort_reversed; + + set_sort_reversed (icon_view, FALSE); + set_sort_criterion (icon_view, &sort_criteria[0]); + + caja_icon_container_sort (icon_container); + caja_icon_container_freeze_icon_positions (icon_container); + + set_sort_reversed (icon_view, saved_sort_reversed); +} + +static void +action_clean_up_callback (GtkAction *action, gpointer callback_data) +{ + fm_icon_view_clean_up (FM_ICON_VIEW (callback_data)); +} + +static void +set_tighter_layout (FMIconView *icon_view, gboolean new_value) +{ + fm_icon_view_set_directory_tighter_layout (icon_view, + fm_directory_view_get_directory_as_file + (FM_DIRECTORY_VIEW (icon_view)), + new_value); + caja_icon_container_set_tighter_layout (get_icon_container (icon_view), + new_value); +} + +static void +action_tighter_layout_callback (GtkAction *action, + gpointer user_data) +{ + g_assert (FM_IS_ICON_VIEW (user_data)); + + set_tighter_layout (FM_ICON_VIEW (user_data), + gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))); +} + + +static gboolean +fm_icon_view_using_auto_layout (FMIconView *icon_view) +{ + return caja_icon_container_is_auto_layout + (get_icon_container (icon_view)); +} + +static gboolean +fm_icon_view_using_tighter_layout (FMIconView *icon_view) +{ + return caja_icon_container_is_tighter_layout + (get_icon_container (icon_view)); +} + +static void +action_sort_radio_callback (GtkAction *action, + GtkRadioAction *current, + FMIconView *view) +{ + CajaFileSortType sort_type; + + sort_type = gtk_radio_action_get_current_value (current); + + /* Note that id might be a toggle item. + * Ignore non-sort ids so that they don't cause sorting. + */ + if (sort_type == CAJA_FILE_SORT_NONE) + { + switch_to_manual_layout (view); + } + else + { + set_sort_criterion_by_sort_type (view, sort_type); + } +} + +static void +list_covers (CajaIconData *data, gpointer callback_data) +{ + GSList **file_list; + + file_list = callback_data; + + *file_list = g_slist_prepend (*file_list, data); +} + +static void +unref_cover (CajaIconData *data, gpointer callback_data) +{ + caja_file_unref (CAJA_FILE (data)); +} + +static void +fm_icon_view_clear (FMDirectoryView *view) +{ + CajaIconContainer *icon_container; + GSList *file_list; + + g_return_if_fail (FM_IS_ICON_VIEW (view)); + + icon_container = get_icon_container (FM_ICON_VIEW (view)); + if (!icon_container) + return; + + /* Clear away the existing icons. */ + file_list = NULL; + caja_icon_container_for_each (icon_container, list_covers, &file_list); + caja_icon_container_clear (icon_container); + g_slist_foreach (file_list, (GFunc)unref_cover, NULL); + g_slist_free (file_list); +} + + +static gboolean +should_show_file_on_screen (FMDirectoryView *view, CajaFile *file) +{ + char *screen_string; + int screen_num; + FMIconView *icon_view; + GdkScreen *screen; + + icon_view = FM_ICON_VIEW (view); + + if (!fm_directory_view_should_show_file (view, file)) + { + return FALSE; + } + + /* Get the screen for this icon from the metadata. */ + screen_string = caja_file_get_metadata + (file, CAJA_METADATA_KEY_SCREEN, "0"); + screen_num = atoi (screen_string); + g_free (screen_string); + screen = gtk_widget_get_screen (GTK_WIDGET (view)); + + if (screen_num != gdk_screen_get_number (screen) && + (screen_num < icon_view->details->num_screens || + gdk_screen_get_number (screen) > 0)) + { + return FALSE; + } + + return TRUE; +} + +static void +fm_icon_view_remove_file (FMDirectoryView *view, CajaFile *file, CajaDirectory *directory) +{ + FMIconView *icon_view; + + /* This used to assert that 'directory == fm_directory_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 != fm_directory_view_get_model (view)) + { + char *file_uri, *dir_uri, *model_uri; + file_uri = caja_file_get_uri (file); + dir_uri = caja_directory_get_uri (directory); + model_uri = caja_directory_get_uri (fm_directory_view_get_model (view)); + g_warning ("fm_icon_view_remove_file() - directory not icon 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, fm_directory_view_get_model (view), model_uri, fm_directory_view_get_loading (view)); + g_free (file_uri); + g_free (dir_uri); + g_free (model_uri); + } + + icon_view = FM_ICON_VIEW (view); + + if (caja_icon_container_remove (get_icon_container (icon_view), + CAJA_ICON_CONTAINER_ICON_DATA (file))) + { + if (file == icon_view->details->audio_preview_file) + { + preview_audio (icon_view, NULL, FALSE); + } + + caja_file_unref (file); + } +} + +static void +fm_icon_view_add_file (FMDirectoryView *view, CajaFile *file, CajaDirectory *directory) +{ + FMIconView *icon_view; + CajaIconContainer *icon_container; + + g_assert (directory == fm_directory_view_get_model (view)); + + icon_view = FM_ICON_VIEW (view); + icon_container = get_icon_container (icon_view); + + if (icon_view->details->filter_by_screen && + !should_show_file_on_screen (view, file)) + { + return; + } + + /* Reset scroll region for the first icon added when loading a directory. */ + if (fm_directory_view_get_loading (view) && caja_icon_container_is_empty (icon_container)) + { + caja_icon_container_reset_scroll_region (icon_container); + } + + if (caja_icon_container_add (icon_container, + CAJA_ICON_CONTAINER_ICON_DATA (file))) + { + caja_file_ref (file); + } +} + +static void +fm_icon_view_flush_added_files (FMDirectoryView *view) +{ + caja_icon_container_layout_now (get_icon_container (FM_ICON_VIEW (view))); +} + +static void +fm_icon_view_file_changed (FMDirectoryView *view, CajaFile *file, CajaDirectory *directory) +{ + FMIconView *icon_view; + + g_assert (directory == fm_directory_view_get_model (view)); + + g_return_if_fail (view != NULL); + icon_view = FM_ICON_VIEW (view); + + if (!icon_view->details->filter_by_screen) + { + caja_icon_container_request_update + (get_icon_container (icon_view), + CAJA_ICON_CONTAINER_ICON_DATA (file)); + return; + } + + if (!should_show_file_on_screen (view, file)) + { + fm_icon_view_remove_file (view, file, directory); + } + else + { + + caja_icon_container_request_update + (get_icon_container (icon_view), + CAJA_ICON_CONTAINER_ICON_DATA (file)); + } +} + +static gboolean +fm_icon_view_supports_auto_layout (FMIconView *view) +{ + g_return_val_if_fail (FM_IS_ICON_VIEW (view), FALSE); + + return EEL_CALL_METHOD_WITH_RETURN_VALUE + (FM_ICON_VIEW_CLASS, view, + supports_auto_layout, (view)); +} + +static gboolean +fm_icon_view_supports_scaling (FMIconView *view) +{ + g_return_val_if_fail (FM_IS_ICON_VIEW (view), FALSE); + + return EEL_CALL_METHOD_WITH_RETURN_VALUE + (FM_ICON_VIEW_CLASS, view, + supports_scaling, (view)); +} + +static gboolean +fm_icon_view_supports_manual_layout (FMIconView *view) +{ + g_return_val_if_fail (FM_IS_ICON_VIEW (view), FALSE); + + return EEL_CALL_METHOD_WITH_RETURN_VALUE + (FM_ICON_VIEW_CLASS, view, + supports_manual_layout, (view)); +} + +static gboolean +fm_icon_view_supports_keep_aligned (FMIconView *view) +{ + g_return_val_if_fail (FM_IS_ICON_VIEW (view), FALSE); + + return EEL_CALL_METHOD_WITH_RETURN_VALUE + (FM_ICON_VIEW_CLASS, view, + supports_keep_aligned, (view)); +} + +static gboolean +fm_icon_view_supports_labels_beside_icons (FMIconView *view) +{ + g_return_val_if_fail (FM_IS_ICON_VIEW (view), FALSE); + + return EEL_CALL_METHOD_WITH_RETURN_VALUE + (FM_ICON_VIEW_CLASS, view, + supports_labels_beside_icons, (view)); +} + +static gboolean +fm_icon_view_supports_tighter_layout (FMIconView *view) +{ + return !fm_icon_view_is_compact (view); +} + +static void +update_layout_menus (FMIconView *view) +{ + gboolean is_auto_layout; + GtkAction *action; + const char *action_name; + CajaFile *file; + + if (view->details->icon_action_group == NULL) + { + return; + } + + is_auto_layout = fm_icon_view_using_auto_layout (view); + file = fm_directory_view_get_directory_as_file (FM_DIRECTORY_VIEW (view)); + + if (fm_icon_view_supports_auto_layout (view)) + { + /* Mark sort criterion. */ + action_name = is_auto_layout ? view->details->sort->action : FM_ACTION_MANUAL_LAYOUT; + action = gtk_action_group_get_action (view->details->icon_action_group, + action_name); + gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE); + + action = gtk_action_group_get_action (view->details->icon_action_group, + FM_ACTION_TIGHTER_LAYOUT); + gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), + fm_icon_view_using_tighter_layout (view)); + gtk_action_set_sensitive (action, fm_icon_view_supports_tighter_layout (view)); + gtk_action_set_visible (action, fm_icon_view_supports_tighter_layout (view)); + + action = gtk_action_group_get_action (view->details->icon_action_group, + FM_ACTION_REVERSED_ORDER); + gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), + view->details->sort_reversed); + gtk_action_set_sensitive (action, is_auto_layout); + + action = gtk_action_group_get_action (view->details->icon_action_group, + FM_ACTION_SORT_TRASH_TIME); + + if (file != NULL && caja_file_is_in_trash (file)) + { + gtk_action_set_visible (action, TRUE); + } + else + { + gtk_action_set_visible (action, FALSE); + } + } + + action = gtk_action_group_get_action (view->details->icon_action_group, + FM_ACTION_MANUAL_LAYOUT); + gtk_action_set_visible (action, + fm_icon_view_supports_manual_layout (view)); + + /* Clean Up is only relevant for manual layout */ + action = gtk_action_group_get_action (view->details->icon_action_group, + FM_ACTION_CLEAN_UP); + gtk_action_set_sensitive (action, !is_auto_layout); + + if (FM_IS_DESKTOP_ICON_VIEW (view)) + { + gtk_action_set_label (action, _("_Organize Desktop by Name")); + } + + action = gtk_action_group_get_action (view->details->icon_action_group, + FM_ACTION_KEEP_ALIGNED); + gtk_action_set_visible (action, + fm_icon_view_supports_keep_aligned (view)); + gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), + caja_icon_container_is_keep_aligned (get_icon_container (view))); + gtk_action_set_sensitive (action, !is_auto_layout); +} + + +static char * +fm_icon_view_get_directory_sort_by (FMIconView *icon_view, + CajaFile *file) +{ + if (!fm_icon_view_supports_auto_layout (icon_view)) + { + return g_strdup ("name"); + } + + return EEL_CALL_METHOD_WITH_RETURN_VALUE + (FM_ICON_VIEW_CLASS, icon_view, + get_directory_sort_by, (icon_view, file)); +} + +static CajaFileSortType default_sort_order = CAJA_FILE_SORT_BY_DISPLAY_NAME; + +static CajaFileSortType +get_default_sort_order (CajaFile *file, gboolean *reversed) +{ + static gboolean auto_storaged_added = FALSE; + CajaFileSortType retval; + + if (auto_storaged_added == FALSE) + { + auto_storaged_added = TRUE; + eel_preferences_add_auto_enum (CAJA_PREFERENCES_ICON_VIEW_DEFAULT_SORT_ORDER, + (int *) &default_sort_order); + eel_preferences_add_auto_boolean (CAJA_PREFERENCES_ICON_VIEW_DEFAULT_SORT_IN_REVERSE_ORDER, + &default_sort_in_reverse_order); + + } + + retval = caja_file_get_default_sort_type (file, reversed); + + if (retval == CAJA_FILE_SORT_NONE) + { + + if (reversed != NULL) + { + *reversed = default_sort_in_reverse_order; + } + + retval = CLAMP (default_sort_order, CAJA_FILE_SORT_BY_DISPLAY_NAME, + CAJA_FILE_SORT_BY_EMBLEMS); + } + + return retval; +} + +static char * +fm_icon_view_real_get_directory_sort_by (FMIconView *icon_view, + CajaFile *file) +{ + const SortCriterion *default_sort_criterion; + default_sort_criterion = get_sort_criterion_by_sort_type (get_default_sort_order (file, NULL)); + g_return_val_if_fail (default_sort_criterion != NULL, NULL); + + return caja_file_get_metadata + (file, CAJA_METADATA_KEY_ICON_VIEW_SORT_BY, + default_sort_criterion->metadata_text); +} + +static void +fm_icon_view_set_directory_sort_by (FMIconView *icon_view, + CajaFile *file, + const char *sort_by) +{ + if (!fm_icon_view_supports_auto_layout (icon_view)) + { + return; + } + + EEL_CALL_METHOD (FM_ICON_VIEW_CLASS, icon_view, + set_directory_sort_by, (icon_view, file, sort_by)); +} + +static void +fm_icon_view_real_set_directory_sort_by (FMIconView *icon_view, + CajaFile *file, + const char *sort_by) +{ + const SortCriterion *default_sort_criterion; + default_sort_criterion = get_sort_criterion_by_sort_type (get_default_sort_order (file, NULL)); + g_return_if_fail (default_sort_criterion != NULL); + + caja_file_set_metadata + (file, CAJA_METADATA_KEY_ICON_VIEW_SORT_BY, + default_sort_criterion->metadata_text, + sort_by); +} + +static gboolean +fm_icon_view_get_directory_sort_reversed (FMIconView *icon_view, + CajaFile *file) +{ + if (!fm_icon_view_supports_auto_layout (icon_view)) + { + return FALSE; + } + + return EEL_CALL_METHOD_WITH_RETURN_VALUE + (FM_ICON_VIEW_CLASS, icon_view, + get_directory_sort_reversed, (icon_view, file)); +} + +static gboolean +fm_icon_view_real_get_directory_sort_reversed (FMIconView *icon_view, + CajaFile *file) +{ + gboolean reversed; + + get_default_sort_order (file, &reversed); + return caja_file_get_boolean_metadata + (file, + CAJA_METADATA_KEY_ICON_VIEW_SORT_REVERSED, + reversed); +} + +static void +fm_icon_view_set_directory_sort_reversed (FMIconView *icon_view, + CajaFile *file, + gboolean sort_reversed) +{ + if (!fm_icon_view_supports_auto_layout (icon_view)) + { + return; + } + + EEL_CALL_METHOD (FM_ICON_VIEW_CLASS, icon_view, + set_directory_sort_reversed, + (icon_view, file, sort_reversed)); +} + +static void +fm_icon_view_real_set_directory_sort_reversed (FMIconView *icon_view, + CajaFile *file, + gboolean sort_reversed) +{ + gboolean reversed; + + get_default_sort_order (file, &reversed); + caja_file_set_boolean_metadata + (file, + CAJA_METADATA_KEY_ICON_VIEW_SORT_REVERSED, + reversed, sort_reversed); +} + +static gboolean +get_default_directory_keep_aligned (void) +{ + return TRUE; +} + +static gboolean +fm_icon_view_get_directory_keep_aligned (FMIconView *icon_view, + CajaFile *file) +{ + if (!fm_icon_view_supports_keep_aligned (icon_view)) + { + return FALSE; + } + + return caja_file_get_boolean_metadata + (file, + CAJA_METADATA_KEY_ICON_VIEW_KEEP_ALIGNED, + get_default_directory_keep_aligned ()); +} + +static void +fm_icon_view_set_directory_keep_aligned (FMIconView *icon_view, + CajaFile *file, + gboolean keep_aligned) +{ + if (!fm_icon_view_supports_keep_aligned (icon_view)) + { + return; + } + + caja_file_set_boolean_metadata + (file, CAJA_METADATA_KEY_ICON_VIEW_KEEP_ALIGNED, + get_default_directory_keep_aligned (), + keep_aligned); +} + +/* maintainence of auto layout boolean */ +static gboolean default_directory_manual_layout = FALSE; + +static gboolean +get_default_directory_manual_layout (void) +{ + static gboolean auto_storaged_added = FALSE; + + if (auto_storaged_added == FALSE) + { + auto_storaged_added = TRUE; + eel_preferences_add_auto_boolean (CAJA_PREFERENCES_ICON_VIEW_DEFAULT_USE_MANUAL_LAYOUT, + &default_directory_manual_layout); + } + + return default_directory_manual_layout; +} + +static gboolean +fm_icon_view_get_directory_auto_layout (FMIconView *icon_view, + CajaFile *file) +{ + if (!fm_icon_view_supports_auto_layout (icon_view)) + { + return FALSE; + } + + if (!fm_icon_view_supports_manual_layout (icon_view)) + { + return TRUE; + } + + return EEL_CALL_METHOD_WITH_RETURN_VALUE + (FM_ICON_VIEW_CLASS, icon_view, + get_directory_auto_layout, (icon_view, file)); +} + +static gboolean +fm_icon_view_real_get_directory_auto_layout (FMIconView *icon_view, + CajaFile *file) +{ + + + return caja_file_get_boolean_metadata + (file, CAJA_METADATA_KEY_ICON_VIEW_AUTO_LAYOUT, !get_default_directory_manual_layout ()); +} + +static void +fm_icon_view_set_directory_auto_layout (FMIconView *icon_view, + CajaFile *file, + gboolean auto_layout) +{ + if (!fm_icon_view_supports_auto_layout (icon_view) || + !fm_icon_view_supports_manual_layout (icon_view)) + { + return; + } + + EEL_CALL_METHOD (FM_ICON_VIEW_CLASS, icon_view, + set_directory_auto_layout, (icon_view, file, auto_layout)); +} + +static void +fm_icon_view_real_set_directory_auto_layout (FMIconView *icon_view, + CajaFile *file, + gboolean auto_layout) +{ + if (!fm_icon_view_supports_manual_layout (icon_view)) + { + return; + } + + caja_file_set_boolean_metadata + (file, CAJA_METADATA_KEY_ICON_VIEW_AUTO_LAYOUT, + !get_default_directory_manual_layout (), + auto_layout); +} +/* maintainence of tighter layout boolean */ + +static gboolean +fm_icon_view_get_directory_tighter_layout (FMIconView *icon_view, + CajaFile *file) +{ + return EEL_CALL_METHOD_WITH_RETURN_VALUE + (FM_ICON_VIEW_CLASS, icon_view, + get_directory_tighter_layout, (icon_view, file)); +} + +static gboolean default_directory_tighter_layout = FALSE; + +static gboolean +get_default_directory_tighter_layout (void) +{ + static gboolean auto_storaged_added = FALSE; + + if (auto_storaged_added == FALSE) + { + auto_storaged_added = TRUE; + eel_preferences_add_auto_boolean (CAJA_PREFERENCES_ICON_VIEW_DEFAULT_USE_TIGHTER_LAYOUT, + &default_directory_tighter_layout); + } + + return default_directory_tighter_layout; +} + +static gboolean +fm_icon_view_real_get_directory_tighter_layout (FMIconView *icon_view, + CajaFile *file) +{ + if (!fm_icon_view_supports_tighter_layout (icon_view)) + { + return FALSE; + } + + return caja_file_get_boolean_metadata + (file, + CAJA_METADATA_KEY_ICON_VIEW_TIGHTER_LAYOUT, + get_default_directory_tighter_layout ()); +} + +static void +fm_icon_view_set_directory_tighter_layout (FMIconView *icon_view, + CajaFile *file, + gboolean tighter_layout) +{ + EEL_CALL_METHOD (FM_ICON_VIEW_CLASS, icon_view, + set_directory_tighter_layout, (icon_view, file, tighter_layout)); +} + +static void +fm_icon_view_real_set_directory_tighter_layout (FMIconView *icon_view, + CajaFile *file, + gboolean tighter_layout) +{ + if (!fm_icon_view_supports_tighter_layout (icon_view)) + { + return; + } + + caja_file_set_boolean_metadata + (file, CAJA_METADATA_KEY_ICON_VIEW_TIGHTER_LAYOUT, + get_default_directory_tighter_layout (), + tighter_layout); +} + +static gboolean +real_supports_auto_layout (FMIconView *view) +{ + g_return_val_if_fail (FM_IS_ICON_VIEW (view), FALSE); + + return TRUE; +} + +static gboolean +real_supports_scaling (FMIconView *view) +{ + g_return_val_if_fail (FM_IS_ICON_VIEW (view), FALSE); + + return FALSE; +} + +static gboolean +real_supports_manual_layout (FMIconView *view) +{ + g_return_val_if_fail (FM_IS_ICON_VIEW (view), FALSE); + + return !fm_icon_view_is_compact (view); +} + +static gboolean +real_supports_keep_aligned (FMIconView *view) +{ + g_return_val_if_fail (FM_IS_ICON_VIEW (view), FALSE); + + return FALSE; +} + +static gboolean +real_supports_labels_beside_icons (FMIconView *view) +{ + g_return_val_if_fail (FM_IS_ICON_VIEW (view), TRUE); + + return TRUE; +} + +static gboolean +set_sort_reversed (FMIconView *icon_view, gboolean new_value) +{ + if (icon_view->details->sort_reversed == new_value) + { + return FALSE; + } + icon_view->details->sort_reversed = new_value; + + /* Store the new sort setting. */ + fm_icon_view_set_directory_sort_reversed (icon_view, fm_directory_view_get_directory_as_file (FM_DIRECTORY_VIEW (icon_view)), new_value); + + /* Update the layout menus to match the new sort-order setting. */ + update_layout_menus (icon_view); + + return TRUE; +} + +static const SortCriterion * +get_sort_criterion_by_metadata_text (const char *metadata_text) +{ + guint i; + + /* Figure out what the new sort setting should be. */ + for (i = 0; i < G_N_ELEMENTS (sort_criteria); i++) + { + if (strcmp (sort_criteria[i].metadata_text, metadata_text) == 0) + { + return &sort_criteria[i]; + } + } + return NULL; +} + +static const SortCriterion * +get_sort_criterion_by_sort_type (CajaFileSortType sort_type) +{ + 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) + { + return &sort_criteria[i]; + } + } + + return NULL; +} + +static CajaZoomLevel default_zoom_level = CAJA_ZOOM_LEVEL_STANDARD; +static CajaZoomLevel default_compact_zoom_level = CAJA_ZOOM_LEVEL_STANDARD; +#define DEFAULT_ZOOM_LEVEL(icon_view) icon_view->details->compact ? default_compact_zoom_level : default_zoom_level + +static CajaZoomLevel +get_default_zoom_level (FMIconView *icon_view) +{ + static gboolean auto_storage_added = FALSE; + + if (!auto_storage_added) + { + auto_storage_added = TRUE; + eel_preferences_add_auto_enum (CAJA_PREFERENCES_ICON_VIEW_DEFAULT_ZOOM_LEVEL, + (int *) &default_zoom_level); + eel_preferences_add_auto_enum (CAJA_PREFERENCES_COMPACT_VIEW_DEFAULT_ZOOM_LEVEL, + (int *) &default_compact_zoom_level); + } + + return CLAMP (DEFAULT_ZOOM_LEVEL(icon_view), CAJA_ZOOM_LEVEL_SMALLEST, CAJA_ZOOM_LEVEL_LARGEST); +} + +static void +set_labels_beside_icons (FMIconView *icon_view) +{ + gboolean labels_beside; + + if (fm_icon_view_supports_labels_beside_icons (icon_view)) + { + labels_beside = fm_icon_view_is_compact (icon_view) || + eel_preferences_get_boolean (CAJA_PREFERENCES_ICON_VIEW_LABELS_BESIDE_ICONS); + + if (labels_beside) + { + caja_icon_container_set_label_position + (get_icon_container (icon_view), + CAJA_ICON_LABEL_POSITION_BESIDE); + } + else + { + caja_icon_container_set_label_position + (get_icon_container (icon_view), + CAJA_ICON_LABEL_POSITION_UNDER); + } + } +} + +static void +set_columns_same_width (FMIconView *icon_view) +{ + gboolean all_columns_same_width; + + if (fm_icon_view_is_compact (icon_view)) + { + all_columns_same_width = eel_preferences_get_boolean (CAJA_PREFERENCES_COMPACT_VIEW_ALL_COLUMNS_SAME_WIDTH); + caja_icon_container_set_all_columns_same_width (get_icon_container (icon_view), all_columns_same_width); + } +} + +static void +fm_icon_view_begin_loading (FMDirectoryView *view) +{ + FMIconView *icon_view; + GtkWidget *icon_container; + CajaFile *file; + int level; + char *sort_name; + + g_return_if_fail (FM_IS_ICON_VIEW (view)); + + icon_view = FM_ICON_VIEW (view); + file = fm_directory_view_get_directory_as_file (view); + icon_container = GTK_WIDGET (get_icon_container (icon_view)); + + caja_icon_container_begin_loading (CAJA_ICON_CONTAINER (icon_container)); + + caja_icon_container_set_allow_moves (CAJA_ICON_CONTAINER (icon_container), + fm_directory_view_get_allow_moves (view)); + + /* kill any sound preview process that is ongoing */ + preview_audio (icon_view, NULL, FALSE); + + /* FIXME bugzilla.gnome.org 45060: Should use methods instead + * of hardcoding desktop knowledge in here. + */ + if (FM_IS_DESKTOP_ICON_VIEW (view)) + { + caja_connect_desktop_background_to_file_metadata (CAJA_ICON_CONTAINER (icon_container), file); + } + else + { + GdkDragAction default_action; + + if (caja_window_info_get_window_type (fm_directory_view_get_caja_window (view)) == CAJA_WINDOW_NAVIGATION) + { + default_action = CAJA_DND_ACTION_SET_AS_GLOBAL_BACKGROUND; + } + else + { + default_action = CAJA_DND_ACTION_SET_AS_FOLDER_BACKGROUND; + } + + caja_connect_background_to_file_metadata + (icon_container, + file, + default_action); + } + + + /* Set up the zoom level from the metadata. */ + if (fm_directory_view_supports_zooming (FM_DIRECTORY_VIEW (icon_view))) + { + if (icon_view->details->compact) + { + level = caja_file_get_integer_metadata + (file, + CAJA_METADATA_KEY_COMPACT_VIEW_ZOOM_LEVEL, + get_default_zoom_level (icon_view)); + } + else + { + level = caja_file_get_integer_metadata + (file, + CAJA_METADATA_KEY_ICON_VIEW_ZOOM_LEVEL, + get_default_zoom_level (icon_view)); + } + + fm_icon_view_set_zoom_level (icon_view, level, TRUE); + } + + /* Set the sort mode. + * It's OK not to resort the icons because the + * container doesn't have any icons at this point. + */ + sort_name = fm_icon_view_get_directory_sort_by (icon_view, file); + set_sort_criterion (icon_view, get_sort_criterion_by_metadata_text (sort_name)); + g_free (sort_name); + + /* Set the sort direction from the metadata. */ + set_sort_reversed (icon_view, fm_icon_view_get_directory_sort_reversed (icon_view, file)); + + caja_icon_container_set_keep_aligned + (get_icon_container (icon_view), + fm_icon_view_get_directory_keep_aligned (icon_view, file)); + caja_icon_container_set_tighter_layout + (get_icon_container (icon_view), + fm_icon_view_get_directory_tighter_layout (icon_view, file)); + + set_labels_beside_icons (icon_view); + set_columns_same_width (icon_view); + + /* We must set auto-layout last, because it invokes the layout_changed + * callback, which works incorrectly if the other layout criteria are + * not already set up properly (see bug 6500, e.g.) + */ + caja_icon_container_set_auto_layout + (get_icon_container (icon_view), + fm_icon_view_get_directory_auto_layout (icon_view, file)); + + /* e.g. keep aligned may have changed */ + update_layout_menus (icon_view); +} + +static void +icon_view_notify_clipboard_info (CajaClipboardMonitor *monitor, + CajaClipboardInfo *info, + FMIconView *icon_view) +{ + GList *icon_data; + + icon_data = NULL; + if (info && info->cut) + { + icon_data = info->files; + } + + caja_icon_container_set_highlighted_for_clipboard ( + get_icon_container (icon_view), icon_data); +} + +static void +fm_icon_view_end_loading (FMDirectoryView *view, + gboolean all_files_seen) +{ + FMIconView *icon_view; + GtkWidget *icon_container; + CajaClipboardMonitor *monitor; + CajaClipboardInfo *info; + + icon_view = FM_ICON_VIEW (view); + + icon_container = GTK_WIDGET (get_icon_container (icon_view)); + caja_icon_container_end_loading (CAJA_ICON_CONTAINER (icon_container), all_files_seen); + + monitor = caja_clipboard_monitor_get (); + info = caja_clipboard_monitor_get_clipboard_info (monitor); + + icon_view_notify_clipboard_info (monitor, info, icon_view); +} + +static CajaZoomLevel +fm_icon_view_get_zoom_level (FMDirectoryView *view) +{ + g_return_val_if_fail (FM_IS_ICON_VIEW (view), CAJA_ZOOM_LEVEL_STANDARD); + + return caja_icon_container_get_zoom_level (get_icon_container (FM_ICON_VIEW (view))); +} + +static void +fm_icon_view_set_zoom_level (FMIconView *view, + CajaZoomLevel new_level, + gboolean always_emit) +{ + CajaIconContainer *icon_container; + + g_return_if_fail (FM_IS_ICON_VIEW (view)); + g_return_if_fail (new_level >= CAJA_ZOOM_LEVEL_SMALLEST && + new_level <= CAJA_ZOOM_LEVEL_LARGEST); + + icon_container = get_icon_container (view); + if (caja_icon_container_get_zoom_level (icon_container) == new_level) + { + if (always_emit) + { + g_signal_emit_by_name (view, "zoom_level_changed"); + } + return; + } + + if (view->details->compact) + { + caja_file_set_integer_metadata + (fm_directory_view_get_directory_as_file (FM_DIRECTORY_VIEW (view)), + CAJA_METADATA_KEY_COMPACT_VIEW_ZOOM_LEVEL, + get_default_zoom_level (view), + new_level); + } + else + { + caja_file_set_integer_metadata + (fm_directory_view_get_directory_as_file (FM_DIRECTORY_VIEW (view)), + CAJA_METADATA_KEY_ICON_VIEW_ZOOM_LEVEL, + get_default_zoom_level (view), + new_level); + } + + caja_icon_container_set_zoom_level (icon_container, new_level); + + g_signal_emit_by_name (view, "zoom_level_changed"); + + if (fm_directory_view_get_active (FM_DIRECTORY_VIEW (view))) + { + fm_directory_view_update_menus (FM_DIRECTORY_VIEW (view)); + } +} + +static void +fm_icon_view_bump_zoom_level (FMDirectoryView *view, int zoom_increment) +{ + FMIconView *icon_view; + CajaZoomLevel new_level; + + g_return_if_fail (FM_IS_ICON_VIEW (view)); + + icon_view = FM_ICON_VIEW (view); + new_level = fm_icon_view_get_zoom_level (view) + zoom_increment; + + if (new_level >= CAJA_ZOOM_LEVEL_SMALLEST && + new_level <= CAJA_ZOOM_LEVEL_LARGEST) + { + fm_directory_view_zoom_to_level (view, new_level); + } +} + +static void +fm_icon_view_zoom_to_level (FMDirectoryView *view, + CajaZoomLevel zoom_level) +{ + FMIconView *icon_view; + + g_assert (FM_IS_ICON_VIEW (view)); + + icon_view = FM_ICON_VIEW (view); + fm_icon_view_set_zoom_level (icon_view, zoom_level, FALSE); +} + +static void +fm_icon_view_restore_default_zoom_level (FMDirectoryView *view) +{ + FMIconView *icon_view; + + g_return_if_fail (FM_IS_ICON_VIEW (view)); + + icon_view = FM_ICON_VIEW (view); + fm_directory_view_zoom_to_level + (view, get_default_zoom_level (icon_view)); +} + +static gboolean +fm_icon_view_can_zoom_in (FMDirectoryView *view) +{ + g_return_val_if_fail (FM_IS_ICON_VIEW (view), FALSE); + + return fm_icon_view_get_zoom_level (view) + < CAJA_ZOOM_LEVEL_LARGEST; +} + +static gboolean +fm_icon_view_can_zoom_out (FMDirectoryView *view) +{ + g_return_val_if_fail (FM_IS_ICON_VIEW (view), FALSE); + + return fm_icon_view_get_zoom_level (view) + > CAJA_ZOOM_LEVEL_SMALLEST; +} + +static GtkWidget * +fm_icon_view_get_background_widget (FMDirectoryView *view) +{ + g_return_val_if_fail (FM_IS_ICON_VIEW (view), NULL); + + return GTK_WIDGET (get_icon_container (FM_ICON_VIEW (view))); +} + +static gboolean +fm_icon_view_is_empty (FMDirectoryView *view) +{ + g_assert (FM_IS_ICON_VIEW (view)); + + return caja_icon_container_is_empty + (get_icon_container (FM_ICON_VIEW (view))); +} + +static GList * +fm_icon_view_get_selection (FMDirectoryView *view) +{ + GList *list; + + g_return_val_if_fail (FM_IS_ICON_VIEW (view), NULL); + + list = caja_icon_container_get_selection + (get_icon_container (FM_ICON_VIEW (view))); + caja_file_list_ref (list); + return list; +} + +static void +count_item (CajaIconData *icon_data, + gpointer callback_data) +{ + guint *count; + + count = callback_data; + (*count)++; +} + +static guint +fm_icon_view_get_item_count (FMDirectoryView *view) +{ + guint count; + + g_return_val_if_fail (FM_IS_ICON_VIEW (view), 0); + + count = 0; + + caja_icon_container_for_each + (get_icon_container (FM_ICON_VIEW (view)), + count_item, &count); + + return count; +} + +static void +set_sort_criterion_by_sort_type (FMIconView *icon_view, + CajaFileSortType sort_type) +{ + const SortCriterion *sort; + + g_assert (FM_IS_ICON_VIEW (icon_view)); + + sort = get_sort_criterion_by_sort_type (sort_type); + g_return_if_fail (sort != NULL); + + if (sort == icon_view->details->sort + && fm_icon_view_using_auto_layout (icon_view)) + { + return; + } + + set_sort_criterion (icon_view, sort); + caja_icon_container_sort (get_icon_container (icon_view)); + fm_icon_view_reveal_selection (FM_DIRECTORY_VIEW (icon_view)); +} + + +static void +action_reversed_order_callback (GtkAction *action, + gpointer user_data) +{ + FMIconView *icon_view; + + icon_view = FM_ICON_VIEW (user_data); + + if (set_sort_reversed (icon_view, + gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))) + { + caja_icon_container_sort (get_icon_container (icon_view)); + fm_icon_view_reveal_selection (FM_DIRECTORY_VIEW (icon_view)); + } +} + +static void +action_keep_aligned_callback (GtkAction *action, + gpointer user_data) +{ + FMIconView *icon_view; + CajaFile *file; + gboolean keep_aligned; + + icon_view = FM_ICON_VIEW (user_data); + + keep_aligned = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)); + + file = fm_directory_view_get_directory_as_file (FM_DIRECTORY_VIEW (icon_view)); + fm_icon_view_set_directory_keep_aligned (icon_view, + file, + keep_aligned); + + caja_icon_container_set_keep_aligned (get_icon_container (icon_view), + keep_aligned); +} + +static void +switch_to_manual_layout (FMIconView *icon_view) +{ + if (!fm_icon_view_using_auto_layout (icon_view)) + { + return; + } + + icon_view->details->sort = &sort_criteria[0]; + + caja_icon_container_set_auto_layout + (get_icon_container (icon_view), FALSE); +} + +static void +layout_changed_callback (CajaIconContainer *container, + FMIconView *icon_view) +{ + CajaFile *file; + + g_assert (FM_IS_ICON_VIEW (icon_view)); + g_assert (container == get_icon_container (icon_view)); + + file = fm_directory_view_get_directory_as_file (FM_DIRECTORY_VIEW (icon_view)); + + if (file != NULL) + { + fm_icon_view_set_directory_auto_layout + (icon_view, + file, + fm_icon_view_using_auto_layout (icon_view)); + fm_icon_view_set_directory_tighter_layout + (icon_view, + file, + fm_icon_view_using_tighter_layout (icon_view)); + } + + update_layout_menus (icon_view); +} + +static gboolean +fm_icon_view_can_rename_file (FMDirectoryView *view, CajaFile *file) +{ + if (!(fm_icon_view_get_zoom_level (view) > CAJA_ZOOM_LEVEL_SMALLEST)) + { + return FALSE; + } + + return FM_DIRECTORY_VIEW_CLASS(fm_icon_view_parent_class)->can_rename_file (view, file); +} + +static void +fm_icon_view_start_renaming_file (FMDirectoryView *view, + CajaFile *file, + gboolean select_all) +{ + /* call parent class to make sure the right icon is selected */ + FM_DIRECTORY_VIEW_CLASS(fm_icon_view_parent_class)->start_renaming_file (view, file, select_all); + + /* start renaming */ + caja_icon_container_start_renaming_selected_item + (get_icon_container (FM_ICON_VIEW (view)), select_all); +} + +static const GtkActionEntry icon_view_entries[] = +{ + /* name, stock id, label */ { "Arrange Items", NULL, N_("Arran_ge Items") }, + /* name, stock id */ { "Stretch", NULL, + /* label, accelerator */ N_("Resize Icon..."), NULL, + /* tooltip */ N_("Make the selected icon resizable"), + G_CALLBACK (action_stretch_callback) + }, + /* name, stock id */ { "Unstretch", NULL, + /* label, accelerator */ N_("Restore Icons' Original Si_zes"), NULL, + /* tooltip */ N_("Restore each selected icon to its original size"), + G_CALLBACK (action_unstretch_callback) + }, + /* name, stock id */ { "Clean Up", NULL, + /* label, accelerator */ N_("_Organize by Name"), NULL, + /* tooltip */ N_("Reposition icons to better fit in the window and avoid overlapping"), + G_CALLBACK (action_clean_up_callback) + }, +}; + +static const GtkToggleActionEntry icon_view_toggle_entries[] = +{ + /* name, stock id */ { "Tighter Layout", NULL, + /* label, accelerator */ N_("Compact _Layout"), NULL, + /* tooltip */ N_("Toggle using a tighter layout scheme"), + G_CALLBACK (action_tighter_layout_callback), + 0 + }, + /* name, stock id */ { "Reversed Order", NULL, + /* label, accelerator */ N_("Re_versed Order"), NULL, + /* tooltip */ N_("Display icons in the opposite order"), + G_CALLBACK (action_reversed_order_callback), + 0 + }, + /* name, stock id */ { "Keep Aligned", NULL, + /* label, accelerator */ N_("_Keep Aligned"), NULL, + /* tooltip */ N_("Keep icons lined up on a grid"), + G_CALLBACK (action_keep_aligned_callback), + 0 + }, +}; + +static const GtkRadioActionEntry arrange_radio_entries[] = +{ + { + "Manual Layout", NULL, + N_("_Manually"), NULL, + N_("Leave icons wherever they are dropped"), + CAJA_FILE_SORT_NONE + }, + { + "Sort by Name", NULL, + N_("By _Name"), NULL, + N_("Keep icons sorted by name in rows"), + CAJA_FILE_SORT_BY_DISPLAY_NAME + }, + { + "Sort by Size", NULL, + N_("By _Size"), NULL, + N_("Keep icons sorted by size in rows"), + CAJA_FILE_SORT_BY_SIZE + }, + { + "Sort by Type", NULL, + N_("By _Type"), NULL, + N_("Keep icons sorted by type in rows"), + CAJA_FILE_SORT_BY_TYPE + }, + { + "Sort by Modification Date", NULL, + N_("By Modification _Date"), NULL, + N_("Keep icons sorted by modification date in rows"), + CAJA_FILE_SORT_BY_MTIME + }, + { + "Sort by Emblems", NULL, + N_("By _Emblems"), NULL, + N_("Keep icons sorted by emblems in rows"), + CAJA_FILE_SORT_BY_EMBLEMS + }, + { + "Sort by Trash Time", NULL, + N_("By T_rash Time"), NULL, + N_("Keep icons sorted by trash time in rows"), + CAJA_FILE_SORT_BY_TRASHED_TIME + }, +}; + +static void +fm_icon_view_merge_menus (FMDirectoryView *view) +{ + FMIconView *icon_view; + GtkUIManager *ui_manager; + GtkActionGroup *action_group; + GtkAction *action; + const char *ui; + + g_assert (FM_IS_ICON_VIEW (view)); + + FM_DIRECTORY_VIEW_CLASS (fm_icon_view_parent_class)->merge_menus (view); + + icon_view = FM_ICON_VIEW (view); + + ui_manager = fm_directory_view_get_ui_manager (FM_DIRECTORY_VIEW (icon_view)); + + action_group = gtk_action_group_new ("IconViewActions"); + gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE); + icon_view->details->icon_action_group = action_group; + gtk_action_group_add_actions (action_group, + icon_view_entries, G_N_ELEMENTS (icon_view_entries), + icon_view); + gtk_action_group_add_toggle_actions (action_group, + icon_view_toggle_entries, G_N_ELEMENTS (icon_view_toggle_entries), + icon_view); + gtk_action_group_add_radio_actions (action_group, + arrange_radio_entries, + G_N_ELEMENTS (arrange_radio_entries), + -1, + G_CALLBACK (action_sort_radio_callback), + icon_view); + + gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); + g_object_unref (action_group); /* owned by ui manager */ + + ui = caja_ui_string_get ("caja-icon-view-ui.xml"); + icon_view->details->icon_merge_id = + gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, NULL); + + /* Do one-time state-setting here; context-dependent state-setting + * is done in update_menus. + */ + if (!fm_icon_view_supports_auto_layout (icon_view)) + { + action = gtk_action_group_get_action (action_group, + FM_ACTION_ARRANGE_ITEMS); + gtk_action_set_visible (action, FALSE); + } + + if (fm_icon_view_supports_scaling (icon_view)) + { + gtk_ui_manager_add_ui (ui_manager, + icon_view->details->icon_merge_id, + POPUP_PATH_ICON_APPEARANCE, + FM_ACTION_STRETCH, + FM_ACTION_STRETCH, + GTK_UI_MANAGER_MENUITEM, + FALSE); + gtk_ui_manager_add_ui (ui_manager, + icon_view->details->icon_merge_id, + POPUP_PATH_ICON_APPEARANCE, + FM_ACTION_UNSTRETCH, + FM_ACTION_UNSTRETCH, + GTK_UI_MANAGER_MENUITEM, + FALSE); + } + + update_layout_menus (icon_view); +} + +static void +fm_icon_view_unmerge_menus (FMDirectoryView *view) +{ + FMIconView *icon_view; + GtkUIManager *ui_manager; + + icon_view = FM_ICON_VIEW (view); + + FM_DIRECTORY_VIEW_CLASS (fm_icon_view_parent_class)->unmerge_menus (view); + + ui_manager = fm_directory_view_get_ui_manager (view); + if (ui_manager != NULL) + { + caja_ui_unmerge_ui (ui_manager, + &icon_view->details->icon_merge_id, + &icon_view->details->icon_action_group); + } +} + +static void +fm_icon_view_update_menus (FMDirectoryView *view) +{ + FMIconView *icon_view; + GList *selection; + int selection_count; + GtkAction *action; + CajaIconContainer *icon_container; + gboolean editable; + + icon_view = FM_ICON_VIEW (view); + + FM_DIRECTORY_VIEW_CLASS (fm_icon_view_parent_class)->update_menus(view); + + selection = fm_directory_view_get_selection (view); + selection_count = g_list_length (selection); + icon_container = get_icon_container (icon_view); + + action = gtk_action_group_get_action (icon_view->details->icon_action_group, + FM_ACTION_STRETCH); + gtk_action_set_sensitive (action, + selection_count == 1 + && icon_container != NULL + && !caja_icon_container_has_stretch_handles (icon_container)); + + gtk_action_set_visible (action, + fm_icon_view_supports_scaling (icon_view)); + + action = gtk_action_group_get_action (icon_view->details->icon_action_group, + FM_ACTION_UNSTRETCH); + g_object_set (action, "label", + eel_g_list_more_than_one_item (selection) + ? _("Restore Icons' Original Si_zes") + : _("Restore Icon's Original Si_ze"), + NULL); + gtk_action_set_sensitive (action, + icon_container != NULL + && caja_icon_container_is_stretched (icon_container)); + + gtk_action_set_visible (action, + fm_icon_view_supports_scaling (icon_view)); + + caja_file_list_free (selection); + + editable = fm_directory_view_is_editable (view); + action = gtk_action_group_get_action (icon_view->details->icon_action_group, + FM_ACTION_MANUAL_LAYOUT); + gtk_action_set_sensitive (action, editable); +} + +static void +fm_icon_view_reset_to_defaults (FMDirectoryView *view) +{ + CajaIconContainer *icon_container; + FMIconView *icon_view; + + icon_view = FM_ICON_VIEW (view); + icon_container = get_icon_container (icon_view); + + clear_sort_criterion (icon_view); + caja_icon_container_set_keep_aligned + (icon_container, get_default_directory_keep_aligned ()); + caja_icon_container_set_tighter_layout + (icon_container, get_default_directory_tighter_layout ()); + + caja_icon_container_sort (icon_container); + + /* Switch to manual layout of the default calls for it. + * This needs to happen last for the sort order menus + * to be in sync. + */ + if (get_default_directory_manual_layout ()) + { + switch_to_manual_layout (icon_view); + } + + update_layout_menus (icon_view); + + fm_icon_view_restore_default_zoom_level (view); +} + +static void +fm_icon_view_select_all (FMDirectoryView *view) +{ + CajaIconContainer *icon_container; + + g_return_if_fail (FM_IS_ICON_VIEW (view)); + + icon_container = get_icon_container (FM_ICON_VIEW (view)); + caja_icon_container_select_all (icon_container); +} + +static void +fm_icon_view_reveal_selection (FMDirectoryView *view) +{ + GList *selection; + + g_return_if_fail (FM_IS_ICON_VIEW (view)); + + selection = fm_directory_view_get_selection (view); + + /* Make sure at least one of the selected items is scrolled into view */ + if (selection != NULL) + { + caja_icon_container_reveal + (get_icon_container (FM_ICON_VIEW (view)), + selection->data); + } + + caja_file_list_free (selection); +} + +static GArray * +fm_icon_view_get_selected_icon_locations (FMDirectoryView *view) +{ + g_return_val_if_fail (FM_IS_ICON_VIEW (view), NULL); + + return caja_icon_container_get_selected_icon_locations + (get_icon_container (FM_ICON_VIEW (view))); +} + + +static void +fm_icon_view_set_selection (FMDirectoryView *view, GList *selection) +{ + g_return_if_fail (FM_IS_ICON_VIEW (view)); + + caja_icon_container_set_selection + (get_icon_container (FM_ICON_VIEW (view)), selection); +} + +static void +fm_icon_view_invert_selection (FMDirectoryView *view) +{ + g_return_if_fail (FM_IS_ICON_VIEW (view)); + + caja_icon_container_invert_selection + (get_icon_container (FM_ICON_VIEW (view))); +} + +static gboolean +fm_icon_view_using_manual_layout (FMDirectoryView *view) +{ + g_return_val_if_fail (FM_IS_ICON_VIEW (view), FALSE); + + return !fm_icon_view_using_auto_layout (FM_ICON_VIEW (view)); +} + +static void +fm_icon_view_widget_to_file_operation_position (FMDirectoryView *view, + GdkPoint *position) +{ + g_assert (FM_IS_ICON_VIEW (view)); + + caja_icon_container_widget_to_file_operation_position + (get_icon_container (FM_ICON_VIEW (view)), position); +} + +static void +icon_container_activate_callback (CajaIconContainer *container, + GList *file_list, + FMIconView *icon_view) +{ + g_assert (FM_IS_ICON_VIEW (icon_view)); + g_assert (container == get_icon_container (icon_view)); + + fm_directory_view_activate_files (FM_DIRECTORY_VIEW (icon_view), + file_list, + CAJA_WINDOW_OPEN_ACCORDING_TO_MODE, 0, + TRUE); +} + +static void +icon_container_activate_alternate_callback (CajaIconContainer *container, + GList *file_list, + FMIconView *icon_view) +{ + GdkEvent *event; + GdkEventButton *button_event; + GdkEventKey *key_event; + gboolean open_in_tab; + CajaWindowInfo *window_info; + CajaWindowOpenFlags flags; + + g_assert (FM_IS_ICON_VIEW (icon_view)); + g_assert (container == get_icon_container (icon_view)); + + open_in_tab = FALSE; + + window_info = fm_directory_view_get_caja_window (FM_DIRECTORY_VIEW (icon_view)); + + if (caja_window_info_get_window_type (window_info) == CAJA_WINDOW_NAVIGATION) + { + event = gtk_get_current_event (); + 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_tab = (button_event->state & GDK_SHIFT_MASK) == 0; + } + 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 && + (key_event->state & GDK_CONTROL_MASK) != 0); + } + else + { + open_in_tab = TRUE; + } + } + + flags = CAJA_WINDOW_OPEN_FLAG_CLOSE_BEHIND; + if (open_in_tab) + { + flags |= CAJA_WINDOW_OPEN_FLAG_NEW_TAB; + } + else + { + flags |= CAJA_WINDOW_OPEN_FLAG_NEW_WINDOW; + } + + fm_directory_view_activate_files (FM_DIRECTORY_VIEW (icon_view), + file_list, + CAJA_WINDOW_OPEN_ACCORDING_TO_MODE, + flags, + TRUE); +} + +static void +band_select_started_callback (CajaIconContainer *container, + FMIconView *icon_view) +{ + g_assert (FM_IS_ICON_VIEW (icon_view)); + g_assert (container == get_icon_container (icon_view)); + + fm_directory_view_start_batching_selection_changes (FM_DIRECTORY_VIEW (icon_view)); +} + +static void +band_select_ended_callback (CajaIconContainer *container, + FMIconView *icon_view) +{ + g_assert (FM_IS_ICON_VIEW (icon_view)); + g_assert (container == get_icon_container (icon_view)); + + fm_directory_view_stop_batching_selection_changes (FM_DIRECTORY_VIEW (icon_view)); +} + +/* handle the preview signal by inspecting the mime type. For now, we only preview local sound files. */ + +static char ** +get_preview_argv (char *uri) +{ + char *command; + char **argv; + int i; + + command = g_find_program_in_path ("totem-audio-preview"); + if (command) + { + argv = g_new (char *, 3); + argv[0] = command; + argv[1] = g_strdup (uri); + argv[2] = NULL; + + return argv; + } + + command = g_find_program_in_path ("gst-launch-0.10"); + if (command) + { + argv = g_new (char *, 10); + i = 0; + argv[i++] = command; + argv[i++] = g_strdup ("playbin"); + argv[i++] = g_strconcat ("uri=", uri, NULL); + /* do not display videos */ + argv[i++] = g_strdup ("current-video=-1"); + argv[i++] = NULL; + return argv; + } + + return NULL; +} + +static void +audio_child_died (GPid pid, + gint status, + gpointer data) +{ + FMIconView *icon_view; + + icon_view = FM_ICON_VIEW (data); + + icon_view->details->audio_preview_child_watch = 0; + icon_view->details->audio_preview_child_pid = 0; +} + +/* here's the timer task that actually plays the file using mpg123, ogg123 or play. */ +/* FIXME bugzilla.gnome.org 41258: we should get the application from our mime-type stuff */ +static gboolean +play_file (gpointer callback_data) +{ + CajaFile *file; + FMIconView *icon_view; + GPid child_pid; + char **argv; + GError *error; + char *uri; + + icon_view = FM_ICON_VIEW (callback_data); + + /* Stop timeout */ + icon_view->details->audio_preview_timeout = 0; + + file = icon_view->details->audio_preview_file; + uri = caja_file_get_uri (file); + argv = get_preview_argv (uri); + g_free (uri); + if (argv == NULL) + { + return FALSE; + } + + error = NULL; + if (!g_spawn_async_with_pipes (NULL, + argv, + NULL, + G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL, + NULL, + NULL /* user_data */, + &child_pid, + NULL, NULL, NULL, + &error)) + { + g_strfreev (argv); + g_warning ("Error spawning sound preview: %s\n", error->message); + g_error_free (error); + return FALSE; + } + g_strfreev (argv); + + icon_view->details->audio_preview_child_watch = + g_child_watch_add (child_pid, + audio_child_died, NULL); + icon_view->details->audio_preview_child_pid = child_pid; + + return FALSE; +} + +/* FIXME bugzilla.gnome.org 42530: Hardcoding this here sucks. We should be using components + * for open ended things like this. + */ + +/* this routine is invoked from the preview signal handler to preview a sound file. We + want to wait a suitable delay until we actually do it, so set up a timer task to actually + start playing. If we move out before the task files, we remove it. */ + +static void +preview_audio (FMIconView *icon_view, CajaFile *file, gboolean start_flag) +{ + /* Stop current audio playback */ + if (icon_view->details->audio_preview_child_pid != 0) + { + kill (icon_view->details->audio_preview_child_pid, SIGTERM); + g_source_remove (icon_view->details->audio_preview_child_watch); + waitpid (icon_view->details->audio_preview_child_pid, NULL, 0); + icon_view->details->audio_preview_child_pid = 0; + } + + if (icon_view->details->audio_preview_timeout != 0) + { + g_source_remove (icon_view->details->audio_preview_timeout); + icon_view->details->audio_preview_timeout = 0; + } + + if (start_flag) + { + icon_view->details->audio_preview_file = file; + icon_view->details->audio_preview_timeout = g_timeout_add_seconds (1, play_file, icon_view); + } +} + +static gboolean +sound_preview_type_supported (CajaFile *file) +{ + char *mime_type; + guint i; + + mime_type = caja_file_get_mime_type (file); + if (mime_type == NULL) + { + return FALSE; + } + for (i = 0; i < G_N_ELEMENTS (audio_mime_types); i++) + { + if (g_content_type_is_a (mime_type, audio_mime_types[i])) + { + g_free (mime_type); + return TRUE; + } + } + + g_free (mime_type); + return FALSE; +} + + +static gboolean +should_preview_sound (CajaFile *file) +{ + GFile *location; + GFilesystemPreviewType use_preview; + + use_preview = caja_file_get_filesystem_use_preview (file); + + location = caja_file_get_location (file); + if (g_file_has_uri_scheme (location, "burn")) + { + g_object_unref (location); + return FALSE; + } + g_object_unref (location); + + /* Check user performance preference */ + if (preview_sound_auto_value == CAJA_SPEED_TRADEOFF_NEVER) + { + return FALSE; + } + + if (preview_sound_auto_value == CAJA_SPEED_TRADEOFF_ALWAYS) + { + if (use_preview == G_FILESYSTEM_PREVIEW_TYPE_NEVER) + { + return FALSE; + } + else + { + return TRUE; + } + } + + if (use_preview == G_FILESYSTEM_PREVIEW_TYPE_NEVER) + { + /* file system says to never preview anything */ + return FALSE; + } + else if (use_preview == G_FILESYSTEM_PREVIEW_TYPE_IF_LOCAL) + { + /* file system says we should treat file as if it's local */ + return TRUE; + } + else + { + /* only local files */ + return caja_file_is_local (file); + } +} + +static int +icon_container_preview_callback (CajaIconContainer *container, + CajaFile *file, + gboolean start_flag, + FMIconView *icon_view) +{ + int result; + char *file_name, *message; + + result = 0; + + /* preview files based on the mime_type. */ + /* at first, we just handle sounds */ + if (should_preview_sound (file)) + { + if (sound_preview_type_supported (file)) + { + result = 1; + preview_audio (icon_view, file, start_flag); + } + } + + /* Display file name in status area at low zoom levels, since + * the name is not displayed or hard to read in the icon view. + */ + if (fm_icon_view_get_zoom_level (FM_DIRECTORY_VIEW (icon_view)) <= CAJA_ZOOM_LEVEL_SMALLER) + { + if (start_flag) + { + file_name = caja_file_get_display_name (file); + message = g_strdup_printf (_("pointing at \"%s\""), file_name); + g_free (file_name); + caja_window_slot_info_set_status + (fm_directory_view_get_caja_window_slot (FM_DIRECTORY_VIEW (icon_view)), + message); + g_free (message); + } + else + { + fm_directory_view_display_selection_info (FM_DIRECTORY_VIEW(icon_view)); + } + } + + return result; +} + +static void +renaming_icon_callback (CajaIconContainer *container, + GtkWidget *widget, + gpointer callback_data) +{ + FMDirectoryView *directory_view; + + directory_view = FM_DIRECTORY_VIEW (callback_data); + caja_clipboard_set_up_editable + (GTK_EDITABLE (widget), + fm_directory_view_get_ui_manager (directory_view), + FALSE); +} + +int +fm_icon_view_compare_files (FMIconView *icon_view, + CajaFile *a, + CajaFile *b) +{ + return caja_file_compare_for_sort + (a, b, icon_view->details->sort->sort_type, + /* Use type-unsafe cast for performance */ + fm_directory_view_should_sort_directories_first ((FMDirectoryView *)icon_view), + icon_view->details->sort_reversed); +} + +static int +compare_files (FMDirectoryView *icon_view, + CajaFile *a, + CajaFile *b) +{ + return fm_icon_view_compare_files ((FMIconView *)icon_view, a, b); +} + + +void +fm_icon_view_filter_by_screen (FMIconView *icon_view, + gboolean filter) +{ + icon_view->details->filter_by_screen = filter; + icon_view->details->num_screens = gdk_display_get_n_screens (gtk_widget_get_display (GTK_WIDGET (icon_view))); +} + +static void +fm_icon_view_screen_changed (GtkWidget *widget, + GdkScreen *previous_screen) +{ + FMDirectoryView *view; + GList *files, *l; + CajaFile *file; + CajaDirectory *directory; + CajaIconContainer *icon_container; + + if (GTK_WIDGET_CLASS (fm_icon_view_parent_class)->screen_changed) + { + GTK_WIDGET_CLASS (fm_icon_view_parent_class)->screen_changed (widget, previous_screen); + } + + view = FM_DIRECTORY_VIEW (widget); + if (FM_ICON_VIEW (view)->details->filter_by_screen) + { + icon_container = get_icon_container (FM_ICON_VIEW (view)); + + directory = fm_directory_view_get_model (view); + files = caja_directory_get_file_list (directory); + + for (l = files; l != NULL; l = l->next) + { + file = l->data; + + if (!should_show_file_on_screen (view, file)) + { + fm_icon_view_remove_file (view, file, directory); + } + else + { + if (caja_icon_container_add (icon_container, + CAJA_ICON_CONTAINER_ICON_DATA (file))) + { + caja_file_ref (file); + } + } + } + + caja_file_list_unref (files); + g_list_free (files); + } +} + +static gboolean +fm_icon_view_scroll_event (GtkWidget *widget, + GdkEventScroll *scroll_event) +{ + FMIconView *icon_view; + GdkEvent *event_copy; + GdkEventScroll *scroll_event_copy; + gboolean ret; + + icon_view = FM_ICON_VIEW (widget); + + if (icon_view->details->compact && + (scroll_event->direction == GDK_SCROLL_UP || + scroll_event->direction == GDK_SCROLL_DOWN)) + { + ret = fm_directory_view_handle_scroll_event (FM_DIRECTORY_VIEW (icon_view), scroll_event); + if (!ret) + { + /* in column-wise layout, re-emit vertical mouse scroll events as horizontal ones, + * if they don't bump zoom */ + event_copy = gdk_event_copy ((GdkEvent *) scroll_event); + + scroll_event_copy = (GdkEventScroll *) event_copy; + if (scroll_event_copy->direction == GDK_SCROLL_UP) + { + scroll_event_copy->direction = GDK_SCROLL_LEFT; + } + else + { + scroll_event_copy->direction = GDK_SCROLL_RIGHT; + } + + ret = gtk_widget_event (widget, event_copy); + gdk_event_free (event_copy); + } + + return ret; + } + + return GTK_WIDGET_CLASS (fm_icon_view_parent_class)->scroll_event (widget, scroll_event); +} + +static void +selection_changed_callback (CajaIconContainer *container, + FMIconView *icon_view) +{ + g_assert (FM_IS_ICON_VIEW (icon_view)); + g_assert (container == get_icon_container (icon_view)); + + fm_directory_view_notify_selection_changed (FM_DIRECTORY_VIEW (icon_view)); +} + +static void +icon_container_context_click_selection_callback (CajaIconContainer *container, + GdkEventButton *event, + FMIconView *icon_view) +{ + g_assert (CAJA_IS_ICON_CONTAINER (container)); + g_assert (FM_IS_ICON_VIEW (icon_view)); + + fm_directory_view_pop_up_selection_context_menu + (FM_DIRECTORY_VIEW (icon_view), event); +} + +static void +icon_container_context_click_background_callback (CajaIconContainer *container, + GdkEventButton *event, + FMIconView *icon_view) +{ + g_assert (CAJA_IS_ICON_CONTAINER (container)); + g_assert (FM_IS_ICON_VIEW (icon_view)); + + fm_directory_view_pop_up_background_context_menu + (FM_DIRECTORY_VIEW (icon_view), event); +} + +static gboolean +fm_icon_view_react_to_icon_change_idle_callback (gpointer data) +{ + FMIconView *icon_view; + + g_assert (FM_IS_ICON_VIEW (data)); + + icon_view = FM_ICON_VIEW (data); + icon_view->details->react_to_icon_change_idle_id = 0; + + /* Rebuild the menus since some of them (e.g. Restore Stretched Icons) + * may be different now. + */ + fm_directory_view_update_menus (FM_DIRECTORY_VIEW (icon_view)); + + /* Don't call this again (unless rescheduled) */ + return FALSE; +} + +static void +icon_position_changed_callback (CajaIconContainer *container, + CajaFile *file, + const CajaIconPosition *position, + FMIconView *icon_view) +{ + char *position_string; + char scale_string[G_ASCII_DTOSTR_BUF_SIZE]; + + g_assert (FM_IS_ICON_VIEW (icon_view)); + g_assert (container == get_icon_container (icon_view)); + g_assert (CAJA_IS_FILE (file)); + + /* Schedule updating menus for the next idle. Doing it directly here + * noticeably slows down icon stretching. The other work here to + * store the icon position and scale does not seem to noticeably + * slow down icon stretching. It would be trickier to move to an + * idle call, because we'd have to keep track of potentially multiple + * sets of file/geometry info. + */ + if (fm_directory_view_get_active (FM_DIRECTORY_VIEW (icon_view)) && + icon_view->details->react_to_icon_change_idle_id == 0) + { + icon_view->details->react_to_icon_change_idle_id + = g_idle_add (fm_icon_view_react_to_icon_change_idle_callback, + icon_view); + } + + /* Store the new position of the icon in the metadata. */ + if (!fm_icon_view_using_auto_layout (icon_view)) + { + position_string = g_strdup_printf + ("%d,%d", position->x, position->y); + caja_file_set_metadata + (file, CAJA_METADATA_KEY_ICON_POSITION, + NULL, position_string); + g_free (position_string); + } + + + g_ascii_dtostr (scale_string, sizeof (scale_string), position->scale); + caja_file_set_metadata + (file, CAJA_METADATA_KEY_ICON_SCALE, + "1.0", scale_string); +} + +/* Attempt to change the filename to the new text. Notify user if operation fails. */ +static void +fm_icon_view_icon_text_changed_callback (CajaIconContainer *container, + CajaFile *file, + char *new_name, + FMIconView *icon_view) +{ + g_assert (CAJA_IS_FILE (file)); + g_assert (new_name != NULL); + + /* Don't allow a rename with an empty string. Revert to original + * without notifying the user. + */ + if (new_name[0] == '\0') + { + return; + } + fm_rename_file (file, new_name, NULL, NULL); +} + +static char * +get_icon_uri_callback (CajaIconContainer *container, + CajaFile *file, + FMIconView *icon_view) +{ + g_assert (CAJA_IS_ICON_CONTAINER (container)); + g_assert (CAJA_IS_FILE (file)); + g_assert (FM_IS_ICON_VIEW (icon_view)); + + return caja_file_get_uri (file); +} + +static char * +get_icon_drop_target_uri_callback (CajaIconContainer *container, + CajaFile *file, + FMIconView *icon_view) +{ + g_return_val_if_fail (CAJA_IS_ICON_CONTAINER (container), NULL); + g_return_val_if_fail (CAJA_IS_FILE (file), NULL); + g_return_val_if_fail (FM_IS_ICON_VIEW (icon_view), NULL); + + return caja_file_get_drop_target_uri (file); +} + +/* Preferences changed callbacks */ +static void +fm_icon_view_text_attribute_names_changed (FMDirectoryView *directory_view) +{ + g_assert (FM_IS_ICON_VIEW (directory_view)); + + caja_icon_container_request_update_all (get_icon_container (FM_ICON_VIEW (directory_view))); +} + +static void +fm_icon_view_embedded_text_policy_changed (FMDirectoryView *directory_view) +{ + g_assert (FM_IS_ICON_VIEW (directory_view)); + + caja_icon_container_request_update_all (get_icon_container (FM_ICON_VIEW (directory_view))); +} + +static void +fm_icon_view_image_display_policy_changed (FMDirectoryView *directory_view) +{ + g_assert (FM_IS_ICON_VIEW (directory_view)); + + caja_icon_container_request_update_all (get_icon_container (FM_ICON_VIEW (directory_view))); +} + +static void +fm_icon_view_click_policy_changed (FMDirectoryView *directory_view) +{ + g_assert (FM_IS_ICON_VIEW (directory_view)); + + fm_icon_view_update_click_mode (FM_ICON_VIEW (directory_view)); +} + +static void +fm_icon_view_emblems_changed (FMDirectoryView *directory_view) +{ + g_assert (FM_IS_ICON_VIEW (directory_view)); + + caja_icon_container_request_update_all (get_icon_container (FM_ICON_VIEW (directory_view))); +} + +static void +default_sort_order_changed_callback (gpointer callback_data) +{ + FMIconView *icon_view; + CajaFile *file; + char *sort_name; + CajaIconContainer *icon_container; + + g_return_if_fail (FM_IS_ICON_VIEW (callback_data)); + + icon_view = FM_ICON_VIEW (callback_data); + + file = fm_directory_view_get_directory_as_file (FM_DIRECTORY_VIEW (icon_view)); + sort_name = fm_icon_view_get_directory_sort_by (icon_view, file); + set_sort_criterion (icon_view, get_sort_criterion_by_metadata_text (sort_name)); + g_free (sort_name); + + icon_container = get_icon_container (icon_view); + g_return_if_fail (CAJA_IS_ICON_CONTAINER (icon_container)); + + caja_icon_container_request_update_all (icon_container); +} + +static void +default_sort_in_reverse_order_changed_callback (gpointer callback_data) +{ + FMIconView *icon_view; + CajaFile *file; + CajaIconContainer *icon_container; + + g_return_if_fail (FM_IS_ICON_VIEW (callback_data)); + + icon_view = FM_ICON_VIEW (callback_data); + + file = fm_directory_view_get_directory_as_file (FM_DIRECTORY_VIEW (icon_view)); + set_sort_reversed (icon_view, fm_icon_view_get_directory_sort_reversed (icon_view, file)); + icon_container = get_icon_container (icon_view); + g_return_if_fail (CAJA_IS_ICON_CONTAINER (icon_container)); + + caja_icon_container_request_update_all (icon_container); +} + +static void +default_use_tighter_layout_changed_callback (gpointer callback_data) +{ + FMIconView *icon_view; + CajaFile *file; + CajaIconContainer *icon_container; + + g_return_if_fail (FM_IS_ICON_VIEW (callback_data)); + + icon_view = FM_ICON_VIEW (callback_data); + + file = fm_directory_view_get_directory_as_file (FM_DIRECTORY_VIEW (icon_view)); + icon_container = get_icon_container (icon_view); + g_return_if_fail (CAJA_IS_ICON_CONTAINER (icon_container)); + + caja_icon_container_set_tighter_layout ( + icon_container, + fm_icon_view_get_directory_tighter_layout (icon_view, file)); + + caja_icon_container_request_update_all (icon_container); +} + +static void +default_use_manual_layout_changed_callback (gpointer callback_data) +{ + FMIconView *icon_view; + CajaFile *file; + CajaIconContainer *icon_container; + + g_return_if_fail (FM_IS_ICON_VIEW (callback_data)); + + icon_view = FM_ICON_VIEW (callback_data); + + file = fm_directory_view_get_directory_as_file (FM_DIRECTORY_VIEW (icon_view)); + icon_container = get_icon_container (icon_view); + g_return_if_fail (CAJA_IS_ICON_CONTAINER (icon_container)); + + caja_icon_container_set_auto_layout ( + icon_container, + fm_icon_view_get_directory_auto_layout (icon_view, file)); + + caja_icon_container_request_update_all (icon_container); +} + +static void +default_zoom_level_changed_callback (gpointer callback_data) +{ + FMIconView *icon_view; + CajaFile *file; + int level; + + g_return_if_fail (FM_IS_ICON_VIEW (callback_data)); + + icon_view = FM_ICON_VIEW (callback_data); + + if (fm_directory_view_supports_zooming (FM_DIRECTORY_VIEW (icon_view))) + { + file = fm_directory_view_get_directory_as_file (FM_DIRECTORY_VIEW (icon_view)); + + if (fm_icon_view_is_compact (icon_view)) + { + level = caja_file_get_integer_metadata (file, + CAJA_METADATA_KEY_COMPACT_VIEW_ZOOM_LEVEL, + get_default_zoom_level (icon_view)); + } + else + { + level = caja_file_get_integer_metadata (file, + CAJA_METADATA_KEY_ICON_VIEW_ZOOM_LEVEL, + get_default_zoom_level (icon_view)); + } + fm_directory_view_zoom_to_level (FM_DIRECTORY_VIEW (icon_view), level); + } +} + +static void +labels_beside_icons_changed_callback (gpointer callback_data) +{ + FMIconView *icon_view; + + g_return_if_fail (FM_IS_ICON_VIEW (callback_data)); + + icon_view = FM_ICON_VIEW (callback_data); + + set_labels_beside_icons (icon_view); +} + +static void +all_columns_same_width_changed_callback (gpointer callback_data) +{ + FMIconView *icon_view; + + g_assert (FM_IS_ICON_VIEW (callback_data)); + + icon_view = FM_ICON_VIEW (callback_data); + + set_columns_same_width (icon_view); +} + + +static void +fm_icon_view_sort_directories_first_changed (FMDirectoryView *directory_view) +{ + FMIconView *icon_view; + + icon_view = FM_ICON_VIEW (directory_view); + + if (fm_icon_view_using_auto_layout (icon_view)) + { + caja_icon_container_sort + (get_icon_container (icon_view)); + } +} + +/* GtkObject methods. */ + +static gboolean +icon_view_can_accept_item (CajaIconContainer *container, + CajaFile *target_item, + const char *item_uri, + FMDirectoryView *view) +{ + return fm_directory_view_can_accept_item (target_item, item_uri, view); +} + +static char * +icon_view_get_container_uri (CajaIconContainer *container, + FMDirectoryView *view) +{ + return fm_directory_view_get_uri (view); +} + +static void +icon_view_move_copy_items (CajaIconContainer *container, + const GList *item_uris, + GArray *relative_item_points, + const char *target_dir, + int copy_action, + int x, int y, + FMDirectoryView *view) +{ + caja_clipboard_clear_if_colliding_uris (GTK_WIDGET (view), + item_uris, + fm_directory_view_get_copied_files_atom (view)); + fm_directory_view_move_copy_items (item_uris, relative_item_points, target_dir, + copy_action, x, y, view); +} + +static void +fm_icon_view_update_click_mode (FMIconView *icon_view) +{ + CajaIconContainer *icon_container; + int click_mode; + + icon_container = get_icon_container (icon_view); + g_assert (icon_container != NULL); + + click_mode = eel_preferences_get_enum (CAJA_PREFERENCES_CLICK_POLICY); + + caja_icon_container_set_single_click_mode (icon_container, + click_mode == CAJA_CLICK_POLICY_SINGLE); +} + +static gboolean +get_stored_layout_timestamp (CajaIconContainer *container, + CajaIconData *icon_data, + time_t *timestamp, + FMIconView *view) +{ + CajaFile *file; + CajaDirectory *directory; + + if (icon_data == NULL) + { + directory = fm_directory_view_get_model (FM_DIRECTORY_VIEW (view)); + if (directory == NULL) + { + return FALSE; + } + + file = caja_directory_get_corresponding_file (directory); + *timestamp = caja_file_get_time_metadata (file, + CAJA_METADATA_KEY_ICON_VIEW_LAYOUT_TIMESTAMP); + caja_file_unref (file); + } + else + { + *timestamp = caja_file_get_time_metadata (CAJA_FILE (icon_data), + CAJA_METADATA_KEY_ICON_POSITION_TIMESTAMP); + } + + return TRUE; +} + +static gboolean +store_layout_timestamp (CajaIconContainer *container, + CajaIconData *icon_data, + const time_t *timestamp, + FMIconView *view) +{ + CajaFile *file; + CajaDirectory *directory; + + if (icon_data == NULL) + { + directory = fm_directory_view_get_model (FM_DIRECTORY_VIEW (view)); + if (directory == NULL) + { + return FALSE; + } + + file = caja_directory_get_corresponding_file (directory); + caja_file_set_time_metadata (file, + CAJA_METADATA_KEY_ICON_VIEW_LAYOUT_TIMESTAMP, + (time_t) *timestamp); + caja_file_unref (file); + } + else + { + caja_file_set_time_metadata (CAJA_FILE (icon_data), + CAJA_METADATA_KEY_ICON_POSITION_TIMESTAMP, + (time_t) *timestamp); + } + + return TRUE; +} + +static gboolean +focus_in_event_callback (GtkWidget *widget, GdkEventFocus *event, gpointer user_data) +{ + CajaWindowSlotInfo *slot_info; + FMIconView *icon_view = FM_ICON_VIEW (user_data); + + /* make the corresponding slot (and the pane that contains it) active */ + slot_info = fm_directory_view_get_caja_window_slot (FM_DIRECTORY_VIEW (icon_view)); + caja_window_slot_info_make_hosting_pane_active (slot_info); + + return FALSE; +} + +static CajaIconContainer * +create_icon_container (FMIconView *icon_view) +{ + CajaIconContainer *icon_container; + + icon_container = fm_icon_container_new (icon_view); + + gtk_widget_set_can_focus (GTK_WIDGET (icon_container), TRUE); + + g_signal_connect_object (icon_container, "focus_in_event", + G_CALLBACK (focus_in_event_callback), icon_view, 0); + g_signal_connect_object (icon_container, "activate", + G_CALLBACK (icon_container_activate_callback), icon_view, 0); + g_signal_connect_object (icon_container, "activate_alternate", + G_CALLBACK (icon_container_activate_alternate_callback), icon_view, 0); + g_signal_connect_object (icon_container, "band_select_started", + G_CALLBACK (band_select_started_callback), icon_view, 0); + g_signal_connect_object (icon_container, "band_select_ended", + G_CALLBACK (band_select_ended_callback), icon_view, 0); + g_signal_connect_object (icon_container, "context_click_selection", + G_CALLBACK (icon_container_context_click_selection_callback), icon_view, 0); + g_signal_connect_object (icon_container, "context_click_background", + G_CALLBACK (icon_container_context_click_background_callback), icon_view, 0); + g_signal_connect_object (icon_container, "icon_position_changed", + G_CALLBACK (icon_position_changed_callback), icon_view, 0); + g_signal_connect_object (icon_container, "icon_text_changed", + G_CALLBACK (fm_icon_view_icon_text_changed_callback), icon_view, 0); + g_signal_connect_object (icon_container, "selection_changed", + G_CALLBACK (selection_changed_callback), icon_view, 0); + /* FIXME: many of these should move into fm-icon-container as virtual methods */ + g_signal_connect_object (icon_container, "get_icon_uri", + G_CALLBACK (get_icon_uri_callback), icon_view, 0); + g_signal_connect_object (icon_container, "get_icon_drop_target_uri", + G_CALLBACK (get_icon_drop_target_uri_callback), icon_view, 0); + g_signal_connect_object (icon_container, "move_copy_items", + G_CALLBACK (icon_view_move_copy_items), icon_view, 0); + g_signal_connect_object (icon_container, "get_container_uri", + G_CALLBACK (icon_view_get_container_uri), icon_view, 0); + g_signal_connect_object (icon_container, "can_accept_item", + G_CALLBACK (icon_view_can_accept_item), icon_view, 0); + g_signal_connect_object (icon_container, "get_stored_icon_position", + G_CALLBACK (get_stored_icon_position_callback), icon_view, 0); + g_signal_connect_object (icon_container, "layout_changed", + G_CALLBACK (layout_changed_callback), icon_view, 0); + g_signal_connect_object (icon_container, "preview", + G_CALLBACK (icon_container_preview_callback), icon_view, 0); + g_signal_connect_object (icon_container, "renaming_icon", + G_CALLBACK (renaming_icon_callback), icon_view, 0); + g_signal_connect_object (icon_container, "icon_stretch_started", + G_CALLBACK (fm_directory_view_update_menus), icon_view, + G_CONNECT_SWAPPED); + g_signal_connect_object (icon_container, "icon_stretch_ended", + G_CALLBACK (fm_directory_view_update_menus), icon_view, + G_CONNECT_SWAPPED); + + g_signal_connect_object (icon_container, "get_stored_layout_timestamp", + G_CALLBACK (get_stored_layout_timestamp), icon_view, 0); + g_signal_connect_object (icon_container, "store_layout_timestamp", + G_CALLBACK (store_layout_timestamp), icon_view, 0); + + gtk_container_add (GTK_CONTAINER (icon_view), + GTK_WIDGET (icon_container)); + + fm_icon_view_update_click_mode (icon_view); + + gtk_widget_show (GTK_WIDGET (icon_container)); + + return icon_container; +} + +/* Handles an URL received from Mozilla */ +static void +icon_view_handle_netscape_url (CajaIconContainer *container, const char *encoded_url, + const char *target_uri, + GdkDragAction action, int x, int y, FMIconView *view) +{ + fm_directory_view_handle_netscape_url_drop (FM_DIRECTORY_VIEW (view), + encoded_url, target_uri, action, x, y); +} + +static void +icon_view_handle_uri_list (CajaIconContainer *container, const char *item_uris, + const char *target_uri, + GdkDragAction action, int x, int y, FMIconView *view) +{ + fm_directory_view_handle_uri_list_drop (FM_DIRECTORY_VIEW (view), + item_uris, target_uri, action, x, y); +} + +static void +icon_view_handle_text (CajaIconContainer *container, const char *text, + const char *target_uri, + GdkDragAction action, int x, int y, FMIconView *view) +{ + fm_directory_view_handle_text_drop (FM_DIRECTORY_VIEW (view), + text, target_uri, action, x, y); +} + +static void +icon_view_handle_raw (CajaIconContainer *container, const char *raw_data, + int length, const char *target_uri, const char *direct_save_uri, + GdkDragAction action, int x, int y, FMIconView *view) +{ + fm_directory_view_handle_raw_drop (FM_DIRECTORY_VIEW (view), + raw_data, length, target_uri, direct_save_uri, action, x, y); +} + +static char * +icon_view_get_first_visible_file (CajaView *view) +{ + CajaFile *file; + FMIconView *icon_view; + + icon_view = FM_ICON_VIEW (view); + + file = CAJA_FILE (caja_icon_container_get_first_visible_icon (get_icon_container (icon_view))); + + if (file) + { + return caja_file_get_uri (file); + } + + return NULL; +} + +static void +icon_view_scroll_to_file (CajaView *view, + const char *uri) +{ + CajaFile *file; + FMIconView *icon_view; + + icon_view = FM_ICON_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 = caja_file_get_existing_by_uri (uri); + if (file != NULL) + { + caja_icon_container_scroll_to_icon (get_icon_container (icon_view), + CAJA_ICON_CONTAINER_ICON_DATA (file)); + caja_file_unref (file); + } + } +} + +static void +fm_icon_view_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + FMIconView *icon_view; + + icon_view = FM_ICON_VIEW (object); + + switch (prop_id) + { + case PROP_COMPACT: + icon_view->details->compact = g_value_get_boolean (value); + if (icon_view->details->compact) + { + caja_icon_container_set_layout_mode (get_icon_container (icon_view), + gtk_widget_get_direction (GTK_WIDGET(icon_view)) == GTK_TEXT_DIR_RTL ? + CAJA_ICON_LAYOUT_T_B_R_L : + CAJA_ICON_LAYOUT_T_B_L_R); + caja_icon_container_set_forced_icon_size (get_icon_container (icon_view), + CAJA_ICON_SIZE_SMALLEST); + } + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + + + +static void +fm_icon_view_class_init (FMIconViewClass *klass) +{ + FMDirectoryViewClass *fm_directory_view_class; + + fm_directory_view_class = FM_DIRECTORY_VIEW_CLASS (klass); + + G_OBJECT_CLASS (klass)->set_property = fm_icon_view_set_property; + G_OBJECT_CLASS (klass)->finalize = fm_icon_view_finalize; + + GTK_OBJECT_CLASS (klass)->destroy = fm_icon_view_destroy; + + GTK_WIDGET_CLASS (klass)->screen_changed = fm_icon_view_screen_changed; + GTK_WIDGET_CLASS (klass)->scroll_event = fm_icon_view_scroll_event; + + fm_directory_view_class->add_file = fm_icon_view_add_file; + fm_directory_view_class->flush_added_files = fm_icon_view_flush_added_files; + fm_directory_view_class->begin_loading = fm_icon_view_begin_loading; + fm_directory_view_class->bump_zoom_level = fm_icon_view_bump_zoom_level; + fm_directory_view_class->can_rename_file = fm_icon_view_can_rename_file; + fm_directory_view_class->can_zoom_in = fm_icon_view_can_zoom_in; + fm_directory_view_class->can_zoom_out = fm_icon_view_can_zoom_out; + fm_directory_view_class->clear = fm_icon_view_clear; + fm_directory_view_class->end_loading = fm_icon_view_end_loading; + fm_directory_view_class->file_changed = fm_icon_view_file_changed; + fm_directory_view_class->get_background_widget = fm_icon_view_get_background_widget; + fm_directory_view_class->get_selected_icon_locations = fm_icon_view_get_selected_icon_locations; + fm_directory_view_class->get_selection = fm_icon_view_get_selection; + fm_directory_view_class->get_selection_for_file_transfer = fm_icon_view_get_selection; + fm_directory_view_class->get_item_count = fm_icon_view_get_item_count; + fm_directory_view_class->is_empty = fm_icon_view_is_empty; + fm_directory_view_class->remove_file = fm_icon_view_remove_file; + fm_directory_view_class->reset_to_defaults = fm_icon_view_reset_to_defaults; + fm_directory_view_class->restore_default_zoom_level = fm_icon_view_restore_default_zoom_level; + fm_directory_view_class->reveal_selection = fm_icon_view_reveal_selection; + fm_directory_view_class->select_all = fm_icon_view_select_all; + fm_directory_view_class->set_selection = fm_icon_view_set_selection; + fm_directory_view_class->invert_selection = fm_icon_view_invert_selection; + fm_directory_view_class->compare_files = compare_files; + fm_directory_view_class->zoom_to_level = fm_icon_view_zoom_to_level; + fm_directory_view_class->get_zoom_level = fm_icon_view_get_zoom_level; + fm_directory_view_class->click_policy_changed = fm_icon_view_click_policy_changed; + fm_directory_view_class->embedded_text_policy_changed = fm_icon_view_embedded_text_policy_changed; + fm_directory_view_class->emblems_changed = fm_icon_view_emblems_changed; + fm_directory_view_class->image_display_policy_changed = fm_icon_view_image_display_policy_changed; + fm_directory_view_class->merge_menus = fm_icon_view_merge_menus; + fm_directory_view_class->unmerge_menus = fm_icon_view_unmerge_menus; + fm_directory_view_class->sort_directories_first_changed = fm_icon_view_sort_directories_first_changed; + fm_directory_view_class->start_renaming_file = fm_icon_view_start_renaming_file; + fm_directory_view_class->text_attribute_names_changed = fm_icon_view_text_attribute_names_changed; + fm_directory_view_class->update_menus = fm_icon_view_update_menus; + fm_directory_view_class->using_manual_layout = fm_icon_view_using_manual_layout; + fm_directory_view_class->widget_to_file_operation_position = fm_icon_view_widget_to_file_operation_position; + + klass->clean_up = fm_icon_view_real_clean_up; + klass->supports_auto_layout = real_supports_auto_layout; + klass->supports_scaling = real_supports_scaling; + klass->supports_manual_layout = real_supports_manual_layout; + klass->supports_keep_aligned = real_supports_keep_aligned; + klass->supports_labels_beside_icons = real_supports_labels_beside_icons; + klass->get_directory_auto_layout = fm_icon_view_real_get_directory_auto_layout; + klass->get_directory_sort_by = fm_icon_view_real_get_directory_sort_by; + klass->get_directory_sort_reversed = fm_icon_view_real_get_directory_sort_reversed; + klass->get_directory_tighter_layout = fm_icon_view_real_get_directory_tighter_layout; + klass->set_directory_auto_layout = fm_icon_view_real_set_directory_auto_layout; + klass->set_directory_sort_by = fm_icon_view_real_set_directory_sort_by; + klass->set_directory_sort_reversed = fm_icon_view_real_set_directory_sort_reversed; + klass->set_directory_tighter_layout = fm_icon_view_real_set_directory_tighter_layout; + + g_object_class_install_property (G_OBJECT_CLASS (klass), + PROP_COMPACT, + g_param_spec_boolean ("compact", + "Compact", + "Whether this view provides a compact listing", + FALSE, + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY)); + +} + +static const char * +fm_icon_view_get_id (CajaView *view) +{ + if (FM_IS_DESKTOP_ICON_VIEW (view)) + { + return FM_DESKTOP_ICON_VIEW_ID; + } + + if (fm_icon_view_is_compact (FM_ICON_VIEW (view))) + { + return FM_COMPACT_VIEW_ID; + } + + return FM_ICON_VIEW_ID; +} + +static void +fm_icon_view_iface_init (CajaViewIface *iface) +{ + fm_directory_view_init_view_iface (iface); + + iface->get_view_id = fm_icon_view_get_id; + iface->get_first_visible_file = icon_view_get_first_visible_file; + iface->scroll_to_file = icon_view_scroll_to_file; + iface->get_title = NULL; +} + +static void +fm_icon_view_init (FMIconView *icon_view) +{ + static gboolean setup_sound_preview = FALSE; + CajaIconContainer *icon_container; + + g_return_if_fail (gtk_bin_get_child (GTK_BIN (icon_view)) == NULL); + + icon_view->details = g_new0 (FMIconViewDetails, 1); + icon_view->details->sort = &sort_criteria[0]; + icon_view->details->filter_by_screen = FALSE; + + icon_container = create_icon_container (icon_view); + + /* Set our default layout mode */ + caja_icon_container_set_layout_mode (icon_container, + gtk_widget_get_direction (GTK_WIDGET(icon_container)) == GTK_TEXT_DIR_RTL ? + CAJA_ICON_LAYOUT_R_L_T_B : + CAJA_ICON_LAYOUT_L_R_T_B); + + if (!setup_sound_preview) + { + eel_preferences_add_auto_enum (CAJA_PREFERENCES_PREVIEW_SOUND, + &preview_sound_auto_value); + + setup_sound_preview = TRUE; + } + + eel_preferences_add_callback_while_alive (CAJA_PREFERENCES_ICON_VIEW_DEFAULT_SORT_ORDER, + default_sort_order_changed_callback, + icon_view, G_OBJECT (icon_view)); + eel_preferences_add_callback_while_alive (CAJA_PREFERENCES_ICON_VIEW_DEFAULT_SORT_IN_REVERSE_ORDER, + default_sort_in_reverse_order_changed_callback, + icon_view, G_OBJECT (icon_view)); + eel_preferences_add_callback_while_alive (CAJA_PREFERENCES_ICON_VIEW_DEFAULT_USE_TIGHTER_LAYOUT, + default_use_tighter_layout_changed_callback, + icon_view, G_OBJECT (icon_view)); + eel_preferences_add_callback_while_alive (CAJA_PREFERENCES_ICON_VIEW_DEFAULT_USE_MANUAL_LAYOUT, + default_use_manual_layout_changed_callback, + icon_view, G_OBJECT (icon_view)); + eel_preferences_add_callback_while_alive (CAJA_PREFERENCES_ICON_VIEW_DEFAULT_ZOOM_LEVEL, + default_zoom_level_changed_callback, + icon_view, G_OBJECT (icon_view)); + eel_preferences_add_callback_while_alive (CAJA_PREFERENCES_ICON_VIEW_LABELS_BESIDE_ICONS, + labels_beside_icons_changed_callback, + icon_view, G_OBJECT (icon_view)); + + eel_preferences_add_callback_while_alive (CAJA_PREFERENCES_COMPACT_VIEW_DEFAULT_ZOOM_LEVEL, + default_zoom_level_changed_callback, + icon_view, G_OBJECT (icon_view)); + eel_preferences_add_callback_while_alive (CAJA_PREFERENCES_COMPACT_VIEW_ALL_COLUMNS_SAME_WIDTH, + all_columns_same_width_changed_callback, + icon_view, G_OBJECT (icon_view)); + + g_signal_connect_object (get_icon_container (icon_view), "handle_netscape_url", + G_CALLBACK (icon_view_handle_netscape_url), icon_view, 0); + g_signal_connect_object (get_icon_container (icon_view), "handle_uri_list", + G_CALLBACK (icon_view_handle_uri_list), icon_view, 0); + g_signal_connect_object (get_icon_container (icon_view), "handle_text", + G_CALLBACK (icon_view_handle_text), icon_view, 0); + g_signal_connect_object (get_icon_container (icon_view), "handle_raw", + G_CALLBACK (icon_view_handle_raw), icon_view, 0); + + icon_view->details->clipboard_handler_id = + g_signal_connect (caja_clipboard_monitor_get (), + "clipboard_info", + G_CALLBACK (icon_view_notify_clipboard_info), icon_view); +} + +static CajaView * +fm_icon_view_create (CajaWindowSlotInfo *slot) +{ + FMIconView *view; + + view = g_object_new (FM_TYPE_ICON_VIEW, + "window-slot", slot, + "compact", FALSE, + NULL); + return CAJA_VIEW (view); +} + +static CajaView * +fm_compact_view_create (CajaWindowSlotInfo *slot) +{ + FMIconView *view; + + view = g_object_new (FM_TYPE_ICON_VIEW, + "window-slot", slot, + "compact", TRUE, + NULL); + return CAJA_VIEW (view); +} + +static gboolean +fm_icon_view_supports_uri (const char *uri, + GFileType file_type, + const char *mime_type) +{ + if (file_type == G_FILE_TYPE_DIRECTORY) + { + return TRUE; + } + if (strcmp (mime_type, CAJA_SAVED_SEARCH_MIMETYPE) == 0) + { + return TRUE; + } + if (g_str_has_prefix (uri, "trash:")) + { + return TRUE; + } + if (g_str_has_prefix (uri, EEL_SEARCH_URI)) + { + return TRUE; + } + + return FALSE; +} + +#define TRANSLATE_VIEW_INFO(view_info) \ + view_info.view_combo_label = _(view_info.view_combo_label); \ + view_info.view_menu_label_with_mnemonic = _(view_info.view_menu_label_with_mnemonic); \ + view_info.error_label = _(view_info.error_label); \ + view_info.startup_error_label = _(view_info.startup_error_label); \ + view_info.display_location_label = _(view_info.display_location_label); \ + + +static CajaViewInfo fm_icon_view = +{ + FM_ICON_VIEW_ID, + /* translators: this is used in the view selection dropdown + * of navigation windows and in the preferences dialog */ + N_("Icon View"), + /* translators: this is used in the view menu */ + N_("_Icons"), + N_("The icon view encountered an error."), + N_("The icon view encountered an error while starting up."), + N_("Display this location with the icon view."), + fm_icon_view_create, + fm_icon_view_supports_uri +}; + +static CajaViewInfo fm_compact_view = +{ + FM_COMPACT_VIEW_ID, + /* translators: this is used in the view selection dropdown + * of navigation windows and in the preferences dialog */ + N_("Compact View"), + /* translators: this is used in the view menu */ + N_("_Compact"), + N_("The compact view encountered an error."), + N_("The compact view encountered an error while starting up."), + N_("Display this location with the compact view."), + fm_compact_view_create, + fm_icon_view_supports_uri +}; + +gboolean +fm_icon_view_is_compact (FMIconView *view) +{ + return view->details->compact; +} + +void +fm_icon_view_register (void) +{ + TRANSLATE_VIEW_INFO (fm_icon_view) + caja_view_factory_register (&fm_icon_view); +} + +void +fm_compact_view_register (void) +{ + TRANSLATE_VIEW_INFO (fm_compact_view) + caja_view_factory_register (&fm_compact_view); +} + |