diff options
author | Georges Basile Stavracas Neto <georges.stavracas@gmail.com> | 2015-08-16 17:42:39 -0300 |
---|---|---|
committer | Georges Basile Stavracas Neto <georges.stavracas@gmail.com> | 2015-08-17 09:27:46 -0300 |
commit | a96615f8f86774033941cb50c9d210b08895ba27 (patch) | |
tree | fe067d08d949efae9c39d45cd7adae1ce20d23b5 /src/nautilus-view.c | |
parent | 271f45a5d304a436f3d369e6b3b984aeb77ab1ba (diff) | |
download | nautilus-a96615f8f86774033941cb50c9d210b08895ba27.tar.gz |
files-view: rename from NautilusView
NautilusView is the proposed name for the new
interface that will cover NautilusFilesView and
NautilusPlacesView.
The current NautilusView name, however, will crash
with the proposed interface name.
Fix that by changing the class name to NautilusFilesView.
As an easter egg, makes it match the current Nautilus
code style.
Diffstat (limited to 'src/nautilus-view.c')
-rw-r--r-- | src/nautilus-view.c | 8113 |
1 files changed, 0 insertions, 8113 deletions
diff --git a/src/nautilus-view.c b/src/nautilus-view.c deleted file mode 100644 index 752334f4d..000000000 --- a/src/nautilus-view.c +++ /dev/null @@ -1,8113 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ - -/* nautilus-view.c - * - * Copyright (C) 1999, 2000 Free Software Foundation - * Copyright (C) 2000, 2001 Eazel, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program 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 - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, see <http://www.gnu.org/licenses/>. - * - * Authors: Ettore Perazzoli, - * John Sullivan <sullivan@eazel.com>, - * Darin Adler <darin@bentspoon.com>, - * Pavel Cisler <pavel@eazel.com>, - * David Emory Watson <dwatson@cs.ucr.edu> - */ - -#include <config.h> - -#include "nautilus-view.h" - -#include "nautilus-application.h" -#include "nautilus-desktop-canvas-view.h" -#include "nautilus-error-reporting.h" -#include "nautilus-floating-bar.h" -#include "nautilus-list-view.h" -#include "nautilus-mime-actions.h" -#include "nautilus-previewer.h" -#include "nautilus-properties-window.h" -#include "nautilus-window.h" -#include "nautilus-toolbar.h" - -#if ENABLE_EMPTY_VIEW -#include "nautilus-empty-view.h" -#endif - -#ifdef HAVE_X11_XF86KEYSYM_H -#include <X11/XF86keysym.h> -#endif - -#include <gdk/gdkx.h> -#include <gdk/gdkkeysyms.h> -#include <gtk/gtk.h> -#include <glib/gi18n.h> -#include <glib/gstdio.h> -#include <gio/gio.h> -#include <math.h> -#include <string.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> - -#include <eel/eel-glib-extensions.h> -#include <eel/eel-gnome-extensions.h> -#include <eel/eel-gtk-extensions.h> -#include <eel/eel-stock-dialogs.h> -#include <eel/eel-string.h> -#include <eel/eel-vfs-extensions.h> - -#include <libnautilus-extension/nautilus-menu-provider.h> -#include <libnautilus-private/nautilus-clipboard.h> -#include <libnautilus-private/nautilus-clipboard-monitor.h> -#include <libnautilus-private/nautilus-desktop-icon-file.h> -#include <libnautilus-private/nautilus-desktop-directory.h> -#include <libnautilus-private/nautilus-search-directory.h> -#include <libnautilus-private/nautilus-directory.h> -#include <libnautilus-private/nautilus-dnd.h> -#include <libnautilus-private/nautilus-file-attributes.h> -#include <libnautilus-private/nautilus-file-changes-queue.h> -#include <libnautilus-private/nautilus-file-dnd.h> -#include <libnautilus-private/nautilus-file-operations.h> -#include <libnautilus-private/nautilus-file-utilities.h> -#include <libnautilus-private/nautilus-file-private.h> -#include <libnautilus-private/nautilus-global-preferences.h> -#include <libnautilus-private/nautilus-link.h> -#include <libnautilus-private/nautilus-metadata.h> -#include <libnautilus-private/nautilus-recent.h> -#include <libnautilus-private/nautilus-module.h> -#include <libnautilus-private/nautilus-profile.h> -#include <libnautilus-private/nautilus-program-choosing.h> -#include <libnautilus-private/nautilus-trash-monitor.h> -#include <libnautilus-private/nautilus-ui-utilities.h> -#include <libnautilus-private/nautilus-signaller.h> -#include <libnautilus-private/nautilus-icon-names.h> - -#define GNOME_DESKTOP_USE_UNSTABLE_API -#include <gdesktop-enums.h> - -#define DEBUG_FLAG NAUTILUS_DEBUG_DIRECTORY_VIEW -#include <libnautilus-private/nautilus-debug.h> - -/* Minimum starting update inverval */ -#define UPDATE_INTERVAL_MIN 100 -/* Maximum update interval */ -#define UPDATE_INTERVAL_MAX 2000 -/* Amount of miliseconds the update interval is increased */ -#define UPDATE_INTERVAL_INC 250 -/* Interval at which the update interval is increased */ -#define UPDATE_INTERVAL_TIMEOUT_INTERVAL 250 -/* Milliseconds that have to pass without a change to reset the update interval */ -#define UPDATE_INTERVAL_RESET 1000 - -#define SILENT_WINDOW_OPEN_LIMIT 5 - -#define DUPLICATE_HORIZONTAL_ICON_OFFSET 70 -#define DUPLICATE_VERTICAL_ICON_OFFSET 30 - -#define MAX_QUEUED_UPDATES 500 - -#define MAX_MENU_LEVELS 5 -#define TEMPLATE_LIMIT 30 - -/* Delay to show the duplicated label when creating a folder */ -#define FILE_NAME_DUPLICATED_LABEL_TIMEOUT 500 - -/* Delay to show the Loading... floating bar */ -#define FLOATING_BAR_LOADING_DELAY 500 /* ms */ - -enum { - ADD_FILE, - BEGIN_FILE_CHANGES, - BEGIN_LOADING, - CLEAR, - END_FILE_CHANGES, - END_LOADING, - FILE_CHANGED, - MOVE_COPY_ITEMS, - REMOVE_FILE, - SELECTION_CHANGED, - TRASH, - DELETE, - LAST_SIGNAL -}; - -enum { - PROP_WINDOW_SLOT = 1, - PROP_SUPPORTS_ZOOMING, - PROP_ICON, - PROP_VIEW_WIDGET, - NUM_PROPERTIES -}; - -static guint signals[LAST_SIGNAL]; -static GParamSpec *properties[NUM_PROPERTIES] = { NULL, }; - -static GdkAtom copied_files_atom; - -static char *scripts_directory_uri = NULL; -static int scripts_directory_uri_length; - -struct NautilusViewDetails -{ - NautilusWindowSlot *slot; - NautilusDirectory *model; - NautilusFile *directory_as_file; - guint dir_merge_id; - - gint duplicated_label_timeout_id; - GtkWidget *rename_file_popover; - - gboolean supports_zooming; - - GList *scripts_directory_list; - GList *templates_directory_list; - - guint display_selection_idle_id; - guint update_context_menus_timeout_id; - guint update_status_idle_id; - guint reveal_selection_idle_id; - - guint display_pending_source_id; - guint changes_timeout_id; - - guint update_interval; - guint64 last_queued; - - guint files_added_handler_id; - guint files_changed_handler_id; - guint load_error_handler_id; - guint done_loading_handler_id; - guint file_changed_handler_id; - - GList *new_added_files; - GList *new_changed_files; - - GHashTable *non_ready_files; - - GList *old_added_files; - GList *old_changed_files; - - GList *pending_selection; - - /* whether we are in the active slot */ - gboolean active; - - /* loading indicates whether this view has begun loading a directory. - * This flag should need not be set inside subclasses. NautilusView automatically - * sets 'loading' to TRUE before it begins loading a directory's contents and to FALSE - * after it finishes loading the directory and its view. - */ - gboolean loading; - gboolean templates_present; - gboolean scripts_present; - - gboolean sort_directories_first; - - gboolean show_foreign_files; - gboolean show_hidden_files; - gboolean ignore_hidden_file_preferences; - - gboolean batching_selection_level; - gboolean selection_changed_while_batched; - - gboolean selection_was_removed; - - gboolean metadata_for_directory_as_file_pending; - gboolean metadata_for_files_in_directory_pending; - - GList *subdirectory_list; - - GdkPoint context_menu_position; - - GMenu *selection_menu; - GMenu *background_menu; - - GActionGroup *view_action_group; - - GtkWidget *scrolled_window; - - /* Empty states */ - GtkWidget *folder_is_empty_widget; - GtkWidget *no_search_results_widget; - - /* Floating bar */ - guint floating_bar_set_status_timeout_id; - guint floating_bar_loading_timeout_id; - GtkWidget *floating_bar; - - /* View menu */ - GtkWidget *view_menu_widget; - GtkWidget *view_icon; - GtkWidget *sort_menu; - GtkWidget *sort_trash_time; - GtkWidget *sort_search_relevance; - GtkWidget *visible_columns; - GtkWidget *stop; - GtkWidget *reload; - GtkAdjustment *zoom_adjustment; - GtkWidget *zoom_level_scale; - - gulong stop_signal_handler; - gulong reload_signal_handler; -}; - -typedef struct { - NautilusFile *file; - NautilusDirectory *directory; -} FileAndDirectory; - -/* forward declarations */ - -static gboolean display_selection_info_idle_callback (gpointer data); -static void trash_or_delete_files (GtkWindow *parent_window, - const GList *files, - NautilusView *view); -static void load_directory (NautilusView *view, - NautilusDirectory *directory); -static void clipboard_changed_callback (NautilusClipboardMonitor *monitor, - NautilusView *view); -static void open_one_in_new_window (gpointer data, - gpointer callback_data); -static void schedule_update_context_menus (NautilusView *view); -static void remove_update_context_menus_timeout_callback (NautilusView *view); -static void schedule_update_status (NautilusView *view); -static void remove_update_status_idle_callback (NautilusView *view); -static void reset_update_interval (NautilusView *view); -static void schedule_idle_display_of_pending_files (NautilusView *view); -static void unschedule_display_of_pending_files (NautilusView *view); -static void disconnect_model_handlers (NautilusView *view); -static void metadata_for_directory_as_file_ready_callback (NautilusFile *file, - gpointer callback_data); -static void metadata_for_files_in_directory_ready_callback (NautilusDirectory *directory, - GList *files, - gpointer callback_data); -static void nautilus_view_trash_state_changed_callback (NautilusTrashMonitor *trash, - gboolean state, - gpointer callback_data); -static void nautilus_view_select_file (NautilusView *view, - NautilusFile *file); - -static void update_templates_directory (NautilusView *view); - -static void check_empty_states (NautilusView *view); - -G_DEFINE_TYPE (NautilusView, nautilus_view, GTK_TYPE_OVERLAY); - -static const struct { - unsigned int keyval; - const char *action; -} extra_view_keybindings [] = { -#ifdef HAVE_X11_XF86KEYSYM_H - /* View actions */ - { XF86XK_ZoomIn, "zoom-in" }, - { XF86XK_ZoomOut, "zoom-out" }, - -#endif -}; - -static void -check_empty_states (NautilusView *view) -{ - GList *files; - GList *filtered; - gboolean show_hidden_files; - - gtk_widget_hide (view->details->no_search_results_widget); - gtk_widget_hide (view->details->folder_is_empty_widget); - if (!view->details->loading && view->details->model) { - files = nautilus_directory_get_file_list (view->details->model); - show_hidden_files = g_settings_get_boolean (gtk_filechooser_preferences, - NAUTILUS_PREFERENCES_SHOW_HIDDEN_FILES); - filtered = nautilus_file_list_filter_hidden (files, show_hidden_files); - if (g_list_length (filtered) == 0) { - if (nautilus_view_is_search (view)) { - gtk_widget_show (view->details->no_search_results_widget); - } else { - gtk_widget_show (view->details->folder_is_empty_widget); - } - } - nautilus_file_list_unref (filtered); - nautilus_file_list_unref (files); - } -} - -/* - * Floating Bar code - */ -static void -remove_loading_floating_bar (NautilusView *view) -{ - if (view->details->floating_bar_loading_timeout_id != 0) { - g_source_remove (view->details->floating_bar_loading_timeout_id); - view->details->floating_bar_loading_timeout_id = 0; - } - - gtk_widget_hide (view->details->floating_bar); - nautilus_floating_bar_cleanup_actions (NAUTILUS_FLOATING_BAR (view->details->floating_bar)); -} - -static void -real_setup_loading_floating_bar (NautilusView *view) -{ - gboolean disable_chrome; - - g_object_get (nautilus_view_get_window (view), - "disable-chrome", &disable_chrome, - NULL); - - if (disable_chrome) { - gtk_widget_hide (view->details->floating_bar); - return; - } - - nautilus_floating_bar_cleanup_actions (NAUTILUS_FLOATING_BAR (view->details->floating_bar)); - nautilus_floating_bar_set_primary_label (NAUTILUS_FLOATING_BAR (view->details->floating_bar), - nautilus_view_is_search (view) ? _("Searching…") : _("Loading…")); - nautilus_floating_bar_set_details_label (NAUTILUS_FLOATING_BAR (view->details->floating_bar), NULL); - nautilus_floating_bar_set_show_spinner (NAUTILUS_FLOATING_BAR (view->details->floating_bar), view->details->loading); - nautilus_floating_bar_add_action (NAUTILUS_FLOATING_BAR (view->details->floating_bar), - "process-stop-symbolic", - NAUTILUS_FLOATING_BAR_ACTION_ID_STOP); - - gtk_widget_set_halign (view->details->floating_bar, GTK_ALIGN_END); - gtk_widget_show (view->details->floating_bar); -} - -static gboolean -setup_loading_floating_bar_timeout_cb (gpointer user_data) -{ - NautilusView *view = user_data; - - view->details->floating_bar_loading_timeout_id = 0; - real_setup_loading_floating_bar (view); - - return FALSE; -} - -static void -setup_loading_floating_bar (NautilusView *view) -{ - /* setup loading overlay */ - if (view->details->floating_bar_set_status_timeout_id != 0) { - g_source_remove (view->details->floating_bar_set_status_timeout_id); - view->details->floating_bar_set_status_timeout_id = 0; - } - - if (view->details->floating_bar_loading_timeout_id != 0) { - g_source_remove (view->details->floating_bar_loading_timeout_id); - view->details->floating_bar_loading_timeout_id = 0; - } - - view->details->floating_bar_loading_timeout_id = - g_timeout_add (FLOATING_BAR_LOADING_DELAY, setup_loading_floating_bar_timeout_cb, view); -} - -static void -floating_bar_action_cb (NautilusFloatingBar *floating_bar, - gint action, - NautilusView *view) -{ - if (action == NAUTILUS_FLOATING_BAR_ACTION_ID_STOP) { - remove_loading_floating_bar (view); - nautilus_window_slot_stop_loading (view->details->slot); - } -} - -static void -real_floating_bar_set_short_status (NautilusView *view, - const gchar *primary_status, - const gchar *detail_status) -{ - gboolean disable_chrome; - - nautilus_floating_bar_cleanup_actions (NAUTILUS_FLOATING_BAR (view->details->floating_bar)); - nautilus_floating_bar_set_show_spinner (NAUTILUS_FLOATING_BAR (view->details->floating_bar), view->details->loading); - - g_object_get (nautilus_view_get_window (view), - "disable-chrome", &disable_chrome, - NULL); - - if ((primary_status == NULL && detail_status == NULL) || disable_chrome) { - gtk_widget_hide (view->details->floating_bar); - return; - } - - nautilus_floating_bar_set_labels (NAUTILUS_FLOATING_BAR (view->details->floating_bar), - primary_status, - detail_status); - - gtk_widget_show (view->details->floating_bar); -} - -typedef struct { - gchar *primary_status; - gchar *detail_status; - NautilusView *view; -} FloatingBarSetStatusData; - -static void -floating_bar_set_status_data_free (gpointer data) -{ - FloatingBarSetStatusData *status_data = data; - - g_free (status_data->primary_status); - g_free (status_data->detail_status); - - g_slice_free (FloatingBarSetStatusData, data); -} - -static gboolean -floating_bar_set_status_timeout_cb (gpointer data) -{ - FloatingBarSetStatusData *status_data = data; - - status_data->view->details->floating_bar_set_status_timeout_id = 0; - real_floating_bar_set_short_status (status_data->view, - status_data->primary_status, - status_data->detail_status); - - return FALSE; -} - -static void -set_floating_bar_status (NautilusView *view, - const gchar *primary_status, - const gchar *detail_status) -{ - GtkSettings *settings; - gint double_click_time; - FloatingBarSetStatusData *status_data; - - if (view->details->floating_bar_set_status_timeout_id != 0) { - g_source_remove (view->details->floating_bar_set_status_timeout_id); - view->details->floating_bar_set_status_timeout_id = 0; - } - - settings = gtk_settings_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (view))); - g_object_get (settings, - "gtk-double-click-time", &double_click_time, - NULL); - - status_data = g_slice_new0 (FloatingBarSetStatusData); - status_data->primary_status = g_strdup (primary_status); - status_data->detail_status = g_strdup (detail_status); - status_data->view = view; - - /* waiting for half of the double-click-time before setting - * the status seems to be a good approximation of not setting it - * too often and not delaying the statusbar too much. - */ - view->details->floating_bar_set_status_timeout_id = - g_timeout_add_full (G_PRIORITY_DEFAULT, - (guint) (double_click_time / 2), - floating_bar_set_status_timeout_cb, - status_data, - floating_bar_set_status_data_free); -} - -static char * -real_get_backing_uri (NautilusView *view) -{ - NautilusDirectory *directory; - char *uri; - - g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL); - - if (view->details->model == NULL) { - return NULL; - } - - directory = view->details->model; - - if (NAUTILUS_IS_DESKTOP_DIRECTORY (directory)) { - directory = nautilus_desktop_directory_get_real_directory (NAUTILUS_DESKTOP_DIRECTORY (directory)); - } else { - nautilus_directory_ref (directory); - } - - uri = nautilus_directory_get_uri (directory); - - nautilus_directory_unref (directory); - - return uri; -} - -/** - * - * nautilus_view_get_backing_uri: - * - * Returns the URI for the target location of new directory, new file, new - * link and paste operations. - */ - -char * -nautilus_view_get_backing_uri (NautilusView *view) -{ - g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL); - - return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_backing_uri (view); -} - -/** - * nautilus_view_select_all: - * - * select all the items in the view - * - **/ -static void -nautilus_view_select_all (NautilusView *view) -{ - g_return_if_fail (NAUTILUS_IS_VIEW (view)); - - NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->select_all (view); -} - -static void -nautilus_view_select_first (NautilusView *view) -{ - g_return_if_fail (NAUTILUS_IS_VIEW (view)); - - NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->select_first (view); -} - -static void -nautilus_view_call_set_selection (NautilusView *view, GList *selection) -{ - g_return_if_fail (NAUTILUS_IS_VIEW (view)); - - NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->set_selection (view, selection); -} - -static GList * -nautilus_view_get_selection_for_file_transfer (NautilusView *view) -{ - g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL); - - return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_selection_for_file_transfer (view); -} - -static void -nautilus_view_invert_selection (NautilusView *view) -{ - g_return_if_fail (NAUTILUS_IS_VIEW (view)); - - NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->invert_selection (view); -} - -/** - * nautilus_view_reveal_selection: - * - * Scroll as necessary to reveal the selected items. - **/ -static void -nautilus_view_reveal_selection (NautilusView *view) -{ - g_return_if_fail (NAUTILUS_IS_VIEW (view)); - - NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->reveal_selection (view); -} - -static gboolean -nautilus_view_using_manual_layout (NautilusView *view) -{ - g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE); - - return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->using_manual_layout (view); -} - -/** - * nautilus_view_get_icon: - * @view: a #NautilusView - * - * Retrieves the #GIcon that represents @view. - * - * Returns: (transfer none): the #Gicon that represents @view - */ -GIcon* -nautilus_view_get_icon (NautilusView *view) -{ - g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL); - - return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_icon (view); -} - -/** - * nautilus_view_get_view_widget: - * @view: a #NautilusView - * - * Retrieves the view menu, as a #GtkWidget. If it's %NULL, - * the button renders insensitive. - * - * Returns: (transfer none): a #GtkWidget for the view menu - */ -GtkWidget* -nautilus_view_get_view_widget (NautilusView *view) -{ - g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL); - - return view->details->view_menu_widget; -} - -/** - * nautilus_view_can_rename_file - * - * Determine whether a file can be renamed. - * @file: A NautilusFile - * - * Return value: TRUE if @file can be renamed, FALSE otherwise. - * - **/ -static gboolean -nautilus_view_can_rename_file (NautilusView *view, NautilusFile *file) -{ - return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->can_rename_file (view, file); -} - -static gboolean -nautilus_view_is_read_only (NautilusView *view) -{ - g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE); - - return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->is_read_only (view); -} - -static gboolean -showing_trash_directory (NautilusView *view) -{ - NautilusFile *file; - - file = nautilus_view_get_directory_as_file (view); - if (file != NULL) { - return nautilus_file_is_in_trash (file); - } - return FALSE; -} - -static gboolean -showing_network_directory (NautilusView *view) -{ - NautilusFile *file; - - file = nautilus_view_get_directory_as_file (view); - if (file != NULL) { - return nautilus_file_is_in_network (file); - } - return FALSE; -} - -static gboolean -showing_recent_directory (NautilusView *view) -{ - NautilusFile *file; - - file = nautilus_view_get_directory_as_file (view); - if (file != NULL) { - return nautilus_file_is_in_recent (file); - } - return FALSE; -} - -static gboolean -nautilus_view_supports_creating_files (NautilusView *view) -{ - g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE); - - return !nautilus_view_is_read_only (view) - && !showing_trash_directory (view) - && !showing_recent_directory (view); -} - -static gboolean -nautilus_view_is_empty (NautilusView *view) -{ - g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE); - - return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->is_empty (view); -} - -/** - * nautilus_view_bump_zoom_level: - * - * bump the current zoom level by invoking the relevant subclass through the slot - * - **/ -void -nautilus_view_bump_zoom_level (NautilusView *view, - int zoom_increment) -{ - g_return_if_fail (NAUTILUS_IS_VIEW (view)); - - if (!nautilus_view_supports_zooming (view)) { - return; - } - - NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->bump_zoom_level (view, zoom_increment); -} - -/** - * nautilus_view_can_zoom_in: - * - * Determine whether the view can be zoomed any closer. - * @view: The zoomable NautilusView. - * - * Return value: TRUE if @view can be zoomed any closer, FALSE otherwise. - * - **/ -gboolean -nautilus_view_can_zoom_in (NautilusView *view) -{ - g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE); - - if (!nautilus_view_supports_zooming (view)) { - return FALSE; - } - - return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->can_zoom_in (view); -} - -/** - * nautilus_view_can_zoom_out: - * - * Determine whether the view can be zoomed any further away. - * @view: The zoomable NautilusView. - * - * Return value: TRUE if @view can be zoomed any further away, FALSE otherwise. - * - **/ -gboolean -nautilus_view_can_zoom_out (NautilusView *view) -{ - g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE); - - if (!nautilus_view_supports_zooming (view)) { - return FALSE; - } - - return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->can_zoom_out (view); -} - -gboolean -nautilus_view_supports_zooming (NautilusView *view) -{ - g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE); - - return view->details->supports_zooming; -} - -/** - * nautilus_view_restore_default_zoom_level: - * - * restore to the default zoom level by invoking the relevant subclass through the slot - * - **/ -void -nautilus_view_restore_default_zoom_level (NautilusView *view) -{ - g_return_if_fail (NAUTILUS_IS_VIEW (view)); - - if (!nautilus_view_supports_zooming (view)) { - return; - } - - NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->restore_default_zoom_level (view); -} - -gboolean -nautilus_view_is_search (NautilusView *view) -{ - if (!view->details->model) - return FALSE; - - return NAUTILUS_IS_SEARCH_DIRECTORY (view->details->model); -} - -const char * -nautilus_view_get_view_id (NautilusView *view) -{ - return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_view_id (view); -} - -char * -nautilus_view_get_first_visible_file (NautilusView *view) -{ - return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_first_visible_file (view); -} - -void -nautilus_view_scroll_to_file (NautilusView *view, - const char *uri) -{ - NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->scroll_to_file (view, uri); -} - -/** - * nautilus_view_get_selection: - * - * Get a list of NautilusFile pointers that represents the - * currently-selected items in this view. Subclasses must override - * the signal handler for the 'get_selection' signal. Callers are - * responsible for g_free-ing the list (but not its data). - * @view: NautilusView whose selected items are of interest. - * - * Return value: GList of NautilusFile pointers representing the selection. - * - **/ -GList * -nautilus_view_get_selection (NautilusView *view) -{ - g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL); - - return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_selection (view); -} - -typedef struct { - NautilusFile *file; - NautilusView *directory_view; -} ScriptLaunchParameters; - -typedef struct { - NautilusFile *file; - NautilusView *directory_view; -} CreateTemplateParameters; - -static GList * -file_and_directory_list_to_files (GList *fad_list) -{ - GList *res, *l; - FileAndDirectory *fad; - - res = NULL; - for (l = fad_list; l != NULL; l = l->next) { - fad = l->data; - res = g_list_prepend (res, nautilus_file_ref (fad->file)); - } - return g_list_reverse (res); -} - - -static GList * -file_and_directory_list_from_files (NautilusDirectory *directory, GList *files) -{ - GList *res, *l; - FileAndDirectory *fad; - - res = NULL; - for (l = files; l != NULL; l = l->next) { - fad = g_new0 (FileAndDirectory, 1); - fad->directory = nautilus_directory_ref (directory); - fad->file = nautilus_file_ref (l->data); - res = g_list_prepend (res, fad); - } - return g_list_reverse (res); -} - -static void -file_and_directory_free (FileAndDirectory *fad) -{ - nautilus_directory_unref (fad->directory); - nautilus_file_unref (fad->file); - g_free (fad); -} - - -static void -file_and_directory_list_free (GList *list) -{ - GList *l; - - for (l = list; l != NULL; l = l->next) { - file_and_directory_free (l->data); - } - - g_list_free (list); -} - -static gboolean -file_and_directory_equal (gconstpointer v1, - gconstpointer v2) -{ - const FileAndDirectory *fad1, *fad2; - fad1 = v1; - fad2 = v2; - - return (fad1->file == fad2->file && - fad1->directory == fad2->directory); -} - -static guint -file_and_directory_hash (gconstpointer v) -{ - const FileAndDirectory *fad; - - fad = v; - return GPOINTER_TO_UINT (fad->file) ^ GPOINTER_TO_UINT (fad->directory); -} - -static ScriptLaunchParameters * -script_launch_parameters_new (NautilusFile *file, - NautilusView *directory_view) -{ - ScriptLaunchParameters *result; - - result = g_new0 (ScriptLaunchParameters, 1); - g_object_ref (directory_view); - result->directory_view = directory_view; - nautilus_file_ref (file); - result->file = file; - - return result; -} - -static void -script_launch_parameters_free (ScriptLaunchParameters *parameters) -{ - g_object_unref (parameters->directory_view); - nautilus_file_unref (parameters->file); - g_free (parameters); -} - -static CreateTemplateParameters * -create_template_parameters_new (NautilusFile *file, - NautilusView *directory_view) -{ - CreateTemplateParameters *result; - - result = g_new0 (CreateTemplateParameters, 1); - g_object_ref (directory_view); - result->directory_view = directory_view; - nautilus_file_ref (file); - result->file = file; - - return result; -} - -static void -create_templates_parameters_free (CreateTemplateParameters *parameters) -{ - g_object_unref (parameters->directory_view); - nautilus_file_unref (parameters->file); - g_free (parameters); -} - -NautilusWindow * -nautilus_view_get_window (NautilusView *view) -{ - return nautilus_window_slot_get_window (view->details->slot); -} - -NautilusWindowSlot * -nautilus_view_get_nautilus_window_slot (NautilusView *view) -{ - g_assert (view->details->slot != NULL); - - return view->details->slot; -} - -/* Returns the GtkWindow that this directory view occupies, or NULL - * if at the moment this directory view is not in a GtkWindow or the - * GtkWindow cannot be determined. Primarily used for parenting dialogs. - */ -static GtkWindow * -nautilus_view_get_containing_window (NautilusView *view) -{ - GtkWidget *window; - - g_assert (NAUTILUS_IS_VIEW (view)); - - window = gtk_widget_get_ancestor (GTK_WIDGET (view), GTK_TYPE_WINDOW); - if (window == NULL) { - return NULL; - } - - return GTK_WINDOW (window); -} - -static gboolean -nautilus_view_confirm_multiple (GtkWindow *parent_window, - int count, - gboolean tabs) -{ - GtkDialog *dialog; - char *prompt; - char *detail; - int response; - - if (count <= SILENT_WINDOW_OPEN_LIMIT) { - return TRUE; - } - - prompt = _("Are you sure you want to open all files?"); - if (tabs) { - detail = g_strdup_printf (ngettext("This will open %'d separate tab.", - "This will open %'d separate tabs.", count), count); - } else { - detail = g_strdup_printf (ngettext("This will open %'d separate window.", - "This will open %'d separate windows.", count), count); - } - dialog = eel_show_yes_no_dialog (prompt, detail, - _("_OK"), _("_Cancel"), - parent_window); - g_free (detail); - - response = gtk_dialog_run (dialog); - gtk_widget_destroy (GTK_WIDGET (dialog)); - - return response == GTK_RESPONSE_YES; -} - -static gboolean -selection_not_empty_in_menu_callback (NautilusView *view, GList *selection) -{ - if (selection != NULL) { - return TRUE; - } - - return FALSE; -} - -static char * -get_view_directory (NautilusView *view) -{ - char *uri, *path; - GFile *f; - - uri = nautilus_directory_get_uri (view->details->model); - if (eel_uri_is_desktop (uri)) { - g_free (uri); - uri = nautilus_get_desktop_directory_uri (); - - } - f = g_file_new_for_uri (uri); - path = g_file_get_path (f); - g_object_unref (f); - g_free (uri); - - return path; -} - -void -nautilus_view_preview_files (NautilusView *view, - GList *files, - GArray *locations) -{ - gchar *uri; - guint xid; - GtkWidget *toplevel; - - uri = nautilus_file_get_uri (files->data); - toplevel = gtk_widget_get_toplevel (GTK_WIDGET (view)); - - xid = gdk_x11_window_get_xid (gtk_widget_get_window (toplevel)); - nautilus_previewer_call_show_file (uri, xid, TRUE); - - g_free (uri); -} - -void -nautilus_view_activate_selection (NautilusView *view) -{ - GList *selection; - - selection = nautilus_view_get_selection (view); - nautilus_view_activate_files (view, - selection, - 0, - TRUE); - nautilus_file_list_free (selection); -} - -void -nautilus_view_activate_files (NautilusView *view, - GList *files, - NautilusWindowOpenFlags flags, - gboolean confirm_multiple) -{ - char *path; - - path = get_view_directory (view); - nautilus_mime_activate_files (nautilus_view_get_containing_window (view), - view->details->slot, - files, - path, - flags, - confirm_multiple); - - g_free (path); -} - -static void -nautilus_view_activate_file (NautilusView *view, - NautilusFile *file, - NautilusWindowOpenFlags flags) -{ - char *path; - - path = get_view_directory (view); - nautilus_mime_activate_file (nautilus_view_get_containing_window (view), - view->details->slot, - file, - path, - flags); - - g_free (path); -} - -static void -action_open_with_default_application (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - NautilusView *view; - - view = NAUTILUS_VIEW (user_data); - nautilus_view_activate_selection (view); -} -static void -action_open_file_and_close_window (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - GList *selection; - NautilusView *view; - - view = NAUTILUS_VIEW (user_data); - - selection = nautilus_view_get_selection (view); - nautilus_view_activate_files (view, - selection, - NAUTILUS_WINDOW_OPEN_FLAG_CLOSE_BEHIND, - TRUE); - nautilus_file_list_free (selection); -} - -static void -got_it_clicked (GtkDialog *dialog, - gint response_id, - gpointer user_data) -{ - g_settings_set_boolean (nautilus_preferences, - NAUTILUS_PREFERENCES_SHOW_MOVE_TO_TRASH_SHORTCUT_CHANGED_DIALOG, - FALSE); -} - -static void -action_show_move_to_trash_shortcut_changed_dialog (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - NautilusView *view; - GtkWindow *dialog; - GtkBuilder *builder; - gboolean show_dialog_preference; - - view = NAUTILUS_VIEW (user_data); - show_dialog_preference = g_settings_get_boolean (nautilus_preferences, - NAUTILUS_PREFERENCES_SHOW_MOVE_TO_TRASH_SHORTCUT_CHANGED_DIALOG); - if (show_dialog_preference) { - builder = gtk_builder_new_from_resource ("/org/gnome/nautilus/nautilus-move-to-trash-shortcut-changed.ui"); - dialog = GTK_WINDOW (gtk_builder_get_object (builder, "move_to_trash_shortcut_changed_dialog")); - - gtk_window_set_transient_for (dialog, GTK_WINDOW (nautilus_view_get_window (view))); - g_signal_connect (dialog, "response", - G_CALLBACK (got_it_clicked), - view); - - gtk_widget_show (GTK_WIDGET (dialog)); - gtk_dialog_run(GTK_DIALOG (dialog)); - gtk_widget_destroy (GTK_WIDGET (dialog)); - - g_object_unref (builder); - } -} -static void -action_open_item_location (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - NautilusView *view; - GList *selection; - NautilusFile *item; - GFile *activation_location; - NautilusFile *activation_file; - NautilusFile *location; - - view = NAUTILUS_VIEW (user_data); - selection = nautilus_view_get_selection (view); - - if (!selection) - return; - - item = NAUTILUS_FILE (selection->data); - activation_location = nautilus_file_get_activation_location (item); - activation_file = nautilus_file_get (activation_location); - location = nautilus_file_get_parent (activation_file); - - nautilus_view_activate_file (view, location, 0); - - nautilus_file_unref (location); - nautilus_file_unref (activation_file); - g_object_unref (activation_location); - nautilus_file_list_free (selection); -} - -static void -action_open_item_new_tab (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - NautilusView *view; - GList *selection; - GtkWindow *window; - - view = NAUTILUS_VIEW (user_data); - selection = nautilus_view_get_selection (view); - - window = nautilus_view_get_containing_window (view); - - if (nautilus_view_confirm_multiple (window, g_list_length (selection), TRUE)) { - nautilus_view_activate_files (view, - selection, - NAUTILUS_WINDOW_OPEN_FLAG_NEW_TAB, - FALSE); - } - - nautilus_file_list_free (selection); -} - -static void -app_chooser_dialog_response_cb (GtkDialog *dialog, - gint response_id, - gpointer user_data) -{ - GtkWindow *parent_window; - GList *files; - GAppInfo *info; - - parent_window = user_data; - files = g_object_get_data (G_OBJECT (dialog), "directory-view:files"); - - if (response_id != GTK_RESPONSE_OK) - goto out; - - info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (dialog)); - - g_signal_emit_by_name (nautilus_signaller_get_current (), "mime-data-changed"); - - nautilus_launch_application (info, files, parent_window); - - g_object_unref (info); -out: - gtk_widget_destroy (GTK_WIDGET (dialog)); -} - -static void -choose_program (NautilusView *view, - GList *files) -{ - GtkWidget *dialog; - gchar *mime_type; - GtkWindow *parent_window; - - g_assert (NAUTILUS_IS_VIEW (view)); - - mime_type = nautilus_file_get_mime_type (files->data); - parent_window = nautilus_view_get_containing_window (view); - - dialog = gtk_app_chooser_dialog_new_for_content_type (parent_window, - GTK_DIALOG_MODAL | - GTK_DIALOG_DESTROY_WITH_PARENT | - GTK_DIALOG_USE_HEADER_BAR, - mime_type); - g_object_set_data_full (G_OBJECT (dialog), - "directory-view:files", - files, - (GDestroyNotify) nautilus_file_list_free); - gtk_widget_show (dialog); - - g_signal_connect_object (dialog, "response", - G_CALLBACK (app_chooser_dialog_response_cb), - parent_window, 0); -} - -static void -open_with_other_program (NautilusView *view) -{ - GList *selection; - - g_assert (NAUTILUS_IS_VIEW (view)); - - selection = nautilus_view_get_selection (view); - choose_program (view, selection); -} - -static void -action_open_with_other_application (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - g_assert (NAUTILUS_IS_VIEW (user_data)); - - open_with_other_program (NAUTILUS_VIEW (user_data)); -} - -static void -trash_or_delete_selected_files (NautilusView *view) -{ - GList *selection; - - /* This might be rapidly called multiple times for the same selection - * when using keybindings. So we remember if the current selection - * was already removed (but the view doesn't know about it yet). - */ - if (!view->details->selection_was_removed) { - selection = nautilus_view_get_selection_for_file_transfer (view); - trash_or_delete_files (nautilus_view_get_containing_window (view), - selection, - view); - nautilus_file_list_free (selection); - view->details->selection_was_removed = TRUE; - } -} - -static void -action_move_to_trash (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - trash_or_delete_selected_files (NAUTILUS_VIEW (user_data)); -} - -static void -action_remove_from_recent (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - /* TODO:implement a set of functions for this, is very confusing to - * call trash_or_delete_file to remove from recent, even if it does like - * that not deleting/moving the files to trash */ - trash_or_delete_selected_files (NAUTILUS_VIEW (user_data)); -} - -static void -delete_selected_files (NautilusView *view) -{ - GList *selection; - GList *node; - GList *locations; - - selection = nautilus_view_get_selection_for_file_transfer (view); - if (selection == NULL) { - return; - } - - locations = NULL; - for (node = selection; node != NULL; node = node->next) { - locations = g_list_prepend (locations, - nautilus_file_get_location ((NautilusFile *) node->data)); - } - locations = g_list_reverse (locations); - - nautilus_file_operations_delete (locations, nautilus_view_get_containing_window (view), NULL, NULL); - - g_list_free_full (locations, g_object_unref); - nautilus_file_list_free (selection); -} - -static void -action_delete (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - delete_selected_files (NAUTILUS_VIEW (user_data)); -} - -static void -action_restore_from_trash (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - NautilusView *view; - GList *selection; - - view = NAUTILUS_VIEW (user_data); - - selection = nautilus_view_get_selection_for_file_transfer (view); - nautilus_restore_files_from_trash (selection, - nautilus_view_get_containing_window (view)); - - nautilus_file_list_free (selection); - -} - -static void -action_select_all (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - NautilusView *view; - - g_assert (NAUTILUS_IS_VIEW (user_data)); - - view = NAUTILUS_VIEW (user_data); - - nautilus_view_select_all (view); -} - -static void -action_invert_selection (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - g_assert (NAUTILUS_IS_VIEW (user_data)); - - nautilus_view_invert_selection (user_data); -} - -static void -pattern_select_response_cb (GtkWidget *dialog, int response, gpointer user_data) -{ - NautilusView *view; - NautilusDirectory *directory; - GtkWidget *entry; - GList *selection; - - view = NAUTILUS_VIEW (user_data); - - switch (response) { - case GTK_RESPONSE_OK : - entry = g_object_get_data (G_OBJECT (dialog), "entry"); - directory = nautilus_view_get_model (view); - selection = nautilus_directory_match_pattern (directory, - gtk_entry_get_text (GTK_ENTRY (entry))); - - if (selection) { - nautilus_view_call_set_selection (view, selection); - nautilus_file_list_free (selection); - - nautilus_view_reveal_selection(view); - } - /* fall through */ - case GTK_RESPONSE_NONE : - case GTK_RESPONSE_DELETE_EVENT : - case GTK_RESPONSE_CANCEL : - gtk_widget_destroy (GTK_WIDGET (dialog)); - break; - default : - g_assert_not_reached (); - } -} - -static void -select_pattern (NautilusView *view) -{ - GtkWidget *dialog; - GtkWidget *label; - GtkWidget *example; - GtkWidget *grid; - GtkWidget *entry; - char *example_pattern; - - dialog = gtk_dialog_new_with_buttons (_("Select Items Matching"), - nautilus_view_get_containing_window (view), - GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_USE_HEADER_BAR, - _("_Cancel"), - GTK_RESPONSE_CANCEL, - _("_Select"), - GTK_RESPONSE_OK, - NULL); - gtk_dialog_set_default_response (GTK_DIALOG (dialog), - GTK_RESPONSE_OK); - gtk_container_set_border_width (GTK_CONTAINER (dialog), 5); - gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 2); - - label = gtk_label_new_with_mnemonic (_("_Pattern:")); - gtk_widget_set_halign (label, GTK_ALIGN_START); - - example = gtk_label_new (NULL); - gtk_widget_set_halign (example, GTK_ALIGN_START); - example_pattern = g_strdup_printf ("%s<i>%s</i> ", - _("Examples: "), - "*.png, file\?\?.txt, pict*.\?\?\?"); - gtk_label_set_markup (GTK_LABEL (example), example_pattern); - g_free (example_pattern); - - entry = gtk_entry_new (); - gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE); - gtk_widget_set_hexpand (entry, TRUE); - - grid = gtk_grid_new (); - g_object_set (grid, - "orientation", GTK_ORIENTATION_VERTICAL, - "border-width", 6, - "row-spacing", 6, - "column-spacing", 12, - NULL); - - gtk_container_add (GTK_CONTAINER (grid), label); - gtk_grid_attach_next_to (GTK_GRID (grid), entry, label, - GTK_POS_RIGHT, 1, 1); - gtk_grid_attach_next_to (GTK_GRID (grid), example, entry, - GTK_POS_BOTTOM, 1, 1); - - gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry); - gtk_widget_show_all (grid); - gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), grid); - g_object_set_data (G_OBJECT (dialog), "entry", entry); - g_signal_connect (dialog, "response", - G_CALLBACK (pattern_select_response_cb), - view); - gtk_widget_show_all (dialog); -} - -static void -action_select_pattern (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - g_assert (NAUTILUS_IS_VIEW (user_data)); - - select_pattern(user_data); -} - -static void -zoom_level_changed (GtkRange *range, - NautilusView *view) -{ - g_action_group_change_action_state (view->details->view_action_group, - "zoom-to-level", - g_variant_new_int32 (gtk_range_get_value (range))); -} - -static void -reveal_newly_added_folder (NautilusView *view, NautilusFile *new_file, - NautilusDirectory *directory, GFile *target_location) -{ - GFile *location; - - location = nautilus_file_get_location (new_file); - if (g_file_equal (location, target_location)) { - g_signal_handlers_disconnect_by_func (view, - G_CALLBACK (reveal_newly_added_folder), - (void *) target_location); - nautilus_view_select_file (view, new_file); - } - g_object_unref (location); -} - -typedef struct { - NautilusView *directory_view; - GHashTable *added_locations; - GList *selection; -} NewFolderData; - -typedef struct { - NautilusView *directory_view; - GHashTable *to_remove_locations; - NautilusFile *new_folder; -} NewFolderSelectionData; - -static void -track_newly_added_locations (NautilusView *view, NautilusFile *new_file, - NautilusDirectory *directory, gpointer user_data) -{ - NewFolderData *data; - - data = user_data; - - g_hash_table_insert (data->added_locations, nautilus_file_get_location (new_file), NULL); -} - -static void -new_folder_done (GFile *new_folder, - gboolean success, - gpointer user_data) -{ - NautilusView *directory_view; - NautilusFile *file; - char screen_string[32]; - GdkScreen *screen; - NewFolderData *data; - - data = (NewFolderData *)user_data; - - directory_view = data->directory_view; - - if (directory_view == NULL) { - goto fail; - } - - g_signal_handlers_disconnect_by_func (directory_view, - G_CALLBACK (track_newly_added_locations), - (void *) data); - - if (new_folder == NULL) { - goto fail; - } - - screen = gtk_widget_get_screen (GTK_WIDGET (directory_view)); - g_snprintf (screen_string, sizeof (screen_string), "%d", gdk_screen_get_number (screen)); - - - file = nautilus_file_get (new_folder); - nautilus_file_set_metadata - (file, NAUTILUS_METADATA_KEY_SCREEN, - NULL, - screen_string); - - if (data->selection != NULL) { - NewFolderSelectionData *sdata; - GList *uris, *l; - char *target_uri; - - sdata = g_new (NewFolderSelectionData, 1); - sdata->directory_view = directory_view; - sdata->to_remove_locations = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, - g_object_unref, NULL); - sdata->new_folder = g_object_ref (file); - - uris = NULL; - for (l = data->selection; l != NULL; l = l->next) { - GFile *old_location; - GFile *new_location; - char *basename; - - uris = g_list_prepend (uris, nautilus_file_get_uri ((NautilusFile *) l->data)); - - old_location = nautilus_file_get_location (l->data); - basename = g_file_get_basename (old_location); - new_location = g_file_resolve_relative_path (new_folder, basename); - g_hash_table_insert (sdata->to_remove_locations, new_location, NULL); - g_free (basename); - g_object_unref (old_location); - } - uris = g_list_reverse (uris); - - target_uri = nautilus_file_get_uri (file); - - nautilus_view_move_copy_items (directory_view, - uris, - NULL, - target_uri, - GDK_ACTION_MOVE, - 0, 0); - g_list_free_full (uris, g_free); - g_free (target_uri); - } else { - if (g_hash_table_lookup_extended (data->added_locations, new_folder, NULL, NULL)) { - /* The file was already added */ - nautilus_view_select_file (directory_view, file); - } else { - /* We need to run after the default handler adds the folder we want to - * operate on. The ADD_FILE signal is registered as G_SIGNAL_RUN_LAST, so we - * must use connect_after. - */ - g_signal_connect_data (directory_view, - "add-file", - G_CALLBACK (reveal_newly_added_folder), - g_object_ref (new_folder), - (GClosureNotify)g_object_unref, - G_CONNECT_AFTER); - } - } - - nautilus_file_unref (file); - - fail: - g_hash_table_destroy (data->added_locations); - - if (data->directory_view != NULL) { - g_object_remove_weak_pointer (G_OBJECT (data->directory_view), - (gpointer *) &data->directory_view); - } - - nautilus_file_list_free (data->selection); - g_free (data); -} - - -static NewFolderData * -new_folder_data_new (NautilusView *directory_view, - gboolean with_selection) -{ - NewFolderData *data; - - data = g_new (NewFolderData, 1); - data->directory_view = directory_view; - data->added_locations = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, - g_object_unref, NULL); - if (with_selection) { - data->selection = nautilus_view_get_selection_for_file_transfer (directory_view); - } else { - data->selection = NULL; - } - g_object_add_weak_pointer (G_OBJECT (data->directory_view), - (gpointer *) &data->directory_view); - - return data; -} - -static GdkPoint * -context_menu_to_file_operation_position (NautilusView *view) -{ - g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL); - - if (nautilus_view_using_manual_layout (view) - && view->details->context_menu_position.x >= 0 - && view->details->context_menu_position.y >= 0) { - NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->widget_to_file_operation_position - (view, &view->details->context_menu_position); - return &view->details->context_menu_position; - } else { - return NULL; - } -} - -typedef struct { - NautilusView *view; - GtkWidget *widget; - GtkWidget *error_label; - GtkWidget *name_entry; - GtkWidget *activate_button; - gboolean target_is_folder; - NautilusFile *target_file; - gboolean duplicated_is_folder; - void (*on_name_accepted) (gpointer data); - /* For create folder only */ - gboolean with_selection; -} FileNameWidgetData; - -static gboolean -duplicated_file_label_show (FileNameWidgetData *data) -{ - if (data->duplicated_is_folder) - gtk_label_set_label (GTK_LABEL (data->error_label), _("A folder with that name already exists.")); - else - gtk_label_set_label (GTK_LABEL (data->error_label), _("A file with that name already exists.")); - - data->view->details->duplicated_label_timeout_id = 0; - - return G_SOURCE_REMOVE; -} - -static gchar* -validate_file_name (const gchar *name, - gboolean is_folder) -{ - gchar *error_message = NULL; - - if (strstr (name, "/") != NULL) { - if (is_folder) - error_message = _("Folder names cannot contain “/”."); - else - error_message = _("Files names cannot contain “/”."); - } else if (strcmp (name, ".") == 0){ - if (is_folder) - error_message = _("A folder can not be called “.”."); - else - error_message = _("A file can not be called “.”."); - } else if (strcmp (name, "..") == 0){ - if (is_folder) - error_message = _("A folder can not be called “..”."); - else - error_message = _("A file can not be called “..”."); - } - - return error_message; -} - -static void -file_name_widget_entry_on_changed (gpointer user_data) -{ - FileNameWidgetData *data; - NautilusFile *existing_file; - gchar *name; - gchar *error_message; - gboolean valid_name; - gboolean duplicated; - - data = (FileNameWidgetData *) user_data; - name = g_strstrip (g_strdup (gtk_entry_get_text (GTK_ENTRY (data->name_entry)))); - error_message = validate_file_name (name, TRUE); - gtk_label_set_label (GTK_LABEL (data->error_label), error_message); - - existing_file = nautilus_directory_get_file_by_name (data->view->details->model, name); - - valid_name = strlen (name) > 0 && error_message == NULL; - /* If there is a target file and the name is the same, we don't show it - * as duplicated. This is the case for renaming. */ - duplicated = existing_file != NULL && - (data->target_file == NULL || - nautilus_file_compare_display_name (data->target_file, name) != 0); - gtk_widget_set_sensitive (data->activate_button, valid_name && !duplicated); - - if (data->view->details->duplicated_label_timeout_id > 0) { - g_source_remove (data->view->details->duplicated_label_timeout_id); - data->view->details->duplicated_label_timeout_id = 0; - } - - /* Report duplicated file only if not other message shown (for instance, - * folders like "." or ".." will always exists, but we consider it as an - * error, not as a duplicated file or if the name is the same as the file - * we are renaming also don't report as a duplicated */ - if (duplicated && valid_name) { - data->duplicated_is_folder = nautilus_file_is_directory (existing_file); - data->view->details->duplicated_label_timeout_id = - g_timeout_add (FILE_NAME_DUPLICATED_LABEL_TIMEOUT, - (GSourceFunc)duplicated_file_label_show, - data); - } - - if (existing_file != NULL) - nautilus_file_unref (existing_file); - - g_free (name); -} - -static void -create_folder_dialog_on_response (GtkDialog *dialog, - gint response_id, - gpointer user_data) -{ - FileNameWidgetData *widget_data; - - widget_data = (FileNameWidgetData *) user_data; - - if (response_id == GTK_RESPONSE_OK) { - NewFolderData *data; - GdkPoint *pos; - char *parent_uri; - gchar *name; - - data = new_folder_data_new (widget_data->view, widget_data->with_selection); - - name = g_strstrip (g_strdup (gtk_entry_get_text (GTK_ENTRY (widget_data->name_entry)))); - g_signal_connect_data (widget_data->view, - "add-file", - G_CALLBACK (track_newly_added_locations), - data, - (GClosureNotify)NULL, - G_CONNECT_AFTER); - - pos = context_menu_to_file_operation_position (widget_data->view); - - parent_uri = nautilus_view_get_backing_uri (widget_data->view); - nautilus_file_operations_new_folder (GTK_WIDGET (widget_data->view), - pos, parent_uri, name, - new_folder_done, data); - - g_free (parent_uri); - g_free (name); - } - - gtk_widget_destroy (GTK_WIDGET (dialog)); - g_free (user_data); -} - - -static void -create_folder_on_name_accepted (gpointer user_data) -{ - FileNameWidgetData *data; - - data = (FileNameWidgetData *) user_data; - gtk_dialog_response (GTK_DIALOG (data->widget), - GTK_RESPONSE_OK); -} - -static void -rename_file_on_name_accepted (gpointer user_data) -{ - FileNameWidgetData *data; - gchar *name; - - data = (FileNameWidgetData *) user_data; - - name = g_strstrip (g_strdup (gtk_entry_get_text (GTK_ENTRY (data->name_entry)))); - nautilus_rename_file (data->target_file, name, NULL, NULL); - - nautilus_view_select_file (data->view, data->target_file); - nautilus_view_reveal_selection (data->view); - - gtk_widget_hide (data->widget); - - g_free (name); -} - -static void -file_name_widget_on_activate (gpointer user_data) -{ - FileNameWidgetData *data; - NautilusFile *existing_file; - gchar *name; - gchar *error_message; - gboolean valid_name; - gboolean duplicated; - - data = (FileNameWidgetData *) user_data; - name = g_strstrip (g_strdup (gtk_entry_get_text (GTK_ENTRY (data->name_entry)))); - existing_file = nautilus_directory_get_file_by_name (data->view->details->model, name); - error_message = validate_file_name (name, TRUE); - valid_name = strlen (name) > 0 && error_message == NULL; - duplicated = existing_file != NULL && - (data->target_file == NULL || - nautilus_file_compare_display_name (data->target_file, name) != 0); - - if (data->view->details->duplicated_label_timeout_id > 0) { - g_source_remove (data->view->details->duplicated_label_timeout_id); - data->view->details->duplicated_label_timeout_id = 0; - } - - if (valid_name && !duplicated) { - data->on_name_accepted ((gpointer) data); - } else { - /* Report duplicated file only if not other message shown (for instance, - * folders like "." or ".." will always exists, but we consider it as an - * error, not as a duplicated file) */ - if (existing_file != NULL && valid_name) { - data->duplicated_is_folder = nautilus_file_is_directory (existing_file); - /* Show it inmediatily since the user tried to trigger the action */ - duplicated_file_label_show (data); - } - } - - if (existing_file != NULL) - nautilus_file_unref (existing_file); - - g_free (name); -} - -static void -rename_file_popover_on_closed (GtkPopover *popover, - gpointer user_data) -{ - FileNameWidgetData *widget_data; - - widget_data = (FileNameWidgetData *) user_data; - widget_data->view->details->rename_file_popover = NULL; - g_free (widget_data); -} - -static GdkRectangle* -nautilus_view_compute_rename_popover_relative_to (NautilusView *view) -{ - return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->compute_rename_popover_relative_to (view); -} - -static void -nautilus_view_rename_file_popover_new (NautilusView *view, - NautilusFile *target_file) -{ - FileNameWidgetData *widget_data; - GtkWidget *label_file_name; - GtkBuilder *builder; - gint start_offset, end_offset; - GdkRectangle *relative_to; - - if (view->details->rename_file_popover != NULL) - return; - - builder = gtk_builder_new_from_resource ("/org/gnome/nautilus/nautilus-rename-file-popover.ui"); - label_file_name = GTK_WIDGET (gtk_builder_get_object (builder, "name_label")); - - widget_data = g_new (FileNameWidgetData, 1); - widget_data->view = view; - widget_data->on_name_accepted = rename_file_on_name_accepted; - widget_data->widget = GTK_WIDGET (gtk_builder_get_object (builder, "rename_file_popover")); - widget_data->activate_button = GTK_WIDGET (gtk_builder_get_object (builder, "rename_button")); - widget_data->error_label = GTK_WIDGET (gtk_builder_get_object (builder, "error_label")); - widget_data->name_entry = GTK_WIDGET (gtk_builder_get_object (builder, "name_entry")); - widget_data->target_is_folder = nautilus_file_is_directory (target_file); - widget_data->target_file = target_file; - - view->details->rename_file_popover = widget_data->widget; - - /* Connect signals */ - gtk_builder_add_callback_symbols (builder, - "file_name_widget_entry_on_changed", - G_CALLBACK (file_name_widget_entry_on_changed), - "file_name_widget_on_activate", - G_CALLBACK (file_name_widget_on_activate), - "rename_file_popover_on_closed", - G_CALLBACK (rename_file_popover_on_closed), - "rename_file_popover_on_unmap", - G_CALLBACK (gtk_widget_destroy), - NULL); - - gtk_builder_connect_signals (builder, widget_data); - - if (widget_data->target_is_folder) - gtk_label_set_text (GTK_LABEL (label_file_name), _("Folder name")); - else - gtk_label_set_text (GTK_LABEL (label_file_name), _("File name")); - gtk_entry_set_text (GTK_ENTRY (widget_data->name_entry), nautilus_file_get_name (target_file)); - - relative_to = nautilus_view_compute_rename_popover_relative_to (view); - gtk_popover_set_default_widget (GTK_POPOVER (widget_data->widget), - widget_data->activate_button); - gtk_popover_set_pointing_to (GTK_POPOVER (widget_data->widget), relative_to); - gtk_popover_set_relative_to (GTK_POPOVER (widget_data->widget), - GTK_WIDGET (view)); - gtk_widget_show (widget_data->widget); - gtk_widget_grab_focus (widget_data->widget); - - /* Select the name part withouth the file extension */ - eel_filename_get_rename_region (nautilus_file_get_name (target_file), - &start_offset, &end_offset); - gtk_editable_select_region (GTK_EDITABLE (widget_data->name_entry), - start_offset, end_offset); - - /* Update the rename button status */ - file_name_widget_entry_on_changed (widget_data); - - - g_object_unref (builder); -} - -static void -nautilus_view_new_folder_dialog_new (NautilusView *view, - gboolean with_selection) -{ - FileNameWidgetData *widget_data; - GtkWidget *label_file_name; - GtkBuilder *builder; - - builder = gtk_builder_new_from_resource ("/org/gnome/nautilus/nautilus-create-folder-dialog.ui"); - label_file_name = GTK_WIDGET (gtk_builder_get_object (builder, "name_label")); - - widget_data = g_new (FileNameWidgetData, 1); - widget_data->view = view; - widget_data->on_name_accepted = create_folder_on_name_accepted; - widget_data->widget = GTK_WIDGET (gtk_builder_get_object (builder, "create_folder_dialog")); - widget_data->activate_button = GTK_WIDGET (gtk_builder_get_object (builder, "ok_button")); - widget_data->error_label = GTK_WIDGET (gtk_builder_get_object (builder, "error_label")); - widget_data->name_entry = GTK_WIDGET (gtk_builder_get_object (builder, "name_entry")); - widget_data->target_is_folder = TRUE; - widget_data->target_file = NULL; - widget_data->with_selection = with_selection; - - gtk_window_set_transient_for (GTK_WINDOW (widget_data->widget), - GTK_WINDOW (nautilus_view_get_window (view))); - - /* Connect signals */ - gtk_builder_add_callback_symbols (builder, - "file_name_widget_entry_on_changed", - G_CALLBACK (file_name_widget_entry_on_changed), - "file_name_widget_on_activate", - G_CALLBACK (file_name_widget_on_activate), - "create_folder_dialog_on_response", - G_CALLBACK (create_folder_dialog_on_response), - NULL); - - gtk_builder_connect_signals (builder, widget_data); - gtk_button_set_label (GTK_BUTTON (widget_data->activate_button), - _("Create")); - gtk_label_set_text (GTK_LABEL (label_file_name), _("Folder name")); - gtk_window_set_title (GTK_WINDOW (widget_data->widget), _("New Folder")); - - gtk_widget_show_all (widget_data->widget); - /* Update the ok button status */ - file_name_widget_entry_on_changed (widget_data); - - g_object_unref (builder); -} - -static void -nautilus_view_new_folder (NautilusView *directory_view, - gboolean with_selection) -{ - nautilus_view_new_folder_dialog_new (directory_view, with_selection); -} - -static NewFolderData * -setup_new_folder_data (NautilusView *directory_view) -{ - NewFolderData *data; - - data = new_folder_data_new (directory_view, FALSE); - - g_signal_connect_data (directory_view, - "add-file", - G_CALLBACK (track_newly_added_locations), - data, - (GClosureNotify)NULL, - G_CONNECT_AFTER); - - return data; -} - -void -nautilus_view_new_file_with_initial_contents (NautilusView *view, - const char *parent_uri, - const char *filename, - const char *initial_contents, - int length, - GdkPoint *pos) -{ - NewFolderData *data; - - g_assert (parent_uri != NULL); - - data = setup_new_folder_data (view); - - if (pos == NULL) { - pos = context_menu_to_file_operation_position (view); - } - - nautilus_file_operations_new_file (GTK_WIDGET (view), - pos, parent_uri, filename, - initial_contents, length, - new_folder_done, data); -} - -static void -nautilus_view_new_file (NautilusView *directory_view, - const char *parent_uri, - NautilusFile *source) -{ - GdkPoint *pos; - NewFolderData *data; - char *source_uri; - char *container_uri; - - container_uri = NULL; - if (parent_uri == NULL) { - container_uri = nautilus_view_get_backing_uri (directory_view); - g_assert (container_uri != NULL); - } - - if (source == NULL) { - nautilus_view_new_file_with_initial_contents (directory_view, - parent_uri != NULL ? parent_uri : container_uri, - NULL, - NULL, - 0, - NULL); - g_free (container_uri); - return; - } - - g_return_if_fail (nautilus_file_is_local (source)); - - pos = context_menu_to_file_operation_position (directory_view); - - data = setup_new_folder_data (directory_view); - - source_uri = nautilus_file_get_uri (source); - - nautilus_file_operations_new_file_from_template (GTK_WIDGET (directory_view), - pos, - parent_uri != NULL ? parent_uri : container_uri, - NULL, - source_uri, - new_folder_done, data); - - g_free (source_uri); - g_free (container_uri); -} - -static void -action_new_folder (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - g_assert (NAUTILUS_IS_VIEW (user_data)); - - nautilus_view_new_folder (NAUTILUS_VIEW (user_data), FALSE); -} - -static void -action_new_folder_with_selection (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - g_assert (NAUTILUS_IS_VIEW (user_data)); - - nautilus_view_new_folder (NAUTILUS_VIEW (user_data), TRUE); -} - -static void -action_properties (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - NautilusView *view; - GList *selection; - GList *files; - - g_assert (NAUTILUS_IS_VIEW (user_data)); - - view = NAUTILUS_VIEW (user_data); - selection = nautilus_view_get_selection (view); - if (g_list_length (selection) == 0) { - if (view->details->directory_as_file != NULL) { - files = g_list_append (NULL, nautilus_file_ref (view->details->directory_as_file)); - - nautilus_properties_window_present (files, GTK_WIDGET (view), NULL); - - nautilus_file_list_free (files); - } - } else { - nautilus_properties_window_present (selection, GTK_WIDGET (view), NULL); - } - nautilus_file_list_free (selection); -} - -static void -nautilus_view_set_show_hidden_files (NautilusView *view, - gboolean show_hidden) -{ - if (view->details->ignore_hidden_file_preferences) { - return; - } - - if (show_hidden != view->details->show_hidden_files) { - view->details->show_hidden_files = show_hidden; - - g_settings_set_boolean (gtk_filechooser_preferences, - NAUTILUS_PREFERENCES_SHOW_HIDDEN_FILES, - show_hidden); - - if (view->details->model != NULL) { - load_directory (view, view->details->model); - } - } -} - -static void -action_show_hidden_files (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - gboolean show_hidden; - NautilusView *view; - - g_assert (NAUTILUS_IS_VIEW (user_data)); - - view = NAUTILUS_VIEW (user_data); - show_hidden = g_variant_get_boolean (state); - - nautilus_view_set_show_hidden_files (view, show_hidden); - - g_simple_action_set_state (action, state); -} - -static void -action_zoom_in (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - NautilusView *view; - - g_assert (NAUTILUS_IS_VIEW (user_data)); - - view = NAUTILUS_VIEW (user_data); - - nautilus_view_bump_zoom_level (view, 1); -} - -static void -action_zoom_out (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - NautilusView *view; - - g_assert (NAUTILUS_IS_VIEW (user_data)); - - view = NAUTILUS_VIEW (user_data); - - nautilus_view_bump_zoom_level (view, -1); -} - -static void -action_zoom_default (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - nautilus_view_restore_default_zoom_level (user_data); -} - -static void -action_open_item_new_window (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - NautilusView *view; - GtkWindow *window; - GList *selection; - - view = NAUTILUS_VIEW (user_data); - selection = nautilus_view_get_selection (view); - window = GTK_WINDOW (nautilus_view_get_containing_window (view)); - - if (nautilus_view_confirm_multiple (window, g_list_length (selection), TRUE)) { - g_list_foreach (selection, open_one_in_new_window, view); - } - - nautilus_file_list_free (selection); -} - -static void -paste_clipboard_data (NautilusView *view, - GtkSelectionData *selection_data, - char *destination_uri) -{ - gboolean cut; - GList *item_uris; - - cut = FALSE; - item_uris = nautilus_clipboard_get_uri_list_from_selection_data (selection_data, &cut, - copied_files_atom); - - if (item_uris != NULL && destination_uri != NULL) { - nautilus_view_move_copy_items (view, item_uris, NULL, destination_uri, - cut ? GDK_ACTION_MOVE : GDK_ACTION_COPY, - 0, 0); - - /* If items are cut then remove from clipboard */ - if (cut) { - gtk_clipboard_clear (nautilus_clipboard_get (GTK_WIDGET (view))); - } - - g_list_free_full (item_uris, g_free); - } -} - -static void -paste_clipboard_received_callback (GtkClipboard *clipboard, - GtkSelectionData *selection_data, - gpointer data) -{ - NautilusView *view; - char *view_uri; - - view = NAUTILUS_VIEW (data); - - view_uri = nautilus_view_get_backing_uri (view); - - if (view->details->slot != NULL) { - paste_clipboard_data (view, selection_data, view_uri); - } - - g_free (view_uri); - - g_object_unref (view); -} - -static void -action_paste_files (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - NautilusView *view; - - g_assert (NAUTILUS_IS_VIEW (user_data)); - - view = NAUTILUS_VIEW (user_data); - - g_object_ref (view); - gtk_clipboard_request_contents (nautilus_clipboard_get (GTK_WIDGET (view)), - copied_files_atom, - paste_clipboard_received_callback, - view); -} - -static void -click_policy_changed_callback (gpointer callback_data) -{ - NautilusView *view; - - view = NAUTILUS_VIEW (callback_data); - - NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->click_policy_changed (view); -} - -gboolean -nautilus_view_should_sort_directories_first (NautilusView *view) -{ - return view->details->sort_directories_first; -} - -static void -sort_directories_first_changed_callback (gpointer callback_data) -{ - NautilusView *view; - gboolean preference_value; - - view = NAUTILUS_VIEW (callback_data); - - preference_value = - g_settings_get_boolean (nautilus_preferences, NAUTILUS_PREFERENCES_SORT_DIRECTORIES_FIRST); - - if (preference_value != view->details->sort_directories_first) { - view->details->sort_directories_first = preference_value; - NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->sort_directories_first_changed (view); - } -} - -static void -show_hidden_files_changed_callback (gpointer callback_data) -{ - NautilusView *view; - gboolean preference_value; - - view = NAUTILUS_VIEW (callback_data); - - preference_value = - g_settings_get_boolean (gtk_filechooser_preferences, NAUTILUS_PREFERENCES_SHOW_HIDDEN_FILES); - - nautilus_view_set_show_hidden_files (view, preference_value); -} - -static gboolean -set_up_scripts_directory_global (void) -{ - char *old_scripts_directory_path; - char *scripts_directory_path; - const char *override; - - if (scripts_directory_uri != NULL) { - return TRUE; - } - - scripts_directory_path = nautilus_get_scripts_directory_path (); - - override = g_getenv ("GNOME22_USER_DIR"); - - if (override) { - old_scripts_directory_path = g_build_filename (override, - "nautilus-scripts", - NULL); - } else { - old_scripts_directory_path = g_build_filename (g_get_home_dir (), - ".gnome2", - "nautilus-scripts", - NULL); - } - - if (g_file_test (old_scripts_directory_path, G_FILE_TEST_IS_DIR) - && !g_file_test (scripts_directory_path, G_FILE_TEST_EXISTS)) { - char *updated; - const char *message; - - /* test if we already attempted to migrate first */ - updated = g_build_filename (old_scripts_directory_path, "DEPRECATED-DIRECTORY", NULL); - message = _("Nautilus 3.6 deprecated this directory and tried migrating " - "this configuration to ~/.local/share/nautilus"); - if (!g_file_test (updated, G_FILE_TEST_EXISTS)) { - char *parent_dir; - - parent_dir = g_path_get_dirname (scripts_directory_path); - if (g_mkdir_with_parents (parent_dir, 0700) == 0) { - int fd, res; - - /* rename() works fine if the destination directory is - * empty. - */ - res = g_rename (old_scripts_directory_path, scripts_directory_path); - if (res == -1) { - fd = g_creat (updated, 0600); - if (fd != -1) { - res = write (fd, message, strlen (message)); - close (fd); - } - } - } - g_free (parent_dir); - } - - g_free (updated); - } - - if (g_mkdir_with_parents (scripts_directory_path, 0700) == 0) { - scripts_directory_uri = g_filename_to_uri (scripts_directory_path, NULL, NULL); - scripts_directory_uri_length = strlen (scripts_directory_uri); - } - - g_free (scripts_directory_path); - g_free (old_scripts_directory_path); - - return (scripts_directory_uri != NULL) ? TRUE : FALSE; -} - -static void -scripts_added_or_changed_callback (NautilusDirectory *directory, - GList *files, - gpointer callback_data) -{ - NautilusView *view; - - view = NAUTILUS_VIEW (callback_data); - - if (view->details->active) { - schedule_update_context_menus (view); - } -} - -static void -templates_added_or_changed_callback (NautilusDirectory *directory, - GList *files, - gpointer callback_data) -{ - NautilusView *view; - - view = NAUTILUS_VIEW (callback_data); - - if (view->details->active) { - schedule_update_context_menus (view); - } -} - -static void -add_directory_to_directory_list (NautilusView *view, - NautilusDirectory *directory, - GList **directory_list, - GCallback changed_callback) -{ - NautilusFileAttributes attributes; - - if (g_list_find (*directory_list, directory) == NULL) { - nautilus_directory_ref (directory); - - attributes = - NAUTILUS_FILE_ATTRIBUTES_FOR_ICON | - NAUTILUS_FILE_ATTRIBUTE_INFO | - NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT; - - nautilus_directory_file_monitor_add (directory, directory_list, - FALSE, attributes, - (NautilusDirectoryCallback)changed_callback, view); - - g_signal_connect_object (directory, "files-added", - G_CALLBACK (changed_callback), view, 0); - g_signal_connect_object (directory, "files-changed", - G_CALLBACK (changed_callback), view, 0); - - *directory_list = g_list_append (*directory_list, directory); - } -} - -static void -remove_directory_from_directory_list (NautilusView *view, - NautilusDirectory *directory, - GList **directory_list, - GCallback changed_callback) -{ - *directory_list = g_list_remove (*directory_list, directory); - - g_signal_handlers_disconnect_by_func (directory, - G_CALLBACK (changed_callback), - view); - - nautilus_directory_file_monitor_remove (directory, directory_list); - - nautilus_directory_unref (directory); -} - - -static void -add_directory_to_scripts_directory_list (NautilusView *view, - NautilusDirectory *directory) -{ - add_directory_to_directory_list (view, directory, - &view->details->scripts_directory_list, - G_CALLBACK (scripts_added_or_changed_callback)); -} - -static void -remove_directory_from_scripts_directory_list (NautilusView *view, - NautilusDirectory *directory) -{ - remove_directory_from_directory_list (view, directory, - &view->details->scripts_directory_list, - G_CALLBACK (scripts_added_or_changed_callback)); -} - -static void -add_directory_to_templates_directory_list (NautilusView *view, - NautilusDirectory *directory) -{ - add_directory_to_directory_list (view, directory, - &view->details->templates_directory_list, - G_CALLBACK (templates_added_or_changed_callback)); -} - -static void -remove_directory_from_templates_directory_list (NautilusView *view, - NautilusDirectory *directory) -{ - remove_directory_from_directory_list (view, directory, - &view->details->templates_directory_list, - G_CALLBACK (templates_added_or_changed_callback)); -} - -static void -slot_active (NautilusWindowSlot *slot, - NautilusView *view) -{ - if (view->details->active) { - return; - } - - view->details->active = TRUE; - - /* Avoid updating the toolbar withouth making sure the toolbar - * zoom slider has the correct adjustment that changes when the - * view mode changes - */ - nautilus_window_slot_sync_view_mode (slot); - nautilus_view_update_context_menus(view); - nautilus_view_update_toolbar_menus (view); - - schedule_update_context_menus (view); - - gtk_widget_insert_action_group (GTK_WIDGET (nautilus_view_get_window (view)), - "view", - G_ACTION_GROUP (view->details->view_action_group)); -} - -static void -slot_inactive (NautilusWindowSlot *slot, - NautilusView *view) -{ - if (!view->details->active) { - return; - } - - view->details->active = FALSE; - - remove_update_context_menus_timeout_callback (view); - gtk_widget_insert_action_group (GTK_WIDGET (nautilus_view_get_window (view)), - "view", - NULL); -} - -static void -nautilus_view_grab_focus (GtkWidget *widget) -{ - /* focus the child of the scrolled window if it exists */ - NautilusView *view; - GtkWidget *child; - - view = NAUTILUS_VIEW (widget); - child = gtk_bin_get_child (GTK_BIN (view->details->scrolled_window)); - - GTK_WIDGET_CLASS (nautilus_view_parent_class)->grab_focus (widget); - - if (child) { - gtk_widget_grab_focus (GTK_WIDGET (child)); - } -} - -int -nautilus_view_get_selection_count (NautilusView *view) -{ - /* FIXME: This could be faster if we special cased it in subclasses */ - GList *files; - int len; - - files = nautilus_view_get_selection (NAUTILUS_VIEW (view)); - len = g_list_length (files); - nautilus_file_list_free (files); - - return len; -} - -void -nautilus_view_set_selection (NautilusView *nautilus_view, - GList *selection) -{ - NautilusView *view; - - view = NAUTILUS_VIEW (nautilus_view); - - if (!view->details->loading) { - /* If we aren't still loading, set the selection right now, - * and reveal the new selection. - */ - nautilus_view_call_set_selection (view, selection); - nautilus_view_reveal_selection (view); - } else { - /* If we are still loading, set the list of pending URIs instead. - * done_loading() will eventually select the pending URIs and reveal them. - */ - g_list_free_full (view->details->pending_selection, g_object_unref); - view->details->pending_selection = - g_list_copy_deep (selection, (GCopyFunc) g_object_ref, NULL); - } -} - -static char * -get_bulk_rename_tool () -{ - char *bulk_rename_tool; - g_settings_get (nautilus_preferences, NAUTILUS_PREFERENCES_BULK_RENAME_TOOL, "^ay", &bulk_rename_tool); - return g_strstrip (bulk_rename_tool); -} - -static gboolean -have_bulk_rename_tool () -{ - char *bulk_rename_tool; - gboolean have_tool; - - bulk_rename_tool = get_bulk_rename_tool (); - have_tool = ((bulk_rename_tool != NULL) && (*bulk_rename_tool != '\0')); - g_free (bulk_rename_tool); - return have_tool; -} - -static void -nautilus_view_destroy (GtkWidget *object) -{ - NautilusView *view; - GList *node, *next; - - view = NAUTILUS_VIEW (object); - - nautilus_view_stop_loading (view); - - for (node = view->details->scripts_directory_list; node != NULL; node = next) { - next = node->next; - remove_directory_from_scripts_directory_list (view, node->data); - } - - for (node = view->details->templates_directory_list; node != NULL; node = next) { - next = node->next; - remove_directory_from_templates_directory_list (view, node->data); - } - - while (view->details->subdirectory_list != NULL) { - nautilus_view_remove_subdirectory (view, - view->details->subdirectory_list->data); - } - - remove_update_context_menus_timeout_callback (view); - remove_update_status_idle_callback (view); - - if (view->details->display_selection_idle_id != 0) { - g_source_remove (view->details->display_selection_idle_id); - view->details->display_selection_idle_id = 0; - } - - if (view->details->reveal_selection_idle_id != 0) { - g_source_remove (view->details->reveal_selection_idle_id); - view->details->reveal_selection_idle_id = 0; - } - - if (view->details->floating_bar_set_status_timeout_id != 0) { - g_source_remove (view->details->floating_bar_set_status_timeout_id); - view->details->floating_bar_set_status_timeout_id = 0; - } - - if (view->details->floating_bar_loading_timeout_id != 0) { - g_source_remove (view->details->floating_bar_loading_timeout_id); - view->details->floating_bar_loading_timeout_id = 0; - } - - - if (view->details->directory_as_file) { - nautilus_file_unref (view->details->directory_as_file); - view->details->directory_as_file = NULL; - } - - /* We don't own the slot, so no unref */ - view->details->slot = NULL; - - GTK_WIDGET_CLASS (nautilus_view_parent_class)->destroy (object); -} - -static void -nautilus_view_finalize (GObject *object) -{ - NautilusView *view; - - view = NAUTILUS_VIEW (object); - - g_signal_handlers_disconnect_by_func (nautilus_preferences, - schedule_update_context_menus, view); - g_signal_handlers_disconnect_by_func (nautilus_preferences, - click_policy_changed_callback, view); - g_signal_handlers_disconnect_by_func (nautilus_preferences, - sort_directories_first_changed_callback, view); - g_signal_handlers_disconnect_by_func (gtk_filechooser_preferences, - show_hidden_files_changed_callback, view); - g_signal_handlers_disconnect_by_func (nautilus_window_state, - nautilus_view_display_selection_info, view); - - g_signal_handlers_disconnect_by_func (gnome_lockdown_preferences, - schedule_update_context_menus, view); - - g_hash_table_destroy (view->details->non_ready_files); - - if (view->details->rename_file_popover != NULL) { - gtk_popover_set_relative_to (GTK_POPOVER (view->details->rename_file_popover), - NULL); - } - - G_OBJECT_CLASS (nautilus_view_parent_class)->finalize (object); -} - -/** - * nautilus_view_display_selection_info: - * - * Display information about the current selection, and notify the view frame of the changed selection. - * @view: NautilusView for which to display selection info. - * - **/ -void -nautilus_view_display_selection_info (NautilusView *view) -{ - GList *selection; - goffset non_folder_size; - gboolean non_folder_size_known; - guint non_folder_count, folder_count, folder_item_count; - gboolean folder_item_count_known; - guint file_item_count; - GList *p; - char *first_item_name; - char *non_folder_count_str; - char *non_folder_item_count_str; - char *folder_count_str; - char *folder_item_count_str; - char *primary_status; - char *detail_status; - NautilusFile *file; - - g_return_if_fail (NAUTILUS_IS_VIEW (view)); - - selection = nautilus_view_get_selection (view); - - folder_item_count_known = TRUE; - folder_count = 0; - folder_item_count = 0; - non_folder_count = 0; - non_folder_size_known = FALSE; - non_folder_size = 0; - first_item_name = NULL; - folder_count_str = NULL; - folder_item_count_str = NULL; - non_folder_count_str = NULL; - non_folder_item_count_str = NULL; - - for (p = selection; p != NULL; p = p->next) { - file = p->data; - if (nautilus_file_is_directory (file)) { - folder_count++; - if (nautilus_file_get_directory_item_count (file, &file_item_count, NULL)) { - folder_item_count += file_item_count; - } else { - folder_item_count_known = FALSE; - } - } else { - non_folder_count++; - if (!nautilus_file_can_get_size (file)) { - non_folder_size_known = TRUE; - non_folder_size += nautilus_file_get_size (file); - } - } - - if (first_item_name == NULL) { - first_item_name = nautilus_file_get_display_name (file); - } - } - - nautilus_file_list_free (selection); - - /* Break out cases for localization's sake. But note that there are still pieces - * being assembled in a particular order, which may be a problem for some localizers. - */ - - if (folder_count != 0) { - if (folder_count == 1 && non_folder_count == 0) { - folder_count_str = g_strdup_printf (_("“%s” selected"), first_item_name); - } else { - folder_count_str = g_strdup_printf (ngettext("%'d folder selected", - "%'d folders selected", - folder_count), - folder_count); - } - - if (folder_count == 1) { - if (!folder_item_count_known) { - folder_item_count_str = g_strdup (""); - } else { - folder_item_count_str = g_strdup_printf (ngettext("(containing %'d item)", - "(containing %'d items)", - folder_item_count), - folder_item_count); - } - } - else { - if (!folder_item_count_known) { - folder_item_count_str = g_strdup (""); - } else { - /* translators: this is preceded with a string of form 'N folders' (N more than 1) */ - folder_item_count_str = g_strdup_printf (ngettext("(containing a total of %'d item)", - "(containing a total of %'d items)", - folder_item_count), - folder_item_count); - } - - } - } - - if (non_folder_count != 0) { - if (folder_count == 0) { - if (non_folder_count == 1) { - non_folder_count_str = g_strdup_printf (_("“%s” selected"), - first_item_name); - } else { - non_folder_count_str = g_strdup_printf (ngettext("%'d item selected", - "%'d items selected", - non_folder_count), - non_folder_count); - } - } else { - /* Folders selected also, use "other" terminology */ - non_folder_count_str = g_strdup_printf (ngettext("%'d other item selected", - "%'d other items selected", - non_folder_count), - non_folder_count); - } - - if (non_folder_size_known) { - char *size_string; - - size_string = g_format_size (non_folder_size); - /* This is marked for translation in case a localiser - * needs to use something other than parentheses. The - * the message in parentheses is the size of the selected items. - */ - non_folder_item_count_str = g_strdup_printf (_("(%s)"), size_string); - g_free (size_string); - } else { - non_folder_item_count_str = g_strdup (""); - } - } - - if (folder_count == 0 && non_folder_count == 0) { - primary_status = NULL; - detail_status = NULL; - } else if (folder_count == 0) { - primary_status = g_strdup (non_folder_count_str); - detail_status = g_strdup (non_folder_item_count_str); - } else if (non_folder_count == 0) { - primary_status = g_strdup (folder_count_str); - detail_status = g_strdup (folder_item_count_str); - } else { - /* This is marked for translation in case a localizer - * needs to change ", " to something else. The comma - * is between the message about the number of folders - * and the number of items in those folders and the - * message about the number of other items and the - * total size of those items. - */ - primary_status = g_strdup_printf (_("%s %s, %s %s"), - folder_count_str, - folder_item_count_str, - non_folder_count_str, - non_folder_item_count_str); - detail_status = NULL; - } - - g_free (first_item_name); - g_free (folder_count_str); - g_free (folder_item_count_str); - g_free (non_folder_count_str); - g_free (non_folder_item_count_str); - - set_floating_bar_status (view, primary_status, detail_status); - - g_free (primary_status); - g_free (detail_status); -} - -static void -nautilus_view_send_selection_change (NautilusView *view) -{ - g_signal_emit (view, signals[SELECTION_CHANGED], 0); -} - -void -nautilus_view_load_location (NautilusView *nautilus_view, - GFile *location) -{ - NautilusDirectory *directory; - - nautilus_profile_start (NULL); - directory = nautilus_directory_get (location); - load_directory (nautilus_view, directory); - nautilus_directory_unref (directory); - nautilus_profile_end (NULL); -} - -static gboolean -reveal_selection_idle_callback (gpointer data) -{ - NautilusView *view; - - view = NAUTILUS_VIEW (data); - - view->details->reveal_selection_idle_id = 0; - nautilus_view_reveal_selection (view); - - return FALSE; -} - -static void -done_loading (NautilusView *view, - gboolean all_files_seen) -{ - GList *selection; - gboolean do_reveal = FALSE; - - if (!view->details->loading) { - return; - } - - nautilus_profile_start (NULL); - - /* This can be called during destruction, in which case we set the model - * as NULL. */ - if (view->details->model != NULL) { - nautilus_view_update_toolbar_menus (view); - remove_loading_floating_bar (view); - schedule_update_context_menus (view); - schedule_update_status (view); - reset_update_interval (view); - - selection = view->details->pending_selection; - - if (nautilus_view_is_search (view) && all_files_seen) { - nautilus_view_select_first (view); - do_reveal = TRUE; - } else if (selection != NULL && all_files_seen) { - view->details->pending_selection = NULL; - - nautilus_view_call_set_selection (view, selection); - g_list_free_full (selection, g_object_unref); - do_reveal = TRUE; - } - - if (do_reveal) { - if (NAUTILUS_IS_LIST_VIEW (view)) { - /* HACK: We should be able to directly call reveal_selection here, - * but at this point the GtkTreeView hasn't allocated the new nodes - * yet, and it has a bug in the scroll calculation dealing with this - * special case. It would always make the selection the top row, even - * if no scrolling would be neccessary to reveal it. So we let it - * allocate before revealing. - */ - if (view->details->reveal_selection_idle_id != 0) { - g_source_remove (view->details->reveal_selection_idle_id); - } - view->details->reveal_selection_idle_id = - g_idle_add (reveal_selection_idle_callback, view); - } else { - nautilus_view_reveal_selection (view); - } - } - nautilus_view_display_selection_info (view); - } - - view->details->loading = FALSE; - g_signal_emit (view, signals[END_LOADING], 0, all_files_seen); - - check_empty_states (view); - - nautilus_profile_end (NULL); -} - - -typedef struct { - GHashTable *debuting_files; - GList *added_files; -} DebutingFilesData; - -static void -debuting_files_data_free (DebutingFilesData *data) -{ - g_hash_table_unref (data->debuting_files); - nautilus_file_list_free (data->added_files); - g_free (data); -} - -/* This signal handler watch for the arrival of the icons created - * as the result of a file operation. Once the last one is detected - * it selects and reveals them all. - */ -static void -debuting_files_add_file_callback (NautilusView *view, - NautilusFile *new_file, - NautilusDirectory *directory, - DebutingFilesData *data) -{ - GFile *location; - - nautilus_profile_start (NULL); - - location = nautilus_file_get_location (new_file); - - if (g_hash_table_remove (data->debuting_files, location)) { - nautilus_file_ref (new_file); - data->added_files = g_list_prepend (data->added_files, new_file); - - if (g_hash_table_size (data->debuting_files) == 0) { - nautilus_view_call_set_selection (view, data->added_files); - nautilus_view_reveal_selection (view); - g_signal_handlers_disconnect_by_func (view, - G_CALLBACK (debuting_files_add_file_callback), - data); - } - } - - nautilus_profile_end (NULL); - - g_object_unref (location); -} - -typedef struct { - GList *added_files; - NautilusView *directory_view; -} CopyMoveDoneData; - -static void -copy_move_done_data_free (CopyMoveDoneData *data) -{ - g_assert (data != NULL); - - if (data->directory_view != NULL) { - g_object_remove_weak_pointer (G_OBJECT (data->directory_view), - (gpointer *) &data->directory_view); - } - - nautilus_file_list_free (data->added_files); - g_free (data); -} - -static void -pre_copy_move_add_file_callback (NautilusView *view, - NautilusFile *new_file, - NautilusDirectory *directory, - CopyMoveDoneData *data) -{ - nautilus_file_ref (new_file); - data->added_files = g_list_prepend (data->added_files, new_file); -} - -/* This needs to be called prior to nautilus_file_operations_copy_move. - * It hooks up a signal handler to catch any icons that get added before - * the copy_done_callback is invoked. The return value should be passed - * as the data for uri_copy_move_done_callback. - */ -static CopyMoveDoneData * -pre_copy_move (NautilusView *directory_view) -{ - CopyMoveDoneData *copy_move_done_data; - - copy_move_done_data = g_new0 (CopyMoveDoneData, 1); - copy_move_done_data->directory_view = directory_view; - - g_object_add_weak_pointer (G_OBJECT (copy_move_done_data->directory_view), - (gpointer *) ©_move_done_data->directory_view); - - /* We need to run after the default handler adds the folder we want to - * operate on. The ADD_FILE signal is registered as G_SIGNAL_RUN_LAST, so we - * must use connect_after. - */ - g_signal_connect (directory_view, "add-file", - G_CALLBACK (pre_copy_move_add_file_callback), copy_move_done_data); - - return copy_move_done_data; -} - -/* This function is used to pull out any debuting uris that were added - * and (as a side effect) remove them from the debuting uri hash table. - */ -static gboolean -copy_move_done_partition_func (gpointer data, gpointer callback_data) -{ - GFile *location; - gboolean result; - - location = nautilus_file_get_location (NAUTILUS_FILE (data)); - result = g_hash_table_remove ((GHashTable *) callback_data, location); - g_object_unref (location); - - return result; -} - -static gboolean -remove_not_really_moved_files (gpointer key, - gpointer value, - gpointer callback_data) -{ - GList **added_files; - GFile *loc; - - loc = key; - - if (GPOINTER_TO_INT (value)) { - return FALSE; - } - - added_files = callback_data; - *added_files = g_list_prepend (*added_files, - nautilus_file_get (loc)); - return TRUE; -} - -/* When this function is invoked, the file operation is over, but all - * the icons may not have been added to the directory view yet, so - * we can't select them yet. - * - * We're passed a hash table of the uri's to look out for, we hook - * up a signal handler to await their arrival. - */ -static void -copy_move_done_callback (GHashTable *debuting_files, - gboolean success, - gpointer data) -{ - NautilusView *directory_view; - CopyMoveDoneData *copy_move_done_data; - DebutingFilesData *debuting_files_data; - - copy_move_done_data = (CopyMoveDoneData *) data; - directory_view = copy_move_done_data->directory_view; - - if (directory_view != NULL) { - g_assert (NAUTILUS_IS_VIEW (directory_view)); - - debuting_files_data = g_new (DebutingFilesData, 1); - debuting_files_data->debuting_files = g_hash_table_ref (debuting_files); - debuting_files_data->added_files = eel_g_list_partition - (copy_move_done_data->added_files, - copy_move_done_partition_func, - debuting_files, - ©_move_done_data->added_files); - - /* We're passed the same data used by pre_copy_move_add_file_callback, so disconnecting - * it will free data. We've already siphoned off the added_files we need, and stashed the - * directory_view pointer. - */ - g_signal_handlers_disconnect_by_func (directory_view, - G_CALLBACK (pre_copy_move_add_file_callback), - data); - - /* Any items in the debuting_files hash table that have - * "FALSE" as their value aren't really being copied - * or moved, so we can't wait for an add_file signal - * to come in for those. - */ - g_hash_table_foreach_remove (debuting_files, - remove_not_really_moved_files, - &debuting_files_data->added_files); - - if (g_hash_table_size (debuting_files) == 0) { - /* on the off-chance that all the icons have already been added */ - if (debuting_files_data->added_files != NULL) { - nautilus_view_call_set_selection (directory_view, - debuting_files_data->added_files); - nautilus_view_reveal_selection (directory_view); - } - debuting_files_data_free (debuting_files_data); - } else { - /* We need to run after the default handler adds the folder we want to - * operate on. The ADD_FILE signal is registered as G_SIGNAL_RUN_LAST, so we - * must use connect_after. - */ - g_signal_connect_data (directory_view, - "add-file", - G_CALLBACK (debuting_files_add_file_callback), - debuting_files_data, - (GClosureNotify) debuting_files_data_free, - G_CONNECT_AFTER); - } - /* Schedule menu update for undo items */ - schedule_update_context_menus (directory_view); - } - - copy_move_done_data_free (copy_move_done_data); -} - -static gboolean -view_file_still_belongs (NautilusView *view, - NautilusFile *file, - NautilusDirectory *directory) -{ - if (view->details->model != directory && - g_list_find (view->details->subdirectory_list, directory) == NULL) { - return FALSE; - } - - return nautilus_directory_contains_file (directory, file); -} - -static gboolean -still_should_show_file (NautilusView *view, NautilusFile *file, NautilusDirectory *directory) -{ - return nautilus_view_should_show_file (view, file) && - view_file_still_belongs (view, file, directory); -} - -static gboolean -ready_to_load (NautilusFile *file) -{ - return nautilus_file_check_if_ready (file, - NAUTILUS_FILE_ATTRIBUTES_FOR_ICON); -} - -static int -compare_files_cover (gconstpointer a, gconstpointer b, gpointer callback_data) -{ - const FileAndDirectory *fad1, *fad2; - NautilusView *view; - - view = callback_data; - fad1 = a; fad2 = b; - - if (fad1->directory < fad2->directory) { - return -1; - } else if (fad1->directory > fad2->directory) { - return 1; - } else { - return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->compare_files (view, fad1->file, fad2->file); - } -} -static void -sort_files (NautilusView *view, GList **list) -{ - *list = g_list_sort_with_data (*list, compare_files_cover, view); - -} - -/* Go through all the new added and changed files. - * Put any that are not ready to load in the non_ready_files hash table. - * Add all the rest to the old_added_files and old_changed_files lists. - * Sort the old_*_files lists if anything was added to them. - */ -static void -process_new_files (NautilusView *view) -{ - GList *new_added_files, *new_changed_files, *old_added_files, *old_changed_files; - GHashTable *non_ready_files; - GList *node, *next; - FileAndDirectory *pending; - gboolean in_non_ready; - - new_added_files = view->details->new_added_files; - view->details->new_added_files = NULL; - new_changed_files = view->details->new_changed_files; - view->details->new_changed_files = NULL; - - non_ready_files = view->details->non_ready_files; - - old_added_files = view->details->old_added_files; - old_changed_files = view->details->old_changed_files; - - /* Newly added files go into the old_added_files list if they're - * ready, and into the hash table if they're not. - */ - for (node = new_added_files; node != NULL; node = next) { - next = node->next; - pending = (FileAndDirectory *)node->data; - in_non_ready = g_hash_table_lookup (non_ready_files, pending) != NULL; - if (nautilus_view_should_show_file (view, pending->file)) { - if (ready_to_load (pending->file)) { - if (in_non_ready) { - g_hash_table_remove (non_ready_files, pending); - } - new_added_files = g_list_delete_link (new_added_files, node); - old_added_files = g_list_prepend (old_added_files, pending); - } else { - if (!in_non_ready) { - new_added_files = g_list_delete_link (new_added_files, node); - g_hash_table_insert (non_ready_files, pending, pending); - } - } - } - } - file_and_directory_list_free (new_added_files); - - /* Newly changed files go into the old_added_files list if they're ready - * and were seen non-ready in the past, into the old_changed_files list - * if they are read and were not seen non-ready in the past, and into - * the hash table if they're not ready. - */ - for (node = new_changed_files; node != NULL; node = next) { - next = node->next; - pending = (FileAndDirectory *)node->data; - if (!still_should_show_file (view, pending->file, pending->directory) || ready_to_load (pending->file)) { - if (g_hash_table_lookup (non_ready_files, pending) != NULL) { - g_hash_table_remove (non_ready_files, pending); - if (still_should_show_file (view, pending->file, pending->directory)) { - new_changed_files = g_list_delete_link (new_changed_files, node); - old_added_files = g_list_prepend (old_added_files, pending); - } - } else if (nautilus_view_should_show_file (view, pending->file)) { - new_changed_files = g_list_delete_link (new_changed_files, node); - old_changed_files = g_list_prepend (old_changed_files, pending); - } - } - } - file_and_directory_list_free (new_changed_files); - - /* If any files were added to old_added_files, then resort it. */ - if (old_added_files != view->details->old_added_files) { - view->details->old_added_files = old_added_files; - sort_files (view, &view->details->old_added_files); - } - - /* Resort old_changed_files too, since file attributes - * relevant to sorting could have changed. - */ - if (old_changed_files != view->details->old_changed_files) { - view->details->old_changed_files = old_changed_files; - sort_files (view, &view->details->old_changed_files); - } - -} - -static void -process_old_files (NautilusView *view) -{ - GList *files_added, *files_changed, *node; - FileAndDirectory *pending; - GList *selection, *files; - gboolean send_selection_change; - - files_added = view->details->old_added_files; - files_changed = view->details->old_changed_files; - - send_selection_change = FALSE; - - if (files_added != NULL || files_changed != NULL) { - g_signal_emit (view, signals[BEGIN_FILE_CHANGES], 0); - - for (node = files_added; node != NULL; node = node->next) { - pending = node->data; - g_signal_emit (view, - signals[ADD_FILE], 0, pending->file, pending->directory); - } - - for (node = files_changed; node != NULL; node = node->next) { - pending = node->data; - g_signal_emit (view, - signals[still_should_show_file (view, pending->file, pending->directory) - ? FILE_CHANGED : REMOVE_FILE], 0, - pending->file, pending->directory); - } - - g_signal_emit (view, signals[END_FILE_CHANGES], 0); - check_empty_states (view); - - if (files_changed != NULL) { - selection = nautilus_view_get_selection (view); - files = file_and_directory_list_to_files (files_changed); - send_selection_change = eel_g_lists_sort_and_check_for_intersection - (&files, &selection); - nautilus_file_list_free (files); - nautilus_file_list_free (selection); - } - - file_and_directory_list_free (view->details->old_added_files); - view->details->old_added_files = NULL; - - file_and_directory_list_free (view->details->old_changed_files); - view->details->old_changed_files = NULL; - } - - if (send_selection_change) { - /* Send a selection change since some file names could - * have changed. - */ - nautilus_view_send_selection_change (view); - } -} - -static void -display_pending_files (NautilusView *view) -{ - process_new_files (view); - process_old_files (view); - - if (view->details->model != NULL - && nautilus_directory_are_all_files_seen (view->details->model) - && g_hash_table_size (view->details->non_ready_files) == 0) { - done_loading (view, TRUE); - } -} - -static gboolean -display_selection_info_idle_callback (gpointer data) -{ - NautilusView *view; - - view = NAUTILUS_VIEW (data); - - g_object_ref (G_OBJECT (view)); - - view->details->display_selection_idle_id = 0; - nautilus_view_display_selection_info (view); - nautilus_view_send_selection_change (view); - - g_object_unref (G_OBJECT (view)); - - return FALSE; -} - -static void -remove_update_context_menus_timeout_callback (NautilusView *view) -{ - if (view->details->update_context_menus_timeout_id != 0) { - g_source_remove (view->details->update_context_menus_timeout_id); - view->details->update_context_menus_timeout_id = 0; - } -} - -static void -update_context_menus_if_pending (NautilusView *view) -{ - remove_update_context_menus_timeout_callback (view); - - nautilus_view_update_context_menus(view); -} - -static gboolean -update_context_menus_timeout_callback (gpointer data) -{ - NautilusView *view; - - view = NAUTILUS_VIEW (data); - - g_object_ref (G_OBJECT (view)); - - view->details->update_context_menus_timeout_id = 0; - nautilus_view_update_context_menus(view); - - g_object_unref (G_OBJECT (view)); - - return FALSE; -} - -static gboolean -display_pending_callback (gpointer data) -{ - NautilusView *view; - - view = NAUTILUS_VIEW (data); - - g_object_ref (G_OBJECT (view)); - - view->details->display_pending_source_id = 0; - - display_pending_files (view); - - g_object_unref (G_OBJECT (view)); - - return FALSE; -} - -static void -schedule_idle_display_of_pending_files (NautilusView *view) -{ - /* Get rid of a pending source as it might be a timeout */ - unschedule_display_of_pending_files (view); - - /* We want higher priority than the idle that handles the relayout - to avoid a resort on each add. But we still want to allow repaints - and other hight prio events while we have pending files to show. */ - view->details->display_pending_source_id = - g_idle_add_full (G_PRIORITY_DEFAULT_IDLE - 20, - display_pending_callback, view, NULL); -} - -static void -schedule_timeout_display_of_pending_files (NautilusView *view, guint interval) -{ - /* No need to schedule an update if there's already one pending. */ - if (view->details->display_pending_source_id != 0) { - return; - } - - view->details->display_pending_source_id = - g_timeout_add (interval, display_pending_callback, view); -} - -static void -unschedule_display_of_pending_files (NautilusView *view) -{ - /* Get rid of source if it's active. */ - if (view->details->display_pending_source_id != 0) { - g_source_remove (view->details->display_pending_source_id); - view->details->display_pending_source_id = 0; - } -} - -static void -queue_pending_files (NautilusView *view, - NautilusDirectory *directory, - GList *files, - GList **pending_list) -{ - if (files == NULL) { - return; - } - - *pending_list = g_list_concat (file_and_directory_list_from_files (directory, files), - *pending_list); - - if (! view->details->loading || nautilus_directory_are_all_files_seen (directory)) { - schedule_timeout_display_of_pending_files (view, view->details->update_interval); - } -} - -static void -remove_changes_timeout_callback (NautilusView *view) -{ - if (view->details->changes_timeout_id != 0) { - g_source_remove (view->details->changes_timeout_id); - view->details->changes_timeout_id = 0; - } -} - -static void -reset_update_interval (NautilusView *view) -{ - view->details->update_interval = UPDATE_INTERVAL_MIN; - remove_changes_timeout_callback (view); - /* Reschedule a pending timeout to idle */ - if (view->details->display_pending_source_id != 0) { - schedule_idle_display_of_pending_files (view); - } -} - -static gboolean -changes_timeout_callback (gpointer data) -{ - gint64 now; - gint64 time_delta; - gboolean ret; - NautilusView *view; - - view = NAUTILUS_VIEW (data); - - g_object_ref (G_OBJECT (view)); - - now = g_get_monotonic_time (); - time_delta = now - view->details->last_queued; - - if (time_delta < UPDATE_INTERVAL_RESET*1000) { - if (view->details->update_interval < UPDATE_INTERVAL_MAX && - view->details->loading) { - /* Increase */ - view->details->update_interval += UPDATE_INTERVAL_INC; - } - ret = TRUE; - } else { - /* Reset */ - reset_update_interval (view); - ret = FALSE; - } - - g_object_unref (G_OBJECT (view)); - - return ret; -} - -static void -schedule_changes (NautilusView *view) -{ - /* Remember when the change was queued */ - view->details->last_queued = g_get_monotonic_time (); - - /* No need to schedule if there are already changes pending or during loading */ - if (view->details->changes_timeout_id != 0 || - view->details->loading) { - return; - } - - view->details->changes_timeout_id = - g_timeout_add (UPDATE_INTERVAL_TIMEOUT_INTERVAL, changes_timeout_callback, view); -} - -static void -files_added_callback (NautilusDirectory *directory, - GList *files, - gpointer callback_data) -{ - NautilusView *view; - GtkWindow *window; - char *uri; - - view = NAUTILUS_VIEW (callback_data); - - nautilus_profile_start (NULL); - - window = nautilus_view_get_containing_window (view); - uri = nautilus_view_get_uri (view); - DEBUG_FILES (files, "Files added in window %p: %s", - window, uri ? uri : "(no directory)"); - g_free (uri); - - schedule_changes (view); - - queue_pending_files (view, directory, files, &view->details->new_added_files); - - /* The number of items could have changed */ - schedule_update_status (view); - - nautilus_profile_end (NULL); -} - -static void -files_changed_callback (NautilusDirectory *directory, - GList *files, - gpointer callback_data) -{ - NautilusView *view; - GtkWindow *window; - char *uri; - - view = NAUTILUS_VIEW (callback_data); - - window = nautilus_view_get_containing_window (view); - uri = nautilus_view_get_uri (view); - DEBUG_FILES (files, "Files changed in window %p: %s", - window, uri ? uri : "(no directory)"); - g_free (uri); - - schedule_changes (view); - - queue_pending_files (view, directory, files, &view->details->new_changed_files); - - /* The free space or the number of items could have changed */ - schedule_update_status (view); - - /* A change in MIME type could affect the Open with menu, for - * one thing, so we need to update menus when files change. - */ - schedule_update_context_menus (view); -} - -static void -done_loading_callback (NautilusDirectory *directory, - gpointer callback_data) -{ - NautilusView *view; - - view = NAUTILUS_VIEW (callback_data); - - nautilus_profile_start (NULL); - process_new_files (view); - if (g_hash_table_size (view->details->non_ready_files) == 0) { - /* Unschedule a pending update and schedule a new one with the minimal - * update interval. This gives the view a short chance at gathering the - * (cached) deep counts. - */ - unschedule_display_of_pending_files (view); - schedule_timeout_display_of_pending_files (view, UPDATE_INTERVAL_MIN); - - remove_loading_floating_bar (view); - } - nautilus_profile_end (NULL); -} - -static void -load_error_callback (NautilusDirectory *directory, - GError *error, - gpointer callback_data) -{ - NautilusView *view; - - view = NAUTILUS_VIEW (callback_data); - - /* FIXME: By doing a stop, we discard some pending files. Is - * that OK? - */ - nautilus_view_stop_loading (view); - - nautilus_report_error_loading_directory - (nautilus_view_get_directory_as_file (view), - error, - nautilus_view_get_containing_window (view)); -} - -void -nautilus_view_add_subdirectory (NautilusView *view, - NautilusDirectory*directory) -{ - NautilusFileAttributes attributes; - - g_assert (!g_list_find (view->details->subdirectory_list, directory)); - - nautilus_directory_ref (directory); - - attributes = - NAUTILUS_FILE_ATTRIBUTES_FOR_ICON | - NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT | - NAUTILUS_FILE_ATTRIBUTE_INFO | - NAUTILUS_FILE_ATTRIBUTE_LINK_INFO | - NAUTILUS_FILE_ATTRIBUTE_MOUNT | - NAUTILUS_FILE_ATTRIBUTE_EXTENSION_INFO; - - nautilus_directory_file_monitor_add (directory, - &view->details->model, - view->details->show_hidden_files, - attributes, - files_added_callback, view); - - g_signal_connect - (directory, "files-added", - G_CALLBACK (files_added_callback), view); - g_signal_connect - (directory, "files-changed", - G_CALLBACK (files_changed_callback), view); - - view->details->subdirectory_list = g_list_prepend ( - view->details->subdirectory_list, directory); -} - -void -nautilus_view_remove_subdirectory (NautilusView *view, - NautilusDirectory*directory) -{ - g_assert (g_list_find (view->details->subdirectory_list, directory)); - - view->details->subdirectory_list = g_list_remove ( - view->details->subdirectory_list, directory); - - g_signal_handlers_disconnect_by_func (directory, - G_CALLBACK (files_added_callback), - view); - g_signal_handlers_disconnect_by_func (directory, - G_CALLBACK (files_changed_callback), - view); - - nautilus_directory_file_monitor_remove (directory, &view->details->model); - - nautilus_directory_unref (directory); -} - -/** - * nautilus_view_get_loading: - * @view: an #NautilusView. - * - * Return value: #gboolean inicating whether @view is currently loaded. - * - **/ -gboolean -nautilus_view_get_loading (NautilusView *view) -{ - g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE); - - return view->details->loading; -} - -/** - * nautilus_view_get_model: - * - * Get the model for this NautilusView. - * @view: NautilusView of interest. - * - * Return value: NautilusDirectory for this view. - * - **/ -NautilusDirectory * -nautilus_view_get_model (NautilusView *view) -{ - g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL); - - return view->details->model; -} - -GtkWidget* -nautilus_view_get_content_widget (NautilusView *view) -{ - g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL); - - return view->details->scrolled_window; -} - -GdkAtom -nautilus_view_get_copied_files_atom (NautilusView *view) -{ - g_return_val_if_fail (NAUTILUS_IS_VIEW (view), GDK_NONE); - - return copied_files_atom; -} - -static void -offset_drop_points (GArray *relative_item_points, - int x_offset, int y_offset) -{ - guint index; - - if (relative_item_points == NULL) { - return; - } - - for (index = 0; index < relative_item_points->len; index++) { - g_array_index (relative_item_points, GdkPoint, index).x += x_offset; - g_array_index (relative_item_points, GdkPoint, index).y += y_offset; - } -} - -/* special_link_in_selection - * - * Return TRUE if one of our special links is in the selection. - * Special links include the following: - * NAUTILUS_DESKTOP_LINK_TRASH, NAUTILUS_DESKTOP_LINK_HOME, NAUTILUS_DESKTOP_LINK_MOUNT - */ - -static gboolean -special_link_in_selection (GList *selection) -{ - gboolean saw_link; - GList *node; - NautilusFile *file; - - saw_link = FALSE; - - for (node = selection; node != NULL; node = node->next) { - file = NAUTILUS_FILE (node->data); - - saw_link = NAUTILUS_IS_DESKTOP_ICON_FILE (file); - - if (saw_link) { - break; - } - } - - return saw_link; -} - -/* desktop_or_home_dir_in_selection - * - * Return TRUE if either the desktop or the home directory is in the selection. - */ - -static gboolean -desktop_or_home_dir_in_selection (GList *selection) -{ - gboolean saw_desktop_or_home_dir; - GList *node; - NautilusFile *file; - - saw_desktop_or_home_dir = FALSE; - - for (node = selection; node != NULL; node = node->next) { - file = NAUTILUS_FILE (node->data); - - saw_desktop_or_home_dir = - nautilus_file_is_home (file) - || nautilus_file_is_desktop_directory (file); - - if (saw_desktop_or_home_dir) { - break; - } - } - - return saw_desktop_or_home_dir; -} - -static void -trash_or_delete_done_cb (GHashTable *debuting_uris, - gboolean user_cancel, - NautilusView *view) -{ - if (user_cancel) { - view->details->selection_was_removed = FALSE; - } -} - -static void -trash_or_delete_files (GtkWindow *parent_window, - const GList *files, - NautilusView *view) -{ - GList *locations; - const GList *node; - - locations = NULL; - for (node = files; node != NULL; node = node->next) { - locations = g_list_prepend (locations, - nautilus_file_get_location ((NautilusFile *) node->data)); - } - - locations = g_list_reverse (locations); - - nautilus_file_operations_trash_or_delete (locations, - parent_window, - (NautilusDeleteCallback) trash_or_delete_done_cb, - view); - g_list_free_full (locations, g_object_unref); -} - -static gboolean -can_rename_file (NautilusView *view, NautilusFile *file) -{ - return nautilus_file_can_rename (file); -} - -static void -open_one_in_new_window (gpointer data, gpointer callback_data) -{ - g_assert (NAUTILUS_IS_FILE (data)); - g_assert (NAUTILUS_IS_VIEW (callback_data)); - - nautilus_view_activate_file (NAUTILUS_VIEW (callback_data), - NAUTILUS_FILE (data), - NAUTILUS_WINDOW_OPEN_FLAG_NEW_WINDOW); -} - -static void -update_context_menu_position_from_event (NautilusView *view, - GdkEventButton *event) -{ - g_return_if_fail (NAUTILUS_IS_VIEW (view)); - - if (event != NULL) { - view->details->context_menu_position.x = event->x; - view->details->context_menu_position.y = event->y; - } else { - view->details->context_menu_position.x = -1; - view->details->context_menu_position.y = -1; - } -} - -NautilusFile * -nautilus_view_get_directory_as_file (NautilusView *view) -{ - g_assert (NAUTILUS_IS_VIEW (view)); - - return view->details->directory_as_file; -} - -static GdkPixbuf * -get_menu_icon_for_file (NautilusFile *file, - GtkWidget *widget) -{ - NautilusIconInfo *info; - GdkPixbuf *pixbuf; - int size, scale; - - size = nautilus_get_icon_size_for_stock_size (GTK_ICON_SIZE_MENU); - scale = gtk_widget_get_scale_factor (widget); - - info = nautilus_file_get_icon (file, size, scale, 0); - pixbuf = nautilus_icon_info_get_pixbuf_nodefault_at_size (info, size); - g_object_unref (info); - - return pixbuf; -} - -static GList * -get_extension_selection_menu_items (NautilusView *view) -{ - NautilusWindow *window; - GList *items; - GList *providers; - GList *l; - GList *selection; - - window = nautilus_view_get_window (view); - selection = nautilus_view_get_selection (view); - providers = nautilus_module_get_extensions_for_type (NAUTILUS_TYPE_MENU_PROVIDER); - items = NULL; - - for (l = providers; l != NULL; l = l->next) { - NautilusMenuProvider *provider; - GList *file_items; - - provider = NAUTILUS_MENU_PROVIDER (l->data); - file_items = nautilus_menu_provider_get_file_items (provider, - GTK_WIDGET (window), - selection); - items = g_list_concat (items, file_items); - } - - nautilus_module_extension_list_free (providers); - - return items; -} - -static GList * -get_extension_background_menu_items (NautilusView *view) -{ - NautilusWindow *window; - NautilusFile *file; - GList *items; - GList *providers; - GList *l; - - window = nautilus_view_get_window (view); - providers = nautilus_module_get_extensions_for_type (NAUTILUS_TYPE_MENU_PROVIDER); - file = nautilus_window_slot_get_file (view->details->slot); - items = NULL; - - for (l = providers; l != NULL; l = l->next) { - NautilusMenuProvider *provider; - GList *file_items; - - provider = NAUTILUS_MENU_PROVIDER (l->data); - file_items = nautilus_menu_provider_get_background_items (provider, - GTK_WIDGET (window), - file); - items = g_list_concat (items, file_items); - } - - nautilus_module_extension_list_free (providers); - - return items; -} - -static void -extension_action_callback (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - NautilusMenuItem *item = user_data; - nautilus_menu_item_activate (item); -} - -static void -add_extension_action (NautilusView *view, - NautilusMenuItem *item, - const char *action_name) -{ - gboolean sensitive; - GSimpleAction *action; - - g_object_get (item, - "sensitive", &sensitive, - NULL); - - action = g_simple_action_new (action_name, NULL); - g_signal_connect_data (action, "activate", - G_CALLBACK (extension_action_callback), - g_object_ref (item), - (GClosureNotify) g_object_unref, 0); - - g_action_map_add_action (G_ACTION_MAP (view->details->view_action_group), - G_ACTION (action)); - g_simple_action_set_enabled (action, sensitive); - - g_object_unref (action); -} - -static GMenu * -build_menu_for_extension_menu_items (NautilusView *view, - const gchar *extension_prefix, - GList *menu_items) -{ - GList *l; - GMenu *gmenu; - gint idx = 0; - - gmenu = g_menu_new (); - - for (l = menu_items; l; l = l->next) { - NautilusMenuItem *item; - NautilusMenu *menu; - GMenuItem *menu_item; - char *name, *label; - char *extension_id, *prefix, *parsed_name, *detailed_action_name; - - item = NAUTILUS_MENU_ITEM (l->data); - - g_object_get (item, - "label", &label, - "menu", &menu, - "name", &name, - NULL); - - extension_id = g_strdup_printf ("%s_%d", extension_prefix, idx); - prefix = g_strdup_printf ("extension_%s_", extension_id); - parsed_name = nautilus_escape_action_name (name, prefix); - add_extension_action (view, item, parsed_name); - - detailed_action_name = g_strconcat ("view.", parsed_name, NULL); - menu_item = g_menu_item_new (label, detailed_action_name); - - if (menu != NULL) { - GList *children; - GMenu *children_menu; - - children = nautilus_menu_get_items (menu); - children_menu = build_menu_for_extension_menu_items (view, extension_id, children); - g_menu_item_set_submenu (menu_item, G_MENU_MODEL (children_menu)); - - nautilus_menu_item_list_free (children); - g_object_unref (children_menu); - } - - g_menu_append_item (gmenu, menu_item); - idx++; - - g_free (extension_id); - g_free (parsed_name); - g_free (prefix); - g_free (detailed_action_name); - g_free (name); - g_free (label); - g_object_unref (menu_item); - } - - return gmenu; -} - -static void -add_extension_menu_items (NautilusView *view, - const gchar *extension_prefix, - GList *menu_items, - GMenu *insertion_menu) -{ - GMenu *menu; - - menu = build_menu_for_extension_menu_items (view, extension_prefix, menu_items); - nautilus_gmenu_merge (insertion_menu, - menu, - "extensions", - FALSE); - - g_object_unref (menu); -} - -static void -update_extensions_menus (NautilusView *view) -{ - GList *selection_items, *background_items; - - selection_items = get_extension_selection_menu_items (view); - if (selection_items != NULL) { - add_extension_menu_items (view, - "selection", - selection_items, - view->details->selection_menu); - nautilus_menu_item_list_free (selection_items); - } - - background_items = get_extension_background_menu_items (view); - if (background_items != NULL) { - add_extension_menu_items (view, - "background", - background_items, - view->details->background_menu); - nautilus_menu_item_list_free (background_items); - } -} - -static char * -change_to_view_directory (NautilusView *view) -{ - char *path; - char *old_path; - - old_path = g_get_current_dir (); - - path = get_view_directory (view); - - /* FIXME: What to do about non-local directories? */ - if (path != NULL) { - g_chdir (path); - } - - g_free (path); - - return old_path; -} - -static char ** -get_file_names_as_parameter_array (GList *selection, - NautilusDirectory *model) -{ - NautilusFile *file; - char **parameters; - GList *node; - GFile *file_location; - GFile *model_location; - int i; - - if (model == NULL) { - return NULL; - } - - parameters = g_new (char *, g_list_length (selection) + 1); - - model_location = nautilus_directory_get_location (model); - - for (node = selection, i = 0; node != NULL; node = node->next, i++) { - file = NAUTILUS_FILE (node->data); - - if (!nautilus_file_is_local (file)) { - parameters[i] = NULL; - g_strfreev (parameters); - return NULL; - } - - file_location = nautilus_file_get_location (NAUTILUS_FILE (node->data)); - parameters[i] = g_file_get_relative_path (model_location, file_location); - if (parameters[i] == NULL) { - parameters[i] = g_file_get_path (file_location); - } - g_object_unref (file_location); - } - - g_object_unref (model_location); - - parameters[i] = NULL; - return parameters; -} - -static char * -get_file_paths_or_uris_as_newline_delimited_string (GList *selection, gboolean get_paths) -{ - char *path; - char *uri; - char *result; - NautilusDesktopLink *link; - GString *expanding_string; - GList *node; - GFile *location; - - expanding_string = g_string_new (""); - for (node = selection; node != NULL; node = node->next) { - uri = NULL; - if (NAUTILUS_IS_DESKTOP_ICON_FILE (node->data)) { - link = nautilus_desktop_icon_file_get_link (NAUTILUS_DESKTOP_ICON_FILE (node->data)); - if (link != NULL) { - location = nautilus_desktop_link_get_activation_location (link); - uri = g_file_get_uri (location); - g_object_unref (location); - g_object_unref (G_OBJECT (link)); - } - } else { - uri = nautilus_file_get_uri (NAUTILUS_FILE (node->data)); - } - if (uri == NULL) { - continue; - } - - if (get_paths) { - path = g_filename_from_uri (uri, NULL, NULL); - if (path != NULL) { - g_string_append (expanding_string, path); - g_free (path); - g_string_append (expanding_string, "\n"); - } - } else { - g_string_append (expanding_string, uri); - g_string_append (expanding_string, "\n"); - } - g_free (uri); - } - - result = expanding_string->str; - g_string_free (expanding_string, FALSE); - - return result; -} - -static char * -get_file_paths_as_newline_delimited_string (GList *selection) -{ - return get_file_paths_or_uris_as_newline_delimited_string (selection, TRUE); -} - -static char * -get_file_uris_as_newline_delimited_string (GList *selection) -{ - return get_file_paths_or_uris_as_newline_delimited_string (selection, FALSE); -} - -/* returns newly allocated strings for setting the environment variables */ -static void -get_strings_for_environment_variables (NautilusView *view, GList *selected_files, - char **file_paths, char **uris, char **uri) -{ - char *directory_uri; - - /* We need to check that the directory uri starts with "file:" since - * nautilus_directory_is_local returns FALSE for nfs. - */ - directory_uri = nautilus_directory_get_uri (view->details->model); - if (g_str_has_prefix (directory_uri, "file:") || - eel_uri_is_desktop (directory_uri) || - eel_uri_is_trash (directory_uri)) { - *file_paths = get_file_paths_as_newline_delimited_string (selected_files); - } else { - *file_paths = g_strdup (""); - } - g_free (directory_uri); - - *uris = get_file_uris_as_newline_delimited_string (selected_files); - - *uri = nautilus_directory_get_uri (view->details->model); - if (eel_uri_is_desktop (*uri)) { - g_free (*uri); - *uri = nautilus_get_desktop_directory_uri (); - } -} - -/* - * Set up some environment variables that scripts can use - * to take advantage of the current Nautilus state. - */ -static void -set_script_environment_variables (NautilusView *view, GList *selected_files) -{ - char *file_paths; - char *uris; - char *uri; - char *geometry_string; - - get_strings_for_environment_variables (view, selected_files, - &file_paths, &uris, &uri); - - g_setenv ("NAUTILUS_SCRIPT_SELECTED_FILE_PATHS", file_paths, TRUE); - g_free (file_paths); - - g_setenv ("NAUTILUS_SCRIPT_SELECTED_URIS", uris, TRUE); - g_free (uris); - - g_setenv ("NAUTILUS_SCRIPT_CURRENT_URI", uri, TRUE); - g_free (uri); - - geometry_string = eel_gtk_window_get_geometry_string - (GTK_WINDOW (nautilus_view_get_containing_window (view))); - g_setenv ("NAUTILUS_SCRIPT_WINDOW_GEOMETRY", geometry_string, TRUE); - g_free (geometry_string); -} - -/* Unset all the special script environment variables. */ -static void -unset_script_environment_variables (void) -{ - g_unsetenv ("NAUTILUS_SCRIPT_SELECTED_FILE_PATHS"); - g_unsetenv ("NAUTILUS_SCRIPT_SELECTED_URIS"); - g_unsetenv ("NAUTILUS_SCRIPT_CURRENT_URI"); - g_unsetenv ("NAUTILUS_SCRIPT_WINDOW_GEOMETRY"); -} - -static void -run_script (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - ScriptLaunchParameters *launch_parameters; - GdkScreen *screen; - GList *selected_files; - char *file_uri; - char *local_file_path; - char *quoted_path; - char *old_working_dir; - char **parameters; - - launch_parameters = (ScriptLaunchParameters *) user_data; - - file_uri = nautilus_file_get_uri (launch_parameters->file); - local_file_path = g_filename_from_uri (file_uri, NULL, NULL); - g_assert (local_file_path != NULL); - g_free (file_uri); - - quoted_path = g_shell_quote (local_file_path); - g_free (local_file_path); - - old_working_dir = change_to_view_directory (launch_parameters->directory_view); - - selected_files = nautilus_view_get_selection (launch_parameters->directory_view); - set_script_environment_variables (launch_parameters->directory_view, selected_files); - - parameters = get_file_names_as_parameter_array (selected_files, - launch_parameters->directory_view->details->model); - - screen = gtk_widget_get_screen (GTK_WIDGET (launch_parameters->directory_view)); - - DEBUG ("run_script, script_path=“%s” (omitting script parameters)", - local_file_path); - - nautilus_launch_application_from_command_array (screen, quoted_path, FALSE, - (const char * const *) parameters); - g_strfreev (parameters); - - nautilus_file_list_free (selected_files); - unset_script_environment_variables (); - g_chdir (old_working_dir); - g_free (old_working_dir); - g_free (quoted_path); -} - -static void -add_script_to_scripts_menus (NautilusView *view, - NautilusFile *file, - GMenu *menu) -{ - gchar *name; - GdkPixbuf *mimetype_icon; - gchar *action_name, *detailed_action_name; - ScriptLaunchParameters *launch_parameters; - GAction *action; - GMenuItem *menu_item; - - launch_parameters = script_launch_parameters_new (file, view); - - name = nautilus_file_get_display_name (file); - action_name = nautilus_escape_action_name (name, "script_"); - - action = G_ACTION (g_simple_action_new (action_name, NULL)); - - g_signal_connect_data (action, "activate", - G_CALLBACK (run_script), - launch_parameters, - (GClosureNotify)script_launch_parameters_free, 0); - - g_action_map_add_action (G_ACTION_MAP (view->details->view_action_group), action); - - g_object_unref (action); - - detailed_action_name = g_strconcat ("view.", action_name, NULL); - menu_item = g_menu_item_new (name, detailed_action_name); - - mimetype_icon = get_menu_icon_for_file (file, GTK_WIDGET (view)); - if (mimetype_icon != NULL) { - g_menu_item_set_icon (menu_item, G_ICON (mimetype_icon)); - g_object_unref (mimetype_icon); - } - - g_menu_append_item (menu, menu_item); - - g_free (name); - g_free (action_name); - g_free (detailed_action_name); - g_object_unref (menu_item); -} - -static gboolean -directory_belongs_in_scripts_menu (const char *uri) -{ - int num_levels; - int i; - - if (!g_str_has_prefix (uri, scripts_directory_uri)) { - return FALSE; - } - - num_levels = 0; - for (i = scripts_directory_uri_length; uri[i] != '\0'; i++) { - if (uri[i] == '/') { - num_levels++; - } - } - - if (num_levels > MAX_MENU_LEVELS) { - return FALSE; - } - - return TRUE; -} - -static GMenu * -update_directory_in_scripts_menu (NautilusView *view, - NautilusDirectory *directory) -{ - GList *file_list, *filtered, *node; - GMenu *menu, *children_menu; - GMenuItem *menu_item; - gboolean any_scripts; - NautilusFile *file; - NautilusDirectory *dir; - char *uri; - gchar *file_name; - int num; - - g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL); - g_return_val_if_fail (NAUTILUS_IS_DIRECTORY (directory), NULL); - - file_list = nautilus_directory_get_file_list (directory); - filtered = nautilus_file_list_filter_hidden (file_list, FALSE); - nautilus_file_list_free (file_list); - menu = g_menu_new (); - - file_list = nautilus_file_list_sort_by_display_name (filtered); - - num = 0; - any_scripts = FALSE; - for (node = file_list; num < TEMPLATE_LIMIT && node != NULL; node = node->next, num++) { - file = node->data; - if (nautilus_file_is_directory (file)) { - uri = nautilus_file_get_uri (file); - if (directory_belongs_in_scripts_menu (uri)) { - dir = nautilus_directory_get_by_uri (uri); - add_directory_to_scripts_directory_list (view, dir); - - children_menu = update_directory_in_scripts_menu (view, dir); - - if (children_menu != NULL) { - file_name = nautilus_file_get_display_name (file); - menu_item = g_menu_item_new_submenu (file_name, - G_MENU_MODEL (children_menu)); - g_menu_append_item (menu, menu_item); - any_scripts = TRUE; - g_object_unref (menu_item); - g_object_unref (children_menu); - g_free (file_name); - } - - nautilus_directory_unref (dir); - } - g_free (uri); - } else if (nautilus_file_is_launchable (file)) { - add_script_to_scripts_menus (view, file, menu); - any_scripts = TRUE; - } - } - - nautilus_file_list_free (file_list); - - if (!any_scripts) { - g_object_unref (menu); - menu = NULL; - } - - return menu; -} - - - -static void -update_scripts_menu (NautilusView *view) -{ - GList *sorted_copy, *node; - NautilusDirectory *directory; - GMenu *submenu; - char *uri; - - sorted_copy = nautilus_directory_list_sort_by_uri - (nautilus_directory_list_copy (view->details->scripts_directory_list)); - - for (node = sorted_copy; node != NULL; node = node->next) { - directory = node->data; - - uri = nautilus_directory_get_uri (directory); - if (!directory_belongs_in_scripts_menu (uri)) { - remove_directory_from_scripts_directory_list (view, directory); - } - g_free (uri); - } - nautilus_directory_list_free (sorted_copy); - - directory = nautilus_directory_get_by_uri (scripts_directory_uri); - submenu = update_directory_in_scripts_menu (view, directory); - if (submenu != NULL) { - nautilus_gmenu_merge (view->details->selection_menu, - submenu, - "scripts-submenu", - TRUE); - g_object_unref (submenu); - } - - view->details->scripts_present = submenu != NULL; -} - -static void -create_template (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - - CreateTemplateParameters *parameters; - - parameters = user_data; - - nautilus_view_new_file (parameters->directory_view, NULL, parameters->file); -} - -static void -add_template_to_templates_menus (NautilusView *view, - NautilusFile *file, - GMenu *menu) -{ - char *tmp, *uri, *name; - GdkPixbuf *mimetype_icon; - char *action_name, *detailed_action_name; - CreateTemplateParameters *parameters; - GAction *action; - GMenuItem *menu_item; - - tmp = nautilus_file_get_display_name (file); - name = eel_filename_strip_extension (tmp); - g_free (tmp); - - uri = nautilus_file_get_uri (file); - action_name = nautilus_escape_action_name (uri, "template_"); - action = G_ACTION (g_simple_action_new (action_name, NULL)); - parameters = create_template_parameters_new (file, view); - - g_signal_connect_data (action, "activate", - G_CALLBACK (create_template), - parameters, - (GClosureNotify)create_templates_parameters_free, 0); - - g_action_map_add_action (G_ACTION_MAP (view->details->view_action_group), action); - - detailed_action_name = g_strconcat ("view.", action_name, NULL); - menu_item = g_menu_item_new (name, detailed_action_name); - - mimetype_icon = get_menu_icon_for_file (file, GTK_WIDGET (view)); - if (mimetype_icon != NULL) { - g_menu_item_set_icon (menu_item, G_ICON (mimetype_icon)); - g_object_unref (mimetype_icon); - } - - g_menu_append_item (menu, menu_item); - - g_free (name); - g_free (uri); - g_free (action_name); - g_free (detailed_action_name); - g_object_unref (action); - g_object_unref (menu_item); -} - -static void -update_templates_directory (NautilusView *view) -{ - NautilusDirectory *templates_directory; - GList *node, *next; - char *templates_uri; - - for (node = view->details->templates_directory_list; node != NULL; node = next) { - next = node->next; - remove_directory_from_templates_directory_list (view, node->data); - } - - if (nautilus_should_use_templates_directory ()) { - templates_uri = nautilus_get_templates_directory_uri (); - templates_directory = nautilus_directory_get_by_uri (templates_uri); - g_free (templates_uri); - add_directory_to_templates_directory_list (view, templates_directory); - nautilus_directory_unref (templates_directory); - } -} - -static gboolean -directory_belongs_in_templates_menu (const char *templates_directory_uri, - const char *uri) -{ - int num_levels; - int i; - - if (templates_directory_uri == NULL) { - return FALSE; - } - - if (!g_str_has_prefix (uri, templates_directory_uri)) { - return FALSE; - } - - num_levels = 0; - for (i = strlen (templates_directory_uri); uri[i] != '\0'; i++) { - if (uri[i] == '/') { - num_levels++; - } - } - - if (num_levels > MAX_MENU_LEVELS) { - return FALSE; - } - - return TRUE; -} - -static GMenu * -update_directory_in_templates_menu (NautilusView *view, - NautilusDirectory *directory) -{ - GList *file_list, *filtered, *node; - GMenu *menu, *children_menu; - GMenuItem *menu_item; - gboolean any_templates; - NautilusFile *file; - NautilusDirectory *dir; - char *uri; - char *templates_directory_uri; - int num; - - g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL); - g_return_val_if_fail (NAUTILUS_IS_DIRECTORY (directory), NULL); - - file_list = nautilus_directory_get_file_list (directory); - filtered = nautilus_file_list_filter_hidden (file_list, FALSE); - nautilus_file_list_free (file_list); - templates_directory_uri = nautilus_get_templates_directory_uri (); - menu = g_menu_new (); - - file_list = nautilus_file_list_sort_by_display_name (filtered); - - num = 0; - any_templates = FALSE; - for (node = file_list; num < TEMPLATE_LIMIT && node != NULL; node = node->next, num++) { - file = node->data; - if (nautilus_file_is_directory (file)) { - uri = nautilus_file_get_uri (file); - if (directory_belongs_in_templates_menu (templates_directory_uri, uri)) { - dir = nautilus_directory_get_by_uri (uri); - add_directory_to_templates_directory_list (view, dir); - - children_menu = update_directory_in_templates_menu (view, dir); - - if (children_menu != NULL) { - menu_item = g_menu_item_new_submenu (nautilus_file_get_display_name (file), - G_MENU_MODEL (children_menu)); - g_menu_append_item (menu, menu_item); - any_templates = TRUE; - g_object_unref (menu_item); - g_object_unref (children_menu); - } - - nautilus_directory_unref (dir); - } - g_free (uri); - } else if (nautilus_file_can_read (file)) { - add_template_to_templates_menus (view, file, menu); - any_templates = TRUE; - } - } - - nautilus_file_list_free (file_list); - g_free (templates_directory_uri); - - if (!any_templates) { - g_object_unref (menu); - menu = NULL; - } - - return menu; -} - - - -static void -update_templates_menu (NautilusView *view) -{ - GList *sorted_copy, *node; - NautilusDirectory *directory; - GMenu *submenu; - char *uri; - char *templates_directory_uri; - - if (nautilus_should_use_templates_directory ()) { - templates_directory_uri = nautilus_get_templates_directory_uri (); - } else { - view->details->templates_present = FALSE; - return; - } - - - sorted_copy = nautilus_directory_list_sort_by_uri - (nautilus_directory_list_copy (view->details->templates_directory_list)); - - for (node = sorted_copy; node != NULL; node = node->next) { - directory = node->data; - - uri = nautilus_directory_get_uri (directory); - if (!directory_belongs_in_templates_menu (templates_directory_uri, uri)) { - remove_directory_from_templates_directory_list (view, directory); - } - g_free (uri); - } - nautilus_directory_list_free (sorted_copy); - - directory = nautilus_directory_get_by_uri (templates_directory_uri); - submenu = update_directory_in_templates_menu (view, directory); - if (submenu != NULL) { - nautilus_gmenu_merge (view->details->background_menu, - submenu, - "templates-submenu", - FALSE); - g_object_unref (submenu); - } - - view->details->templates_present = submenu != NULL; - - g_free (templates_directory_uri); -} - - -static void -action_open_scripts_folder (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - NautilusView *view; - static GFile *location = NULL; - - if (location == NULL) { - location = g_file_new_for_uri (scripts_directory_uri); - } - - view = NAUTILUS_VIEW (user_data); - nautilus_window_slot_open_location (view->details->slot, location, 0); -} - -typedef struct _CopyCallbackData { - NautilusView *view; - GtkFileChooser *chooser; - GHashTable *locations; - GList *selection; - gboolean is_move; -} CopyCallbackData; - -static void -add_bookmark_for_uri (CopyCallbackData *data, - const char *uri) -{ - GError *error = NULL; - int count; - - count = GPOINTER_TO_INT (g_hash_table_lookup (data->locations, uri)); - if (count == 0) { - gtk_file_chooser_add_shortcut_folder_uri (data->chooser, - uri, - &error); - if (error != NULL) { - DEBUG ("Unable to add location '%s' to file selector: %s", uri, error->message); - g_clear_error (&error); - } - } - g_hash_table_replace (data->locations, g_strdup (uri), GINT_TO_POINTER (count + 1)); -} - -static void -remove_bookmark_for_uri (CopyCallbackData *data, - const char *uri) -{ - GError *error = NULL; - int count; - - count = GPOINTER_TO_INT (g_hash_table_lookup (data->locations, uri)); - if (count == 1) { - gtk_file_chooser_remove_shortcut_folder_uri (data->chooser, - uri, - &error); - if (error != NULL) { - DEBUG ("Unable to remove location '%s' to file selector: %s", uri, error->message); - g_clear_error (&error); - } - g_hash_table_remove (data->locations, uri); - } else { - g_hash_table_replace (data->locations, g_strdup (uri), GINT_TO_POINTER (count - 1)); - } -} - -static void -add_bookmarks_for_window_slot (CopyCallbackData *data, - NautilusWindowSlot *slot) -{ - char *uri; - - uri = nautilus_window_slot_get_location_uri (slot); - if (uri != NULL) { - add_bookmark_for_uri (data, uri); - } - g_free (uri); -} - -static void -remove_bookmarks_for_window_slot (CopyCallbackData *data, - NautilusWindowSlot *slot) -{ - char *uri; - - uri = nautilus_window_slot_get_location_uri (slot); - if (uri != NULL) { - remove_bookmark_for_uri (data, uri); - } - g_free (uri); -} - -static void -on_slot_location_changed (NautilusWindowSlot *slot, - const char *from, - const char *to, - CopyCallbackData *data) -{ - if (from != NULL) { - remove_bookmark_for_uri (data, from); - } - - if (to != NULL) { - add_bookmark_for_uri (data, to); - } -} - -static void -on_slot_added (NautilusWindow *window, - NautilusWindowSlot *slot, - CopyCallbackData *data) -{ - add_bookmarks_for_window_slot (data, slot); - g_signal_connect (slot, "location-changed", G_CALLBACK (on_slot_location_changed), data); -} - -static void -on_slot_removed (NautilusWindow *window, - NautilusWindowSlot *slot, - CopyCallbackData *data) -{ - remove_bookmarks_for_window_slot (data, slot); - g_signal_handlers_disconnect_by_func (slot, - G_CALLBACK (on_slot_location_changed), - data); -} - -static void -add_bookmarks_for_window (CopyCallbackData *data, - NautilusWindow *window) -{ - GList *s; - GList *slots; - - slots = nautilus_window_get_slots (window); - for (s = slots; s != NULL; s = s->next) { - NautilusWindowSlot *slot = s->data; - add_bookmarks_for_window_slot (data, slot); - g_signal_connect (slot, "location-changed", G_CALLBACK (on_slot_location_changed), data); - } - g_signal_connect (window, "slot-added", G_CALLBACK (on_slot_added), data); - g_signal_connect (window, "slot-removed", G_CALLBACK (on_slot_removed), data); -} - -static void -remove_bookmarks_for_window (CopyCallbackData *data, - NautilusWindow *window) -{ - GList *s; - GList *slots; - - slots = nautilus_window_get_slots (window); - for (s = slots; s != NULL; s = s->next) { - NautilusWindowSlot *slot = s->data; - remove_bookmarks_for_window_slot (data, slot); - g_signal_handlers_disconnect_by_func (slot, - G_CALLBACK (on_slot_location_changed), - data); - } - g_signal_handlers_disconnect_by_func (window, - G_CALLBACK (on_slot_added), - data); - g_signal_handlers_disconnect_by_func (window, - G_CALLBACK (on_slot_removed), - data); -} - -static void -on_app_window_added (GtkApplication *application, - GtkWindow *window, - CopyCallbackData *data) -{ - add_bookmarks_for_window (data, NAUTILUS_WINDOW (window)); -} - -static void -on_app_window_removed (GtkApplication *application, - GtkWindow *window, - CopyCallbackData *data) -{ - remove_bookmarks_for_window (data, NAUTILUS_WINDOW (window)); -} - -static void -copy_data_free (CopyCallbackData *data) -{ - NautilusApplication *application; - GList *windows; - GList *w; - - application = NAUTILUS_APPLICATION (g_application_get_default ()); - g_signal_handlers_disconnect_by_func (application, - G_CALLBACK (on_app_window_added), - data); - g_signal_handlers_disconnect_by_func (application, - G_CALLBACK (on_app_window_removed), - data); - - windows = nautilus_application_get_windows (application); - for (w = windows; w != NULL; w = w->next) { - NautilusWindow *window = w->data; - GList *slots; - GList *s; - - slots = nautilus_window_get_slots (window); - for (s = slots; s != NULL; s = s->next) { - NautilusWindowSlot *slot = s->data; - g_signal_handlers_disconnect_by_func (slot, G_CALLBACK (on_slot_location_changed), data); - } - g_signal_handlers_disconnect_by_func (window, G_CALLBACK (on_slot_added), data); - g_signal_handlers_disconnect_by_func (window, G_CALLBACK (on_slot_removed), data); - } - - nautilus_file_list_free (data->selection); - g_hash_table_destroy (data->locations); - g_free (data); -} - -static gboolean -uri_is_parent_of_selection (GList *selection, - const char *uri) -{ - gboolean found; - GList *l; - GFile *file; - - found = FALSE; - - file = g_file_new_for_uri (uri); - for (l = selection; !found && l != NULL; l = l->next) { - GFile *parent; - parent = nautilus_file_get_parent_location (l->data); - found = g_file_equal (file, parent); - g_object_unref (parent); - } - g_object_unref (file); - return found; -} - -static void -on_destination_dialog_folder_changed (GtkFileChooser *chooser, - gpointer user_data) -{ - CopyCallbackData *copy_data = user_data; - char *uri; - gboolean found; - - uri = gtk_file_chooser_get_current_folder_uri (chooser); - found = uri_is_parent_of_selection (copy_data->selection, uri); - gtk_dialog_set_response_sensitive (GTK_DIALOG (chooser), GTK_RESPONSE_OK, !found); - g_free (uri); -} - -static void -on_destination_dialog_response (GtkDialog *dialog, - gint response_id, - gpointer user_data) -{ - CopyCallbackData *copy_data = user_data; - - if (response_id == GTK_RESPONSE_OK) { - char *target_uri; - GList *uris, *l; - - target_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog)); - - uris = NULL; - for (l = copy_data->selection; l != NULL; l = l->next) { - uris = g_list_prepend (uris, - nautilus_file_get_uri ((NautilusFile *) l->data)); - } - uris = g_list_reverse (uris); - - nautilus_view_move_copy_items (copy_data->view, uris, NULL, target_uri, - copy_data->is_move ? GDK_ACTION_MOVE : GDK_ACTION_COPY, - 0, 0); - - g_list_free_full (uris, g_free); - g_free (target_uri); - } - - copy_data_free (copy_data); - gtk_widget_destroy (GTK_WIDGET (dialog)); -} - -static gboolean -destination_dialog_filter_cb (const GtkFileFilterInfo *filter_info, - gpointer user_data) -{ - GList *selection = user_data; - GList *l; - - for (l = selection; l != NULL; l = l->next) { - char *uri; - uri = nautilus_file_get_uri (l->data); - if (strcmp (uri, filter_info->uri) == 0) { - g_free (uri); - return FALSE; - } - g_free (uri); - } - - return TRUE; -} - -static GList * -get_selected_folders (GList *selection) -{ - GList *folders; - GList *l; - - folders = NULL; - for (l = selection; l != NULL; l = l->next) { - if (nautilus_file_is_directory (l->data)) - folders = g_list_prepend (folders, nautilus_file_ref (l->data)); - } - return g_list_reverse (folders); -} - -static void -add_window_location_bookmarks (CopyCallbackData *data) -{ - NautilusApplication *application; - GList *windows; - GList *w; - - application = NAUTILUS_APPLICATION (g_application_get_default ()); - windows = nautilus_application_get_windows (application); - g_signal_connect (application, "window-added", G_CALLBACK (on_app_window_added), data); - g_signal_connect (application, "window-removed", G_CALLBACK (on_app_window_removed), data); - - for (w = windows; w != NULL; w = w->next) { - NautilusWindow *window = w->data; - add_bookmarks_for_window (data, window); - } -} - -static void -copy_or_move_selection (NautilusView *view, - gboolean is_move) -{ - GtkWidget *dialog; - char *uri; - CopyCallbackData *copy_data; - GList *selection; - const gchar *title; - - if (is_move) { - title = _("Select Move Destination"); - } else { - title = _("Select Copy Destination"); - } - - selection = nautilus_view_get_selection_for_file_transfer (view); - - dialog = gtk_file_chooser_dialog_new (title, - GTK_WINDOW (nautilus_view_get_window (view)), - GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, - _("_Cancel"), GTK_RESPONSE_CANCEL, - _("_Select"), GTK_RESPONSE_OK, - NULL); - gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE); - gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); - - copy_data = g_new0 (CopyCallbackData, 1); - copy_data->view = view; - copy_data->selection = selection; - copy_data->is_move = is_move; - copy_data->chooser = GTK_FILE_CHOOSER (dialog); - copy_data->locations = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - - add_window_location_bookmarks (copy_data); - - if (selection != NULL) { - GtkFileFilter *filter; - GList *folders; - - folders = get_selected_folders (selection); - - filter = gtk_file_filter_new (); - gtk_file_filter_add_custom (filter, - GTK_FILE_FILTER_URI, - destination_dialog_filter_cb, - folders, - (GDestroyNotify)nautilus_file_list_free); - gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), filter); - } - - uri = nautilus_directory_get_uri (view->details->model); - gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dialog), uri); - g_free (uri); - g_signal_connect (dialog, "current-folder-changed", - G_CALLBACK (on_destination_dialog_folder_changed), - copy_data); - g_signal_connect (dialog, "response", - G_CALLBACK (on_destination_dialog_response), - copy_data); - - gtk_widget_show_all (dialog); -} - -static void -copy_or_cut_files (NautilusView *view, - GList *clipboard_contents, - gboolean cut) -{ - NautilusClipboardInfo info; - GtkTargetList *target_list; - GtkTargetEntry *targets; - int n_targets; - - info.files = clipboard_contents; - info.cut = cut; - - target_list = gtk_target_list_new (NULL, 0); - gtk_target_list_add (target_list, copied_files_atom, 0, 0); - gtk_target_list_add_uri_targets (target_list, 0); - gtk_target_list_add_text_targets (target_list, 0); - - targets = gtk_target_table_new_from_list (target_list, &n_targets); - gtk_target_list_unref (target_list); - - gtk_clipboard_set_with_data (nautilus_clipboard_get (GTK_WIDGET (view)), - targets, n_targets, - nautilus_get_clipboard_callback, nautilus_clear_clipboard_callback, - NULL); - gtk_target_table_free (targets, n_targets); - - nautilus_clipboard_monitor_set_clipboard_info (nautilus_clipboard_monitor_get (), &info); -} - -static void -action_copy (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - NautilusView *view; - GList *selection; - - view = NAUTILUS_VIEW (user_data); - - selection = nautilus_view_get_selection_for_file_transfer (view); - copy_or_cut_files (view, selection, FALSE); - nautilus_file_list_free (selection); -} - -static void -action_cut (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - NautilusView *view; - GList *selection; - - view = NAUTILUS_VIEW (user_data); - - selection = nautilus_view_get_selection_for_file_transfer (view); - copy_or_cut_files (view, selection, TRUE); - nautilus_file_list_free (selection); -} - -static void -action_copy_to (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - NautilusView *view; - - view = NAUTILUS_VIEW (user_data); - copy_or_move_selection (view, FALSE); -} - -static void -action_move_to (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - NautilusView *view; - - view = NAUTILUS_VIEW (user_data); - copy_or_move_selection (view, TRUE); -} - -typedef struct { - NautilusView *view; - NautilusFile *target; -} PasteIntoData; - -static void -paste_into_clipboard_received_callback (GtkClipboard *clipboard, - GtkSelectionData *selection_data, - gpointer callback_data) -{ - PasteIntoData *data; - NautilusView *view; - char *directory_uri; - - data = (PasteIntoData *) callback_data; - - view = NAUTILUS_VIEW (data->view); - - if (view->details->slot != NULL) { - directory_uri = nautilus_file_get_activation_uri (data->target); - - paste_clipboard_data (view, selection_data, directory_uri); - - g_free (directory_uri); - } - - g_object_unref (view); - nautilus_file_unref (data->target); - g_free (data); -} - -static void -paste_into (NautilusView *view, - NautilusFile *target) -{ - PasteIntoData *data; - - g_assert (NAUTILUS_IS_VIEW (view)); - g_assert (NAUTILUS_IS_FILE (target)); - - data = g_new (PasteIntoData, 1); - - data->view = g_object_ref (view); - data->target = nautilus_file_ref (target); - - gtk_clipboard_request_contents (nautilus_clipboard_get (GTK_WIDGET (view)), - copied_files_atom, - paste_into_clipboard_received_callback, - data); -} - -static void -action_paste_files_into (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - NautilusView *view; - GList *selection; - - view = NAUTILUS_VIEW (user_data); - selection = nautilus_view_get_selection (view); - if (selection != NULL) { - paste_into (view, NAUTILUS_FILE (selection->data)); - nautilus_file_list_free (selection); - } - -} - -static void -invoke_external_bulk_rename_utility (NautilusView *view, - GList *selection) -{ - GString *cmd; - char *parameter; - char *quoted_parameter; - char *bulk_rename_tool; - GList *walk; - NautilusFile *file; - - /* assemble command line */ - bulk_rename_tool = get_bulk_rename_tool (); - cmd = g_string_new (bulk_rename_tool); - g_free (bulk_rename_tool); - for (walk = selection; walk; walk = walk->next) { - file = walk->data; - parameter = nautilus_file_get_uri (file); - quoted_parameter = g_shell_quote (parameter); - g_free (parameter); - cmd = g_string_append (cmd, " "); - cmd = g_string_append (cmd, quoted_parameter); - g_free (quoted_parameter); - } - - /* spawning and error handling */ - nautilus_launch_application_from_command (gtk_widget_get_screen (GTK_WIDGET (view)), - cmd->str, FALSE, NULL); - g_string_free (cmd, TRUE); -} - -static void -real_action_rename (NautilusView *view, - gboolean select_all) -{ - NautilusFile *file; - GList *selection; - - g_assert (NAUTILUS_IS_VIEW (view)); - - selection = nautilus_view_get_selection (view); - - if (selection_not_empty_in_menu_callback (view, selection)) { - /* If there is more than one file selected, invoke a batch renamer */ - if (selection->next != NULL) { - if (have_bulk_rename_tool ()) { - invoke_external_bulk_rename_utility (view, selection); - } - } else { - file = NAUTILUS_FILE (selection->data); - if (!select_all) { - /* directories don't have a file extension, so - * they are always pre-selected as a whole */ - select_all = nautilus_file_is_directory (file); - } - nautilus_view_rename_file_popover_new (view, file); - } - } - - nautilus_file_list_free (selection); -} - -static void -action_rename (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - real_action_rename (NAUTILUS_VIEW (user_data), FALSE); -} - -#define BG_KEY_PRIMARY_COLOR "primary-color" -#define BG_KEY_SECONDARY_COLOR "secondary-color" -#define BG_KEY_COLOR_TYPE "color-shading-type" -#define BG_KEY_PICTURE_PLACEMENT "picture-options" -#define BG_KEY_PICTURE_URI "picture-uri" - -static void -set_uri_as_wallpaper (const char *uri) -{ - GSettings *settings; - - settings = gnome_background_preferences; - - g_settings_delay (settings); - - if (uri == NULL) - uri = ""; - - g_settings_set_string (settings, BG_KEY_PICTURE_URI, uri); - g_settings_set_string (settings, BG_KEY_PRIMARY_COLOR, "#000000"); - g_settings_set_string (settings, BG_KEY_SECONDARY_COLOR, "#000000"); - g_settings_set_enum (settings, BG_KEY_COLOR_TYPE, G_DESKTOP_BACKGROUND_SHADING_SOLID); - g_settings_set_enum (settings, BG_KEY_PICTURE_PLACEMENT, G_DESKTOP_BACKGROUND_STYLE_ZOOM); - - /* Apply changes atomically. */ - g_settings_apply (settings); -} - -static void -wallpaper_copy_done_callback (GHashTable *debuting_files, - gboolean success, - gpointer data) -{ - GHashTableIter iter; - gpointer key, value; - - g_hash_table_iter_init (&iter, debuting_files); - while (g_hash_table_iter_next (&iter, &key, &value)) { - char *uri; - uri = g_file_get_uri (G_FILE (key)); - set_uri_as_wallpaper (uri); - g_free (uri); - break; - } -} - -static gboolean -can_set_wallpaper (GList *selection) -{ - NautilusFile *file; - - if (g_list_length (selection) != 1) { - return FALSE; - } - - file = NAUTILUS_FILE (selection->data); - if (!nautilus_file_is_mime_type (file, "image/*")) { - return FALSE; - } - - /* FIXME: check file size? */ - - return TRUE; -} - -static void -action_set_as_wallpaper (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - GList *selection; - - /* Copy the item to Pictures/Wallpaper since it may be - remote. Then set it as the current wallpaper. */ - - g_assert (NAUTILUS_IS_VIEW (user_data)); - - selection = nautilus_view_get_selection (user_data); - - if (can_set_wallpaper (selection) - && selection_not_empty_in_menu_callback (user_data, selection)) { - NautilusFile *file; - char *target_uri; - GList *uris; - GFile *parent; - GFile *target; - - file = NAUTILUS_FILE (selection->data); - - parent = g_file_new_for_path (g_get_user_special_dir (G_USER_DIRECTORY_PICTURES)); - target = g_file_get_child (parent, "Wallpapers"); - g_object_unref (parent); - g_file_make_directory_with_parents (target, NULL, NULL); - target_uri = g_file_get_uri (target); - g_object_unref (target); - uris = g_list_prepend (NULL, nautilus_file_get_uri (file)); - nautilus_file_operations_copy_move (uris, - NULL, - target_uri, - GDK_ACTION_COPY, - GTK_WIDGET (user_data), - wallpaper_copy_done_callback, - NULL); - g_free (target_uri); - g_list_free_full (uris, g_free); - } - - nautilus_file_list_free (selection); -} - -static void -file_mount_callback (NautilusFile *file, - GFile *result_location, - GError *error, - gpointer callback_data) -{ - NautilusView *view; - - view = NAUTILUS_VIEW (callback_data); - - if (error != NULL && - (error->domain != G_IO_ERROR || - (error->code != G_IO_ERROR_CANCELLED && - error->code != G_IO_ERROR_FAILED_HANDLED && - error->code != G_IO_ERROR_ALREADY_MOUNTED))) { - char *text; - char *name; - name = nautilus_file_get_display_name (file); - /* Translators: %s is a file name formatted for display */ - text = g_strdup_printf (_("Unable to access “%s”"), name); - eel_show_error_dialog (text, error->message, - GTK_WINDOW (nautilus_view_get_window (view))); - g_free (text); - g_free (name); - } -} - -static void -file_unmount_callback (NautilusFile *file, - GFile *result_location, - GError *error, - gpointer callback_data) -{ - NautilusView *view; - - view = NAUTILUS_VIEW (callback_data); - g_object_unref (view); - - if (error != NULL && - (error->domain != G_IO_ERROR || - (error->code != G_IO_ERROR_CANCELLED && - error->code != G_IO_ERROR_FAILED_HANDLED))) { - char *text; - char *name; - name = nautilus_file_get_display_name (file); - /* Translators: %s is a file name formatted for display */ - text = g_strdup_printf (_("Unable to remove “%s”"), name); - eel_show_error_dialog (text, error->message, - GTK_WINDOW (nautilus_view_get_window (view))); - g_free (text); - g_free (name); - } -} - -static void -file_eject_callback (NautilusFile *file, - GFile *result_location, - GError *error, - gpointer callback_data) -{ - NautilusView *view; - - view = NAUTILUS_VIEW (callback_data); - g_object_unref (view); - - if (error != NULL && - (error->domain != G_IO_ERROR || - (error->code != G_IO_ERROR_CANCELLED && - error->code != G_IO_ERROR_FAILED_HANDLED))) { - char *text; - char *name; - name = nautilus_file_get_display_name (file); - /* Translators: %s is a file name formatted for display */ - text = g_strdup_printf (_("Unable to eject “%s”"), name); - eel_show_error_dialog (text, error->message, - GTK_WINDOW (nautilus_view_get_window (view))); - g_free (text); - g_free (name); - } -} - -static void -file_stop_callback (NautilusFile *file, - GFile *result_location, - GError *error, - gpointer callback_data) -{ - NautilusView *view; - - view = NAUTILUS_VIEW (callback_data); - - if (error != NULL && - (error->domain != G_IO_ERROR || - (error->code != G_IO_ERROR_CANCELLED && - error->code != G_IO_ERROR_FAILED_HANDLED))) { - eel_show_error_dialog (_("Unable to stop drive"), - error->message, - GTK_WINDOW (nautilus_view_get_window (view))); - } -} - -static void -action_mount_volume (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - NautilusFile *file; - GList *selection, *l; - NautilusView *view; - GMountOperation *mount_op; - - view = NAUTILUS_VIEW (user_data); - - selection = nautilus_view_get_selection (view); - for (l = selection; l != NULL; l = l->next) { - file = NAUTILUS_FILE (l->data); - - if (nautilus_file_can_mount (file)) { - mount_op = gtk_mount_operation_new (nautilus_view_get_containing_window (view)); - g_mount_operation_set_password_save (mount_op, G_PASSWORD_SAVE_FOR_SESSION); - nautilus_file_mount (file, mount_op, NULL, - file_mount_callback, - view); - g_object_unref (mount_op); - } - } - nautilus_file_list_free (selection); -} - -static void -action_unmount_volume (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - NautilusFile *file; - GList *selection, *l; - NautilusView *view; - - view = NAUTILUS_VIEW (user_data); - - selection = nautilus_view_get_selection (view); - - for (l = selection; l != NULL; l = l->next) { - file = NAUTILUS_FILE (l->data); - if (nautilus_file_can_unmount (file)) { - GMountOperation *mount_op; - mount_op = gtk_mount_operation_new (nautilus_view_get_containing_window (view)); - nautilus_file_unmount (file, mount_op, NULL, - file_unmount_callback, g_object_ref (view)); - g_object_unref (mount_op); - } - } - nautilus_file_list_free (selection); -} - -static void -action_eject_volume (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - NautilusFile *file; - GList *selection, *l; - NautilusView *view; - - view = NAUTILUS_VIEW (user_data); - - selection = nautilus_view_get_selection (view); - for (l = selection; l != NULL; l = l->next) { - file = NAUTILUS_FILE (l->data); - - if (nautilus_file_can_eject (file)) { - GMountOperation *mount_op; - mount_op = gtk_mount_operation_new (nautilus_view_get_containing_window (view)); - nautilus_file_eject (file, mount_op, NULL, - file_eject_callback, g_object_ref (view)); - g_object_unref (mount_op); - } - } - nautilus_file_list_free (selection); -} - -static void -file_start_callback (NautilusFile *file, - GFile *result_location, - GError *error, - gpointer callback_data) -{ - NautilusView *view; - - view = NAUTILUS_VIEW (callback_data); - - if (error != NULL && - (error->domain != G_IO_ERROR || - (error->code != G_IO_ERROR_CANCELLED && - error->code != G_IO_ERROR_FAILED_HANDLED && - error->code != G_IO_ERROR_ALREADY_MOUNTED))) { - char *text; - char *name; - name = nautilus_file_get_display_name (file); - /* Translators: %s is a file name formatted for display */ - text = g_strdup_printf (_("Unable to start “%s”"), name); - eel_show_error_dialog (text, error->message, - GTK_WINDOW (nautilus_view_get_window (view))); - g_free (text); - g_free (name); - } -} - -static void -action_start_volume (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - NautilusFile *file; - GList *selection, *l; - NautilusView *view; - GMountOperation *mount_op; - - view = NAUTILUS_VIEW (user_data); - - selection = nautilus_view_get_selection (view); - for (l = selection; l != NULL; l = l->next) { - file = NAUTILUS_FILE (l->data); - - if (nautilus_file_can_start (file) || nautilus_file_can_start_degraded (file)) { - mount_op = gtk_mount_operation_new (nautilus_view_get_containing_window (view)); - nautilus_file_start (file, mount_op, NULL, - file_start_callback, view); - g_object_unref (mount_op); - } - } - nautilus_file_list_free (selection); -} - -static void -action_stop_volume (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - NautilusFile *file; - GList *selection, *l; - NautilusView *view; - - view = NAUTILUS_VIEW (user_data); - - selection = nautilus_view_get_selection (view); - for (l = selection; l != NULL; l = l->next) { - file = NAUTILUS_FILE (l->data); - - if (nautilus_file_can_stop (file)) { - GMountOperation *mount_op; - mount_op = gtk_mount_operation_new (nautilus_view_get_containing_window (view)); - nautilus_file_stop (file, mount_op, NULL, - file_stop_callback, view); - g_object_unref (mount_op); - } - } - nautilus_file_list_free (selection); -} - -static void -action_detect_media (GSimpleAction *action, - GVariant *state, - gpointer user_data) -{ - NautilusFile *file; - GList *selection, *l; - NautilusView *view; - - view = NAUTILUS_VIEW (user_data); - - selection = nautilus_view_get_selection (view); - for (l = selection; l != NULL; l = l->next) { - file = NAUTILUS_FILE (l->data); - - if (nautilus_file_can_poll_for_media (file) && !nautilus_file_is_media_check_automatic (file)) { - nautilus_file_poll_for_media (file); - } - } - nautilus_file_list_free (selection); -} - -const GActionEntry view_entries[] = { - /* Toolbar menu */ - { "zoom-in", action_zoom_in }, - { "zoom-out", action_zoom_out }, - { "zoom-default", action_zoom_default }, - { "show-hidden-files", NULL, NULL, "true", action_show_hidden_files }, - /* Background menu */ - { "new-folder", action_new_folder }, - { "select-all", action_select_all }, - { "paste", action_paste_files }, - { "new-document" }, - /* Selection menu */ - { "scripts" }, - { "new-folder-with-selection", action_new_folder_with_selection }, - { "open-scripts-folder", action_open_scripts_folder }, - { "open-item-location", action_open_item_location }, - { "open-with-default-application", action_open_with_default_application }, - { "open-with-other-application", action_open_with_other_application }, - { "open-item-new-window", action_open_item_new_window }, - { "open-item-new-tab", action_open_item_new_tab }, - { "cut", action_cut}, - { "copy", action_copy}, - { "move-to", action_move_to}, - { "copy-to", action_copy_to}, - { "move-to-trash", action_move_to_trash}, - { "delete-from-trash", action_delete }, - /* We separate the shortcut and the menu item since we want the shortcut - * to always be available, but we don't want the menu item shown if not - * completely necesary. Since the visibility of the menu item is based on - * the action enability, we need to split the actions for the menu and the - * shortcut. */ - { "delete-permanently-shortcut", action_delete }, - { "delete-permanently-menu-item", action_delete }, - { "remove-from-recent", action_remove_from_recent }, - { "restore-from-trash", action_restore_from_trash}, - { "paste-into", action_paste_files_into }, - { "rename", action_rename}, - { "properties", action_properties}, - { "set-as-wallpaper", action_set_as_wallpaper }, - { "mount-volume", action_mount_volume }, - { "unmount-volume", action_unmount_volume }, - { "eject-volume", action_eject_volume }, - { "start-volume", action_start_volume }, - { "stop-volume", action_stop_volume }, - { "detect-media", action_detect_media }, - /* Only accesible by shorcuts */ - { "select-pattern", action_select_pattern }, - { "invert-selection", action_invert_selection }, - { "open-file-and-close-window", action_open_file_and_close_window }, - /* Warning dialog for the change of the shorcut to move to trash */ - { "show-move-to-trash-shortcut-changed-dialog", action_show_move_to_trash_shortcut_changed_dialog } -}; - -static gboolean -can_paste_into_file (NautilusFile *file) -{ - if (nautilus_file_is_directory (file) && - nautilus_file_can_write (file)) { - return TRUE; - } - if (nautilus_file_has_activation_uri (file)) { - GFile *location; - NautilusFile *activation_file; - gboolean res; - - location = nautilus_file_get_activation_location (file); - activation_file = nautilus_file_get (location); - g_object_unref (location); - - /* The target location might not have data for it read yet, - and we can't want to do sync I/O, so treat the unknown - case as can-write */ - res = (nautilus_file_get_file_type (activation_file) == G_FILE_TYPE_UNKNOWN) || - (nautilus_file_get_file_type (activation_file) == G_FILE_TYPE_DIRECTORY && - nautilus_file_can_write (activation_file)); - - nautilus_file_unref (activation_file); - - return res; - } - - return FALSE; -} - -static void -clipboard_targets_received (GtkClipboard *clipboard, - GdkAtom *targets, - int n_targets, - gpointer user_data) -{ - NautilusView *view; - gboolean can_paste; - int i; - GAction *action; - - view = NAUTILUS_VIEW (user_data); - can_paste = FALSE; - - if (view->details->slot == NULL || - !view->details->active) { - /* We've been destroyed or became inactive since call */ - g_object_unref (view); - return; - } - - if (targets) { - for (i = 0; i < n_targets; i++) { - if (targets[i] == copied_files_atom) { - can_paste = TRUE; - } - } - } - - action = g_action_map_lookup_action (G_ACTION_MAP (view->details->view_action_group), - "paste"); - /* Take into account if the action was previously disabled for other reasons, - * like the directory not being writabble */ - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), - can_paste && g_action_get_enabled (action)); - - action = g_action_map_lookup_action (G_ACTION_MAP (view->details->view_action_group), - "paste-into"); - - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), - can_paste && g_action_get_enabled (action)); - - g_object_unref (view); -} - -static void -file_should_show_foreach (NautilusFile *file, - gboolean *show_mount, - gboolean *show_unmount, - gboolean *show_eject, - gboolean *show_start, - gboolean *show_stop, - gboolean *show_poll, - GDriveStartStopType *start_stop_type) -{ - *show_mount = FALSE; - *show_unmount = FALSE; - *show_eject = FALSE; - *show_start = FALSE; - *show_stop = FALSE; - *show_poll = FALSE; - - if (nautilus_file_can_eject (file)) { - *show_eject = TRUE; - } - - if (nautilus_file_can_mount (file)) { - *show_mount = TRUE; - } - - if (nautilus_file_can_start (file) || nautilus_file_can_start_degraded (file)) { - *show_start = TRUE; - } - - if (nautilus_file_can_stop (file)) { - *show_stop = TRUE; - } - - /* Dot not show both Unmount and Eject/Safe Removal; too confusing to - * have too many menu entries */ - if (nautilus_file_can_unmount (file) && !*show_eject && !*show_stop) { - *show_unmount = TRUE; - } - - if (nautilus_file_can_poll_for_media (file) && !nautilus_file_is_media_check_automatic (file)) { - *show_poll = TRUE; - } - - *start_stop_type = nautilus_file_get_start_stop_type (file); -} - -static gboolean -can_restore_from_trash (GList *files) -{ - NautilusFile *original_file; - NautilusFile *original_dir; - GHashTable *original_dirs_hash; - GList *original_dirs; - gboolean can_restore; - - original_file = NULL; - original_dir = NULL; - original_dirs = NULL; - original_dirs_hash = NULL; - - if (files != NULL) { - if (g_list_length (files) == 1) { - original_file = nautilus_file_get_trash_original_file (files->data); - } else { - original_dirs_hash = nautilus_trashed_files_get_original_directories (files, NULL); - if (original_dirs_hash != NULL) { - original_dirs = g_hash_table_get_keys (original_dirs_hash); - if (g_list_length (original_dirs) == 1) { - original_dir = nautilus_file_ref (NAUTILUS_FILE (original_dirs->data)); - } - } - } - } - - can_restore = original_file != NULL || original_dirs != NULL; - - nautilus_file_unref (original_file); - nautilus_file_unref (original_dir); - g_list_free (original_dirs); - - if (original_dirs_hash != NULL) { - g_hash_table_destroy (original_dirs_hash); - } - return can_restore; -} - -static void -clipboard_changed_callback (NautilusClipboardMonitor *monitor, NautilusView *view) -{ - /* Update paste menu item */ - nautilus_view_update_context_menus (view); -} - -static gboolean -can_delete_all (GList *files) -{ - NautilusFile *file; - GList *l; - - for (l = files; l != NULL; l = l->next) { - file = l->data; - if (!nautilus_file_can_delete (file)) { - return FALSE; - } - } - return TRUE; -} - -static gboolean -can_trash_all (GList *files) -{ - NautilusFile *file; - GList *l; - - for (l = files; l != NULL; l = l->next) { - file = l->data; - if (!nautilus_file_can_trash (file)) { - return FALSE; - } - } - return TRUE; -} - -static gboolean -all_in_trash (GList *files) -{ - NautilusFile *file; - GList *l; - - for (l = files; l != NULL; l = l->next) { - file = l->data; - if (!nautilus_file_is_in_trash (file)) { - return FALSE; - } - } - return TRUE; -} - -GActionGroup * -nautilus_view_get_action_group (NautilusView *view) -{ - g_assert (NAUTILUS_IS_VIEW (view)); - - return view->details->view_action_group; -} - -static void -real_update_actions_state (NautilusView *view) -{ - GList *selection, *l; - NautilusFile *file; - gint selection_count; - gboolean selection_contains_special_link; - gboolean selection_contains_desktop_or_home_dir; - gboolean selection_contains_recent; - gboolean selection_contains_search; - gboolean selection_all_in_trash; - gboolean selection_is_read_only; - gboolean can_create_files; - gboolean can_delete_files; - gboolean can_move_files; - gboolean can_trash_files; - gboolean can_copy_files; - gboolean can_paste_files_into; - gboolean show_app, show_run; - gboolean item_opens_in_view; - gboolean is_read_only; - GAction *action; - GAppInfo *app; - gboolean show_properties; - GActionGroup *view_action_group; - gboolean show_mount; - gboolean show_unmount; - gboolean show_eject; - gboolean show_start; - gboolean show_stop; - gboolean show_detect_media; - GDriveStartStopType start_stop_type; - - view_action_group = view->details->view_action_group; - - selection = nautilus_view_get_selection (view); - selection_count = g_list_length (selection); - selection_contains_special_link = special_link_in_selection (selection); - selection_contains_desktop_or_home_dir = desktop_or_home_dir_in_selection (selection); - selection_contains_recent = showing_recent_directory (view); - selection_contains_search = nautilus_view_is_search (view); - selection_is_read_only = selection_count == 1 && - (!nautilus_file_can_write (NAUTILUS_FILE (selection->data)) && - !nautilus_file_has_activation_uri (NAUTILUS_FILE (selection->data))); - selection_all_in_trash = all_in_trash (selection); - - is_read_only = nautilus_view_is_read_only (view); - can_create_files = nautilus_view_supports_creating_files (view); - can_delete_files = - can_delete_all (selection) && - selection_count != 0 && - !selection_contains_special_link && - !selection_contains_desktop_or_home_dir; - can_trash_files = - can_trash_all (selection) && - selection_count != 0 && - !selection_contains_special_link && - !selection_contains_desktop_or_home_dir; - can_copy_files = selection_count != 0 - && !selection_contains_special_link; - can_move_files = can_delete_files && !selection_contains_recent; - can_paste_files_into = (!selection_contains_recent && - selection_count == 1 && - can_paste_into_file (NAUTILUS_FILE (selection->data))); - show_properties = !showing_network_directory (view) && - (!NAUTILUS_IS_DESKTOP_CANVAS_VIEW (view) || selection_count > 0); - - /* Right click actions */ - /* Selection menu actions */ - action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), - "new-folder-with-selection"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), - can_create_files && can_delete_files && (selection_count > 1) && !selection_contains_recent); - - action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), - "rename"); - if (selection_count > 1) { - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), - have_bulk_rename_tool ()); - } else { - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), - selection_count == 1 && - nautilus_view_can_rename_file (view, selection->data)); - } - - action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), - "open-item-location"); - - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), - selection_count == 1 && - (selection_contains_recent || selection_contains_search)); - - action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), - "new-folder"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), can_create_files); - - - selection = nautilus_view_get_selection (view); - selection_count = g_list_length (selection); - - show_app = show_run = item_opens_in_view = selection_count != 0; - - for (l = selection; l != NULL; l = l->next) { - NautilusFile *file; - - file = NAUTILUS_FILE (selection->data); - - if (!nautilus_mime_file_opens_in_external_app (file)) { - show_app = FALSE; - } - - if (!nautilus_mime_file_launches (file)) { - show_run = FALSE; - } - - if (!nautilus_mime_file_opens_in_view (file)) { - item_opens_in_view = FALSE; - } - - if (!show_app && !show_run && !item_opens_in_view) { - break; - } - } - - /* Open With <App> menu item */ - app = NULL; - if (show_app) { - app = nautilus_mime_get_default_application_for_files (selection); - } - - action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), - "open-with-default-application"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), selection_count != 0); - - /* Allow to select a different application to open the item */ - action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), - "open-with-other-application"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), - app != NULL || - (selection_count > 0 && - nautilus_file_is_directory (NAUTILUS_FILE (selection->data)))); - - action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), - "open-item-new-tab"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), item_opens_in_view); - action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), - "open-item-new-window"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), item_opens_in_view); - action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), - "set-as-wallpaper"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), can_set_wallpaper (selection)); - action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), - "restore-from-trash"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), can_restore_from_trash (selection)); - - action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), - "move-to-trash"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), can_trash_files); - - action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), - "delete-from-trash"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), - can_delete_files && selection_all_in_trash); - - action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), - "delete-permanently-shortcut"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), - can_delete_files); - - action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), - "delete-permanently-menu-item"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), - can_delete_files && !can_trash_files && - !selection_all_in_trash && !selection_contains_recent); - - action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), - "remove-from-recent"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), - selection_contains_recent && selection_count > 0); - - action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), - "cut"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), - can_move_files && !selection_contains_recent); - action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), - "copy"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), - can_copy_files); - action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), - "copy-to"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), - can_copy_files); - action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), - "move-to"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), - can_move_files && !selection_contains_recent); - - /* Drive menu */ - show_mount = show_unmount = show_eject = show_start = show_stop = show_detect_media = FALSE; - for (l = selection; l != NULL && (show_mount || show_unmount - || show_eject - || show_start || show_stop - || show_detect_media); - l = l->next) { - gboolean show_mount_one; - gboolean show_unmount_one; - gboolean show_eject_one; - gboolean show_start_one; - gboolean show_stop_one; - gboolean show_detect_media_one; - - file = NAUTILUS_FILE (l->data); - file_should_show_foreach (file, - &show_mount_one, - &show_unmount_one, - &show_eject_one, - &show_start_one, - &show_stop_one, - &show_detect_media_one, - &start_stop_type); - - show_mount &= show_mount_one; - show_unmount &= show_unmount_one; - show_eject &= show_eject_one; - show_start &= show_start_one; - show_stop &= show_stop_one; - show_detect_media &= show_detect_media_one; - } - - action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), - "mount-volume"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), - show_mount); - action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), - "unmount-volume"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), - show_unmount); - action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), - "eject-volume"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), - show_eject); - action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), - "start-volume"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), - show_start); - action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), - "stop-volume"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), - show_stop); - action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), - "detect-media"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), - show_detect_media); - - action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), - "scripts"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), - view->details->scripts_present); - - /* Background menu actions */ - action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), - "new-folder"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), can_create_files); - action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), - "paste"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), - !is_read_only && !selection_contains_recent); - - action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), - "paste-into"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), - !selection_is_read_only && !selection_contains_recent && - can_paste_files_into); - - action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), - "properties"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), - show_properties); - action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), - "new-document"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), - can_create_files && - !selection_contains_recent && - view->details->templates_present); - - /* Ask the clipboard */ - g_object_ref (view); /* Need to keep the object alive until we get the reply */ - gtk_clipboard_request_targets (nautilus_clipboard_get (GTK_WIDGET (view)), - clipboard_targets_received, - view); - - action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), - "select-all"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), - !nautilus_view_is_empty (view)); - - /* Toolbar menu actions */ - g_action_group_change_action_state (view_action_group, - "show-hidden-files", - g_variant_new_boolean (view->details->show_hidden_files)); - - /* Zoom */ - action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), - "zoom-in"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), - nautilus_view_can_zoom_in (view)); - action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), - "zoom-out"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), - nautilus_view_can_zoom_out (view)); - action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), - "zoom-default"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), - nautilus_view_supports_zooming (view)); -} - -/* Convenience function to be called when updating menus, - * so children can subclass it and it will be called when - * they chain up to the parent in update_context_menus - * or update_toolbar_menus - */ -void -nautilus_view_update_actions_state (NautilusView *view) -{ - g_assert(NAUTILUS_IS_VIEW (view)); - - NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->update_actions_state (view); -} - -static void -update_selection_menu (NautilusView *view) -{ - GList *selection, *l; - NautilusFile *file; - gint selection_count; - gboolean show_app, show_run; - gboolean item_opens_in_view; - gchar *item_label; - GAppInfo *app; - GIcon *app_icon; - GMenuItem *menu_item; - gboolean show_mount; - gboolean show_unmount; - gboolean show_eject; - gboolean show_start; - gboolean show_stop; - gboolean show_detect_media; - GDriveStartStopType start_stop_type; - - selection = nautilus_view_get_selection (view); - selection_count = g_list_length (selection); - - show_mount = (selection != NULL); - show_unmount = (selection != NULL); - show_eject = (selection != NULL); - show_start = (selection != NULL && selection_count == 1); - show_stop = (selection != NULL && selection_count == 1); - show_detect_media = (selection != NULL && selection_count == 1); - start_stop_type = G_DRIVE_START_STOP_TYPE_UNKNOWN; - item_label = g_strdup_printf (ngettext ("New Folder with Selection (%'d Item)", - "New Folder with Selection (%'d Items)", - selection_count), - selection_count); - menu_item = g_menu_item_new (item_label, "view.new-folder-with-selection"); - g_menu_item_set_attribute (menu_item, "hidden-when", "s", "action-disabled"); - nautilus_gmenu_add_item_in_submodel (view->details->selection_menu, - menu_item, - "new-folder-with-selection-section", - FALSE); - g_object_unref (menu_item); - g_free (item_label); - - /* Open With <App> menu item */ - show_app = show_run = item_opens_in_view = selection_count != 0; - for (l = selection; l != NULL; l = l->next) { - NautilusFile *file; - - file = NAUTILUS_FILE (selection->data); - - if (!nautilus_mime_file_opens_in_external_app (file)) { - show_app = FALSE; - } - - if (!nautilus_mime_file_launches (file)) { - show_run = FALSE; - } - - if (!nautilus_mime_file_opens_in_view (file)) { - item_opens_in_view = FALSE; - } - - if (!show_app && !show_run && !item_opens_in_view) { - break; - } - } - - item_label = NULL; - app = NULL; - app_icon = NULL; - if (show_app) { - app = nautilus_mime_get_default_application_for_files (selection); - } - - char *escaped_app; - - if (app != NULL) { - escaped_app = eel_str_double_underscores (g_app_info_get_name (app)); - item_label = g_strdup_printf (_("Open With %s"), escaped_app); - - app_icon = g_app_info_get_icon (app); - if (app_icon != NULL) { - g_object_ref (app_icon); - } - g_free (escaped_app); - g_object_unref (app); - } else if (show_run) { - item_label = g_strdup (_("Run")); - } else { - item_label = g_strdup (_("Open")); - } - - menu_item = g_menu_item_new (item_label, "view.open-with-default-application"); - if (app_icon != NULL) - g_menu_item_set_icon (menu_item, app_icon); - - nautilus_gmenu_add_item_in_submodel (view->details->selection_menu, - menu_item, - "open-with-default-application-section", - FALSE); - - g_free (item_label); - g_object_unref (menu_item); - - /* Drives */ - for (l = selection; l != NULL && (show_mount || show_unmount - || show_eject - || show_start || show_stop - || show_detect_media); - l = l->next) { - gboolean show_mount_one; - gboolean show_unmount_one; - gboolean show_eject_one; - gboolean show_start_one; - gboolean show_stop_one; - gboolean show_detect_media_one; - - file = NAUTILUS_FILE (l->data); - file_should_show_foreach (file, - &show_mount_one, - &show_unmount_one, - &show_eject_one, - &show_start_one, - &show_stop_one, - &show_detect_media_one, - &start_stop_type); - - show_mount &= show_mount_one; - show_unmount &= show_unmount_one; - show_eject &= show_eject_one; - show_start &= show_start_one; - show_stop &= show_stop_one; - show_detect_media &= show_detect_media_one; - } - - if (show_start) { - switch (start_stop_type) { - default: - case G_DRIVE_START_STOP_TYPE_UNKNOWN: - case G_DRIVE_START_STOP_TYPE_SHUTDOWN: - item_label = _("_Start"); - break; - case G_DRIVE_START_STOP_TYPE_NETWORK: - item_label = _("_Connect"); - break; - case G_DRIVE_START_STOP_TYPE_MULTIDISK: - item_label = _("_Start Multi-disk Drive"); - break; - case G_DRIVE_START_STOP_TYPE_PASSWORD: - item_label = _("U_nlock Drive"); - break; - } - - menu_item = g_menu_item_new (item_label, "view.start-volume"); - nautilus_gmenu_add_item_in_submodel (view->details->selection_menu, - menu_item, - "drive-section", - FALSE); - g_object_unref (menu_item); - } - - if (show_stop) { - switch (start_stop_type) { - default: - case G_DRIVE_START_STOP_TYPE_UNKNOWN: - item_label = _("Stop Drive"); - break; - case G_DRIVE_START_STOP_TYPE_SHUTDOWN: - item_label = _("_Safely Remove Drive"); - break; - case G_DRIVE_START_STOP_TYPE_NETWORK: - item_label = _("_Disconnect"); - break; - case G_DRIVE_START_STOP_TYPE_MULTIDISK: - item_label = _("_Stop Multi-disk Drive"); - break; - case G_DRIVE_START_STOP_TYPE_PASSWORD: - item_label = _("_Lock Drive"); - break; - } - - menu_item = g_menu_item_new (item_label, "view.stop-volume"); - nautilus_gmenu_add_item_in_submodel (view->details->selection_menu, - menu_item, - "drive-section", - FALSE); - g_object_unref (menu_item); - } - - update_scripts_menu (view); -} - -static void -update_background_menu (NautilusView *view) -{ - - if (nautilus_view_supports_creating_files (view) && - !showing_recent_directory (view)) - update_templates_menu (view); -} - -static void -real_update_context_menus (NautilusView *view) -{ - g_clear_object (&view->details->background_menu); - g_clear_object (&view->details->selection_menu); - - GtkBuilder *builder; - builder = gtk_builder_new_from_resource ("/org/gnome/nautilus/nautilus-view-context-menus.xml"); - view->details->background_menu = g_object_ref (G_MENU (gtk_builder_get_object (builder, "background-menu"))); - view->details->selection_menu = g_object_ref (G_MENU (gtk_builder_get_object (builder, "selection-menu"))); - g_object_unref (builder); - - update_selection_menu (view); - update_background_menu (view); - update_extensions_menus (view); - - nautilus_view_update_actions_state (view); -} - -/* Convenience function to reset the context menus owned by the view and update - * them with the current state. - * Children can subclass it and add items on the menu after chaining up to the - * parent, so menus are already reseted. - * It will also update the actions state, which will also update children - * actions state if the children subclass nautilus_view_update_actions_state - */ -void -nautilus_view_update_context_menus (NautilusView *view) -{ - g_assert(NAUTILUS_IS_VIEW (view)); - - NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->update_context_menus (view); -} - -static void -nautilus_view_reset_view_menu (NautilusView *view) -{ - GActionGroup *view_action_group; - GVariant *variant; - GVariantIter iter; - gboolean show_sort_trash, show_sort_search, show_sort_access, show_sort_modification, enable_sort; - const gchar *hint; - - view_action_group = nautilus_view_get_action_group (view); - - gtk_widget_set_visible (view->details->visible_columns, - g_action_group_has_action (view_action_group, "visible-columns")); - - enable_sort = g_action_group_get_action_enabled (view_action_group, "sort"); - show_sort_trash = show_sort_search = show_sort_modification = show_sort_access = FALSE; - gtk_widget_set_visible (view->details->sort_menu, enable_sort); - - if (enable_sort) { - variant = g_action_group_get_action_state_hint (view_action_group, "sort"); - g_variant_iter_init (&iter, variant); - - while (g_variant_iter_next (&iter, "&s", &hint)) { - if (g_strcmp0 (hint, "trash-time") == 0) - show_sort_trash = TRUE; - if (g_strcmp0 (hint, "search-relevance") == 0) - show_sort_search = TRUE; - } - - g_variant_unref (variant); - } - - gtk_widget_set_visible (view->details->sort_trash_time, show_sort_trash); - gtk_widget_set_visible (view->details->sort_search_relevance, show_sort_search); - - variant = g_action_group_get_action_state (view_action_group, "zoom-to-level"); - gtk_adjustment_set_value (view->details->zoom_adjustment, - g_variant_get_int32 (variant)); - g_variant_unref (variant); -} - -/* Convenience function to reset the menus owned by the view but managed on - * the toolbar, and update them with the current state. - * It will also update the actions state, which will also update children - * actions state if the children subclass nautilus_view_update_actions_state - */ -void -nautilus_view_update_toolbar_menus (NautilusView *view) -{ - NautilusWindow *window; - - g_assert (NAUTILUS_IS_VIEW (view)); - - /* Don't update after destroy (#349551), - * or if we are not active. - */ - if (view->details->slot == NULL || - !view->details->active) { - return; - } - window = nautilus_view_get_window (view); - nautilus_window_reset_menus (window); - - nautilus_view_reset_view_menu (view); - nautilus_view_update_actions_state (view); -} - -/** - * nautilus_view_pop_up_selection_context_menu - * - * Pop up a context menu appropriate to the selected items. - * @view: NautilusView of interest. - * @event: The event that triggered this context menu. - * - **/ -void -nautilus_view_pop_up_selection_context_menu (NautilusView *view, - GdkEventButton *event) -{ - g_assert (NAUTILUS_IS_VIEW (view)); - - /* Make the context menu items not flash as they update to proper disabled, - * etc. states by forcing menus to update now. - */ - update_context_menus_if_pending (view); - - update_context_menu_position_from_event (view, event); - - nautilus_pop_up_context_menu (GTK_WIDGET (view), view->details->selection_menu, event); -} - -/** - * nautilus_view_pop_up_background_context_menu - * - * Pop up a context menu appropriate to the view globally at the last right click location. - * @view: NautilusView of interest. - * - **/ -void -nautilus_view_pop_up_background_context_menu (NautilusView *view, - GdkEventButton *event) -{ - g_assert (NAUTILUS_IS_VIEW (view)); - - /* Make the context menu items not flash as they update to proper disabled, - * etc. states by forcing menus to update now. - */ - update_context_menus_if_pending (view); - - update_context_menu_position_from_event (view, event); - - nautilus_pop_up_context_menu (GTK_WIDGET (view), view->details->background_menu, event); -} - -static void -schedule_update_context_menus (NautilusView *view) -{ - g_assert (NAUTILUS_IS_VIEW (view)); - - /* Don't schedule updates after destroy (#349551), - * or if we are not active. - */ - if (view->details->slot == NULL || - !view->details->active) { - return; - } - - /* Schedule a menu update with the current update interval */ - if (view->details->update_context_menus_timeout_id == 0) { - view->details->update_context_menus_timeout_id - = g_timeout_add (view->details->update_interval, update_context_menus_timeout_callback, view); - } -} - -static void -remove_update_status_idle_callback (NautilusView *view) -{ - if (view->details->update_status_idle_id != 0) { - g_source_remove (view->details->update_status_idle_id); - view->details->update_status_idle_id = 0; - } -} - -static gboolean -update_status_idle_callback (gpointer data) -{ - NautilusView *view; - - view = NAUTILUS_VIEW (data); - nautilus_view_display_selection_info (view); - view->details->update_status_idle_id = 0; - return FALSE; -} - -static void -schedule_update_status (NautilusView *view) -{ - g_assert (NAUTILUS_IS_VIEW (view)); - - /* Make sure we haven't already destroyed it */ - if (view->details->slot == NULL) { - return; - } - - if (view->details->loading) { - /* Don't update status bar while loading the dir */ - return; - } - - if (view->details->update_status_idle_id == 0) { - view->details->update_status_idle_id = - g_idle_add_full (G_PRIORITY_DEFAULT_IDLE - 20, - update_status_idle_callback, view, NULL); - } -} - -/** - * nautilus_view_notify_selection_changed: - * - * Notify this view that the selection has changed. This is normally - * called only by subclasses. - * @view: NautilusView whose selection has changed. - * - **/ -void -nautilus_view_notify_selection_changed (NautilusView *view) -{ - GtkWindow *window; - GList *selection; - - g_return_if_fail (NAUTILUS_IS_VIEW (view)); - - selection = nautilus_view_get_selection (view); - window = nautilus_view_get_containing_window (view); - DEBUG_FILES (selection, "Selection changed in window %p", window); - nautilus_file_list_free (selection); - - view->details->selection_was_removed = FALSE; - - /* Schedule a display of the new selection. */ - if (view->details->display_selection_idle_id == 0) { - view->details->display_selection_idle_id - = g_idle_add (display_selection_info_idle_callback, - view); - } - - if (view->details->batching_selection_level != 0) { - view->details->selection_changed_while_batched = TRUE; - } else { - /* Here is the work we do only when we're not - * batching selection changes. In other words, it's the slower - * stuff that we don't want to slow down selection techniques - * such as rubberband-selecting in icon view. - */ - - /* Schedule an update of menu item states to match selection */ - schedule_update_context_menus (view); - } -} - -static void -file_changed_callback (NautilusFile *file, gpointer callback_data) -{ - NautilusView *view = NAUTILUS_VIEW (callback_data); - - schedule_changes (view); - - schedule_update_context_menus (view); - schedule_update_status (view); -} - -/** - * load_directory: - * - * Switch the displayed location to a new uri. If the uri is not valid, - * the location will not be switched; user feedback will be provided instead. - * @view: NautilusView whose location will be changed. - * @uri: A string representing the uri to switch to. - * - **/ -static void -load_directory (NautilusView *view, - NautilusDirectory *directory) -{ - NautilusDirectory *old_directory; - NautilusFile *old_file; - NautilusFileAttributes attributes; - - g_assert (NAUTILUS_IS_VIEW (view)); - g_assert (NAUTILUS_IS_DIRECTORY (directory)); - - nautilus_profile_start (NULL); - - nautilus_view_stop_loading (view); - g_signal_emit (view, signals[CLEAR], 0); - - view->details->loading = TRUE; - - setup_loading_floating_bar (view); - - /* Update menus when directory is empty, before going to new - * location, so they won't have any false lingering knowledge - * of old selection. - */ - schedule_update_context_menus (view); - - while (view->details->subdirectory_list != NULL) { - nautilus_view_remove_subdirectory (view, - view->details->subdirectory_list->data); - } - - old_directory = view->details->model; - - nautilus_directory_ref (directory); - view->details->model = directory; - nautilus_directory_unref (old_directory); - - old_file = view->details->directory_as_file; - view->details->directory_as_file = - nautilus_directory_get_corresponding_file (directory); - nautilus_file_unref (old_file); - - /* FIXME bugzilla.gnome.org 45062: In theory, we also need to monitor metadata here (as - * well as doing a call when ready), in case external forces - * change the directory's file metadata. - */ - attributes = - NAUTILUS_FILE_ATTRIBUTE_INFO | - NAUTILUS_FILE_ATTRIBUTE_MOUNT | - NAUTILUS_FILE_ATTRIBUTE_FILESYSTEM_INFO; - view->details->metadata_for_directory_as_file_pending = TRUE; - view->details->metadata_for_files_in_directory_pending = TRUE; - nautilus_file_call_when_ready - (view->details->directory_as_file, - attributes, - metadata_for_directory_as_file_ready_callback, view); - nautilus_directory_call_when_ready - (view->details->model, - attributes, - FALSE, - metadata_for_files_in_directory_ready_callback, view); - - /* If capabilities change, then we need to update the menus - * because of New Folder, and relative emblems. - */ - attributes = - NAUTILUS_FILE_ATTRIBUTE_INFO | - NAUTILUS_FILE_ATTRIBUTE_FILESYSTEM_INFO; - nautilus_file_monitor_add (view->details->directory_as_file, - &view->details->directory_as_file, - attributes); - - view->details->file_changed_handler_id = g_signal_connect - (view->details->directory_as_file, "changed", - G_CALLBACK (file_changed_callback), view); - - nautilus_profile_end (NULL); -} - -static void -finish_loading (NautilusView *view) -{ - NautilusFileAttributes attributes; - - nautilus_profile_start (NULL); - - /* Tell interested parties that we've begun loading this directory now. - * Subclasses use this to know that the new metadata is now available. - */ - nautilus_profile_start ("BEGIN_LOADING"); - g_signal_emit (view, signals[BEGIN_LOADING], 0); - nautilus_profile_end ("BEGIN_LOADING"); - - check_empty_states (view); - - if (nautilus_directory_are_all_files_seen (view->details->model)) { - /* Unschedule a pending update and schedule a new one with the minimal - * update interval. This gives the view a short chance at gathering the - * (cached) deep counts. - */ - unschedule_display_of_pending_files (view); - schedule_timeout_display_of_pending_files (view, UPDATE_INTERVAL_MIN); - } - - /* Start loading. */ - - /* Connect handlers to learn about loading progress. */ - view->details->done_loading_handler_id = g_signal_connect - (view->details->model, "done-loading", - G_CALLBACK (done_loading_callback), view); - view->details->load_error_handler_id = g_signal_connect - (view->details->model, "load-error", - G_CALLBACK (load_error_callback), view); - - /* Monitor the things needed to get the right icon. Also - * monitor a directory's item count because the "size" - * attribute is based on that, and the file's metadata - * and possible custom name. - */ - attributes = - NAUTILUS_FILE_ATTRIBUTES_FOR_ICON | - NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT | - NAUTILUS_FILE_ATTRIBUTE_INFO | - NAUTILUS_FILE_ATTRIBUTE_LINK_INFO | - NAUTILUS_FILE_ATTRIBUTE_MOUNT | - NAUTILUS_FILE_ATTRIBUTE_EXTENSION_INFO; - - nautilus_directory_file_monitor_add (view->details->model, - &view->details->model, - view->details->show_hidden_files, - attributes, - files_added_callback, view); - - view->details->files_added_handler_id = g_signal_connect - (view->details->model, "files-added", - G_CALLBACK (files_added_callback), view); - view->details->files_changed_handler_id = g_signal_connect - (view->details->model, "files-changed", - G_CALLBACK (files_changed_callback), view); - - nautilus_profile_end (NULL); -} - -static void -finish_loading_if_all_metadata_loaded (NautilusView *view) -{ - if (!view->details->metadata_for_directory_as_file_pending && - !view->details->metadata_for_files_in_directory_pending) { - finish_loading (view); - } -} - -static void -metadata_for_directory_as_file_ready_callback (NautilusFile *file, - gpointer callback_data) -{ - NautilusView *view; - - view = callback_data; - - g_assert (NAUTILUS_IS_VIEW (view)); - g_assert (view->details->directory_as_file == file); - g_assert (view->details->metadata_for_directory_as_file_pending); - - nautilus_profile_start (NULL); - - view->details->metadata_for_directory_as_file_pending = FALSE; - - finish_loading_if_all_metadata_loaded (view); - nautilus_profile_end (NULL); -} - -static void -metadata_for_files_in_directory_ready_callback (NautilusDirectory *directory, - GList *files, - gpointer callback_data) -{ - NautilusView *view; - - view = callback_data; - - g_assert (NAUTILUS_IS_VIEW (view)); - g_assert (view->details->model == directory); - g_assert (view->details->metadata_for_files_in_directory_pending); - - nautilus_profile_start (NULL); - - view->details->metadata_for_files_in_directory_pending = FALSE; - - finish_loading_if_all_metadata_loaded (view); - nautilus_profile_end (NULL); -} - -static void -disconnect_handler (GObject *object, guint *id) -{ - if (*id != 0) { - g_signal_handler_disconnect (object, *id); - *id = 0; - } -} - -static void -disconnect_directory_handler (NautilusView *view, guint *id) -{ - disconnect_handler (G_OBJECT (view->details->model), id); -} - -static void -disconnect_directory_as_file_handler (NautilusView *view, guint *id) -{ - disconnect_handler (G_OBJECT (view->details->directory_as_file), id); -} - -static void -disconnect_model_handlers (NautilusView *view) -{ - if (view->details->model == NULL) { - return; - } - disconnect_directory_handler (view, &view->details->files_added_handler_id); - disconnect_directory_handler (view, &view->details->files_changed_handler_id); - disconnect_directory_handler (view, &view->details->done_loading_handler_id); - disconnect_directory_handler (view, &view->details->load_error_handler_id); - disconnect_directory_as_file_handler (view, &view->details->file_changed_handler_id); - nautilus_file_cancel_call_when_ready (view->details->directory_as_file, - metadata_for_directory_as_file_ready_callback, - view); - nautilus_directory_cancel_callback (view->details->model, - metadata_for_files_in_directory_ready_callback, - view); - nautilus_directory_file_monitor_remove (view->details->model, - &view->details->model); - nautilus_file_monitor_remove (view->details->directory_as_file, - &view->details->directory_as_file); -} - -static void -nautilus_view_select_file (NautilusView *view, NautilusFile *file) -{ - GList file_list; - - file_list.data = file; - file_list.next = NULL; - file_list.prev = NULL; - nautilus_view_call_set_selection (view, &file_list); -} - -static gboolean -remove_all (gpointer key, gpointer value, gpointer callback_data) -{ - return TRUE; -} - -/** - * nautilus_view_stop_loading: - * - * Stop the current ongoing process, such as switching to a new uri. - * @view: NautilusView in question. - * - **/ -void -nautilus_view_stop_loading (NautilusView *view) -{ - g_return_if_fail (NAUTILUS_IS_VIEW (view)); - - disconnect_model_handlers (view); - if (view->details->model) { - nautilus_directory_unref (view->details->model); - view->details->model = NULL; - } - unschedule_display_of_pending_files (view); - reset_update_interval (view); - - /* Free extra undisplayed files */ - file_and_directory_list_free (view->details->new_added_files); - view->details->new_added_files = NULL; - - file_and_directory_list_free (view->details->new_changed_files); - view->details->new_changed_files = NULL; - - g_hash_table_foreach_remove (view->details->non_ready_files, remove_all, NULL); - - file_and_directory_list_free (view->details->old_added_files); - view->details->old_added_files = NULL; - - file_and_directory_list_free (view->details->old_changed_files); - view->details->old_changed_files = NULL; - - g_list_free_full (view->details->pending_selection, g_object_unref); - view->details->pending_selection = NULL; - - done_loading (view, FALSE); -} - -gboolean -nautilus_view_is_editable (NautilusView *view) -{ - NautilusDirectory *directory; - - directory = nautilus_view_get_model (view); - - if (directory != NULL) { - return nautilus_directory_is_editable (directory); - } - - return TRUE; -} - -static gboolean -real_is_read_only (NautilusView *view) -{ - NautilusFile *file; - - if (!nautilus_view_is_editable (view)) { - return TRUE; - } - - file = nautilus_view_get_directory_as_file (view); - if (file != NULL) { - return !nautilus_file_can_write (file); - } - return FALSE; -} - -/** - * nautilus_view_should_show_file - * - * Returns whether or not this file should be displayed based on - * current filtering options. - */ -gboolean -nautilus_view_should_show_file (NautilusView *view, NautilusFile *file) -{ - return nautilus_file_should_show (file, - view->details->show_hidden_files, - view->details->show_foreign_files); -} - -static gboolean -real_using_manual_layout (NautilusView *view) -{ - g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE); - - return FALSE; -} - -void -nautilus_view_ignore_hidden_file_preferences (NautilusView *view) -{ - g_return_if_fail (view->details->model == NULL); - - if (view->details->ignore_hidden_file_preferences) { - return; - } - - view->details->show_hidden_files = FALSE; - view->details->ignore_hidden_file_preferences = TRUE; -} - -void -nautilus_view_set_show_foreign (NautilusView *view, - gboolean show_foreign) -{ - view->details->show_foreign_files = show_foreign; -} - -char * -nautilus_view_get_uri (NautilusView *view) -{ - g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL); - if (view->details->model == NULL) { - return NULL; - } - return nautilus_directory_get_uri (view->details->model); -} - -void -nautilus_view_move_copy_items (NautilusView *view, - const GList *item_uris, - GArray *relative_item_points, - const char *target_uri, - int copy_action, - int x, int y) -{ - NautilusFile *target_file; - - g_assert (relative_item_points == NULL - || relative_item_points->len == 0 - || g_list_length ((GList *)item_uris) == relative_item_points->len); - - /* add the drop location to the icon offsets */ - offset_drop_points (relative_item_points, x, y); - - target_file = nautilus_file_get_existing_by_uri (target_uri); - /* special-case "command:" here instead of starting a move/copy */ - if (target_file != NULL && nautilus_file_is_launcher (target_file)) { - nautilus_file_unref (target_file); - nautilus_launch_desktop_file ( - gtk_widget_get_screen (GTK_WIDGET (view)), - target_uri, item_uris, - nautilus_view_get_containing_window (view)); - return; - } else if (copy_action == GDK_ACTION_COPY && - nautilus_is_file_roller_installed () && - target_file != NULL && - nautilus_file_is_archive (target_file)) { - char *command, *quoted_uri, *tmp; - const GList *l; - GdkScreen *screen; - - /* Handle dropping onto a file-roller archiver file, instead of starting a move/copy */ - - nautilus_file_unref (target_file); - - quoted_uri = g_shell_quote (target_uri); - command = g_strconcat ("file-roller -a ", quoted_uri, NULL); - g_free (quoted_uri); - - for (l = item_uris; l != NULL; l = l->next) { - quoted_uri = g_shell_quote ((char *) l->data); - - tmp = g_strconcat (command, " ", quoted_uri, NULL); - g_free (command); - command = tmp; - - g_free (quoted_uri); - } - - screen = gtk_widget_get_screen (GTK_WIDGET (view)); - if (screen == NULL) { - screen = gdk_screen_get_default (); - } - - nautilus_launch_application_from_command (screen, command, FALSE, NULL); - g_free (command); - - return; - } - nautilus_file_unref (target_file); - - nautilus_file_operations_copy_move - (item_uris, relative_item_points, - target_uri, copy_action, GTK_WIDGET (view), - copy_move_done_callback, pre_copy_move (view)); -} - -static void -nautilus_view_trash_state_changed_callback (NautilusTrashMonitor *trash_monitor, - gboolean state, gpointer callback_data) -{ - NautilusView *view; - - view = (NautilusView *) callback_data; - g_assert (NAUTILUS_IS_VIEW (view)); - - schedule_update_context_menus (view); -} - -void -nautilus_view_start_batching_selection_changes (NautilusView *view) -{ - g_return_if_fail (NAUTILUS_IS_VIEW (view)); - - ++view->details->batching_selection_level; - view->details->selection_changed_while_batched = FALSE; -} - -void -nautilus_view_stop_batching_selection_changes (NautilusView *view) -{ - g_return_if_fail (NAUTILUS_IS_VIEW (view)); - g_return_if_fail (view->details->batching_selection_level > 0); - - if (--view->details->batching_selection_level == 0) { - if (view->details->selection_changed_while_batched) { - nautilus_view_notify_selection_changed (view); - } - } -} - -static GArray * -real_get_selected_icon_locations (NautilusView *view) -{ - /* By default, just return an empty list. */ - return g_array_new (FALSE, TRUE, sizeof (GdkPoint)); -} - -static void -nautilus_view_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - NautilusView *view = NAUTILUS_VIEW (object); - - switch (prop_id) { - case PROP_ICON: - g_value_set_object (value, nautilus_view_get_icon (view)); - break; - - case PROP_VIEW_WIDGET: - g_value_set_object (value, nautilus_view_get_view_widget (view)); - break; - - default: - g_assert_not_reached (); - - } -} - -static void -nautilus_view_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - NautilusView *directory_view; - NautilusWindowSlot *slot; - - directory_view = NAUTILUS_VIEW (object); - - switch (prop_id) { - case PROP_WINDOW_SLOT: - g_assert (directory_view->details->slot == NULL); - - slot = NAUTILUS_WINDOW_SLOT (g_value_get_object (value)); - directory_view->details->slot = slot; - - g_signal_connect_object (directory_view->details->slot, - "active", G_CALLBACK (slot_active), - directory_view, 0); - g_signal_connect_object (directory_view->details->slot, - "inactive", G_CALLBACK (slot_inactive), - directory_view, 0); - break; - case PROP_SUPPORTS_ZOOMING: - directory_view->details->supports_zooming = g_value_get_boolean (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - - -gboolean -nautilus_view_handle_scroll_event (NautilusView *directory_view, - GdkEventScroll *event) -{ - static gdouble total_delta_y = 0; - gdouble delta_x, delta_y; - - if (event->state & GDK_CONTROL_MASK) { - switch (event->direction) { - case GDK_SCROLL_UP: - /* Zoom In */ - nautilus_view_bump_zoom_level (directory_view, 1); - return TRUE; - - case GDK_SCROLL_DOWN: - /* Zoom Out */ - nautilus_view_bump_zoom_level (directory_view, -1); - return TRUE; - - case GDK_SCROLL_SMOOTH: - gdk_event_get_scroll_deltas ((const GdkEvent *) event, - &delta_x, &delta_y); - - /* try to emulate a normal scrolling event by summing deltas */ - total_delta_y += delta_y; - - if (total_delta_y >= 1) { - total_delta_y = 0; - /* emulate scroll down */ - nautilus_view_bump_zoom_level (directory_view, -1); - return TRUE; - } else if (total_delta_y <= - 1) { - total_delta_y = 0; - /* emulate scroll up */ - nautilus_view_bump_zoom_level (directory_view, 1); - return TRUE; - } else { - /* eat event */ - return TRUE; - } - - case GDK_SCROLL_LEFT: - case GDK_SCROLL_RIGHT: - break; - - default: - g_assert_not_reached (); - } - } - - return FALSE; -} - -/* handle Shift+Scroll, which will cause a zoom-in/out */ -static gboolean -nautilus_view_scroll_event (GtkWidget *widget, - GdkEventScroll *event) -{ - NautilusView *directory_view; - - directory_view = NAUTILUS_VIEW (widget); - if (nautilus_view_handle_scroll_event (directory_view, event)) { - return TRUE; - } - - return FALSE; -} - - -static void -action_reload_enabled_changed (GActionGroup *action_group, - gchar *action_name, - gboolean enabled, - NautilusView *view) -{ - gtk_widget_set_visible (view->details->reload, enabled); -} - -static void -action_stop_enabled_changed (GActionGroup *action_group, - gchar *action_name, - gboolean enabled, - NautilusView *view) -{ - gtk_widget_set_visible (view->details->stop, enabled); -} - -static void -nautilus_view_parent_set (GtkWidget *widget, - GtkWidget *old_parent) -{ - NautilusWindow *window; - NautilusView *view; - GtkWidget *parent; - - view = NAUTILUS_VIEW (widget); - - parent = gtk_widget_get_parent (widget); - window = nautilus_view_get_window (view); - g_assert (parent == NULL || old_parent == NULL); - - if (GTK_WIDGET_CLASS (nautilus_view_parent_class)->parent_set != NULL) { - GTK_WIDGET_CLASS (nautilus_view_parent_class)->parent_set (widget, old_parent); - } - - if (view->details->stop_signal_handler > 0) { - g_signal_handler_disconnect (window, view->details->stop_signal_handler); - view->details->stop_signal_handler = 0; - } - - if (view->details->reload_signal_handler > 0) { - g_signal_handler_disconnect (window, view->details->reload_signal_handler); - view->details->reload_signal_handler = 0; - } - - if (parent != NULL) { - g_assert (old_parent == NULL); - - if (view->details->slot == nautilus_window_get_active_slot (window)) { - view->details->active = TRUE; - gtk_widget_insert_action_group (GTK_WIDGET (nautilus_view_get_window (view)), - "view", - G_ACTION_GROUP (view->details->view_action_group)); - } - - view->details->stop_signal_handler = - g_signal_connect (window, - "action-enabled-changed::stop", - G_CALLBACK (action_stop_enabled_changed), - view); - view->details->reload_signal_handler = - g_signal_connect (window, - "action-enabled-changed::reload", - G_CALLBACK (action_reload_enabled_changed), - view); - } else { - remove_update_context_menus_timeout_callback (view); - gtk_widget_insert_action_group (GTK_WIDGET (nautilus_view_get_window (view)), - "view", - NULL); - } -} - -static gboolean -nautilus_view_key_press_event (GtkWidget *widget, - GdkEventKey *event) -{ - NautilusView *view; - gint i; - - view = NAUTILUS_VIEW (widget); - - for (i = 0; i < G_N_ELEMENTS (extra_view_keybindings); i++) { - if (extra_view_keybindings[i].keyval == event->keyval) { - GAction *action; - - action = g_action_map_lookup_action (G_ACTION_MAP (view->details->view_action_group), - extra_view_keybindings[i].action); - - if (g_action_get_enabled (action)) { - g_action_activate (action, NULL); - return GDK_EVENT_STOP; - } - - break; - } - } - - return GDK_EVENT_PROPAGATE; -} - -static void -nautilus_view_class_init (NautilusViewClass *klass) -{ - GObjectClass *oclass; - GtkWidgetClass *widget_class; - - widget_class = GTK_WIDGET_CLASS (klass); - oclass = G_OBJECT_CLASS (klass); - - oclass->finalize = nautilus_view_finalize; - oclass->get_property = nautilus_view_get_property; - oclass->set_property = nautilus_view_set_property; - - widget_class->destroy = nautilus_view_destroy; - widget_class->key_press_event = nautilus_view_key_press_event; - widget_class->scroll_event = nautilus_view_scroll_event; - widget_class->parent_set = nautilus_view_parent_set; - widget_class->grab_focus = nautilus_view_grab_focus; - - g_type_class_add_private (klass, sizeof (NautilusViewDetails)); - - signals[ADD_FILE] = - g_signal_new ("add-file", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NautilusViewClass, add_file), - NULL, NULL, - g_cclosure_marshal_generic, - G_TYPE_NONE, 2, NAUTILUS_TYPE_FILE, NAUTILUS_TYPE_DIRECTORY); - signals[BEGIN_FILE_CHANGES] = - g_signal_new ("begin-file-changes", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NautilusViewClass, begin_file_changes), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - signals[BEGIN_LOADING] = - g_signal_new ("begin-loading", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NautilusViewClass, begin_loading), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - signals[CLEAR] = - g_signal_new ("clear", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NautilusViewClass, clear), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - signals[END_FILE_CHANGES] = - g_signal_new ("end-file-changes", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NautilusViewClass, end_file_changes), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - signals[END_LOADING] = - g_signal_new ("end-loading", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NautilusViewClass, end_loading), - NULL, NULL, - g_cclosure_marshal_VOID__BOOLEAN, - G_TYPE_NONE, 1, G_TYPE_BOOLEAN); - signals[FILE_CHANGED] = - g_signal_new ("file-changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NautilusViewClass, file_changed), - NULL, NULL, - g_cclosure_marshal_generic, - G_TYPE_NONE, 2, NAUTILUS_TYPE_FILE, NAUTILUS_TYPE_DIRECTORY); - signals[REMOVE_FILE] = - g_signal_new ("remove-file", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NautilusViewClass, remove_file), - NULL, NULL, - g_cclosure_marshal_generic, - G_TYPE_NONE, 2, NAUTILUS_TYPE_FILE, NAUTILUS_TYPE_DIRECTORY); - signals[SELECTION_CHANGED] = - g_signal_new ("selection-changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - klass->get_selected_icon_locations = real_get_selected_icon_locations; - klass->is_read_only = real_is_read_only; - klass->can_rename_file = can_rename_file; - klass->get_backing_uri = real_get_backing_uri; - klass->using_manual_layout = real_using_manual_layout; - klass->get_window = nautilus_view_get_window; - klass->update_context_menus = real_update_context_menus; - klass->update_actions_state = real_update_actions_state; - - copied_files_atom = gdk_atom_intern ("x-special/gnome-copied-files", FALSE); - - properties[PROP_WINDOW_SLOT] = - g_param_spec_object ("window-slot", - "Window Slot", - "The parent window slot reference", - NAUTILUS_TYPE_WINDOW_SLOT, - G_PARAM_WRITABLE | - G_PARAM_CONSTRUCT_ONLY); - properties[PROP_SUPPORTS_ZOOMING] = - g_param_spec_boolean ("supports-zooming", - "Supports zooming", - "Whether the view supports zooming", - TRUE, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); - properties[PROP_ICON] = - g_param_spec_object ("icon", - "Icon", - "The icon that represents the view", - G_TYPE_ICON, - G_PARAM_READABLE); - - properties[PROP_VIEW_WIDGET] = - g_param_spec_object ("view-widget", - "View widget", - "The view's widget that will appear under the view menu button", - GTK_TYPE_WIDGET, - G_PARAM_READABLE); - - g_object_class_install_properties (oclass, NUM_PROPERTIES, properties); -} - -static void -nautilus_view_init (NautilusView *view) -{ - GtkBuilder *builder; - AtkObject *atk_object; - NautilusDirectory *scripts_directory; - NautilusDirectory *templates_directory; - gchar *templates_uri; - GApplication *app; - const gchar *open_accels[] = { - "<control>o", - "<alt>Down", - NULL - }; - - nautilus_profile_start (NULL); - - view->details = G_TYPE_INSTANCE_GET_PRIVATE (view, NAUTILUS_TYPE_VIEW, - NautilusViewDetails); - - /* NautilusFloatingBar listen to its parent's 'enter-notify-event' signal - * and GtkOverlay doesn't have it enabled by default, so we have to add them - * here. - */ - gtk_widget_add_events (GTK_WIDGET (view), - GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); - - /* View menu */ - builder = gtk_builder_new_from_resource ("/org/gnome/nautilus/nautilus-toolbar-view-menu.xml"); - view->details->view_menu_widget = g_object_ref (gtk_builder_get_object (builder, "view_menu_widget")); - view->details->zoom_level_scale = GTK_WIDGET (gtk_builder_get_object (builder, "zoom_level_scale")); - view->details->zoom_adjustment = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "zoom_adjustment")); - - view->details->sort_menu = GTK_WIDGET (gtk_builder_get_object (builder, "sort_menu")); - view->details->sort_trash_time = GTK_WIDGET (gtk_builder_get_object (builder, "sort_trash_time")); - view->details->sort_search_relevance = GTK_WIDGET (gtk_builder_get_object (builder, "sort_search_relevance")); - view->details->visible_columns = GTK_WIDGET (gtk_builder_get_object (builder, "visible_columns")); - view->details->reload = GTK_WIDGET (gtk_builder_get_object (builder, "reload")); - view->details->stop = GTK_WIDGET (gtk_builder_get_object (builder, "stop")); - - g_signal_connect (view->details->zoom_level_scale, "value-changed", - G_CALLBACK (zoom_level_changed), view); - - g_object_unref (builder); - - /* Scrolled Window */ - view->details->scrolled_window = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (view->details->scrolled_window), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_AUTOMATIC); - gtk_widget_show (view->details->scrolled_window); - - g_signal_connect_swapped (view->details->scrolled_window, - "scroll-event", - G_CALLBACK (nautilus_view_scroll_event), - view); - - gtk_container_add (GTK_CONTAINER (view), view->details->scrolled_window); - - /* Empty states */ - builder = gtk_builder_new_from_resource ("/org/gnome/nautilus/nautilus-no-search-results.ui"); - view->details->no_search_results_widget = GTK_WIDGET (gtk_builder_get_object (builder, "no_search_results")); - gtk_overlay_add_overlay (GTK_OVERLAY (view), view->details->no_search_results_widget); - g_object_unref (builder); - - builder = gtk_builder_new_from_resource ("/org/gnome/nautilus/nautilus-folder-is-empty.ui"); - view->details->folder_is_empty_widget = GTK_WIDGET (gtk_builder_get_object (builder, "folder_is_empty")); - gtk_overlay_add_overlay (GTK_OVERLAY (view), view->details->folder_is_empty_widget); - g_object_unref (builder); - - /* Floating bar */ - view->details->floating_bar = nautilus_floating_bar_new (NULL, NULL, FALSE); - gtk_widget_set_halign (view->details->floating_bar, GTK_ALIGN_END); - gtk_widget_set_valign (view->details->floating_bar, GTK_ALIGN_END); - gtk_overlay_add_overlay (GTK_OVERLAY (view), view->details->floating_bar); - - g_signal_connect (view->details->floating_bar, - "action", - G_CALLBACK (floating_bar_action_cb), - view); - - /* Default to true; desktop-icon-view sets to false */ - view->details->show_foreign_files = TRUE; - - view->details->non_ready_files = - g_hash_table_new_full (file_and_directory_hash, - file_and_directory_equal, - (GDestroyNotify)file_and_directory_free, - NULL); - - gtk_style_context_set_junction_sides (gtk_widget_get_style_context (GTK_WIDGET (view)), - GTK_JUNCTION_TOP | GTK_JUNCTION_LEFT); - - if (set_up_scripts_directory_global ()) { - scripts_directory = nautilus_directory_get_by_uri (scripts_directory_uri); - add_directory_to_scripts_directory_list (view, scripts_directory); - nautilus_directory_unref (scripts_directory); - } else { - g_warning ("Ignoring scripts directory, it may be a broken link\n"); - } - - if (nautilus_should_use_templates_directory ()) { - templates_uri = nautilus_get_templates_directory_uri (); - templates_directory = nautilus_directory_get_by_uri (templates_uri); - g_free (templates_uri); - add_directory_to_templates_directory_list (view, templates_directory); - nautilus_directory_unref (templates_directory); - } - update_templates_directory (view); - - view->details->sort_directories_first = - g_settings_get_boolean (nautilus_preferences, NAUTILUS_PREFERENCES_SORT_DIRECTORIES_FIRST); - view->details->show_hidden_files = - g_settings_get_boolean (gtk_filechooser_preferences, NAUTILUS_PREFERENCES_SHOW_HIDDEN_FILES); - - g_signal_connect_object (nautilus_trash_monitor_get (), "trash-state-changed", - G_CALLBACK (nautilus_view_trash_state_changed_callback), view, 0); - - /* React to clipboard changes */ - g_signal_connect_object (nautilus_clipboard_monitor_get (), "clipboard-changed", - G_CALLBACK (clipboard_changed_callback), view, 0); - - /* Register to menu provider extension signal managing menu updates */ - g_signal_connect_object (nautilus_signaller_get_current (), "popup-menu-changed", - G_CALLBACK (schedule_update_context_menus), view, G_CONNECT_SWAPPED); - - gtk_widget_show (GTK_WIDGET (view)); - - g_signal_connect_swapped (nautilus_preferences, - "changed::" NAUTILUS_PREFERENCES_CLICK_POLICY, - G_CALLBACK (click_policy_changed_callback), - view); - g_signal_connect_swapped (nautilus_preferences, - "changed::" NAUTILUS_PREFERENCES_SORT_DIRECTORIES_FIRST, - G_CALLBACK (sort_directories_first_changed_callback), view); - g_signal_connect_swapped (gtk_filechooser_preferences, - "changed::" NAUTILUS_PREFERENCES_SHOW_HIDDEN_FILES, - G_CALLBACK (show_hidden_files_changed_callback), view); - g_signal_connect_swapped (gnome_lockdown_preferences, - "changed::" NAUTILUS_PREFERENCES_LOCKDOWN_COMMAND_LINE, - G_CALLBACK (schedule_update_context_menus), view); - - /* Accessibility */ - atk_object = gtk_widget_get_accessible (GTK_WIDGET (view)); - atk_object_set_name (atk_object, _("Content View")); - atk_object_set_description (atk_object, _("View of the current folder")); - - view->details->view_action_group = G_ACTION_GROUP (g_simple_action_group_new ()); - g_action_map_add_action_entries (G_ACTION_MAP (view->details->view_action_group), - view_entries, - G_N_ELEMENTS (view_entries), - view); - gtk_widget_insert_action_group (GTK_WIDGET (view), - "view", - G_ACTION_GROUP (view->details->view_action_group)); - app = g_application_get_default (); - - /* Toolbar menu */ - nautilus_application_add_accelerator (app, "view.zoom-in", "<control>plus"); - nautilus_application_add_accelerator (app, "view.zoom-out", "<control>minus"); - nautilus_application_add_accelerator (app, "view.show-hidden-files", "<control>h"); - /* Background menu */ - nautilus_application_add_accelerator (app, "view.select-all", "<control>a"); - nautilus_application_add_accelerator (app, "view.paste", "<control>v"); - /* Selection menu */ - gtk_application_set_accels_for_action (GTK_APPLICATION (app), - "view.open-with-default-application", open_accels); - nautilus_application_add_accelerator (app, "view.open-item-new-tab", "<shift><control>t"); - nautilus_application_add_accelerator (app, "view.open-item-new-window", "<shift><control>w"); - nautilus_application_add_accelerator (app, "view.move-to-trash", "Delete"); - nautilus_application_add_accelerator (app, "view.delete-from-trash", "Delete"); - nautilus_application_add_accelerator (app, "view.delete-permanently-shortcut", "<shift>Delete"); - nautilus_application_add_accelerator (app, "view.properties", "<control>i"); - nautilus_application_add_accelerator (app, "view.open-item-location", "<control><alt>o"); - nautilus_application_add_accelerator (app, "view.rename", "F2"); - nautilus_application_add_accelerator (app, "view.cut", "<control>x"); - nautilus_application_add_accelerator (app, "view.copy", "<control>c"); - nautilus_application_add_accelerator (app, "view.new-folder", "<control><shift>n"); - /* Only accesible by shorcuts */ - nautilus_application_add_accelerator (app, "view.select-pattern", "<control>s"); - nautilus_application_add_accelerator (app, "view.zoom-default", "<control>0"); - nautilus_application_add_accelerator (app, "view.invert-selection", "<shift><control>i"); - nautilus_application_add_accelerator (app, "view.open-file-and-close-window", "<control><shift>Down"); - - /* Show a warning dialog to inform the user that the shorcut for move to trash - * changed */ - nautilus_application_add_accelerator (app, "view.show-move-to-trash-shortcut-changed-dialog", "<control>Delete"); - - nautilus_profile_end (NULL); -} - -NautilusView * -nautilus_view_new (const gchar *id, - NautilusWindowSlot *slot) -{ - NautilusView *view = NULL; - - if (g_strcmp0 (id, NAUTILUS_CANVAS_VIEW_ID) == 0) { - view = nautilus_canvas_view_new (slot); - } else if (g_strcmp0 (id, NAUTILUS_LIST_VIEW_ID) == 0) { - view = nautilus_list_view_new (slot); - } else if (g_strcmp0 (id, NAUTILUS_DESKTOP_CANVAS_VIEW_ID) == 0) { - view = nautilus_desktop_canvas_view_new (slot); - } -#if ENABLE_EMPTY_VIEW - else if (g_strcmp0 (id, NAUTILUS_EMPTY_VIEW_ID) == 0) { - view = nautilus_empty_view_new (slot); - } -#endif - - if (view == NULL) { - g_critical ("Unknown view type ID: %s", id); - } else if (g_object_is_floating (view)) { - g_object_ref_sink (view); - } - - return view; -} |