nautilus-3.6.3/src/nautilus-view.c

Location Tool Test ID Function Issue
nautilus-view.c:1750:2 clang-analyzer Access to field 'g_class' results in a dereference of a null pointer (loaded from variable 'view')
nautilus-view.c:2283:7 clang-analyzer Value stored to 'res' is never read
   1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
   2 
   3 /* nautilus-view.c
   4  *
   5  * Copyright (C) 1999, 2000  Free Software Foundation
   6  * Copyright (C) 2000, 2001  Eazel, Inc.
   7  *
   8  * This program is free software; you can redistribute it and/or
   9  * modify it under the terms of the GNU General Public License as
  10  * published by the Free Software Foundation; either version 2 of the
  11  * License, or (at your option) any later version.
  12  *
  13  * This program is distributed in the hope that it will be useful,
  14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16  * General Public License for more details.
  17  *
  18  * You should have received a copy of the GNU General Public
  19  * License along with this program; if not, write to the
  20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  21  * Boston, MA 02111-1307, USA.
  22  *
  23  * Authors: Ettore Perazzoli,
  24  *          John Sullivan <sullivan@eazel.com>,
  25  *          Darin Adler <darin@bentspoon.com>,
  26  *          Pavel Cisler <pavel@eazel.com>,
  27  *          David Emory Watson <dwatson@cs.ucr.edu>
  28  */
  29 
  30 #include <config.h>
  31 
  32 #include "nautilus-view.h"
  33 
  34 #include "nautilus-actions.h"
  35 #include "nautilus-desktop-canvas-view.h"
  36 #include "nautilus-error-reporting.h"
  37 #include "nautilus-list-view.h"
  38 #include "nautilus-mime-actions.h"
  39 #include "nautilus-previewer.h"
  40 #include "nautilus-properties-window.h"
  41 
  42 #include <gdk/gdkx.h>
  43 #include <gdk/gdkkeysyms.h>
  44 #include <gtk/gtk.h>
  45 #include <glib/gi18n.h>
  46 #include <glib/gstdio.h>
  47 #include <gio/gio.h>
  48 #include <math.h>
  49 #include <sys/types.h>
  50 #include <sys/stat.h>
  51 #include <fcntl.h>
  52 
  53 #include <eel/eel-glib-extensions.h>
  54 #include <eel/eel-gnome-extensions.h>
  55 #include <eel/eel-gtk-extensions.h>
  56 #include <eel/eel-stock-dialogs.h>
  57 #include <eel/eel-string.h>
  58 #include <eel/eel-vfs-extensions.h>
  59 
  60 #include <libnautilus-extension/nautilus-menu-provider.h>
  61 #include <libnautilus-private/nautilus-clipboard.h>
  62 #include <libnautilus-private/nautilus-clipboard-monitor.h>
  63 #include <libnautilus-private/nautilus-desktop-icon-file.h>
  64 #include <libnautilus-private/nautilus-desktop-directory.h>
  65 #include <libnautilus-private/nautilus-search-directory.h>
  66 #include <libnautilus-private/nautilus-directory.h>
  67 #include <libnautilus-private/nautilus-dnd.h>
  68 #include <libnautilus-private/nautilus-file-attributes.h>
  69 #include <libnautilus-private/nautilus-file-changes-queue.h>
  70 #include <libnautilus-private/nautilus-file-dnd.h>
  71 #include <libnautilus-private/nautilus-file-operations.h>
  72 #include <libnautilus-private/nautilus-file-utilities.h>
  73 #include <libnautilus-private/nautilus-file-private.h>
  74 #include <libnautilus-private/nautilus-global-preferences.h>
  75 #include <libnautilus-private/nautilus-link.h>
  76 #include <libnautilus-private/nautilus-metadata.h>
  77 #include <libnautilus-private/nautilus-recent.h>
  78 #include <libnautilus-private/nautilus-module.h>
  79 #include <libnautilus-private/nautilus-profile.h>
  80 #include <libnautilus-private/nautilus-program-choosing.h>
  81 #include <libnautilus-private/nautilus-trash-monitor.h>
  82 #include <libnautilus-private/nautilus-ui-utilities.h>
  83 #include <libnautilus-private/nautilus-signaller.h>
  84 #include <libnautilus-private/nautilus-icon-names.h>
  85 #include <libnautilus-private/nautilus-file-undo-manager.h>
  86 
  87 #define GNOME_DESKTOP_USE_UNSTABLE_API
  88 #include <gdesktop-enums.h>
  89 
  90 #define DEBUG_FLAG NAUTILUS_DEBUG_DIRECTORY_VIEW
  91 #include <libnautilus-private/nautilus-debug.h>
  92 
  93 /* Minimum starting update inverval */
  94 #define UPDATE_INTERVAL_MIN 100
  95 /* Maximum update interval */
  96 #define UPDATE_INTERVAL_MAX 2000
  97 /* Amount of miliseconds the update interval is increased */
  98 #define UPDATE_INTERVAL_INC 250
  99 /* Interval at which the update interval is increased */
 100 #define UPDATE_INTERVAL_TIMEOUT_INTERVAL 250
 101 /* Milliseconds that have to pass without a change to reset the update interval */
 102 #define UPDATE_INTERVAL_RESET 1000
 103 
 104 #define SILENT_WINDOW_OPEN_LIMIT 5
 105 
 106 #define DUPLICATE_HORIZONTAL_ICON_OFFSET 70
 107 #define DUPLICATE_VERTICAL_ICON_OFFSET   30
 108 
 109 #define MAX_QUEUED_UPDATES 500
 110 
 111 #define NAUTILUS_VIEW_MENU_PATH_APPLICATIONS_SUBMENU_PLACEHOLDER  "/ActionMenu/Open Placeholder/Open With/Applications Placeholder"
 112 #define NAUTILUS_VIEW_MENU_PATH_APPLICATIONS_PLACEHOLDER    	  "/ActionMenu/Open Placeholder/Applications Placeholder"
 113 #define NAUTILUS_VIEW_MENU_PATH_SCRIPTS_PLACEHOLDER               "/ActionMenu/Open Placeholder/Scripts/Scripts Placeholder"
 114 #define NAUTILUS_VIEW_MENU_PATH_EXTENSION_ACTIONS_PLACEHOLDER     "/ActionMenu/Edit/Extension Actions"
 115 #define NAUTILUS_VIEW_MENU_PATH_NEW_DOCUMENTS_PLACEHOLDER  	  "/ActionMenu/New Items Placeholder/New Documents/New Documents Placeholder"
 116 #define NAUTILUS_VIEW_MENU_PATH_OPEN				  "/ActionMenu/Open Placeholder/Open"
 117 
 118 #define NAUTILUS_VIEW_POPUP_PATH_SELECTION			  "/selection"
 119 #define NAUTILUS_VIEW_POPUP_PATH_APPLICATIONS_SUBMENU_PLACEHOLDER "/selection/Open Placeholder/Open With/Applications Placeholder"
 120 #define NAUTILUS_VIEW_POPUP_PATH_APPLICATIONS_PLACEHOLDER    	  "/selection/Open Placeholder/Applications Placeholder"
 121 #define NAUTILUS_VIEW_POPUP_PATH_SCRIPTS_PLACEHOLDER    	  "/selection/Open Placeholder/Scripts/Scripts Placeholder"
 122 #define NAUTILUS_VIEW_POPUP_PATH_EXTENSION_ACTIONS		  "/selection/Extension Actions"
 123 #define NAUTILUS_VIEW_POPUP_PATH_OPEN				  "/selection/Open Placeholder/Open"
 124 
 125 #define NAUTILUS_VIEW_POPUP_PATH_BACKGROUND			  "/background"
 126 #define NAUTILUS_VIEW_POPUP_PATH_BACKGROUND_SCRIPTS_PLACEHOLDER	  "/background/Before Zoom Items/New Object Items/Scripts/Scripts Placeholder"
 127 #define NAUTILUS_VIEW_POPUP_PATH_BACKGROUND_NEW_DOCUMENTS_PLACEHOLDER "/background/Before Zoom Items/New Object Items/New Documents/New Documents Placeholder"
 128 
 129 #define NAUTILUS_VIEW_POPUP_PATH_LOCATION			  "/location"
 130 
 131 #define MAX_MENU_LEVELS 5
 132 #define TEMPLATE_LIMIT 30
 133 
 134 enum {
 135 	ADD_FILE,
 136 	BEGIN_FILE_CHANGES,
 137 	BEGIN_LOADING,
 138 	CLEAR,
 139 	END_FILE_CHANGES,
 140 	END_LOADING,
 141 	FILE_CHANGED,
 142 	LOAD_ERROR,
 143 	MOVE_COPY_ITEMS,
 144 	REMOVE_FILE,
 145 	ZOOM_LEVEL_CHANGED,
 146 	SELECTION_CHANGED,
 147 	TRASH,
 148 	DELETE,
 149 	LAST_SIGNAL
 150 };
 151 
 152 enum {
 153 	PROP_WINDOW_SLOT = 1,
 154 	PROP_SUPPORTS_ZOOMING,
 155 	NUM_PROPERTIES
 156 };
 157 
 158 static guint signals[LAST_SIGNAL];
 159 static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
 160 
 161 static GdkAtom copied_files_atom;
 162 
 163 static char *scripts_directory_uri = NULL;
 164 static int scripts_directory_uri_length;
 165 
 166 struct NautilusViewDetails
 167 {
 168 	NautilusWindowSlot *slot;
 169 	NautilusDirectory *model;
 170 	NautilusFile *directory_as_file;
 171 	NautilusFile *location_popup_directory_as_file;
 172 	GdkEventButton *location_popup_event;
 173 	GtkActionGroup *dir_action_group;
 174 	guint dir_merge_id;
 175 
 176 	gboolean supports_zooming;
 177 
 178 	GList *scripts_directory_list;
 179 	GtkActionGroup *scripts_action_group;
 180 	guint scripts_merge_id;
 181 	
 182 	GList *templates_directory_list;
 183 	GtkActionGroup *templates_action_group;
 184 	guint templates_merge_id;
 185 
 186 	GtkActionGroup *extensions_menu_action_group;
 187 	guint extensions_menu_merge_id;
 188 	
 189 	guint display_selection_idle_id;
 190 	guint update_menus_timeout_id;
 191 	guint update_status_idle_id;
 192 	guint reveal_selection_idle_id;
 193 
 194 	guint display_pending_source_id;
 195 	guint changes_timeout_id;
 196 
 197 	guint update_interval;
 198  	guint64 last_queued;
 199 	
 200 	guint files_added_handler_id;
 201 	guint files_changed_handler_id;
 202 	guint load_error_handler_id;
 203 	guint done_loading_handler_id;
 204 	guint file_changed_handler_id;
 205 
 206 	guint delayed_rename_file_id;
 207 
 208 	GList *new_added_files;
 209 	GList *new_changed_files;
 210 
 211 	GHashTable *non_ready_files;
 212 
 213 	GList *old_added_files;
 214 	GList *old_changed_files;
 215 
 216 	GList *pending_selection;
 217 
 218 	/* whether we are in the active slot */
 219 	gboolean active;
 220 
 221 	/* loading indicates whether this view has begun loading a directory.
 222 	 * This flag should need not be set inside subclasses. NautilusView automatically
 223 	 * sets 'loading' to TRUE before it begins loading a directory's contents and to FALSE
 224 	 * after it finishes loading the directory and its view.
 225 	 */
 226 	gboolean loading;
 227 	gboolean menu_states_untrustworthy;
 228 	gboolean scripts_invalid;
 229 	gboolean templates_invalid;
 230 	gboolean templates_present;
 231 	gboolean reported_load_error;
 232 
 233 	/* flag to indicate that no file updates should be dispatched to subclasses.
 234 	 * This is a workaround for bug #87701 that prevents the list view from
 235 	 * losing focus when the underlying GtkTreeView is updated.
 236 	 */
 237 	gboolean updates_frozen;
 238 	guint	 updates_queued;
 239 	gboolean needs_reload;
 240 
 241 	gboolean is_renaming;
 242 
 243 	gboolean sort_directories_first;
 244 
 245 	gboolean show_foreign_files;
 246 	gboolean show_hidden_files;
 247 	gboolean ignore_hidden_file_preferences;
 248 
 249 	gboolean batching_selection_level;
 250 	gboolean selection_changed_while_batched;
 251 
 252 	gboolean selection_was_removed;
 253 
 254 	gboolean metadata_for_directory_as_file_pending;
 255 	gboolean metadata_for_files_in_directory_pending;
 256 
 257 	gboolean selection_change_is_due_to_shell;
 258 	gboolean send_selection_change_to_shell;
 259 
 260 	GtkActionGroup *open_with_action_group;
 261 	guint open_with_merge_id;
 262 
 263 	GList *subdirectory_list;
 264 
 265 	GdkPoint context_menu_position;
 266 };
 267 
 268 typedef struct {
 269 	NautilusFile *file;
 270 	NautilusDirectory *directory;
 271 } FileAndDirectory;
 272 
 273 /* forward declarations */
 274 
 275 static gboolean display_selection_info_idle_callback           (gpointer              data);
 276 static void     nautilus_view_create_links_for_files           (NautilusView      *view,
 277 							        GList                *files,
 278 							        GArray               *item_locations);
 279 static void     trash_or_delete_files                          (GtkWindow            *parent_window,
 280 								const GList          *files,
 281 								gboolean              delete_if_all_already_in_trash,
 282 								NautilusView      *view);
 283 static void     load_directory                                 (NautilusView      *view,
 284 								NautilusDirectory    *directory);
 285 static void     nautilus_view_merge_menus                      (NautilusView      *view);
 286 static void     nautilus_view_unmerge_menus                    (NautilusView      *view);
 287 static void     nautilus_view_set_show_hidden_files           (NautilusView      *view,
 288 							       gboolean           show_hidden);
 289 static void     clipboard_changed_callback                     (NautilusClipboardMonitor *monitor,
 290 								NautilusView      *view);
 291 static void     open_one_in_new_window                         (gpointer              data,
 292 								gpointer              callback_data);
 293 static void     schedule_update_menus                          (NautilusView      *view);
 294 static void     remove_update_menus_timeout_callback           (NautilusView      *view);
 295 static void     schedule_update_status                          (NautilusView      *view);
 296 static void     remove_update_status_idle_callback             (NautilusView *view); 
 297 static void     reset_update_interval                          (NautilusView      *view);
 298 static void     schedule_idle_display_of_pending_files         (NautilusView      *view);
 299 static void     unschedule_display_of_pending_files            (NautilusView      *view);
 300 static void     disconnect_model_handlers                      (NautilusView      *view);
 301 static void     metadata_for_directory_as_file_ready_callback  (NautilusFile         *file,
 302 								gpointer              callback_data);
 303 static void     metadata_for_files_in_directory_ready_callback (NautilusDirectory    *directory,
 304 								GList                *files,
 305 								gpointer              callback_data);
 306 static void     nautilus_view_trash_state_changed_callback     (NautilusTrashMonitor *trash,
 307 							        gboolean              state,
 308 							        gpointer              callback_data);
 309 static void     nautilus_view_select_file                      (NautilusView      *view,
 310 							        NautilusFile         *file);
 311 
 312 static void     update_templates_directory                     (NautilusView *view);
 313 static void     user_dirs_changed                              (NautilusView *view);
 314 
 315 static gboolean file_list_all_are_folders                      (GList *file_list);
 316 
 317 static void unschedule_pop_up_location_context_menu (NautilusView *view);
 318 
 319 G_DEFINE_TYPE (NautilusView, nautilus_view, GTK_TYPE_SCROLLED_WINDOW);
 320 #define parent_class nautilus_view_parent_class
 321 
 322 /* virtual methods (public and non-public) */
 323 
 324 /**
 325  * nautilus_view_merge_menus:
 326  * 
 327  * Add this view's menus to the window's menu bar.
 328  * @view: NautilusView in question.
 329  */
 330 static void
 331 nautilus_view_merge_menus (NautilusView *view)
 332 {
 333 	g_return_if_fail (NAUTILUS_IS_VIEW (view));
 334 
 335 	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->merge_menus (view);
 336 }
 337 
 338 static void
 339 nautilus_view_unmerge_menus (NautilusView *view)
 340 {
 341 	g_return_if_fail (NAUTILUS_IS_VIEW (view));
 342 
 343 	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->unmerge_menus (view);}
 344 
 345 static char *
 346 real_get_backing_uri (NautilusView *view)
 347 {
 348 	NautilusDirectory *directory;
 349 	char *uri;
 350        
 351 	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL);
 352 
 353 	if (view->details->model == NULL) {
 354 		return NULL;
 355 	}
 356        
 357 	directory = view->details->model;
 358        
 359 	if (NAUTILUS_IS_DESKTOP_DIRECTORY (directory)) {
 360 		directory = nautilus_desktop_directory_get_real_directory (NAUTILUS_DESKTOP_DIRECTORY (directory));
 361 	} else {
 362 		nautilus_directory_ref (directory);
 363 	}
 364        
 365 	uri = nautilus_directory_get_uri (directory);
 366 
 367 	nautilus_directory_unref (directory);
 368 
 369 	return uri;
 370 }
 371 
 372 /**
 373  *
 374  * nautilus_view_get_backing_uri:
 375  *
 376  * Returns the URI for the target location of new directory, new file, new
 377  * link and paste operations.
 378  */
 379 
 380 char *
 381 nautilus_view_get_backing_uri (NautilusView *view)
 382 {
 383 	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL);
 384 
 385 	return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_backing_uri (view);
 386 }
 387 
 388 /**
 389  * nautilus_view_select_all:
 390  *
 391  * select all the items in the view
 392  * 
 393  **/
 394 static void
 395 nautilus_view_select_all (NautilusView *view)
 396 {
 397 	g_return_if_fail (NAUTILUS_IS_VIEW (view));
 398 
 399 	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->select_all (view);
 400 }
 401 
 402 static void
 403 nautilus_view_select_first (NautilusView *view)
 404 {
 405 	g_return_if_fail (NAUTILUS_IS_VIEW (view));
 406 
 407 	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->select_first (view);
 408 }
 409 
 410 static void
 411 nautilus_view_call_set_selection (NautilusView *view, GList *selection)
 412 {
 413 	g_return_if_fail (NAUTILUS_IS_VIEW (view));
 414 
 415 	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->set_selection (view, selection);
 416 }
 417 
 418 static GList *
 419 nautilus_view_get_selection_for_file_transfer (NautilusView *view)
 420 {
 421 	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL);
 422 
 423 	return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_selection_for_file_transfer (view);
 424 }
 425 
 426 /**
 427  * nautilus_view_get_selected_icon_locations:
 428  *
 429  * return an array of locations of selected icons if available
 430  * Return value: GArray of GdkPoints
 431  * 
 432  **/
 433 static GArray *
 434 nautilus_view_get_selected_icon_locations (NautilusView *view)
 435 {
 436 	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL);
 437 
 438 	return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_selected_icon_locations (view);
 439 }
 440 
 441 static void
 442 nautilus_view_invert_selection (NautilusView *view)
 443 {
 444 	g_return_if_fail (NAUTILUS_IS_VIEW (view));
 445 
 446 	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->invert_selection (view);
 447 }
 448 
 449 /**
 450  * nautilus_view_reveal_selection:
 451  *
 452  * Scroll as necessary to reveal the selected items.
 453  **/
 454 static void
 455 nautilus_view_reveal_selection (NautilusView *view)
 456 {
 457 	g_return_if_fail (NAUTILUS_IS_VIEW (view));
 458 
 459 	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->reveal_selection (view);
 460 }
 461 
 462 /**
 463  * nautilus_view_reset_to_defaults:
 464  *
 465  * set sorting order, zoom level, etc. to match defaults
 466  * 
 467  **/
 468 static void
 469 nautilus_view_reset_to_defaults (NautilusView *view)
 470 {
 471 	GtkAction *action;
 472 
 473 	action = gtk_action_group_get_action (view->details->dir_action_group,
 474 					      NAUTILUS_ACTION_SHOW_HIDDEN_FILES);
 475 	gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
 476 				      g_settings_get_boolean (nautilus_preferences, NAUTILUS_PREFERENCES_SHOW_HIDDEN_FILES));
 477 }
 478 
 479 static gboolean
 480 nautilus_view_using_manual_layout (NautilusView  *view)
 481 {
 482 	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE);
 483 
 484 	return 	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->using_manual_layout (view);
 485 }
 486 
 487 /**
 488  * nautilus_view_can_rename_file
 489  *
 490  * Determine whether a file can be renamed.
 491  * @file: A NautilusFile
 492  * 
 493  * Return value: TRUE if @file can be renamed, FALSE otherwise.
 494  * 
 495  **/
 496 static gboolean
 497 nautilus_view_can_rename_file (NautilusView *view, NautilusFile *file)
 498 {
 499 	return 	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->can_rename_file (view, file);
 500 }
 501 
 502 static gboolean
 503 nautilus_view_is_read_only (NautilusView *view)
 504 {
 505 	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE);
 506 
 507 	return 	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->is_read_only (view);
 508 }
 509 
 510 static gboolean
 511 showing_trash_directory (NautilusView *view)
 512 {
 513 	NautilusFile *file;
 514 
 515 	file = nautilus_view_get_directory_as_file (view);
 516 	if (file != NULL) {
 517 		return nautilus_file_is_in_trash (file);
 518 	}
 519 	return FALSE;
 520 }
 521 
 522 static gboolean
 523 showing_network_directory (NautilusView *view)
 524 {
 525 	NautilusFile *file;
 526 
 527 	file = nautilus_view_get_directory_as_file (view);
 528 	if (file != NULL) {
 529 		return nautilus_file_is_in_network (file);
 530 	}
 531 	return FALSE;
 532 }
 533 
 534 static gboolean
 535 showing_recent_directory (NautilusView *view)
 536 {
 537 	NautilusFile *file;
 538 
 539 	file = nautilus_view_get_directory_as_file (view);
 540 	if (file != NULL) {
 541 		return nautilus_file_is_in_recent (file);
 542 	}
 543 	return FALSE;
 544 }
 545 
 546 static gboolean
 547 nautilus_view_supports_creating_files (NautilusView *view)
 548 {
 549 	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE);
 550 
 551 	return !nautilus_view_is_read_only (view)
 552 		&& !showing_trash_directory (view)
 553 		&& !showing_recent_directory (view);
 554 }
 555 
 556 static gboolean
 557 nautilus_view_is_empty (NautilusView *view)
 558 {
 559 	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE);
 560 
 561 	return 	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->is_empty (view);
 562 }
 563 
 564 /**
 565  * nautilus_view_bump_zoom_level:
 566  *
 567  * bump the current zoom level by invoking the relevant subclass through the slot
 568  * 
 569  **/
 570 void
 571 nautilus_view_bump_zoom_level (NautilusView *view,
 572 			       int zoom_increment)
 573 {
 574 	g_return_if_fail (NAUTILUS_IS_VIEW (view));
 575 
 576 	if (!nautilus_view_supports_zooming (view)) {
 577 		return;
 578 	}
 579 
 580 	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->bump_zoom_level (view, zoom_increment);
 581 }
 582 
 583 /**
 584  * nautilus_view_zoom_to_level:
 585  *
 586  * Set the current zoom level by invoking the relevant subclass through the slot
 587  * 
 588  **/
 589 void
 590 nautilus_view_zoom_to_level (NautilusView *view,
 591 			     NautilusZoomLevel zoom_level)
 592 {
 593 	g_return_if_fail (NAUTILUS_IS_VIEW (view));
 594 
 595 	if (!nautilus_view_supports_zooming (view)) {
 596 		return;
 597 	}
 598 
 599 	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->zoom_to_level (view, zoom_level);
 600 }
 601 
 602 NautilusZoomLevel
 603 nautilus_view_get_zoom_level (NautilusView *view)
 604 {
 605 	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NAUTILUS_ZOOM_LEVEL_STANDARD);
 606 
 607 	if (!nautilus_view_supports_zooming (view)) {
 608 		return NAUTILUS_ZOOM_LEVEL_STANDARD;
 609 	}
 610 
 611 	return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_zoom_level (view);
 612 }
 613 
 614 /**
 615  * nautilus_view_can_zoom_in:
 616  *
 617  * Determine whether the view can be zoomed any closer.
 618  * @view: The zoomable NautilusView.
 619  * 
 620  * Return value: TRUE if @view can be zoomed any closer, FALSE otherwise.
 621  * 
 622  **/
 623 gboolean
 624 nautilus_view_can_zoom_in (NautilusView *view)
 625 {
 626 	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE);
 627 
 628 	if (!nautilus_view_supports_zooming (view)) {
 629 		return FALSE;
 630 	}
 631 
 632 	return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->can_zoom_in (view);
 633 }
 634 
 635 /**
 636  * nautilus_view_can_zoom_out:
 637  *
 638  * Determine whether the view can be zoomed any further away.
 639  * @view: The zoomable NautilusView.
 640  * 
 641  * Return value: TRUE if @view can be zoomed any further away, FALSE otherwise.
 642  * 
 643  **/
 644 gboolean
 645 nautilus_view_can_zoom_out (NautilusView *view)
 646 {
 647 	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE);
 648 
 649 	if (!nautilus_view_supports_zooming (view)) {
 650 		return FALSE;
 651 	}
 652 
 653 	return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->can_zoom_out (view);
 654 }
 655 
 656 gboolean
 657 nautilus_view_supports_zooming (NautilusView *view)
 658 {
 659 	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE);
 660 
 661 	return view->details->supports_zooming;
 662 }
 663 
 664 /**
 665  * nautilus_view_restore_default_zoom_level:
 666  *
 667  * restore to the default zoom level by invoking the relevant subclass through the slot
 668  * 
 669  **/
 670 void
 671 nautilus_view_restore_default_zoom_level (NautilusView *view)
 672 {
 673 	g_return_if_fail (NAUTILUS_IS_VIEW (view));
 674 
 675 	if (!nautilus_view_supports_zooming (view)) {
 676 		return;
 677 	}
 678 
 679 	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->restore_default_zoom_level (view);
 680 }
 681 
 682 const char *
 683 nautilus_view_get_view_id (NautilusView *view)
 684 {
 685 	return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_view_id (view);
 686 }
 687 
 688 char *
 689 nautilus_view_get_first_visible_file (NautilusView *view)
 690 {
 691 	return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_first_visible_file (view);
 692 }
 693 
 694 void
 695 nautilus_view_scroll_to_file (NautilusView *view,
 696 			      const char *uri)
 697 {
 698 	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->scroll_to_file (view, uri);
 699 }
 700 
 701 /**
 702  * nautilus_view_get_selection:
 703  *
 704  * Get a list of NautilusFile pointers that represents the
 705  * currently-selected items in this view. Subclasses must override
 706  * the signal handler for the 'get_selection' signal. Callers are
 707  * responsible for g_free-ing the list (but not its data).
 708  * @view: NautilusView whose selected items are of interest.
 709  * 
 710  * Return value: GList of NautilusFile pointers representing the selection.
 711  * 
 712  **/
 713 GList *
 714 nautilus_view_get_selection (NautilusView *view)
 715 {
 716 	g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL);
 717 
 718 	return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_selection (view);
 719 }
 720 
 721 /**
 722  * nautilus_view_update_menus:
 723  * 
 724  * Update the sensitivity and wording of dynamic menu items.
 725  * @view: NautilusView in question.
 726  */
 727 void
 728 nautilus_view_update_menus (NautilusView *view)
 729 {
 730 	g_return_if_fail (NAUTILUS_IS_VIEW (view));
 731 
 732 	if (!view->details->active) {
 733 		return;
 734 	}
 735 
 736 	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->update_menus (view);
 737 
 738 	view->details->menu_states_untrustworthy = FALSE;
 739 }
 740 
 741 typedef struct {
 742 	GAppInfo *application;
 743 	GList *files;
 744 	NautilusView *directory_view;
 745 } ApplicationLaunchParameters;
 746 
 747 typedef struct {
 748 	NautilusFile *file;
 749 	NautilusView *directory_view;
 750 } ScriptLaunchParameters;
 751 
 752 typedef struct {
 753 	NautilusFile *file;
 754 	NautilusView *directory_view;
 755 } CreateTemplateParameters;
 756 
 757 static ApplicationLaunchParameters *
 758 application_launch_parameters_new (GAppInfo *application,
 759 			      	   GList *files,
 760 			           NautilusView *directory_view)
 761 {
 762 	ApplicationLaunchParameters *result;
 763 
 764 	result = g_new0 (ApplicationLaunchParameters, 1);
 765 	result->application = g_object_ref (application);
 766 	result->files = nautilus_file_list_copy (files);
 767 
 768 	if (directory_view != NULL) {
 769 		g_object_ref (directory_view);
 770 		result->directory_view = directory_view;
 771 	}
 772 
 773 	return result;
 774 }
 775 
 776 static void
 777 application_launch_parameters_free (ApplicationLaunchParameters *parameters)
 778 {
 779 	g_object_unref (parameters->application);
 780 	nautilus_file_list_free (parameters->files);
 781 
 782 	if (parameters->directory_view != NULL) {
 783 		g_object_unref (parameters->directory_view);
 784 	}
 785 
 786 	g_free (parameters);
 787 }			      
 788 
 789 static GList *
 790 file_and_directory_list_to_files (GList *fad_list)
 791 {
 792 	GList *res, *l;
 793 	FileAndDirectory *fad;
 794 
 795 	res = NULL;
 796 	for (l = fad_list; l != NULL; l = l->next) {
 797 		fad = l->data;
 798 		res = g_list_prepend (res, nautilus_file_ref (fad->file));
 799 	}
 800 	return g_list_reverse (res);
 801 }
 802 
 803 
 804 static GList *
 805 file_and_directory_list_from_files (NautilusDirectory *directory, GList *files)
 806 {
 807 	GList *res, *l;
 808 	FileAndDirectory *fad;
 809 
 810 	res = NULL;
 811 	for (l = files; l != NULL; l = l->next) {
 812 		fad = g_new0 (FileAndDirectory, 1);
 813 		fad->directory = nautilus_directory_ref (directory);
 814 		fad->file = nautilus_file_ref (l->data);
 815 		res = g_list_prepend (res, fad);
 816 	}
 817 	return g_list_reverse (res);
 818 }
 819 
 820 static void
 821 file_and_directory_free (FileAndDirectory *fad)
 822 {
 823 	nautilus_directory_unref (fad->directory);
 824 	nautilus_file_unref (fad->file);
 825 	g_free (fad);
 826 }
 827 
 828 
 829 static void
 830 file_and_directory_list_free (GList *list)
 831 {
 832 	GList *l;
 833 
 834 	for (l = list; l != NULL; l = l->next) {
 835 		file_and_directory_free (l->data);
 836 	}
 837 
 838 	g_list_free (list);
 839 }
 840 
 841 static gboolean
 842 file_and_directory_equal (gconstpointer  v1,
 843 			  gconstpointer  v2)
 844 {
 845 	const FileAndDirectory *fad1, *fad2;
 846 	fad1 = v1;
 847 	fad2 = v2;
 848 
 849 	return (fad1->file == fad2->file &&
 850 		fad1->directory == fad2->directory);
 851 }
 852 
 853 static guint
 854 file_and_directory_hash  (gconstpointer  v)
 855 {
 856 	const FileAndDirectory *fad;
 857 
 858 	fad = v;
 859 	return GPOINTER_TO_UINT (fad->file) ^ GPOINTER_TO_UINT (fad->directory);
 860 }
 861 
 862 
 863 
 864 
 865 static ScriptLaunchParameters *
 866 script_launch_parameters_new (NautilusFile *file,
 867 			      NautilusView *directory_view)
 868 {
 869 	ScriptLaunchParameters *result;
 870 
 871 	result = g_new0 (ScriptLaunchParameters, 1);
 872 	g_object_ref (directory_view);
 873 	result->directory_view = directory_view;
 874 	nautilus_file_ref (file);
 875 	result->file = file;
 876 
 877 	return result;
 878 }
 879 
 880 static void
 881 script_launch_parameters_free (ScriptLaunchParameters *parameters)
 882 {
 883 	g_object_unref (parameters->directory_view);
 884 	nautilus_file_unref (parameters->file);
 885 	g_free (parameters);
 886 }			      
 887 
 888 static CreateTemplateParameters *
 889 create_template_parameters_new (NautilusFile *file,
 890 				NautilusView *directory_view)
 891 {
 892 	CreateTemplateParameters *result;
 893 
 894 	result = g_new0 (CreateTemplateParameters, 1);
 895 	g_object_ref (directory_view);
 896 	result->directory_view = directory_view;
 897 	nautilus_file_ref (file);
 898 	result->file = file;
 899 
 900 	return result;
 901 }
 902 
 903 static void
 904 create_templates_parameters_free (CreateTemplateParameters *parameters)
 905 {
 906 	g_object_unref (parameters->directory_view);
 907 	nautilus_file_unref (parameters->file);
 908 	g_free (parameters);
 909 }			      
 910 
 911 static NautilusWindow *
 912 nautilus_view_get_window (NautilusView  *view)
 913 {
 914 	return nautilus_window_slot_get_window (view->details->slot);
 915 }
 916 
 917 NautilusWindowSlot *
 918 nautilus_view_get_nautilus_window_slot (NautilusView  *view)
 919 {
 920 	g_assert (view->details->slot != NULL);
 921 
 922 	return view->details->slot;
 923 }
 924 
 925 /* Returns the GtkWindow that this directory view occupies, or NULL
 926  * if at the moment this directory view is not in a GtkWindow or the
 927  * GtkWindow cannot be determined. Primarily used for parenting dialogs.
 928  */
 929 static GtkWindow *
 930 nautilus_view_get_containing_window (NautilusView *view)
 931 {
 932 	GtkWidget *window;
 933 
 934 	g_assert (NAUTILUS_IS_VIEW (view));
 935 	
 936 	window = gtk_widget_get_ancestor (GTK_WIDGET (view), GTK_TYPE_WINDOW);
 937 	if (window == NULL) {
 938 		return NULL;
 939 	}
 940 
 941 	return GTK_WINDOW (window);
 942 }
 943 
 944 static gboolean
 945 nautilus_view_confirm_multiple (GtkWindow *parent_window,
 946 				int count,
 947 				gboolean tabs)
 948 {
 949 	GtkDialog *dialog;
 950 	char *prompt;
 951 	char *detail;
 952 	int response;
 953 
 954 	if (count <= SILENT_WINDOW_OPEN_LIMIT) {
 955 		return TRUE;
 956 	}
 957 
 958 	prompt = _("Are you sure you want to open all files?");
 959 	if (tabs) {
 960 		detail = g_strdup_printf (ngettext("This will open %'d separate tab.",
 961 						   "This will open %'d separate tabs.", count), count);
 962 	} else {
 963 		detail = g_strdup_printf (ngettext("This will open %'d separate window.",
 964 						   "This will open %'d separate windows.", count), count);
 965 	}
 966 	dialog = eel_show_yes_no_dialog (prompt, detail, 
 967 					 GTK_STOCK_OK, GTK_STOCK_CANCEL,
 968 					 parent_window);
 969 	g_free (detail);
 970 
 971 	response = gtk_dialog_run (dialog);
 972 	gtk_widget_destroy (GTK_WIDGET (dialog));
 973 
 974 	return response == GTK_RESPONSE_YES;
 975 }
 976 
 977 static gboolean
 978 selection_contains_one_item_in_menu_callback (NautilusView *view, GList *selection)
 979 {
 980 	if (g_list_length (selection) == 1) {
 981 		return TRUE;
 982 	}
 983 
 984 	/* If we've requested a menu update that hasn't yet occurred, then
 985 	 * the mismatch here doesn't surprise us, and we won't complain.
 986 	 * Otherwise, we will complain.
 987 	 */
 988 	if (!view->details->menu_states_untrustworthy) {
 989 		g_warning ("Expected one selected item, found %'d. No action will be performed.", 	
 990 			   g_list_length (selection));
 991 	}
 992 
 993 	return FALSE;
 994 }
 995 
 996 static gboolean
 997 selection_not_empty_in_menu_callback (NautilusView *view, GList *selection)
 998 {
 999 	if (selection != NULL) {
1000 		return TRUE;
1001 	}
1002 
1003 	/* If we've requested a menu update that hasn't yet occurred, then
1004 	 * the mismatch here doesn't surprise us, and we won't complain.
1005 	 * Otherwise, we will complain.
1006 	 */
1007 	if (!view->details->menu_states_untrustworthy) {
1008 		g_warning ("Empty selection found when selection was expected. No action will be performed.");
1009 	}
1010 
1011 	return FALSE;
1012 }
1013 
1014 static char *
1015 get_view_directory (NautilusView *view)
1016 {
1017 	char *uri, *path;
1018 	GFile *f;
1019 	
1020 	uri = nautilus_directory_get_uri (view->details->model);
1021 	if (eel_uri_is_desktop (uri)) {
1022 		g_free (uri);
1023 		uri = nautilus_get_desktop_directory_uri ();
1024 		
1025 	}
1026 	f = g_file_new_for_uri (uri);
1027 	path = g_file_get_path (f);
1028 	g_object_unref (f);
1029 	g_free (uri);
1030 	
1031 	return path;
1032 }
1033 
1034 void
1035 nautilus_view_preview_files (NautilusView *view,
1036 			     GList *files,
1037 			     GArray *locations)
1038 {
1039 	NautilusPreviewer *previewer;
1040 	gchar *uri;
1041 	guint xid;
1042 	GtkWidget *toplevel;
1043 
1044 	previewer = nautilus_previewer_get_singleton ();
1045 	uri = nautilus_file_get_uri (files->data);
1046 	toplevel = gtk_widget_get_toplevel (GTK_WIDGET (view));
1047 
1048 	xid = gdk_x11_window_get_xid (gtk_widget_get_window (toplevel));
1049 	nautilus_previewer_call_show_file (previewer, uri, xid, TRUE);
1050 
1051 	g_free (uri);
1052 }
1053 
1054 void
1055 nautilus_view_activate_selection (NautilusView *view)
1056 {
1057 	GList *selection;
1058 
1059 	selection = nautilus_view_get_selection (view);
1060 	nautilus_view_activate_files (view,
1061 				      selection,
1062 				      0,
1063 				      TRUE);
1064 	nautilus_file_list_free (selection);
1065 }
1066 
1067 void
1068 nautilus_view_activate_files (NautilusView *view,
1069 			      GList *files,
1070 			      NautilusWindowOpenFlags flags,
1071 			      gboolean confirm_multiple)
1072 {
1073 	char *path;
1074 
1075 	path = get_view_directory (view);
1076 	nautilus_mime_activate_files (nautilus_view_get_containing_window (view),
1077 				      view->details->slot,
1078 				      files,
1079 				      path,
1080 				      flags,
1081 				      confirm_multiple);
1082 
1083 	g_free (path);
1084 }
1085 
1086 static void
1087 nautilus_view_activate_file (NautilusView *view,
1088 			     NautilusFile *file,
1089 			     NautilusWindowOpenFlags flags)
1090 {
1091 	char *path;
1092 
1093 	path = get_view_directory (view);
1094 	nautilus_mime_activate_file (nautilus_view_get_containing_window (view),
1095 				     view->details->slot,
1096 				     file,
1097 				     path,
1098 				     flags);
1099 
1100 	g_free (path);
1101 }
1102 
1103 static void
1104 action_open_callback (GtkAction *action,
1105 		      gpointer callback_data)
1106 {
1107 	NautilusView *view;
1108 
1109 	view = NAUTILUS_VIEW (callback_data);
1110 	nautilus_view_activate_selection (view);
1111 }
1112 
1113 static void
1114 action_open_close_parent_callback (GtkAction *action,
1115 				   gpointer callback_data)
1116 {
1117 	GList *selection;
1118 	NautilusView *view;
1119 
1120 	view = NAUTILUS_VIEW (callback_data);
1121 
1122 	selection = nautilus_view_get_selection (view);
1123 	nautilus_view_activate_files (view,
1124 				      selection,
1125 				      NAUTILUS_WINDOW_OPEN_FLAG_CLOSE_BEHIND,
1126 				      TRUE);
1127 	nautilus_file_list_free (selection);
1128 }
1129 
1130 
1131 static void
1132 action_open_alternate_callback (GtkAction *action,
1133 				gpointer callback_data)
1134 {
1135 	NautilusView *view;
1136 	GList *selection;
1137 	GtkWindow *window;
1138 
1139 	view = NAUTILUS_VIEW (callback_data);
1140 	selection = nautilus_view_get_selection (view);
1141 
1142 	window = nautilus_view_get_containing_window (view);
1143 
1144 	if (nautilus_view_confirm_multiple (window, g_list_length (selection), FALSE)) {
1145 		g_list_foreach (selection, open_one_in_new_window, view);
1146 	}
1147 
1148 	nautilus_file_list_free (selection);
1149 }
1150 
1151 static void
1152 action_open_new_tab_callback (GtkAction *action,
1153 			      gpointer callback_data)
1154 {
1155 	NautilusView *view;
1156 	GList *selection;
1157 	GtkWindow *window;
1158 
1159 	view = NAUTILUS_VIEW (callback_data);
1160 	selection = nautilus_view_get_selection (view);
1161 
1162 	window = nautilus_view_get_containing_window (view);
1163 
1164 	if (nautilus_view_confirm_multiple (window, g_list_length (selection), TRUE)) {
1165 		nautilus_view_activate_files (view,
1166 					      selection,
1167 					      NAUTILUS_WINDOW_OPEN_FLAG_NEW_TAB,
1168 					      FALSE);
1169 	}
1170 
1171 	nautilus_file_list_free (selection);
1172 }
1173 
1174 static void
1175 app_chooser_dialog_response_cb (GtkDialog *dialog,
1176 				gint response_id,
1177 				gpointer user_data)
1178 {
1179 	GtkWindow *parent_window;
1180 	NautilusFile *file;
1181 	GAppInfo *info;
1182 	GList files;
1183 
1184 	parent_window = user_data;
1185 
1186 	if (response_id != GTK_RESPONSE_OK) {
1187 		gtk_widget_destroy (GTK_WIDGET (dialog));
1188 		return;
1189 	}
1190 
1191 	info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (dialog));
1192 	file = g_object_get_data (G_OBJECT (dialog), "directory-view:file");
1193 
1194 	g_signal_emit_by_name (nautilus_signaller_get_current (), "mime_data_changed");
1195 
1196 	files.next = NULL;
1197 	files.prev = NULL;
1198 	files.data = file;
1199 	nautilus_launch_application (info, &files, parent_window);
1200 
1201 	gtk_widget_destroy (GTK_WIDGET (dialog));
1202 	g_object_unref (info);
1203 }
1204 
1205 static void
1206 choose_program (NautilusView *view,
1207 		NautilusFile *file)
1208 {
1209 	GtkWidget *dialog;
1210 	GFile *location;
1211 	GtkWindow *parent_window;
1212 
1213 	g_assert (NAUTILUS_IS_VIEW (view));
1214 	g_assert (NAUTILUS_IS_FILE (file));
1215 
1216 	nautilus_file_ref (file);
1217 	location = nautilus_file_get_location (file);
1218 	parent_window = nautilus_view_get_containing_window (view);
1219 
1220 	dialog = gtk_app_chooser_dialog_new (parent_window, 0,
1221 					     location);
1222 	g_object_set_data_full (G_OBJECT (dialog), 
1223 				"directory-view:file",
1224 				g_object_ref (file),
1225 				(GDestroyNotify)g_object_unref);
1226 	gtk_widget_show (dialog);
1227 
1228 	g_signal_connect_object (dialog, "response", 
1229 				 G_CALLBACK (app_chooser_dialog_response_cb),
1230 				 parent_window, 0);
1231 
1232 	g_object_unref (location);
1233 	nautilus_file_unref (file);	
1234 }
1235 
1236 static void
1237 open_with_other_program (NautilusView *view)
1238 {
1239         GList *selection;
1240 
1241 	g_assert (NAUTILUS_IS_VIEW (view));
1242 
1243        	selection = nautilus_view_get_selection (view);
1244 
1245 	if (selection_contains_one_item_in_menu_callback (view, selection)) {
1246 		choose_program (view, NAUTILUS_FILE (selection->data));
1247 	}
1248 
1249 	nautilus_file_list_free (selection);
1250 }
1251 
1252 static void
1253 action_other_application_callback (GtkAction *action,
1254 				   gpointer callback_data)
1255 {
1256 	g_assert (NAUTILUS_IS_VIEW (callback_data));
1257 
1258 	open_with_other_program (NAUTILUS_VIEW (callback_data));
1259 }
1260 
1261 static void
1262 trash_or_delete_selected_files (NautilusView *view)
1263 {
1264         GList *selection;
1265 
1266 	/* This might be rapidly called multiple times for the same selection
1267 	 * when using keybindings. So we remember if the current selection
1268 	 * was already removed (but the view doesn't know about it yet).
1269 	 */
1270 	if (!view->details->selection_was_removed) {
1271 		selection = nautilus_view_get_selection_for_file_transfer (view);
1272 		trash_or_delete_files (nautilus_view_get_containing_window (view),
1273 				       selection, TRUE,
1274 				       view);
1275 		nautilus_file_list_free (selection);
1276 		view->details->selection_was_removed = TRUE;
1277 	}
1278 }
1279 
1280 static gboolean
1281 real_trash (NautilusView *view)
1282 {
1283 	GtkAction *action;
1284 
1285 	action = gtk_action_group_get_action (view->details->dir_action_group,
1286 					      NAUTILUS_ACTION_TRASH);
1287 	if (gtk_action_get_sensitive (action) &&
1288 	    gtk_action_get_visible (action)) {
1289 		trash_or_delete_selected_files (view);
1290 		return TRUE;
1291 	}
1292 	return FALSE;
1293 }
1294 
1295 static void
1296 action_trash_callback (GtkAction *action,
1297 		       gpointer callback_data)
1298 {
1299         trash_or_delete_selected_files (NAUTILUS_VIEW (callback_data));
1300 }
1301 
1302 static void
1303 delete_selected_files (NautilusView *view)
1304 {
1305         GList *selection;
1306 	GList *node;
1307 	GList *locations;
1308 
1309 	selection = nautilus_view_get_selection_for_file_transfer (view);
1310 	if (selection == NULL) {
1311 		return;
1312 	}
1313 
1314 	locations = NULL;
1315 	for (node = selection; node != NULL; node = node->next) {
1316 		locations = g_list_prepend (locations,
1317 					    nautilus_file_get_location ((NautilusFile *) node->data));
1318 	}
1319 	locations = g_list_reverse (locations);
1320 
1321 	nautilus_file_operations_delete (locations, nautilus_view_get_containing_window (view), NULL, NULL);
1322 
1323 	g_list_free_full (locations, g_object_unref);
1324         nautilus_file_list_free (selection);
1325 }
1326 
1327 static void
1328 action_delete_callback (GtkAction *action,
1329 			gpointer callback_data)
1330 {
1331         delete_selected_files (NAUTILUS_VIEW (callback_data));
1332 }
1333 
1334 static void
1335 action_restore_from_trash_callback (GtkAction *action,
1336 				    gpointer callback_data)
1337 {
1338 	NautilusView *view;
1339 	GList *selection;
1340 
1341 	view = NAUTILUS_VIEW (callback_data);
1342 
1343 	selection = nautilus_view_get_selection_for_file_transfer (view);
1344 	nautilus_restore_files_from_trash (selection,
1345 					   nautilus_view_get_containing_window (view));
1346 
1347 	nautilus_file_list_free (selection);
1348 
1349 }
1350 
1351 static gboolean
1352 real_delete (NautilusView *view)
1353 {
1354 	GtkAction *action;
1355 
1356 	action = gtk_action_group_get_action (view->details->dir_action_group,
1357 					      NAUTILUS_ACTION_DELETE);
1358 	if (gtk_action_get_sensitive (action) &&
1359 	    gtk_action_get_visible (action)) {
1360 		delete_selected_files (view);
1361 		return TRUE;
1362 	}
1363 	return FALSE;
1364 }
1365 
1366 static void
1367 action_create_link_callback (GtkAction *action,
1368 			     gpointer callback_data)
1369 {
1370         NautilusView *view;
1371         GList *selection;
1372         GArray *selected_item_locations;
1373         
1374         g_assert (NAUTILUS_IS_VIEW (callback_data));
1375 
1376         view = NAUTILUS_VIEW (callback_data);
1377 	selection = nautilus_view_get_selection (view);
1378 	if (selection_not_empty_in_menu_callback (view, selection)) {
1379 		selected_item_locations = nautilus_view_get_selected_icon_locations (view);
1380 	        nautilus_view_create_links_for_files (view, selection, selected_item_locations);
1381 	        g_array_free (selected_item_locations, TRUE);
1382 	}
1383 
1384         nautilus_file_list_free (selection);
1385 }
1386 
1387 static void
1388 action_select_all_callback (GtkAction *action, 
1389 			    gpointer callback_data)
1390 {
1391 	g_assert (NAUTILUS_IS_VIEW (callback_data));
1392 
1393 	nautilus_view_select_all (callback_data);
1394 }
1395 
1396 static void
1397 action_invert_selection_callback (GtkAction *action,
1398 				  gpointer callback_data)
1399 {
1400 	g_assert (NAUTILUS_IS_VIEW (callback_data));
1401 
1402 	nautilus_view_invert_selection (callback_data);
1403 }
1404 
1405 static void
1406 pattern_select_response_cb (GtkWidget *dialog, int response, gpointer user_data)
1407 {
1408 	NautilusView *view;
1409 	NautilusDirectory *directory;
1410 	GtkWidget *entry;
1411 	GList *selection;
1412 	GError *error;
1413 
1414 	view = NAUTILUS_VIEW (user_data);
1415 
1416 	switch (response) {
1417 	case GTK_RESPONSE_OK :
1418 		entry = g_object_get_data (G_OBJECT (dialog), "entry");
1419 		directory = nautilus_view_get_model (view);
1420 		selection = nautilus_directory_match_pattern (directory,
1421 							      gtk_entry_get_text (GTK_ENTRY (entry)));
1422 			
1423 		if (selection) {
1424 			nautilus_view_call_set_selection (view, selection);
1425 			nautilus_file_list_free (selection);
1426 
1427 			nautilus_view_reveal_selection(view);
1428 		}
1429 		/* fall through */
1430 	case GTK_RESPONSE_NONE :
1431 	case GTK_RESPONSE_DELETE_EVENT :
1432 	case GTK_RESPONSE_CANCEL :
1433 		gtk_widget_destroy (GTK_WIDGET (dialog));
1434 		break;
1435 	case GTK_RESPONSE_HELP :
1436 		error = NULL;
1437 		gtk_show_uri (gtk_window_get_screen (GTK_WINDOW (dialog)),
1438 			      "help:gnome-help/files-select",
1439 			      gtk_get_current_event_time (), &error);
1440 		if (error) {
1441 			eel_show_error_dialog (_("There was an error displaying help."), error->message,
1442 					       GTK_WINDOW (dialog));
1443 			g_error_free (error);
1444 		}
1445 		break;
1446 	default :
1447 		g_assert_not_reached ();
1448 	}
1449 }
1450 
1451 static void
1452 select_pattern (NautilusView *view)
1453 {
1454 	GtkWidget *dialog;
1455 	GtkWidget *label;
1456 	GtkWidget *example;
1457 	GtkWidget *grid;
1458 	GtkWidget *entry;
1459 	char *example_pattern;
1460 
1461 	dialog = gtk_dialog_new_with_buttons (_("Select Items Matching"),
1462 					      nautilus_view_get_containing_window (view),
1463 					      GTK_DIALOG_DESTROY_WITH_PARENT,
1464 					      GTK_STOCK_HELP,
1465 					      GTK_RESPONSE_HELP,
1466 					      GTK_STOCK_CANCEL,
1467 					      GTK_RESPONSE_CANCEL,
1468 					      GTK_STOCK_OK,
1469 					      GTK_RESPONSE_OK,
1470 					      NULL);
1471 	gtk_dialog_set_default_response (GTK_DIALOG (dialog),
1472 					 GTK_RESPONSE_OK);
1473 	gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
1474 	gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 2);
1475 
1476 	label = gtk_label_new_with_mnemonic (_("_Pattern:"));
1477 	gtk_widget_set_halign (label, GTK_ALIGN_START);
1478 
1479 	example = gtk_label_new (NULL);
1480 	gtk_widget_set_halign (example, GTK_ALIGN_START);
1481 	example_pattern = g_strdup_printf ("%s<i>%s</i> ", 
1482 					   _("Examples: "),
1483 					   "*.png, file\?\?.txt, pict*.\?\?\?");
1484 	gtk_label_set_markup (GTK_LABEL (example), example_pattern);
1485 	g_free (example_pattern);
1486 
1487 	entry = gtk_entry_new ();
1488 	gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
1489 	gtk_widget_set_hexpand (entry, TRUE);
1490 
1491 	grid = gtk_grid_new ();
1492 	g_object_set (grid,
1493 		      "orientation", GTK_ORIENTATION_VERTICAL,
1494 		      "border-width", 6,
1495 		      "row-spacing", 6,
1496 		      "column-spacing", 12,
1497 		      NULL);
1498 
1499 	gtk_container_add (GTK_CONTAINER (grid), label);
1500 	gtk_grid_attach_next_to (GTK_GRID (grid), entry, label,
1501 				 GTK_POS_RIGHT, 1, 1);
1502 	gtk_grid_attach_next_to (GTK_GRID (grid), example, entry,
1503 				 GTK_POS_BOTTOM, 1, 1);
1504 
1505 	gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
1506 	gtk_widget_show_all (grid);
1507 	gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), grid);
1508 	g_object_set_data (G_OBJECT (dialog), "entry", entry);
1509 	g_signal_connect (dialog, "response",
1510 			  G_CALLBACK (pattern_select_response_cb),
1511 			  view);
1512 	gtk_widget_show_all (dialog);
1513 }
1514 
1515 static void
1516 action_select_pattern_callback (GtkAction *action, 
1517 				gpointer callback_data)
1518 {
1519 	g_assert (NAUTILUS_IS_VIEW (callback_data));
1520 
1521 	select_pattern(callback_data);
1522 }
1523 
1524 static void
1525 action_reset_to_defaults_callback (GtkAction *action, 
1526 				   gpointer callback_data)
1527 {
1528 	g_assert (NAUTILUS_IS_VIEW (callback_data));
1529 
1530 	nautilus_view_reset_to_defaults (callback_data);
1531 }
1532 
1533 static void
1534 action_save_search_callback (GtkAction *action,
1535 			     gpointer callback_data)
1536 {                
1537 	NautilusSearchDirectory *search;
1538 	NautilusView	*directory_view;
1539 	
1540         directory_view = NAUTILUS_VIEW (callback_data);
1541 
1542 	if (directory_view->details->model &&
1543 	    NAUTILUS_IS_SEARCH_DIRECTORY (directory_view->details->model)) {
1544 		search = NAUTILUS_SEARCH_DIRECTORY (directory_view->details->model);
1545 		nautilus_search_directory_save_search (search);
1546 
1547 		/* Save search is disabled */
1548 		schedule_update_menus (directory_view);
1549 	}
1550 }
1551 
1552 static void
1553 query_name_entry_changed_cb  (GtkWidget *entry, GtkWidget *button)
1554 {
1555 	const char *text;
1556 	gboolean sensitive;
1557 	
1558 	text = gtk_entry_get_text (GTK_ENTRY (entry));
1559 
1560 	sensitive = (text != NULL) && (*text != 0);
1561 
1562 	gtk_widget_set_sensitive (button, sensitive);
1563 }
1564 
1565 
1566 static void
1567 action_save_search_as_callback (GtkAction *action,
1568 				gpointer callback_data)
1569 {
1570 	NautilusView	*directory_view;
1571 	NautilusSearchDirectory *search;
1572 	GtkWidget *dialog, *grid, *label, *entry, *chooser, *save_button;
1573 	const char *entry_text;
1574 	char *filename, *filename_utf8, *dirname, *path, *uri;
1575 	GFile *location;
1576 	
1577         directory_view = NAUTILUS_VIEW (callback_data);
1578 
1579 	if (directory_view->details->model &&
1580 	    NAUTILUS_IS_SEARCH_DIRECTORY (directory_view->details->model)) {
1581 		search = NAUTILUS_SEARCH_DIRECTORY (directory_view->details->model);
1582 		
1583 		dialog = gtk_dialog_new_with_buttons (_("Save Search as"),
1584 						      nautilus_view_get_containing_window (directory_view),
1585 						      0,
1586 						      GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1587 						      NULL);
1588 		save_button = gtk_dialog_add_button (GTK_DIALOG (dialog),
1589 						     GTK_STOCK_SAVE, GTK_RESPONSE_OK);
1590 		gtk_dialog_set_default_response (GTK_DIALOG (dialog),
1591 						 GTK_RESPONSE_OK);
1592 		gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
1593 		gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 2);
1594 		gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
1595 
1596 		grid = gtk_grid_new ();
1597 		g_object_set (grid,
1598 			      "orientation", GTK_ORIENTATION_VERTICAL,
1599 			      "border-width", 5,
1600 			      "row-spacing", 6,
1601 			      "column-spacing", 12,
1602 			      NULL);
1603 		gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), grid, TRUE, TRUE, 0);
1604 		gtk_widget_show (grid);
1605 		
1606 		label = gtk_label_new_with_mnemonic (_("Search _name:"));
1607 		gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1608 		gtk_container_add (GTK_CONTAINER (grid), label);
1609 		gtk_widget_show (label);
1610 
1611 		entry = gtk_entry_new ();
1612 		gtk_widget_set_hexpand (entry, TRUE);
1613 		gtk_grid_attach_next_to (GTK_GRID (grid), entry, label,
1614 					 GTK_POS_RIGHT, 1, 1);
1615 		gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
1616 		gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
1617 		
1618 		gtk_widget_set_sensitive (save_button, FALSE);
1619 		g_signal_connect (entry, "changed",
1620 				  G_CALLBACK (query_name_entry_changed_cb), save_button);
1621 		
1622 		gtk_widget_show (entry);
1623 		label = gtk_label_new_with_mnemonic (_("_Folder:"));
1624 		gtk_misc_set_alignment (GTK_MISC(label), 0.0, 0.5);
1625 		gtk_container_add (GTK_CONTAINER (grid), label);
1626 		gtk_widget_show (label);
1627 
1628 		chooser = gtk_file_chooser_button_new (_("Select Folder to Save Search In"),
1629 						       GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
1630 		gtk_widget_set_hexpand (chooser, TRUE);
1631 		gtk_grid_attach_next_to (GTK_GRID (grid), chooser, label,
1632 					 GTK_POS_RIGHT, 1, 1);
1633 		gtk_label_set_mnemonic_widget (GTK_LABEL (label), chooser);
1634 		gtk_widget_show (chooser);
1635 
1636 		gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (chooser), TRUE);
1637 
1638 		gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (chooser),
1639 						     g_get_home_dir ());
1640 		
1641 		if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1642 			entry_text = gtk_entry_get_text (GTK_ENTRY (entry));
1643 			if (g_str_has_suffix (entry_text, NAUTILUS_SAVED_SEARCH_EXTENSION)) {
1644 				filename_utf8 = g_strdup (entry_text);
1645 			} else {
1646 				filename_utf8 = g_strconcat (entry_text, NAUTILUS_SAVED_SEARCH_EXTENSION, NULL);
1647 			}
1648 
1649 			filename = g_filename_from_utf8 (filename_utf8, -1, NULL, NULL, NULL);
1650 			g_free (filename_utf8);
1651 
1652 			dirname = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser));
1653 			
1654 			path = g_build_filename (dirname, filename, NULL);
1655 			g_free (filename);
1656 			g_free (dirname);
1657 
1658 			uri = g_filename_to_uri (path, NULL, NULL);
1659 			g_free (path);
1660 			
1661 			nautilus_search_directory_save_to_file (search, uri);
1662 			location = g_file_new_for_uri (uri);
1663 			nautilus_file_changes_queue_file_added (location);
1664 			g_object_unref (location);
1665 			nautilus_file_changes_consume_changes (TRUE);
1666 			g_free (uri);
1667 		}
1668 		
1669 		gtk_widget_destroy (dialog);
1670 	}
1671 }
1672 
1673 
1674 static void
1675 action_empty_trash_callback (GtkAction *action,
1676 			     gpointer callback_data)
1677 {                
1678         g_assert (NAUTILUS_IS_VIEW (callback_data));
1679 
1680 	nautilus_file_operations_empty_trash (GTK_WIDGET (callback_data));
1681 }
1682 
1683 typedef struct {
1684 	NautilusView *view;
1685 	NautilusFile *new_file;
1686 } RenameData;
1687 
1688 static gboolean
1689 delayed_rename_file_hack_callback (RenameData *data)
1690 {
1691 	NautilusView *view;
1692 	NautilusFile *new_file;
1693 
1694 	view = data->view;
1695 	new_file = data->new_file;
1696 
1697 	if (view->details->slot != NULL &&
1698 	    view->details->active) {
1699 		NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->start_renaming_file (view, new_file, FALSE);
1700 		nautilus_view_reveal_selection (view);
1701 	}
1702 
1703 	return FALSE;
1704 }
1705 
1706 static void
1707 delayed_rename_file_hack_removed (RenameData *data)
1708 {
1709 	g_object_unref (data->view);
1710 	nautilus_file_unref (data->new_file);
1711 	g_free (data);
1712 }
1713 
1714 
1715 static void
1716 rename_file (NautilusView *view, NautilusFile *new_file)
1717 {
1718 	RenameData *data;
1719 
1720 	/* HACK!!!!
1721 	   This is a work around bug in listview. After the rename is
1722 	   enabled we will get file changes due to info about the new
1723 	   file being read, which will cause the model to change. When
1724 	   the model changes GtkTreeView clears the editing. This hack just
1725 	   delays editing for some time to try to avoid this problem.
1726 	   A major problem is that the selection of the row causes us
1727 	   to load the slow mimetype for the file, which leads to a
1728 	   file_changed. So, before we delay we select the row.
1729 	*/
1730 	if (NAUTILUS_IS_LIST_VIEW (view)) {
1731 		nautilus_view_select_file (view, new_file);
1732 		
1733 		data = g_new (RenameData, 1);
1734 		data->view = g_object_ref (view);
1735 		data->new_file = nautilus_file_ref (new_file);
1736 		if (view->details->delayed_rename_file_id != 0) {
1737 			g_source_remove (view->details->delayed_rename_file_id);
1738 		}
1739 		view->details->delayed_rename_file_id = 
1740 			g_timeout_add_full (G_PRIORITY_DEFAULT,
1741 					    100, (GSourceFunc)delayed_rename_file_hack_callback,
1742 					    data, (GDestroyNotify) delayed_rename_file_hack_removed);
1743 		
1744 		return;
1745 	}
1746 
1747 	/* no need to select because start_renaming_file selects
1748 	 * nautilus_view_select_file (view, new_file);
1749 	 */
1750 	NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->start_renaming_file (view, new_file, FALSE);
Access to field 'g_class' results in a dereference of a null pointer (loaded from variable 'view')
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

1751 nautilus_view_reveal_selection (view); 1752 } 1753 1754 static void 1755 reveal_newly_added_folder (NautilusView *view, NautilusFile *new_file, 1756 NautilusDirectory *directory, GFile *target_location) 1757 { 1758 GFile *location; 1759 1760 location = nautilus_file_get_location (new_file); 1761 if (g_file_equal (location, target_location)) { 1762 g_signal_handlers_disconnect_by_func (view, 1763 G_CALLBACK (reveal_newly_added_folder), 1764 (void *) target_location); 1765 rename_file (view, new_file); 1766 } 1767 g_object_unref (location); 1768 } 1769 1770 typedef struct { 1771 NautilusView *directory_view; 1772 GHashTable *added_locations; 1773 GList *selection; 1774 } NewFolderData; 1775 1776 typedef struct { 1777 NautilusView *directory_view; 1778 GHashTable *to_remove_locations; 1779 NautilusFile *new_folder; 1780 } NewFolderSelectionData; 1781 1782 static void 1783 rename_newly_added_folder (NautilusView *view, NautilusFile *removed_file, 1784 NautilusDirectory *directory, NewFolderSelectionData *data); 1785 1786 static void 1787 rename_newly_added_folder (NautilusView *view, NautilusFile *removed_file, 1788 NautilusDirectory *directory, NewFolderSelectionData *data) 1789 { 1790 GFile *location; 1791 1792 location = nautilus_file_get_location (removed_file); 1793 if (!g_hash_table_remove (data->to_remove_locations, location)) { 1794 g_assert_not_reached (); 1795 } 1796 g_object_unref (location); 1797 if (g_hash_table_size (data->to_remove_locations) == 0) { 1798 nautilus_view_set_selection (data->directory_view, NULL); 1799 g_signal_handlers_disconnect_by_func (data->directory_view, 1800 G_CALLBACK (rename_newly_added_folder), 1801 (void *) data); 1802 1803 rename_file (data->directory_view, data->new_folder); 1804 g_object_unref (data->new_folder); 1805 g_hash_table_destroy (data->to_remove_locations); 1806 g_free (data); 1807 } 1808 } 1809 1810 static void 1811 track_newly_added_locations (NautilusView *view, NautilusFile *new_file, 1812 NautilusDirectory *directory, gpointer user_data) 1813 { 1814 NewFolderData *data; 1815 1816 data = user_data; 1817 1818 g_hash_table_insert (data->added_locations, nautilus_file_get_location (new_file), NULL); 1819 } 1820 1821 static void 1822 new_folder_done (GFile *new_folder, 1823 gboolean success, 1824 gpointer user_data) 1825 { 1826 NautilusView *directory_view; 1827 NautilusFile *file; 1828 char screen_string[32]; 1829 GdkScreen *screen; 1830 NewFolderData *data; 1831 1832 data = (NewFolderData *)user_data; 1833 1834 directory_view = data->directory_view; 1835 1836 if (directory_view == NULL) { 1837 goto fail; 1838 } 1839 1840 g_signal_handlers_disconnect_by_func (directory_view, 1841 G_CALLBACK (track_newly_added_locations), 1842 (void *) data); 1843 1844 if (new_folder == NULL) { 1845 goto fail; 1846 } 1847 1848 screen = gtk_widget_get_screen (GTK_WIDGET (directory_view)); 1849 g_snprintf (screen_string, sizeof (screen_string), "%d", gdk_screen_get_number (screen)); 1850 1851 1852 file = nautilus_file_get (new_folder); 1853 nautilus_file_set_metadata 1854 (file, NAUTILUS_METADATA_KEY_SCREEN, 1855 NULL, 1856 screen_string); 1857 1858 if (data->selection != NULL) { 1859 NewFolderSelectionData *sdata; 1860 GList *uris, *l; 1861 1862 sdata = g_new (NewFolderSelectionData, 1); 1863 sdata->directory_view = directory_view; 1864 sdata->to_remove_locations = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, 1865 g_object_unref, NULL); 1866 sdata->new_folder = g_object_ref (file); 1867 1868 uris = NULL; 1869 for (l = data->selection; l != NULL; l = l->next) { 1870 GFile *old_location; 1871 GFile *new_location; 1872 char *basename; 1873 1874 uris = g_list_prepend (uris, nautilus_file_get_uri ((NautilusFile *) l->data)); 1875 1876 old_location = nautilus_file_get_location (l->data); 1877 basename = g_file_get_basename (old_location); 1878 new_location = g_file_resolve_relative_path (new_folder, basename); 1879 g_hash_table_insert (sdata->to_remove_locations, new_location, NULL); 1880 g_free (basename); 1881 g_object_unref (old_location); 1882 } 1883 uris = g_list_reverse (uris); 1884 1885 g_signal_connect_data (directory_view, 1886 "remove_file", 1887 G_CALLBACK (rename_newly_added_folder), 1888 sdata, 1889 (GClosureNotify)NULL, 1890 G_CONNECT_AFTER); 1891 1892 nautilus_view_move_copy_items (directory_view, 1893 uris, 1894 NULL, 1895 nautilus_file_get_uri (file), 1896 GDK_ACTION_MOVE, 1897 0, 0); 1898 g_list_free_full (uris, g_free); 1899 } else { 1900 if (g_hash_table_lookup_extended (data->added_locations, new_folder, NULL, NULL)) { 1901 /* The file was already added */ 1902 rename_file (directory_view, file); 1903 } else { 1904 /* We need to run after the default handler adds the folder we want to 1905 * operate on. The ADD_FILE signal is registered as G_SIGNAL_RUN_LAST, so we 1906 * must use connect_after. 1907 */ 1908 g_signal_connect_data (directory_view, 1909 "add_file", 1910 G_CALLBACK (reveal_newly_added_folder), 1911 g_object_ref (new_folder), 1912 (GClosureNotify)g_object_unref, 1913 G_CONNECT_AFTER); 1914 } 1915 } 1916 1917 nautilus_file_unref (file); 1918 1919 fail: 1920 g_hash_table_destroy (data->added_locations); 1921 1922 if (data->directory_view != NULL) { 1923 g_object_remove_weak_pointer (G_OBJECT (data->directory_view), 1924 (gpointer *) &data->directory_view); 1925 } 1926 1927 nautilus_file_list_free (data->selection); 1928 g_free (data); 1929 } 1930 1931 1932 static NewFolderData * 1933 new_folder_data_new (NautilusView *directory_view, 1934 gboolean with_selection) 1935 { 1936 NewFolderData *data; 1937 1938 data = g_new (NewFolderData, 1); 1939 data->directory_view = directory_view; 1940 data->added_locations = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, 1941 g_object_unref, NULL); 1942 if (with_selection) { 1943 data->selection = nautilus_view_get_selection_for_file_transfer (directory_view); 1944 } else { 1945 data->selection = NULL; 1946 } 1947 g_object_add_weak_pointer (G_OBJECT (data->directory_view), 1948 (gpointer *) &data->directory_view); 1949 1950 return data; 1951 } 1952 1953 static GdkPoint * 1954 context_menu_to_file_operation_position (NautilusView *view) 1955 { 1956 g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL); 1957 1958 if (nautilus_view_using_manual_layout (view) 1959 && view->details->context_menu_position.x >= 0 1960 && view->details->context_menu_position.y >= 0) { 1961 NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->widget_to_file_operation_position 1962 (view, &view->details->context_menu_position); 1963 return &view->details->context_menu_position; 1964 } else { 1965 return NULL; 1966 } 1967 } 1968 1969 static void 1970 nautilus_view_new_folder (NautilusView *directory_view, 1971 gboolean with_selection) 1972 { 1973 char *parent_uri; 1974 NewFolderData *data; 1975 GdkPoint *pos; 1976 1977 data = new_folder_data_new (directory_view, with_selection); 1978 1979 g_signal_connect_data (directory_view, 1980 "add_file", 1981 G_CALLBACK (track_newly_added_locations), 1982 data, 1983 (GClosureNotify)NULL, 1984 G_CONNECT_AFTER); 1985 1986 pos = context_menu_to_file_operation_position (directory_view); 1987 1988 parent_uri = nautilus_view_get_backing_uri (directory_view); 1989 nautilus_file_operations_new_folder (GTK_WIDGET (directory_view), 1990 pos, parent_uri, 1991 new_folder_done, data); 1992 1993 g_free (parent_uri); 1994 } 1995 1996 static NewFolderData * 1997 setup_new_folder_data (NautilusView *directory_view) 1998 { 1999 NewFolderData *data; 2000 2001 data = new_folder_data_new (directory_view, FALSE); 2002 2003 g_signal_connect_data (directory_view, 2004 "add_file", 2005 G_CALLBACK (track_newly_added_locations), 2006 data, 2007 (GClosureNotify)NULL, 2008 G_CONNECT_AFTER); 2009 2010 return data; 2011 } 2012 2013 void 2014 nautilus_view_new_file_with_initial_contents (NautilusView *view, 2015 const char *parent_uri, 2016 const char *filename, 2017 const char *initial_contents, 2018 int length, 2019 GdkPoint *pos) 2020 { 2021 NewFolderData *data; 2022 2023 g_assert (parent_uri != NULL); 2024 2025 data = setup_new_folder_data (view); 2026 2027 if (pos == NULL) { 2028 pos = context_menu_to_file_operation_position (view); 2029 } 2030 2031 nautilus_file_operations_new_file (GTK_WIDGET (view), 2032 pos, parent_uri, filename, 2033 initial_contents, length, 2034 new_folder_done, data); 2035 } 2036 2037 static void 2038 nautilus_view_new_file (NautilusView *directory_view, 2039 const char *parent_uri, 2040 NautilusFile *source) 2041 { 2042 GdkPoint *pos; 2043 NewFolderData *data; 2044 char *source_uri; 2045 char *container_uri; 2046 2047 container_uri = NULL; 2048 if (parent_uri == NULL) { 2049 container_uri = nautilus_view_get_backing_uri (directory_view); 2050 g_assert (container_uri != NULL); 2051 } 2052 2053 if (source == NULL) { 2054 nautilus_view_new_file_with_initial_contents (directory_view, 2055 parent_uri != NULL ? parent_uri : container_uri, 2056 NULL, 2057 NULL, 2058 0, 2059 NULL); 2060 g_free (container_uri); 2061 return; 2062 } 2063 2064 g_return_if_fail (nautilus_file_is_local (source)); 2065 2066 pos = context_menu_to_file_operation_position (directory_view); 2067 2068 data = setup_new_folder_data (directory_view); 2069 2070 source_uri = nautilus_file_get_uri (source); 2071 2072 nautilus_file_operations_new_file_from_template (GTK_WIDGET (directory_view), 2073 pos, 2074 parent_uri != NULL ? parent_uri : container_uri, 2075 NULL, 2076 source_uri, 2077 new_folder_done, data); 2078 2079 g_free (source_uri); 2080 g_free (container_uri); 2081 } 2082 2083 static void 2084 action_new_folder_callback (GtkAction *action, 2085 gpointer callback_data) 2086 { 2087 g_assert (NAUTILUS_IS_VIEW (callback_data)); 2088 2089 nautilus_view_new_folder (NAUTILUS_VIEW (callback_data), FALSE); 2090 } 2091 2092 static void 2093 action_new_folder_with_selection_callback (GtkAction *action, 2094 gpointer callback_data) 2095 { 2096 g_assert (NAUTILUS_IS_VIEW (callback_data)); 2097 2098 nautilus_view_new_folder (NAUTILUS_VIEW (callback_data), TRUE); 2099 } 2100 2101 static void 2102 action_new_empty_file_callback (GtkAction *action, 2103 gpointer callback_data) 2104 { 2105 g_assert (NAUTILUS_IS_VIEW (callback_data)); 2106 2107 nautilus_view_new_file (NAUTILUS_VIEW (callback_data), NULL, NULL); 2108 } 2109 2110 static void 2111 action_properties_callback (GtkAction *action, 2112 gpointer callback_data) 2113 { 2114 NautilusView *view; 2115 GList *selection; 2116 GList *files; 2117 2118 g_assert (NAUTILUS_IS_VIEW (callback_data)); 2119 2120 view = NAUTILUS_VIEW (callback_data); 2121 selection = nautilus_view_get_selection (view); 2122 if (g_list_length (selection) == 0) { 2123 if (view->details->directory_as_file != NULL) { 2124 files = g_list_append (NULL, nautilus_file_ref (view->details->directory_as_file)); 2125 2126 nautilus_properties_window_present (files, GTK_WIDGET (view), NULL); 2127 2128 nautilus_file_list_free (files); 2129 } 2130 } else { 2131 nautilus_properties_window_present (selection, GTK_WIDGET (view), NULL); 2132 } 2133 nautilus_file_list_free (selection); 2134 } 2135 2136 static void 2137 action_location_properties_callback (GtkAction *action, 2138 gpointer callback_data) 2139 { 2140 NautilusView *view; 2141 GList *files; 2142 2143 g_assert (NAUTILUS_IS_VIEW (callback_data)); 2144 2145 view = NAUTILUS_VIEW (callback_data); 2146 g_assert (NAUTILUS_IS_FILE (view->details->location_popup_directory_as_file)); 2147 2148 files = g_list_append (NULL, nautilus_file_ref (view->details->location_popup_directory_as_file)); 2149 2150 nautilus_properties_window_present (files, GTK_WIDGET (view), NULL); 2151 2152 nautilus_file_list_free (files); 2153 } 2154 2155 static gboolean 2156 all_files_in_trash (GList *files) 2157 { 2158 GList *node; 2159 2160 /* Result is ambiguous if called on NULL, so disallow. */ 2161 g_return_val_if_fail (files != NULL, FALSE); 2162 2163 for (node = files; node != NULL; node = node->next) { 2164 if (!nautilus_file_is_in_trash (NAUTILUS_FILE (node->data))) { 2165 return FALSE; 2166 } 2167 } 2168 2169 return TRUE; 2170 } 2171 2172 static gboolean 2173 all_selected_items_in_trash (NautilusView *view) 2174 { 2175 GList *selection; 2176 gboolean result; 2177 2178 /* If the contents share a parent directory, we need only 2179 * check that parent directory. Otherwise we have to inspect 2180 * each selected item. 2181 */ 2182 selection = nautilus_view_get_selection (view); 2183 result = (selection == NULL) ? FALSE : all_files_in_trash (selection); 2184 nautilus_file_list_free (selection); 2185 2186 return result; 2187 } 2188 2189 static void 2190 action_show_hidden_files_callback (GtkAction *action, 2191 gpointer callback_data) 2192 { 2193 NautilusView *view; 2194 2195 view = NAUTILUS_VIEW (callback_data); 2196 2197 nautilus_view_set_show_hidden_files 2198 (view, gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))); 2199 } 2200 2201 static void 2202 click_policy_changed_callback (gpointer callback_data) 2203 { 2204 NautilusView *view; 2205 2206 view = NAUTILUS_VIEW (callback_data); 2207 2208 NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->click_policy_changed (view); 2209 } 2210 2211 gboolean 2212 nautilus_view_should_sort_directories_first (NautilusView *view) 2213 { 2214 return view->details->sort_directories_first; 2215 } 2216 2217 static void 2218 sort_directories_first_changed_callback (gpointer callback_data) 2219 { 2220 NautilusView *view; 2221 gboolean preference_value; 2222 2223 view = NAUTILUS_VIEW (callback_data); 2224 2225 preference_value = 2226 g_settings_get_boolean (nautilus_preferences, NAUTILUS_PREFERENCES_SORT_DIRECTORIES_FIRST); 2227 2228 if (preference_value != view->details->sort_directories_first) { 2229 view->details->sort_directories_first = preference_value; 2230 NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->sort_directories_first_changed (view); 2231 } 2232 } 2233 2234 static gboolean 2235 set_up_scripts_directory_global (void) 2236 { 2237 char *old_scripts_directory_path; 2238 char *scripts_directory_path; 2239 const char *override; 2240 2241 if (scripts_directory_uri != NULL) { 2242 return TRUE; 2243 } 2244 2245 scripts_directory_path = nautilus_get_scripts_directory_path (); 2246 2247 override = g_getenv ("GNOME22_USER_DIR"); 2248 2249 if (override) { 2250 old_scripts_directory_path = g_build_filename (override, 2251 "nautilus-scripts", 2252 NULL); 2253 } else { 2254 old_scripts_directory_path = g_build_filename (g_get_home_dir (), 2255 ".gnome2", 2256 "nautilus-scripts", 2257 NULL); 2258 } 2259 2260 if (g_file_test (old_scripts_directory_path, G_FILE_TEST_IS_DIR) 2261 && !g_file_test (scripts_directory_path, G_FILE_TEST_EXISTS)) { 2262 char *updated; 2263 const char *message; 2264 2265 /* test if we already attempted to migrate first */ 2266 updated = g_build_filename (old_scripts_directory_path, "DEPRECATED-DIRECTORY", NULL); 2267 message = _("Nautilus 3.6 deprecated this directory and tried migrating " 2268 "this configuration to ~/.local/share/nautilus"); 2269 if (!g_file_test (updated, G_FILE_TEST_EXISTS)) { 2270 char *parent_dir; 2271 2272 parent_dir = g_path_get_dirname (scripts_directory_path); 2273 if (g_mkdir_with_parents (parent_dir, 0700) == 0) { 2274 int fd, res; 2275 2276 /* rename() works fine if the destination directory is 2277 * empty. 2278 */ 2279 res = g_rename (old_scripts_directory_path, scripts_directory_path); 2280 if (res == -1) { 2281 fd = g_creat (updated, 0600); 2282 if (fd != -1) { 2283 res = write (fd, message, strlen (message));
Value stored to 'res' is never read
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

2284 close (fd); 2285 } 2286 } 2287 } 2288 g_free (parent_dir); 2289 } 2290 2291 g_free (updated); 2292 } 2293 2294 if (g_mkdir_with_parents (scripts_directory_path, 0700) == 0) { 2295 scripts_directory_uri = g_filename_to_uri (scripts_directory_path, NULL, NULL); 2296 scripts_directory_uri_length = strlen (scripts_directory_uri); 2297 } 2298 2299 g_free (scripts_directory_path); 2300 g_free (old_scripts_directory_path); 2301 2302 return (scripts_directory_uri != NULL) ? TRUE : FALSE; 2303 } 2304 2305 static void 2306 scripts_added_or_changed_callback (NautilusDirectory *directory, 2307 GList *files, 2308 gpointer callback_data) 2309 { 2310 NautilusView *view; 2311 2312 view = NAUTILUS_VIEW (callback_data); 2313 2314 view->details->scripts_invalid = TRUE; 2315 if (view->details->active) { 2316 schedule_update_menus (view); 2317 } 2318 } 2319 2320 static void 2321 templates_added_or_changed_callback (NautilusDirectory *directory, 2322 GList *files, 2323 gpointer callback_data) 2324 { 2325 NautilusView *view; 2326 2327 view = NAUTILUS_VIEW (callback_data); 2328 2329 view->details->templates_invalid = TRUE; 2330 if (view->details->active) { 2331 schedule_update_menus (view); 2332 } 2333 } 2334 2335 static void 2336 add_directory_to_directory_list (NautilusView *view, 2337 NautilusDirectory *directory, 2338 GList **directory_list, 2339 GCallback changed_callback) 2340 { 2341 NautilusFileAttributes attributes; 2342 2343 if (g_list_find (*directory_list, directory) == NULL) { 2344 nautilus_directory_ref (directory); 2345 2346 attributes = 2347 NAUTILUS_FILE_ATTRIBUTES_FOR_ICON | 2348 NAUTILUS_FILE_ATTRIBUTE_INFO | 2349 NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT; 2350 2351 nautilus_directory_file_monitor_add (directory, directory_list, 2352 FALSE, attributes, 2353 (NautilusDirectoryCallback)changed_callback, view); 2354 2355 g_signal_connect_object (directory, "files_added", 2356 G_CALLBACK (changed_callback), view, 0); 2357 g_signal_connect_object (directory, "files_changed", 2358 G_CALLBACK (changed_callback), view, 0); 2359 2360 *directory_list = g_list_append (*directory_list, directory); 2361 } 2362 } 2363 2364 static void 2365 remove_directory_from_directory_list (NautilusView *view, 2366 NautilusDirectory *directory, 2367 GList **directory_list, 2368 GCallback changed_callback) 2369 { 2370 *directory_list = g_list_remove (*directory_list, directory); 2371 2372 g_signal_handlers_disconnect_by_func (directory, 2373 G_CALLBACK (changed_callback), 2374 view); 2375 2376 nautilus_directory_file_monitor_remove (directory, directory_list); 2377 2378 nautilus_directory_unref (directory); 2379 } 2380 2381 2382 static void 2383 add_directory_to_scripts_directory_list (NautilusView *view, 2384 NautilusDirectory *directory) 2385 { 2386 add_directory_to_directory_list (view, directory, 2387 &view->details->scripts_directory_list, 2388 G_CALLBACK (scripts_added_or_changed_callback)); 2389 } 2390 2391 static void 2392 remove_directory_from_scripts_directory_list (NautilusView *view, 2393 NautilusDirectory *directory) 2394 { 2395 remove_directory_from_directory_list (view, directory, 2396 &view->details->scripts_directory_list, 2397 G_CALLBACK (scripts_added_or_changed_callback)); 2398 } 2399 2400 static void 2401 add_directory_to_templates_directory_list (NautilusView *view, 2402 NautilusDirectory *directory) 2403 { 2404 add_directory_to_directory_list (view, directory, 2405 &view->details->templates_directory_list, 2406 G_CALLBACK (templates_added_or_changed_callback)); 2407 } 2408 2409 static void 2410 remove_directory_from_templates_directory_list (NautilusView *view, 2411 NautilusDirectory *directory) 2412 { 2413 remove_directory_from_directory_list (view, directory, 2414 &view->details->templates_directory_list, 2415 G_CALLBACK (templates_added_or_changed_callback)); 2416 } 2417 2418 static void 2419 slot_active (NautilusWindowSlot *slot, 2420 NautilusView *view) 2421 { 2422 if (view->details->active) { 2423 return; 2424 } 2425 2426 view->details->active = TRUE; 2427 2428 nautilus_view_merge_menus (view); 2429 schedule_update_menus (view); 2430 } 2431 2432 static void 2433 slot_inactive (NautilusWindowSlot *slot, 2434 NautilusView *view) 2435 { 2436 if (!view->details->active) { 2437 return; 2438 } 2439 2440 view->details->active = FALSE; 2441 2442 nautilus_view_unmerge_menus (view); 2443 remove_update_menus_timeout_callback (view); 2444 } 2445 2446 void 2447 nautilus_view_grab_focus (NautilusView *view) 2448 { 2449 /* focus the child of the scrolled window if it exists */ 2450 GtkWidget *child; 2451 child = gtk_bin_get_child (GTK_BIN (view)); 2452 if (child) { 2453 gtk_widget_grab_focus (GTK_WIDGET (child)); 2454 } 2455 } 2456 2457 int 2458 nautilus_view_get_selection_count (NautilusView *view) 2459 { 2460 /* FIXME: This could be faster if we special cased it in subclasses */ 2461 GList *files; 2462 int len; 2463 2464 files = nautilus_view_get_selection (NAUTILUS_VIEW (view)); 2465 len = g_list_length (files); 2466 nautilus_file_list_free (files); 2467 2468 return len; 2469 } 2470 2471 static void 2472 update_undo_actions (NautilusView *view) 2473 { 2474 NautilusFileUndoInfo *info; 2475 NautilusFileUndoManagerState undo_state; 2476 GtkAction *action; 2477 const gchar *label, *tooltip; 2478 gboolean available, is_undo; 2479 gboolean undo_active, redo_active; 2480 gchar *undo_label, *undo_description, *redo_label, *redo_description; 2481 2482 undo_label = undo_description = redo_label = redo_description = NULL; 2483 2484 undo_active = FALSE; 2485 redo_active = FALSE; 2486 2487 info = nautilus_file_undo_manager_get_action (); 2488 undo_state = nautilus_file_undo_manager_get_state (); 2489 2490 if (info != NULL && 2491 (undo_state > NAUTILUS_FILE_UNDO_MANAGER_STATE_NONE)) { 2492 is_undo = (undo_state == NAUTILUS_FILE_UNDO_MANAGER_STATE_UNDO); 2493 2494 if (is_undo) { 2495 undo_active = TRUE; 2496 } else { 2497 redo_active = TRUE; 2498 } 2499 2500 nautilus_file_undo_info_get_strings (info, 2501 &undo_label, &undo_description, 2502 &redo_label, &redo_description); 2503 } 2504 2505 /* Update undo entry */ 2506 action = gtk_action_group_get_action (view->details->dir_action_group, 2507 "Undo"); 2508 available = undo_active; 2509 if (available) { 2510 label = undo_label; 2511 tooltip = undo_description; 2512 } else { 2513 /* Reset to default info */ 2514 label = _("Undo"); 2515 tooltip = _("Undo last action"); 2516 } 2517 2518 g_object_set (action, 2519 "label", label, 2520 "tooltip", tooltip, 2521 NULL); 2522 gtk_action_set_sensitive (action, available); 2523 2524 /* Update redo entry */ 2525 action = gtk_action_group_get_action (view->details->dir_action_group, 2526 "Redo"); 2527 available = redo_active; 2528 if (available) { 2529 label = redo_label; 2530 tooltip = redo_description; 2531 } else { 2532 /* Reset to default info */ 2533 label = _("Redo"); 2534 tooltip = _("Redo last undone action"); 2535 } 2536 2537 g_object_set (action, 2538 "label", label, 2539 "tooltip", tooltip, 2540 NULL); 2541 gtk_action_set_sensitive (action, available); 2542 2543 g_free (undo_label); 2544 g_free (undo_description); 2545 g_free (redo_label); 2546 g_free (redo_description); 2547 } 2548 2549 static void 2550 undo_manager_changed_cb (NautilusFileUndoManager* manager, 2551 NautilusView *view) 2552 { 2553 if (!view->details->active) { 2554 return; 2555 } 2556 2557 update_undo_actions (view); 2558 } 2559 2560 void 2561 nautilus_view_set_selection (NautilusView *nautilus_view, 2562 GList *selection) 2563 { 2564 NautilusView *view; 2565 2566 view = NAUTILUS_VIEW (nautilus_view); 2567 2568 if (!view->details->loading) { 2569 /* If we aren't still loading, set the selection right now, 2570 * and reveal the new selection. 2571 */ 2572 view->details->selection_change_is_due_to_shell = TRUE; 2573 nautilus_view_call_set_selection (view, selection); 2574 view->details->selection_change_is_due_to_shell = FALSE; 2575 nautilus_view_reveal_selection (view); 2576 } else { 2577 /* If we are still loading, set the list of pending URIs instead. 2578 * done_loading() will eventually select the pending URIs and reveal them. 2579 */ 2580 g_list_free_full (view->details->pending_selection, g_object_unref); 2581 view->details->pending_selection = 2582 eel_g_object_list_copy (selection); 2583 } 2584 } 2585 2586 static char * 2587 get_bulk_rename_tool () 2588 { 2589 char *bulk_rename_tool; 2590 g_settings_get (nautilus_preferences, NAUTILUS_PREFERENCES_BULK_RENAME_TOOL, "^ay", &bulk_rename_tool); 2591 return g_strstrip (bulk_rename_tool); 2592 } 2593 2594 static gboolean 2595 have_bulk_rename_tool () 2596 { 2597 char *bulk_rename_tool; 2598 gboolean have_tool; 2599 2600 bulk_rename_tool = get_bulk_rename_tool (); 2601 have_tool = ((bulk_rename_tool != NULL) && (*bulk_rename_tool != '\0')); 2602 g_free (bulk_rename_tool); 2603 return have_tool; 2604 } 2605 2606 static void 2607 nautilus_view_init (NautilusView *view) 2608 { 2609 AtkObject *atk_object; 2610 NautilusDirectory *scripts_directory; 2611 NautilusDirectory *templates_directory; 2612 char *templates_uri; 2613 2614 nautilus_profile_start (NULL); 2615 2616 view->details = G_TYPE_INSTANCE_GET_PRIVATE (view, NAUTILUS_TYPE_VIEW, 2617 NautilusViewDetails); 2618 2619 /* Default to true; desktop-icon-view sets to false */ 2620 view->details->show_foreign_files = TRUE; 2621 2622 view->details->non_ready_files = 2623 g_hash_table_new_full (file_and_directory_hash, 2624 file_and_directory_equal, 2625 (GDestroyNotify)file_and_directory_free, 2626 NULL); 2627 2628 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (view), 2629 GTK_POLICY_AUTOMATIC, 2630 GTK_POLICY_AUTOMATIC); 2631 gtk_scrolled_window_set_hadjustment (GTK_SCROLLED_WINDOW (view), NULL); 2632 gtk_scrolled_window_set_vadjustment (GTK_SCROLLED_WINDOW (view), NULL); 2633 2634 gtk_style_context_set_junction_sides (gtk_widget_get_style_context (GTK_WIDGET (view)), 2635 GTK_JUNCTION_TOP | GTK_JUNCTION_LEFT); 2636 2637 if (set_up_scripts_directory_global ()) { 2638 scripts_directory = nautilus_directory_get_by_uri (scripts_directory_uri); 2639 add_directory_to_scripts_directory_list (view, scripts_directory); 2640 nautilus_directory_unref (scripts_directory); 2641 } else { 2642 g_warning ("Ignoring scripts directory, it may be a broken link\n"); 2643 } 2644 2645 if (nautilus_should_use_templates_directory ()) { 2646 templates_uri = nautilus_get_templates_directory_uri (); 2647 templates_directory = nautilus_directory_get_by_uri (templates_uri); 2648 g_free (templates_uri); 2649 add_directory_to_templates_directory_list (view, templates_directory); 2650 nautilus_directory_unref (templates_directory); 2651 } 2652 update_templates_directory (view); 2653 g_signal_connect_object (nautilus_signaller_get_current (), 2654 "user_dirs_changed", 2655 G_CALLBACK (user_dirs_changed), 2656 view, G_CONNECT_SWAPPED); 2657 2658 view->details->sort_directories_first = 2659 g_settings_get_boolean (nautilus_preferences, NAUTILUS_PREFERENCES_SORT_DIRECTORIES_FIRST); 2660 view->details->show_hidden_files = 2661 g_settings_get_boolean (nautilus_preferences, NAUTILUS_PREFERENCES_SHOW_HIDDEN_FILES); 2662 2663 g_signal_connect_object (nautilus_trash_monitor_get (), "trash_state_changed", 2664 G_CALLBACK (nautilus_view_trash_state_changed_callback), view, 0); 2665 2666 /* React to clipboard changes */ 2667 g_signal_connect_object (nautilus_clipboard_monitor_get (), "clipboard_changed", 2668 G_CALLBACK (clipboard_changed_callback), view, 0); 2669 2670 /* Register to menu provider extension signal managing menu updates */ 2671 g_signal_connect_object (nautilus_signaller_get_current (), "popup_menu_changed", 2672 G_CALLBACK (schedule_update_menus), view, G_CONNECT_SWAPPED); 2673 2674 gtk_widget_show (GTK_WIDGET (view)); 2675 2676 g_signal_connect_swapped (nautilus_preferences, 2677 "changed::" NAUTILUS_PREFERENCES_ENABLE_DELETE, 2678 G_CALLBACK (schedule_update_menus), view); 2679 g_signal_connect_swapped (nautilus_preferences, 2680 "changed::" NAUTILUS_PREFERENCES_CLICK_POLICY, 2681 G_CALLBACK(click_policy_changed_callback), 2682 view); 2683 g_signal_connect_swapped (nautilus_preferences, 2684 "changed::" NAUTILUS_PREFERENCES_SORT_DIRECTORIES_FIRST, 2685 G_CALLBACK(sort_directories_first_changed_callback), view); 2686 g_signal_connect_swapped (gnome_lockdown_preferences, 2687 "changed::" NAUTILUS_PREFERENCES_LOCKDOWN_COMMAND_LINE, 2688 G_CALLBACK (schedule_update_menus), view); 2689 2690 g_signal_connect_object (nautilus_file_undo_manager_get (), "undo-changed", 2691 G_CALLBACK (undo_manager_changed_cb), view, 0); 2692 2693 /* Accessibility */ 2694 atk_object = gtk_widget_get_accessible (GTK_WIDGET (view)); 2695 atk_object_set_name (atk_object, _("Content View")); 2696 atk_object_set_description (atk_object, _("View of the current folder")); 2697 2698 nautilus_profile_end (NULL); 2699 } 2700 2701 static void 2702 real_unmerge_menus (NautilusView *view) 2703 { 2704 GtkUIManager *ui_manager; 2705 2706 ui_manager = nautilus_view_get_ui_manager (view); 2707 if (ui_manager == NULL) { 2708 return; 2709 } 2710 2711 nautilus_ui_unmerge_ui (ui_manager, 2712 &view->details->dir_merge_id, 2713 &view->details->dir_action_group); 2714 nautilus_ui_unmerge_ui (ui_manager, 2715 &view->details->extensions_menu_merge_id, 2716 &view->details->extensions_menu_action_group); 2717 nautilus_ui_unmerge_ui (ui_manager, 2718 &view->details->open_with_merge_id, 2719 &view->details->open_with_action_group); 2720 nautilus_ui_unmerge_ui (ui_manager, 2721 &view->details->scripts_merge_id, 2722 &view->details->scripts_action_group); 2723 nautilus_ui_unmerge_ui (ui_manager, 2724 &view->details->templates_merge_id, 2725 &view->details->templates_action_group); 2726 } 2727 2728 static void 2729 nautilus_view_destroy (GtkWidget *object) 2730 { 2731 NautilusView *view; 2732 GList *node, *next; 2733 2734 view = NAUTILUS_VIEW (object); 2735 2736 disconnect_model_handlers (view); 2737 2738 nautilus_view_unmerge_menus (view); 2739 nautilus_view_stop_loading (view); 2740 2741 for (node = view->details->scripts_directory_list; node != NULL; node = next) { 2742 next = node->next; 2743 remove_directory_from_scripts_directory_list (view, node->data); 2744 } 2745 2746 for (node = view->details->templates_directory_list; node != NULL; node = next) { 2747 next = node->next; 2748 remove_directory_from_templates_directory_list (view, node->data); 2749 } 2750 2751 while (view->details->subdirectory_list != NULL) { 2752 nautilus_view_remove_subdirectory (view, 2753 view->details->subdirectory_list->data); 2754 } 2755 2756 remove_update_menus_timeout_callback (view); 2757 remove_update_status_idle_callback (view); 2758 2759 if (view->details->display_selection_idle_id != 0) { 2760 g_source_remove (view->details->display_selection_idle_id); 2761 view->details->display_selection_idle_id = 0; 2762 } 2763 2764 if (view->details->reveal_selection_idle_id != 0) { 2765 g_source_remove (view->details->reveal_selection_idle_id); 2766 view->details->reveal_selection_idle_id = 0; 2767 } 2768 2769 if (view->details->delayed_rename_file_id != 0) { 2770 g_source_remove (view->details->delayed_rename_file_id); 2771 view->details->delayed_rename_file_id = 0; 2772 } 2773 2774 if (view->details->model) { 2775 nautilus_directory_unref (view->details->model); 2776 view->details->model = NULL; 2777 } 2778 2779 if (view->details->directory_as_file) { 2780 nautilus_file_unref (view->details->directory_as_file); 2781 view->details->directory_as_file = NULL; 2782 } 2783 2784 /* We don't own the slot, so no unref */ 2785 view->details->slot = NULL; 2786 2787 GTK_WIDGET_CLASS (nautilus_view_parent_class)->destroy (object); 2788 } 2789 2790 static void 2791 nautilus_view_finalize (GObject *object) 2792 { 2793 NautilusView *view; 2794 2795 view = NAUTILUS_VIEW (object); 2796 2797 g_signal_handlers_disconnect_by_func (nautilus_preferences, 2798 schedule_update_menus, view); 2799 g_signal_handlers_disconnect_by_func (nautilus_preferences, 2800 click_policy_changed_callback, view); 2801 g_signal_handlers_disconnect_by_func (nautilus_preferences, 2802 sort_directories_first_changed_callback, view); 2803 g_signal_handlers_disconnect_by_func (nautilus_window_state, 2804 nautilus_view_display_selection_info, view); 2805 2806 g_signal_handlers_disconnect_by_func (gnome_lockdown_preferences, 2807 schedule_update_menus, view); 2808 2809 unschedule_pop_up_location_context_menu (view); 2810 if (view->details->location_popup_event != NULL) { 2811 gdk_event_free ((GdkEvent *) view->details->location_popup_event); 2812 } 2813 2814 g_hash_table_destroy (view->details->non_ready_files); 2815 2816 G_OBJECT_CLASS (nautilus_view_parent_class)->finalize (object); 2817 } 2818 2819 /** 2820 * nautilus_view_display_selection_info: 2821 * 2822 * Display information about the current selection, and notify the view frame of the changed selection. 2823 * @view: NautilusView for which to display selection info. 2824 * 2825 **/ 2826 void 2827 nautilus_view_display_selection_info (NautilusView *view) 2828 { 2829 GList *selection; 2830 goffset non_folder_size; 2831 gboolean non_folder_size_known; 2832 guint non_folder_count, folder_count, folder_item_count; 2833 gboolean folder_item_count_known; 2834 guint file_item_count; 2835 GList *p; 2836 char *first_item_name; 2837 char *non_folder_count_str; 2838 char *non_folder_item_count_str; 2839 char *folder_count_str; 2840 char *folder_item_count_str; 2841 char *primary_status; 2842 char *detail_status; 2843 NautilusFile *file; 2844 2845 g_return_if_fail (NAUTILUS_IS_VIEW (view)); 2846 2847 selection = nautilus_view_get_selection (view); 2848 2849 folder_item_count_known = TRUE; 2850 folder_count = 0; 2851 folder_item_count = 0; 2852 non_folder_count = 0; 2853 non_folder_size_known = FALSE; 2854 non_folder_size = 0; 2855 first_item_name = NULL; 2856 folder_count_str = NULL; 2857 folder_item_count_str = NULL; 2858 non_folder_count_str = NULL; 2859 non_folder_item_count_str = NULL; 2860 2861 for (p = selection; p != NULL; p = p->next) { 2862 file = p->data; 2863 if (nautilus_file_is_directory (file)) { 2864 folder_count++; 2865 if (nautilus_file_get_directory_item_count (file, &file_item_count, NULL)) { 2866 folder_item_count += file_item_count; 2867 } else { 2868 folder_item_count_known = FALSE; 2869 } 2870 } else { 2871 non_folder_count++; 2872 if (!nautilus_file_can_get_size (file)) { 2873 non_folder_size_known = TRUE; 2874 non_folder_size += nautilus_file_get_size (file); 2875 } 2876 } 2877 2878 if (first_item_name == NULL) { 2879 first_item_name = nautilus_file_get_display_name (file); 2880 } 2881 } 2882 2883 nautilus_file_list_free (selection); 2884 2885 /* Break out cases for localization's sake. But note that there are still pieces 2886 * being assembled in a particular order, which may be a problem for some localizers. 2887 */ 2888 2889 if (folder_count != 0) { 2890 if (folder_count == 1 && non_folder_count == 0) { 2891 folder_count_str = g_strdup_printf (_("“%s” selected"), first_item_name); 2892 } else { 2893 folder_count_str = g_strdup_printf (ngettext("%'d folder selected", 2894 "%'d folders selected", 2895 folder_count), 2896 folder_count); 2897 } 2898 2899 if (folder_count == 1) { 2900 if (!folder_item_count_known) { 2901 folder_item_count_str = g_strdup (""); 2902 } else { 2903 folder_item_count_str = g_strdup_printf (ngettext("(containing %'d item)", 2904 "(containing %'d items)", 2905 folder_item_count), 2906 folder_item_count); 2907 } 2908 } 2909 else { 2910 if (!folder_item_count_known) { 2911 folder_item_count_str = g_strdup (""); 2912 } else { 2913 /* translators: this is preceded with a string of form 'N folders' (N more than 1) */ 2914 folder_item_count_str = g_strdup_printf (ngettext("(containing a total of %'d item)", 2915 "(containing a total of %'d items)", 2916 folder_item_count), 2917 folder_item_count); 2918 } 2919 2920 } 2921 } 2922 2923 if (non_folder_count != 0) { 2924 if (folder_count == 0) { 2925 if (non_folder_count == 1) { 2926 non_folder_count_str = g_strdup_printf (_("“%s” selected"), 2927 first_item_name); 2928 } else { 2929 non_folder_count_str = g_strdup_printf (ngettext("%'d item selected", 2930 "%'d items selected", 2931 non_folder_count), 2932 non_folder_count); 2933 } 2934 } else { 2935 /* Folders selected also, use "other" terminology */ 2936 non_folder_count_str = g_strdup_printf (ngettext("%'d other item selected", 2937 "%'d other items selected", 2938 non_folder_count), 2939 non_folder_count); 2940 } 2941 2942 if (non_folder_size_known) { 2943 char *size_string; 2944 2945 size_string = g_format_size (non_folder_size); 2946 /* This is marked for translation in case a localiser 2947 * needs to use something other than parentheses. The 2948 * the message in parentheses is the size of the selected items. 2949 */ 2950 non_folder_item_count_str = g_strdup_printf (_("(%s)"), size_string); 2951 g_free (size_string); 2952 } else { 2953 non_folder_item_count_str = g_strdup (""); 2954 } 2955 } 2956 2957 if (folder_count == 0 && non_folder_count == 0) { 2958 primary_status = NULL; 2959 detail_status = NULL; 2960 } else if (folder_count == 0) { 2961 primary_status = g_strdup (non_folder_count_str); 2962 detail_status = g_strdup (non_folder_item_count_str); 2963 } else if (non_folder_count == 0) { 2964 primary_status = g_strdup (folder_count_str); 2965 detail_status = g_strdup (folder_item_count_str); 2966 } else { 2967 /* This is marked for translation in case a localizer 2968 * needs to change ", " to something else. The comma 2969 * is between the message about the number of folders 2970 * and the number of items in those folders and the 2971 * message about the number of other items and the 2972 * total size of those items. 2973 */ 2974 primary_status = g_strdup_printf (_("%s %s, %s %s"), 2975 folder_count_str, 2976 folder_item_count_str, 2977 non_folder_count_str, 2978 non_folder_item_count_str); 2979 detail_status = NULL; 2980 } 2981 2982 g_free (first_item_name); 2983 g_free (folder_count_str); 2984 g_free (folder_item_count_str); 2985 g_free (non_folder_count_str); 2986 g_free (non_folder_item_count_str); 2987 2988 nautilus_window_slot_set_status (view->details->slot, 2989 primary_status, detail_status); 2990 2991 g_free (primary_status); 2992 g_free (detail_status); 2993 } 2994 2995 static void 2996 nautilus_view_send_selection_change (NautilusView *view) 2997 { 2998 g_signal_emit (view, signals[SELECTION_CHANGED], 0); 2999 3000 view->details->send_selection_change_to_shell = FALSE; 3001 } 3002 3003 void 3004 nautilus_view_load_location (NautilusView *nautilus_view, 3005 GFile *location) 3006 { 3007 NautilusDirectory *directory; 3008 NautilusView *directory_view; 3009 3010 directory_view = NAUTILUS_VIEW (nautilus_view); 3011 nautilus_profile_start (NULL); 3012 directory = nautilus_directory_get (location); 3013 load_directory (directory_view, directory); 3014 nautilus_directory_unref (directory); 3015 nautilus_profile_end (NULL); 3016 } 3017 3018 static gboolean 3019 reveal_selection_idle_callback (gpointer data) 3020 { 3021 NautilusView *view; 3022 3023 view = NAUTILUS_VIEW (data); 3024 3025 view->details->reveal_selection_idle_id = 0; 3026 nautilus_view_reveal_selection (view); 3027 3028 return FALSE; 3029 } 3030 3031 static void 3032 done_loading (NautilusView *view, 3033 gboolean all_files_seen) 3034 { 3035 GList *selection; 3036 gboolean do_reveal = FALSE; 3037 NautilusWindow *window; 3038 3039 if (!view->details->loading) { 3040 return; 3041 } 3042 3043 nautilus_profile_start (NULL); 3044 3045 window = nautilus_view_get_window (view); 3046 3047 /* This can be called during destruction, in which case there 3048 * is no NautilusWindow any more. 3049 */ 3050 if (window != NULL) { 3051 if (all_files_seen) { 3052 nautilus_window_report_load_complete (window, NAUTILUS_VIEW (view)); 3053 } 3054 3055 schedule_update_menus (view); 3056 schedule_update_status (view); 3057 reset_update_interval (view); 3058 3059 selection = view->details->pending_selection; 3060 3061 if (NAUTILUS_IS_SEARCH_DIRECTORY (view->details->model) 3062 && all_files_seen) { 3063 nautilus_view_select_first (view); 3064 do_reveal = TRUE; 3065 } else if (selection != NULL && all_files_seen) { 3066 view->details->pending_selection = NULL; 3067 3068 view->details->selection_change_is_due_to_shell = TRUE; 3069 nautilus_view_call_set_selection (view, selection); 3070 view->details->selection_change_is_due_to_shell = FALSE; 3071 g_list_free_full (selection, g_object_unref); 3072 do_reveal = TRUE; 3073 } 3074 3075 if (do_reveal) { 3076 if (NAUTILUS_IS_LIST_VIEW (view)) { 3077 /* HACK: We should be able to directly call reveal_selection here, 3078 * but at this point the GtkTreeView hasn't allocated the new nodes 3079 * yet, and it has a bug in the scroll calculation dealing with this 3080 * special case. It would always make the selection the top row, even 3081 * if no scrolling would be neccessary to reveal it. So we let it 3082 * allocate before revealing. 3083 */ 3084 if (view->details->reveal_selection_idle_id != 0) { 3085 g_source_remove (view->details->reveal_selection_idle_id); 3086 } 3087 view->details->reveal_selection_idle_id = 3088 g_idle_add (reveal_selection_idle_callback, view); 3089 } else { 3090 nautilus_view_reveal_selection (view); 3091 } 3092 } 3093 nautilus_view_display_selection_info (view); 3094 } 3095 3096 view->details->loading = FALSE; 3097 g_signal_emit (view, signals[END_LOADING], 0, all_files_seen); 3098 3099 nautilus_profile_end (NULL); 3100 } 3101 3102 3103 typedef struct { 3104 GHashTable *debuting_files; 3105 GList *added_files; 3106 } DebutingFilesData; 3107 3108 static void 3109 debuting_files_data_free (DebutingFilesData *data) 3110 { 3111 g_hash_table_unref (data->debuting_files); 3112 nautilus_file_list_free (data->added_files); 3113 g_free (data); 3114 } 3115 3116 /* This signal handler watch for the arrival of the icons created 3117 * as the result of a file operation. Once the last one is detected 3118 * it selects and reveals them all. 3119 */ 3120 static void 3121 debuting_files_add_file_callback (NautilusView *view, 3122 NautilusFile *new_file, 3123 NautilusDirectory *directory, 3124 DebutingFilesData *data) 3125 { 3126 GFile *location; 3127 3128 nautilus_profile_start (NULL); 3129 3130 location = nautilus_file_get_location (new_file); 3131 3132 if (g_hash_table_remove (data->debuting_files, location)) { 3133 nautilus_file_ref (new_file); 3134 data->added_files = g_list_prepend (data->added_files, new_file); 3135 3136 if (g_hash_table_size (data->debuting_files) == 0) { 3137 nautilus_view_call_set_selection (view, data->added_files); 3138 nautilus_view_reveal_selection (view); 3139 g_signal_handlers_disconnect_by_func (view, 3140 G_CALLBACK (debuting_files_add_file_callback), 3141 data); 3142 } 3143 } 3144 3145 nautilus_profile_end (NULL); 3146 3147 g_object_unref (location); 3148 } 3149 3150 typedef struct { 3151 GList *added_files; 3152 NautilusView *directory_view; 3153 } CopyMoveDoneData; 3154 3155 static void 3156 copy_move_done_data_free (CopyMoveDoneData *data) 3157 { 3158 g_assert (data != NULL); 3159 3160 if (data->directory_view != NULL) { 3161 g_object_remove_weak_pointer (G_OBJECT (data->directory_view), 3162 (gpointer *) &data->directory_view); 3163 } 3164 3165 nautilus_file_list_free (data->added_files); 3166 g_free (data); 3167 } 3168 3169 static void 3170 pre_copy_move_add_file_callback (NautilusView *view, 3171 NautilusFile *new_file, 3172 NautilusDirectory *directory, 3173 CopyMoveDoneData *data) 3174 { 3175 nautilus_file_ref (new_file); 3176 data->added_files = g_list_prepend (data->added_files, new_file); 3177 } 3178 3179 /* This needs to be called prior to nautilus_file_operations_copy_move. 3180 * It hooks up a signal handler to catch any icons that get added before 3181 * the copy_done_callback is invoked. The return value should be passed 3182 * as the data for uri_copy_move_done_callback. 3183 */ 3184 static CopyMoveDoneData * 3185 pre_copy_move (NautilusView *directory_view) 3186 { 3187 CopyMoveDoneData *copy_move_done_data; 3188 3189 copy_move_done_data = g_new0 (CopyMoveDoneData, 1); 3190 copy_move_done_data->directory_view = directory_view; 3191 3192 g_object_add_weak_pointer (G_OBJECT (copy_move_done_data->directory_view), 3193 (gpointer *) &copy_move_done_data->directory_view); 3194 3195 /* We need to run after the default handler adds the folder we want to 3196 * operate on. The ADD_FILE signal is registered as G_SIGNAL_RUN_LAST, so we 3197 * must use connect_after. 3198 */ 3199 g_signal_connect (directory_view, "add_file", 3200 G_CALLBACK (pre_copy_move_add_file_callback), copy_move_done_data); 3201 3202 return copy_move_done_data; 3203 } 3204 3205 /* This function is used to pull out any debuting uris that were added 3206 * and (as a side effect) remove them from the debuting uri hash table. 3207 */ 3208 static gboolean 3209 copy_move_done_partition_func (gpointer data, gpointer callback_data) 3210 { 3211 GFile *location; 3212 gboolean result; 3213 3214 location = nautilus_file_get_location (NAUTILUS_FILE (data)); 3215 result = g_hash_table_remove ((GHashTable *) callback_data, location); 3216 g_object_unref (location); 3217 3218 return result; 3219 } 3220 3221 static gboolean 3222 remove_not_really_moved_files (gpointer key, 3223 gpointer value, 3224 gpointer callback_data) 3225 { 3226 GList **added_files; 3227 GFile *loc; 3228 3229 loc = key; 3230 3231 if (GPOINTER_TO_INT (value)) { 3232 return FALSE; 3233 } 3234 3235 added_files = callback_data; 3236 *added_files = g_list_prepend (*added_files, 3237 nautilus_file_get (loc)); 3238 return TRUE; 3239 } 3240 3241 /* When this function is invoked, the file operation is over, but all 3242 * the icons may not have been added to the directory view yet, so 3243 * we can't select them yet. 3244 * 3245 * We're passed a hash table of the uri's to look out for, we hook 3246 * up a signal handler to await their arrival. 3247 */ 3248 static void 3249 copy_move_done_callback (GHashTable *debuting_files, 3250 gboolean success, 3251 gpointer data) 3252 { 3253 NautilusView *directory_view; 3254 CopyMoveDoneData *copy_move_done_data; 3255 DebutingFilesData *debuting_files_data; 3256 3257 copy_move_done_data = (CopyMoveDoneData *) data; 3258 directory_view = copy_move_done_data->directory_view; 3259 3260 if (directory_view != NULL) { 3261 g_assert (NAUTILUS_IS_VIEW (directory_view)); 3262 3263 debuting_files_data = g_new (DebutingFilesData, 1); 3264 debuting_files_data->debuting_files = g_hash_table_ref (debuting_files); 3265 debuting_files_data->added_files = eel_g_list_partition 3266 (copy_move_done_data->added_files, 3267 copy_move_done_partition_func, 3268 debuting_files, 3269 &copy_move_done_data->added_files); 3270 3271 /* We're passed the same data used by pre_copy_move_add_file_callback, so disconnecting 3272 * it will free data. We've already siphoned off the added_files we need, and stashed the 3273 * directory_view pointer. 3274 */ 3275 g_signal_handlers_disconnect_by_func (directory_view, 3276 G_CALLBACK (pre_copy_move_add_file_callback), 3277 data); 3278 3279 /* Any items in the debuting_files hash table that have 3280 * "FALSE" as their value aren't really being copied 3281 * or moved, so we can't wait for an add_file signal 3282 * to come in for those. 3283 */ 3284 g_hash_table_foreach_remove (debuting_files, 3285 remove_not_really_moved_files, 3286 &debuting_files_data->added_files); 3287 3288 if (g_hash_table_size (debuting_files) == 0) { 3289 /* on the off-chance that all the icons have already been added */ 3290 if (debuting_files_data->added_files != NULL) { 3291 nautilus_view_call_set_selection (directory_view, 3292 debuting_files_data->added_files); 3293 nautilus_view_reveal_selection (directory_view); 3294 } 3295 debuting_files_data_free (debuting_files_data); 3296 } else { 3297 /* We need to run after the default handler adds the folder we want to 3298 * operate on. The ADD_FILE signal is registered as G_SIGNAL_RUN_LAST, so we 3299 * must use connect_after. 3300 */ 3301 g_signal_connect_data (directory_view, 3302 "add_file", 3303 G_CALLBACK (debuting_files_add_file_callback), 3304 debuting_files_data, 3305 (GClosureNotify) debuting_files_data_free, 3306 G_CONNECT_AFTER); 3307 } 3308 /* Schedule menu update for undo items */ 3309 schedule_update_menus (directory_view); 3310 } 3311 3312 copy_move_done_data_free (copy_move_done_data); 3313 } 3314 3315 static gboolean 3316 view_file_still_belongs (NautilusView *view, 3317 NautilusFile *file, 3318 NautilusDirectory *directory) 3319 { 3320 if (view->details->model != directory && 3321 g_list_find (view->details->subdirectory_list, directory) == NULL) { 3322 return FALSE; 3323 } 3324 3325 return nautilus_directory_contains_file (directory, file); 3326 } 3327 3328 static gboolean 3329 still_should_show_file (NautilusView *view, NautilusFile *file, NautilusDirectory *directory) 3330 { 3331 return nautilus_view_should_show_file (view, file) && 3332 view_file_still_belongs (view, file, directory); 3333 } 3334 3335 static gboolean 3336 ready_to_load (NautilusFile *file) 3337 { 3338 return nautilus_file_check_if_ready (file, 3339 NAUTILUS_FILE_ATTRIBUTES_FOR_ICON); 3340 } 3341 3342 static int 3343 compare_files_cover (gconstpointer a, gconstpointer b, gpointer callback_data) 3344 { 3345 const FileAndDirectory *fad1, *fad2; 3346 NautilusView *view; 3347 3348 view = callback_data; 3349 fad1 = a; fad2 = b; 3350 3351 if (fad1->directory < fad2->directory) { 3352 return -1; 3353 } else if (fad1->directory > fad2->directory) { 3354 return 1; 3355 } else { 3356 return NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->compare_files (view, fad1->file, fad2->file); 3357 } 3358 } 3359 static void 3360 sort_files (NautilusView *view, GList **list) 3361 { 3362 *list = g_list_sort_with_data (*list, compare_files_cover, view); 3363 3364 } 3365 3366 /* Go through all the new added and changed files. 3367 * Put any that are not ready to load in the non_ready_files hash table. 3368 * Add all the rest to the old_added_files and old_changed_files lists. 3369 * Sort the old_*_files lists if anything was added to them. 3370 */ 3371 static void 3372 process_new_files (NautilusView *view) 3373 { 3374 GList *new_added_files, *new_changed_files, *old_added_files, *old_changed_files; 3375 GHashTable *non_ready_files; 3376 GList *node, *next; 3377 FileAndDirectory *pending; 3378 gboolean in_non_ready; 3379 3380 new_added_files = view->details->new_added_files; 3381 view->details->new_added_files = NULL; 3382 new_changed_files = view->details->new_changed_files; 3383 view->details->new_changed_files = NULL; 3384 3385 non_ready_files = view->details->non_ready_files; 3386 3387 old_added_files = view->details->old_added_files; 3388 old_changed_files = view->details->old_changed_files; 3389 3390 /* Newly added files go into the old_added_files list if they're 3391 * ready, and into the hash table if they're not. 3392 */ 3393 for (node = new_added_files; node != NULL; node = next) { 3394 next = node->next; 3395 pending = (FileAndDirectory *)node->data; 3396 in_non_ready = g_hash_table_lookup (non_ready_files, pending) != NULL; 3397 if (nautilus_view_should_show_file (view, pending->file)) { 3398 if (ready_to_load (pending->file)) { 3399 if (in_non_ready) { 3400 g_hash_table_remove (non_ready_files, pending); 3401 } 3402 new_added_files = g_list_delete_link (new_added_files, node); 3403 old_added_files = g_list_prepend (old_added_files, pending); 3404 } else { 3405 if (!in_non_ready) { 3406 new_added_files = g_list_delete_link (new_added_files, node); 3407 g_hash_table_insert (non_ready_files, pending, pending); 3408 } 3409 } 3410 } 3411 } 3412 file_and_directory_list_free (new_added_files); 3413 3414 /* Newly changed files go into the old_added_files list if they're ready 3415 * and were seen non-ready in the past, into the old_changed_files list 3416 * if they are read and were not seen non-ready in the past, and into 3417 * the hash table if they're not ready. 3418 */ 3419 for (node = new_changed_files; node != NULL; node = next) { 3420 next = node->next; 3421 pending = (FileAndDirectory *)node->data; 3422 if (!still_should_show_file (view, pending->file, pending->directory) || ready_to_load (pending->file)) { 3423 if (g_hash_table_lookup (non_ready_files, pending) != NULL) { 3424 g_hash_table_remove (non_ready_files, pending); 3425 if (still_should_show_file (view, pending->file, pending->directory)) { 3426 new_changed_files = g_list_delete_link (new_changed_files, node); 3427 old_added_files = g_list_prepend (old_added_files, pending); 3428 } 3429 } else if (nautilus_view_should_show_file (view, pending->file)) { 3430 new_changed_files = g_list_delete_link (new_changed_files, node); 3431 old_changed_files = g_list_prepend (old_changed_files, pending); 3432 } 3433 } 3434 } 3435 file_and_directory_list_free (new_changed_files); 3436 3437 /* If any files were added to old_added_files, then resort it. */ 3438 if (old_added_files != view->details->old_added_files) { 3439 view->details->old_added_files = old_added_files; 3440 sort_files (view, &view->details->old_added_files); 3441 } 3442 3443 /* Resort old_changed_files too, since file attributes 3444 * relevant to sorting could have changed. 3445 */ 3446 if (old_changed_files != view->details->old_changed_files) { 3447 view->details->old_changed_files = old_changed_files; 3448 sort_files (view, &view->details->old_changed_files); 3449 } 3450 3451 } 3452 3453 static void 3454 process_old_files (NautilusView *view) 3455 { 3456 GList *files_added, *files_changed, *node; 3457 FileAndDirectory *pending; 3458 GList *selection, *files; 3459 gboolean send_selection_change; 3460 3461 files_added = view->details->old_added_files; 3462 files_changed = view->details->old_changed_files; 3463 3464 send_selection_change = FALSE; 3465 3466 if (files_added != NULL || files_changed != NULL) { 3467 g_signal_emit (view, signals[BEGIN_FILE_CHANGES], 0); 3468 3469 for (node = files_added; node != NULL; node = node->next) { 3470 pending = node->data; 3471 g_signal_emit (view, 3472 signals[ADD_FILE], 0, pending->file, pending->directory); 3473 } 3474 3475 for (node = files_changed; node != NULL; node = node->next) { 3476 pending = node->data; 3477 g_signal_emit (view, 3478 signals[still_should_show_file (view, pending->file, pending->directory) 3479 ? FILE_CHANGED : REMOVE_FILE], 0, 3480 pending->file, pending->directory); 3481 } 3482 3483 g_signal_emit (view, signals[END_FILE_CHANGES], 0); 3484 3485 if (files_changed != NULL) { 3486 selection = nautilus_view_get_selection (view); 3487 files = file_and_directory_list_to_files (files_changed); 3488 send_selection_change = eel_g_lists_sort_and_check_for_intersection 3489 (&files, &selection); 3490 nautilus_file_list_free (files); 3491 nautilus_file_list_free (selection); 3492 } 3493 3494 file_and_directory_list_free (view->details->old_added_files); 3495 view->details->old_added_files = NULL; 3496 3497 file_and_directory_list_free (view->details->old_changed_files); 3498 view->details->old_changed_files = NULL; 3499 } 3500 3501 if (send_selection_change) { 3502 /* Send a selection change since some file names could 3503 * have changed. 3504 */ 3505 nautilus_view_send_selection_change (view); 3506 } 3507 } 3508 3509 static void 3510 display_pending_files (NautilusView *view) 3511 { 3512 3513 /* Don't dispatch any updates while the view is frozen. */ 3514 if (view->details->updates_frozen) { 3515 return; 3516 } 3517 3518 process_new_files (view); 3519 process_old_files (view); 3520 3521 if (view->details->model != NULL 3522 && nautilus_directory_are_all_files_seen (view->details->model) 3523 && g_hash_table_size (view->details->non_ready_files) == 0) { 3524 done_loading (view, TRUE); 3525 } 3526 } 3527 3528 void 3529 nautilus_view_freeze_updates (NautilusView *view) 3530 { 3531 view->details->updates_frozen = TRUE; 3532 view->details->updates_queued = 0; 3533 view->details->needs_reload = FALSE; 3534 } 3535 3536 void 3537 nautilus_view_unfreeze_updates (NautilusView *view) 3538 { 3539 view->details->updates_frozen = FALSE; 3540 3541 if (view->details->needs_reload) { 3542 view->details->needs_reload = FALSE; 3543 if (view->details->model != NULL) { 3544 load_directory (view, view->details->model); 3545 } 3546 } else { 3547 schedule_idle_display_of_pending_files (view); 3548 } 3549 } 3550 3551 static gboolean 3552 display_selection_info_idle_callback (gpointer data) 3553 { 3554 NautilusView *view; 3555 3556 view = NAUTILUS_VIEW (data); 3557 3558 g_object_ref (G_OBJECT (view)); 3559 3560 view->details->display_selection_idle_id = 0; 3561 nautilus_view_display_selection_info (view); 3562 if (view->details->send_selection_change_to_shell) { 3563 nautilus_view_send_selection_change (view); 3564 } 3565 3566 g_object_unref (G_OBJECT (view)); 3567 3568 return FALSE; 3569 } 3570 3571 static void 3572 remove_update_menus_timeout_callback (NautilusView *view) 3573 { 3574 if (view->details->update_menus_timeout_id != 0) { 3575 g_source_remove (view->details->update_menus_timeout_id); 3576 view->details->update_menus_timeout_id = 0; 3577 } 3578 } 3579 3580 static void 3581 update_menus_if_pending (NautilusView *view) 3582 { 3583 if (!view->details->menu_states_untrustworthy) { 3584 return; 3585 } 3586 3587 remove_update_menus_timeout_callback (view); 3588 nautilus_view_update_menus (view); 3589 } 3590 3591 static gboolean 3592 update_menus_timeout_callback (gpointer data) 3593 { 3594 NautilusView *view; 3595 3596 view = NAUTILUS_VIEW (data); 3597 3598 g_object_ref (G_OBJECT (view)); 3599 3600 view->details->update_menus_timeout_id = 0; 3601 nautilus_view_update_menus (view); 3602 3603 g_object_unref (G_OBJECT (view)); 3604 3605 return FALSE; 3606 } 3607 3608 static gboolean 3609 display_pending_callback (gpointer data) 3610 { 3611 NautilusView *view; 3612 3613 view = NAUTILUS_VIEW (data); 3614 3615 g_object_ref (G_OBJECT (view)); 3616 3617 view->details->display_pending_source_id = 0; 3618 3619 display_pending_files (view); 3620 3621 g_object_unref (G_OBJECT (view)); 3622 3623 return FALSE; 3624 } 3625 3626 static void 3627 schedule_idle_display_of_pending_files (NautilusView *view) 3628 { 3629 /* Get rid of a pending source as it might be a timeout */ 3630 unschedule_display_of_pending_files (view); 3631 3632 /* We want higher priority than the idle that handles the relayout 3633 to avoid a resort on each add. But we still want to allow repaints 3634 and other hight prio events while we have pending files to show. */ 3635 view->details->display_pending_source_id = 3636 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE - 20, 3637 display_pending_callback, view, NULL); 3638 } 3639 3640 static void 3641 schedule_timeout_display_of_pending_files (NautilusView *view, guint interval) 3642 { 3643 /* No need to schedule an update if there's already one pending. */ 3644 if (view->details->display_pending_source_id != 0) { 3645 return; 3646 } 3647 3648 view->details->display_pending_source_id = 3649 g_timeout_add (interval, display_pending_callback, view); 3650 } 3651 3652 static void 3653 unschedule_display_of_pending_files (NautilusView *view) 3654 { 3655 /* Get rid of source if it's active. */ 3656 if (view->details->display_pending_source_id != 0) { 3657 g_source_remove (view->details->display_pending_source_id); 3658 view->details->display_pending_source_id = 0; 3659 } 3660 } 3661 3662 static void 3663 queue_pending_files (NautilusView *view, 3664 NautilusDirectory *directory, 3665 GList *files, 3666 GList **pending_list) 3667 { 3668 if (files == NULL) { 3669 return; 3670 } 3671 3672 /* Don't queue any more updates if we need to reload anyway */ 3673 if (view->details->needs_reload) { 3674 return; 3675 } 3676 3677 if (view->details->updates_frozen) { 3678 view->details->updates_queued += g_list_length (files); 3679 /* Mark the directory for reload when there are too much queued 3680 * changes to prevent the pending list from growing infinitely. 3681 */ 3682 if (view->details->updates_queued > MAX_QUEUED_UPDATES) { 3683 view->details->needs_reload = TRUE; 3684 return; 3685 } 3686 } 3687 3688 3689 3690 *pending_list = g_list_concat (file_and_directory_list_from_files (directory, files), 3691 *pending_list); 3692 3693 if (! view->details->loading || nautilus_directory_are_all_files_seen (directory)) { 3694 schedule_timeout_display_of_pending_files (view, view->details->update_interval); 3695 } 3696 } 3697 3698 static void 3699 remove_changes_timeout_callback (NautilusView *view) 3700 { 3701 if (view->details->changes_timeout_id != 0) { 3702 g_source_remove (view->details->changes_timeout_id); 3703 view->details->changes_timeout_id = 0; 3704 } 3705 } 3706 3707 static void 3708 reset_update_interval (NautilusView *view) 3709 { 3710 view->details->update_interval = UPDATE_INTERVAL_MIN; 3711 remove_changes_timeout_callback (view); 3712 /* Reschedule a pending timeout to idle */ 3713 if (view->details->display_pending_source_id != 0) { 3714 schedule_idle_display_of_pending_files (view); 3715 } 3716 } 3717 3718 static gboolean 3719 changes_timeout_callback (gpointer data) 3720 { 3721 gint64 now; 3722 gint64 time_delta; 3723 gboolean ret; 3724 NautilusView *view; 3725 3726 view = NAUTILUS_VIEW (data); 3727 3728 g_object_ref (G_OBJECT (view)); 3729 3730 now = g_get_monotonic_time (); 3731 time_delta = now - view->details->last_queued; 3732 3733 if (time_delta < UPDATE_INTERVAL_RESET*1000) { 3734 if (view->details->update_interval < UPDATE_INTERVAL_MAX && 3735 view->details->loading) { 3736 /* Increase */ 3737 view->details->update_interval += UPDATE_INTERVAL_INC; 3738 } 3739 ret = TRUE; 3740 } else { 3741 /* Reset */ 3742 reset_update_interval (view); 3743 ret = FALSE; 3744 } 3745 3746 g_object_unref (G_OBJECT (view)); 3747 3748 return ret; 3749 } 3750 3751 static void 3752 schedule_changes (NautilusView *view) 3753 { 3754 /* Remember when the change was queued */ 3755 view->details->last_queued = g_get_monotonic_time (); 3756 3757 /* No need to schedule if there are already changes pending or during loading */ 3758 if (view->details->changes_timeout_id != 0 || 3759 view->details->loading) { 3760 return; 3761 } 3762 3763 view->details->changes_timeout_id = 3764 g_timeout_add (UPDATE_INTERVAL_TIMEOUT_INTERVAL, changes_timeout_callback, view); 3765 } 3766 3767 static void 3768 files_added_callback (NautilusDirectory *directory, 3769 GList *files, 3770 gpointer callback_data) 3771 { 3772 NautilusView *view; 3773 GtkWindow *window; 3774 char *uri; 3775 3776 view = NAUTILUS_VIEW (callback_data); 3777 3778 nautilus_profile_start (NULL); 3779 3780 window = nautilus_view_get_containing_window (view); 3781 uri = nautilus_view_get_uri (view); 3782 DEBUG_FILES (files, "Files added in window %p: %s", 3783 window, uri ? uri : "(no directory)"); 3784 g_free (uri); 3785 3786 schedule_changes (view); 3787 3788 queue_pending_files (view, directory, files, &view->details->new_added_files); 3789 3790 /* The number of items could have changed */ 3791 schedule_update_status (view); 3792 3793 nautilus_profile_end (NULL); 3794 } 3795 3796 static void 3797 files_changed_callback (NautilusDirectory *directory, 3798 GList *files, 3799 gpointer callback_data) 3800 { 3801 NautilusView *view; 3802 GtkWindow *window; 3803 char *uri; 3804 3805 view = NAUTILUS_VIEW (callback_data); 3806 3807 window = nautilus_view_get_containing_window (view); 3808 uri = nautilus_view_get_uri (view); 3809 DEBUG_FILES (files, "Files changed in window %p: %s", 3810 window, uri ? uri : "(no directory)"); 3811 g_free (uri); 3812 3813 schedule_changes (view); 3814 3815 queue_pending_files (view, directory, files, &view->details->new_changed_files); 3816 3817 /* The free space or the number of items could have changed */ 3818 schedule_update_status (view); 3819 3820 /* A change in MIME type could affect the Open with menu, for 3821 * one thing, so we need to update menus when files change. 3822 */ 3823 schedule_update_menus (view); 3824 } 3825 3826 static void 3827 done_loading_callback (NautilusDirectory *directory, 3828 gpointer callback_data) 3829 { 3830 NautilusView *view; 3831 3832 view = NAUTILUS_VIEW (callback_data); 3833 3834 nautilus_profile_start (NULL); 3835 process_new_files (view); 3836 if (g_hash_table_size (view->details->non_ready_files) == 0) { 3837 /* Unschedule a pending update and schedule a new one with the minimal 3838 * update interval. This gives the view a short chance at gathering the 3839 * (cached) deep counts. 3840 */ 3841 unschedule_display_of_pending_files (view); 3842 schedule_timeout_display_of_pending_files (view, UPDATE_INTERVAL_MIN); 3843 } 3844 nautilus_profile_end (NULL); 3845 } 3846 3847 static void 3848 load_error_callback (NautilusDirectory *directory, 3849 GError *error, 3850 gpointer callback_data) 3851 { 3852 NautilusView *view; 3853 3854 view = NAUTILUS_VIEW (callback_data); 3855 3856 /* FIXME: By doing a stop, we discard some pending files. Is 3857 * that OK? 3858 */ 3859 nautilus_view_stop_loading (view); 3860 3861 /* Emit a signal to tell subclasses that a load error has 3862 * occurred, so they can handle it in the UI. 3863 */ 3864 g_signal_emit (view, 3865 signals[LOAD_ERROR], 0, error); 3866 } 3867 3868 static void 3869 real_load_error (NautilusView *view, GError *error) 3870 { 3871 /* Report only one error per failed directory load (from the UI 3872 * point of view, not from the NautilusDirectory point of view). 3873 * Otherwise you can get multiple identical errors caused by 3874 * unrelated code that just happens to try to iterate this 3875 * directory. 3876 */ 3877 if (!view->details->reported_load_error) { 3878 nautilus_report_error_loading_directory 3879 (nautilus_view_get_directory_as_file (view), 3880 error, 3881 nautilus_view_get_containing_window (view)); 3882 } 3883 view->details->reported_load_error = TRUE; 3884 } 3885 3886 void 3887 nautilus_view_add_subdirectory (NautilusView *view, 3888 NautilusDirectory*directory) 3889 { 3890 NautilusFileAttributes attributes; 3891 3892 g_assert (!g_list_find (view->details->subdirectory_list, directory)); 3893 3894 nautilus_directory_ref (directory); 3895 3896 attributes = 3897 NAUTILUS_FILE_ATTRIBUTES_FOR_ICON | 3898 NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT | 3899 NAUTILUS_FILE_ATTRIBUTE_INFO | 3900 NAUTILUS_FILE_ATTRIBUTE_LINK_INFO | 3901 NAUTILUS_FILE_ATTRIBUTE_MOUNT | 3902 NAUTILUS_FILE_ATTRIBUTE_EXTENSION_INFO; 3903 3904 nautilus_directory_file_monitor_add (directory, 3905 &view->details->model, 3906 view->details->show_hidden_files, 3907 attributes, 3908 files_added_callback, view); 3909 3910 g_signal_connect 3911 (directory, "files_added", 3912 G_CALLBACK (files_added_callback), view); 3913 g_signal_connect 3914 (directory, "files_changed", 3915 G_CALLBACK (files_changed_callback), view); 3916 3917 view->details->subdirectory_list = g_list_prepend ( 3918 view->details->subdirectory_list, directory); 3919 } 3920 3921 void 3922 nautilus_view_remove_subdirectory (NautilusView *view, 3923 NautilusDirectory*directory) 3924 { 3925 g_assert (g_list_find (view->details->subdirectory_list, directory)); 3926 3927 view->details->subdirectory_list = g_list_remove ( 3928 view->details->subdirectory_list, directory); 3929 3930 g_signal_handlers_disconnect_by_func (directory, 3931 G_CALLBACK (files_added_callback), 3932 view); 3933 g_signal_handlers_disconnect_by_func (directory, 3934 G_CALLBACK (files_changed_callback), 3935 view); 3936 3937 nautilus_directory_file_monitor_remove (directory, &view->details->model); 3938 3939 nautilus_directory_unref (directory); 3940 } 3941 3942 /** 3943 * nautilus_view_get_loading: 3944 * @view: an #NautilusView. 3945 * 3946 * Return value: #gboolean inicating whether @view is currently loaded. 3947 * 3948 **/ 3949 gboolean 3950 nautilus_view_get_loading (NautilusView *view) 3951 { 3952 g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE); 3953 3954 return view->details->loading; 3955 } 3956 3957 GtkUIManager * 3958 nautilus_view_get_ui_manager (NautilusView *view) 3959 { 3960 NautilusWindow *window; 3961 3962 if (view->details->slot == NULL) { 3963 return NULL; 3964 } 3965 3966 window = nautilus_window_slot_get_window (view->details->slot); 3967 return nautilus_window_get_ui_manager (window); 3968 } 3969 3970 /** 3971 * nautilus_view_get_model: 3972 * 3973 * Get the model for this NautilusView. 3974 * @view: NautilusView of interest. 3975 * 3976 * Return value: NautilusDirectory for this view. 3977 * 3978 **/ 3979 NautilusDirectory * 3980 nautilus_view_get_model (NautilusView *view) 3981 { 3982 g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL); 3983 3984 return view->details->model; 3985 } 3986 3987 GdkAtom 3988 nautilus_view_get_copied_files_atom (NautilusView *view) 3989 { 3990 g_return_val_if_fail (NAUTILUS_IS_VIEW (view), GDK_NONE); 3991 3992 return copied_files_atom; 3993 } 3994 3995 static void 3996 prepend_uri_one (gpointer data, gpointer callback_data) 3997 { 3998 NautilusFile *file; 3999 GList **result; 4000 4001 g_assert (NAUTILUS_IS_FILE (data)); 4002 g_assert (callback_data != NULL); 4003 4004 result = (GList **) callback_data; 4005 file = (NautilusFile *) data; 4006 *result = g_list_prepend (*result, nautilus_file_get_uri (file)); 4007 } 4008 4009 static void 4010 offset_drop_points (GArray *relative_item_points, 4011 int x_offset, int y_offset) 4012 { 4013 guint index; 4014 4015 if (relative_item_points == NULL) { 4016 return; 4017 } 4018 4019 for (index = 0; index < relative_item_points->len; index++) { 4020 g_array_index (relative_item_points, GdkPoint, index).x += x_offset; 4021 g_array_index (relative_item_points, GdkPoint, index).y += y_offset; 4022 } 4023 } 4024 4025 static void 4026 nautilus_view_create_links_for_files (NautilusView *view, GList *files, 4027 GArray *relative_item_points) 4028 { 4029 GList *uris; 4030 char *dir_uri; 4031 CopyMoveDoneData *copy_move_done_data; 4032 g_assert (relative_item_points->len == 0 4033 || g_list_length (files) == relative_item_points->len); 4034 4035 g_assert (NAUTILUS_IS_VIEW (view)); 4036 g_assert (files != NULL); 4037 4038 /* create a list of URIs */ 4039 uris = NULL; 4040 g_list_foreach (files, prepend_uri_one, &uris); 4041 uris = g_list_reverse (uris); 4042 4043 g_assert (g_list_length (uris) == g_list_length (files)); 4044 4045 /* offset the drop locations a bit so that we don't pile 4046 * up the icons on top of each other 4047 */ 4048 offset_drop_points (relative_item_points, 4049 DUPLICATE_HORIZONTAL_ICON_OFFSET, 4050 DUPLICATE_VERTICAL_ICON_OFFSET); 4051 4052 copy_move_done_data = pre_copy_move (view); 4053 dir_uri = nautilus_view_get_backing_uri (view); 4054 nautilus_file_operations_copy_move (uris, relative_item_points, dir_uri, GDK_ACTION_LINK, 4055 GTK_WIDGET (view), copy_move_done_callback, copy_move_done_data); 4056 g_free (dir_uri); 4057 g_list_free_full (uris, g_free); 4058 } 4059 4060 /* special_link_in_selection 4061 * 4062 * Return TRUE if one of our special links is in the selection. 4063 * Special links include the following: 4064 * NAUTILUS_DESKTOP_LINK_TRASH, NAUTILUS_DESKTOP_LINK_HOME, NAUTILUS_DESKTOP_LINK_MOUNT 4065 */ 4066 4067 static gboolean 4068 special_link_in_selection (NautilusView *view) 4069 { 4070 gboolean saw_link; 4071 GList *selection, *node; 4072 NautilusFile *file; 4073 4074 g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE); 4075 4076 saw_link = FALSE; 4077 4078 selection = nautilus_view_get_selection (NAUTILUS_VIEW (view)); 4079 4080 for (node = selection; node != NULL; node = node->next) { 4081 file = NAUTILUS_FILE (node->data); 4082 4083 saw_link = NAUTILUS_IS_DESKTOP_ICON_FILE (file); 4084 4085 if (saw_link) { 4086 break; 4087 } 4088 } 4089 4090 nautilus_file_list_free (selection); 4091 4092 return saw_link; 4093 } 4094 4095 /* desktop_or_home_dir_in_selection 4096 * 4097 * Return TRUE if either the desktop or the home directory is in the selection. 4098 */ 4099 4100 static gboolean 4101 desktop_or_home_dir_in_selection (NautilusView *view) 4102 { 4103 gboolean saw_desktop_or_home_dir; 4104 GList *selection, *node; 4105 NautilusFile *file; 4106 4107 g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE); 4108 4109 saw_desktop_or_home_dir = FALSE; 4110 4111 selection = nautilus_view_get_selection (NAUTILUS_VIEW (view)); 4112 4113 for (node = selection; node != NULL; node = node->next) { 4114 file = NAUTILUS_FILE (node->data); 4115 4116 saw_desktop_or_home_dir = 4117 nautilus_file_is_home (file) 4118 || nautilus_file_is_desktop_directory (file); 4119 4120 if (saw_desktop_or_home_dir) { 4121 break; 4122 } 4123 } 4124 4125 nautilus_file_list_free (selection); 4126 4127 return saw_desktop_or_home_dir; 4128 } 4129 4130 static void 4131 trash_or_delete_done_cb (GHashTable *debuting_uris, 4132 gboolean user_cancel, 4133 NautilusView *view) 4134 { 4135 if (user_cancel) { 4136 view->details->selection_was_removed = FALSE; 4137 } 4138 } 4139 4140 static void 4141 trash_or_delete_files (GtkWindow *parent_window, 4142 const GList *files, 4143 gboolean delete_if_all_already_in_trash, 4144 NautilusView *view) 4145 { 4146 GList *locations; 4147 const GList *node; 4148 4149 locations = NULL; 4150 for (node = files; node != NULL; node = node->next) { 4151 locations = g_list_prepend (locations, 4152 nautilus_file_get_location ((NautilusFile *) node->data)); 4153 } 4154 4155 locations = g_list_reverse (locations); 4156 4157 nautilus_file_operations_trash_or_delete (locations, 4158 parent_window, 4159 (NautilusDeleteCallback) trash_or_delete_done_cb, 4160 view); 4161 g_list_free_full (locations, g_object_unref); 4162 } 4163 4164 static gboolean 4165 can_rename_file (NautilusView *view, NautilusFile *file) 4166 { 4167 return nautilus_file_can_rename (file); 4168 } 4169 4170 gboolean 4171 nautilus_view_get_is_renaming (NautilusView *view) 4172 { 4173 return view->details->is_renaming; 4174 } 4175 4176 void 4177 nautilus_view_set_is_renaming (NautilusView *view, 4178 gboolean is_renaming) 4179 { 4180 view->details->is_renaming = is_renaming; 4181 } 4182 4183 static void 4184 start_renaming_file (NautilusView *view, 4185 NautilusFile *file, 4186 gboolean select_all) 4187 { 4188 view->details->is_renaming = TRUE; 4189 4190 if (file != NULL) { 4191 nautilus_view_select_file (view, file); 4192 } 4193 } 4194 4195 static void 4196 update_context_menu_position_from_event (NautilusView *view, 4197 GdkEventButton *event) 4198 { 4199 g_return_if_fail (NAUTILUS_IS_VIEW (view)); 4200 4201 if (event != NULL) { 4202 view->details->context_menu_position.x = event->x; 4203 view->details->context_menu_position.y = event->y; 4204 } else { 4205 view->details->context_menu_position.x = -1; 4206 view->details->context_menu_position.y = -1; 4207 } 4208 } 4209 4210 /* handle the open command */ 4211 4212 static void 4213 open_one_in_new_window (gpointer data, gpointer callback_data) 4214 { 4215 g_assert (NAUTILUS_IS_FILE (data)); 4216 g_assert (NAUTILUS_IS_VIEW (callback_data)); 4217 4218 nautilus_view_activate_file (NAUTILUS_VIEW (callback_data), 4219 NAUTILUS_FILE (data), 4220 NAUTILUS_WINDOW_OPEN_FLAG_NEW_WINDOW); 4221 } 4222 4223 NautilusFile * 4224 nautilus_view_get_directory_as_file (NautilusView *view) 4225 { 4226 g_assert (NAUTILUS_IS_VIEW (view)); 4227 4228 return view->details->directory_as_file; 4229 } 4230 4231 static void 4232 open_with_launch_application_callback (GtkAction *action, 4233 gpointer callback_data) 4234 { 4235 ApplicationLaunchParameters *launch_parameters; 4236 4237 launch_parameters = (ApplicationLaunchParameters *) callback_data; 4238 nautilus_launch_application 4239 (launch_parameters->application, 4240 launch_parameters->files, 4241 nautilus_view_get_containing_window (launch_parameters->directory_view)); 4242 } 4243 4244 static char * 4245 escape_action_path (const char *action_path) 4246 { 4247 GString *s; 4248 4249 if (action_path == NULL) { 4250 return NULL; 4251 } 4252 4253 s = g_string_sized_new (strlen (action_path) + 2); 4254 4255 while (*action_path != 0) { 4256 switch (*action_path) { 4257 case '\\': 4258 g_string_append (s, "\\\\"); 4259 break; 4260 case '&': 4261 g_string_append (s, "\\a"); 4262 break; 4263 case '"': 4264 g_string_append (s, "\\q"); 4265 break; 4266 default: 4267 g_string_append_c (s, *action_path); 4268 } 4269 4270 action_path ++; 4271 } 4272 return g_string_free (s, FALSE); 4273 } 4274 4275 4276 static void 4277 add_submenu (GtkUIManager *ui_manager, 4278 GtkActionGroup *action_group, 4279 guint merge_id, 4280 const char *parent_path, 4281 const char *uri, 4282 const char *label, 4283 GdkPixbuf *pixbuf, 4284 gboolean add_action) 4285 { 4286 char *escaped_label; 4287 char *action_name; 4288 char *submenu_name; 4289 char *escaped_submenu_name; 4290 GtkAction *action; 4291 4292 if (parent_path != NULL) { 4293 action_name = nautilus_escape_action_name (uri, "submenu_"); 4294 submenu_name = g_path_get_basename (uri); 4295 escaped_submenu_name = escape_action_path (submenu_name); 4296 escaped_label = eel_str_double_underscores (label); 4297 4298 if (add_action) { 4299 action = gtk_action_new (action_name, 4300 escaped_label, 4301 NULL, 4302 NULL); 4303 if (pixbuf != NULL) { 4304 gtk_action_set_gicon (action, G_ICON (pixbuf)); 4305 } 4306 4307 g_object_set (action, "hide-if-empty", FALSE, NULL); 4308 4309 gtk_action_group_add_action (action_group, 4310 action); 4311 g_object_unref (action); 4312 } 4313 4314 gtk_ui_manager_add_ui (ui_manager, 4315 merge_id, 4316 parent_path, 4317 escaped_submenu_name, 4318 action_name, 4319 GTK_UI_MANAGER_MENU, 4320 FALSE); 4321 g_free (action_name); 4322 g_free (escaped_label); 4323 g_free (submenu_name); 4324 g_free (escaped_submenu_name); 4325 } 4326 } 4327 4328 static void 4329 menu_item_show_image (GtkUIManager *ui_manager, 4330 const char *parent_path, 4331 const char *action_name) 4332 { 4333 char *path; 4334 GtkWidget *menuitem; 4335 4336 path = g_strdup_printf ("%s/%s", parent_path, action_name); 4337 menuitem = gtk_ui_manager_get_widget (ui_manager, 4338 path); 4339 if (menuitem != NULL) { 4340 gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (menuitem), 4341 TRUE); 4342 } 4343 g_free (path); 4344 } 4345 4346 static void 4347 add_application_to_open_with_menu (NautilusView *view, 4348 GAppInfo *application, 4349 GList *files, 4350 int index, 4351 const char *menu_placeholder, 4352 const char *popup_placeholder, 4353 const gboolean submenu) 4354 { 4355 ApplicationLaunchParameters *launch_parameters; 4356 char *tip; 4357 char *label; 4358 char *action_name; 4359 char *escaped_app; 4360 GtkAction *action; 4361 GIcon *app_icon; 4362 GtkUIManager *ui_manager; 4363 4364 launch_parameters = application_launch_parameters_new 4365 (application, files, view); 4366 escaped_app = eel_str_double_underscores (g_app_info_get_display_name (application)); 4367 if (submenu) 4368 label = g_strdup_printf ("%s", escaped_app); 4369 else 4370 label = g_strdup_printf (_("Open With %s"), escaped_app); 4371 4372 tip = g_strdup_printf (ngettext ("Use “%s” to open the selected item", 4373 "Use “%s” to open the selected items", 4374 g_list_length (files)), 4375 escaped_app); 4376 g_free (escaped_app); 4377 4378 action_name = g_strdup_printf ("open_with_%d", index); 4379 4380 action = gtk_action_new (action_name, 4381 label, 4382 tip, 4383 NULL); 4384 4385 app_icon = g_app_info_get_icon (application); 4386 if (app_icon != NULL) { 4387 g_object_ref (app_icon); 4388 } else { 4389 app_icon = g_themed_icon_new ("application-x-executable"); 4390 } 4391 4392 gtk_action_set_gicon (action, app_icon); 4393 g_object_unref (app_icon); 4394 4395 g_signal_connect_data (action, "activate", 4396 G_CALLBACK (open_with_launch_application_callback), 4397 launch_parameters, 4398 (GClosureNotify)application_launch_parameters_free, 0); 4399 4400 gtk_action_group_add_action (view->details->open_with_action_group, 4401 action); 4402 g_object_unref (action); 4403 4404 ui_manager = nautilus_view_get_ui_manager (view); 4405 gtk_ui_manager_add_ui (ui_manager, 4406 view->details->open_with_merge_id, 4407 popup_placeholder, 4408 action_name, 4409 action_name, 4410 GTK_UI_MANAGER_MENUITEM, 4411 FALSE); 4412 4413 menu_item_show_image (ui_manager, popup_placeholder, action_name); 4414 4415 g_free (action_name); 4416 g_free (label); 4417 g_free (tip); 4418 } 4419 4420 static void 4421 get_x_content_async_callback (const char **content, 4422 gpointer user_data) 4423 { 4424 NautilusView *view; 4425 4426 view = NAUTILUS_VIEW (user_data); 4427 4428 if (view->details->slot != NULL) { 4429 schedule_update_menus (view); 4430 } 4431 g_object_unref (view); 4432 } 4433 4434 static void 4435 add_x_content_apps (NautilusView *view, NautilusFile *file, GList **applications) 4436 { 4437 GMount *mount; 4438 char **x_content_types; 4439 unsigned int n; 4440 4441 g_return_if_fail (applications != NULL); 4442 4443 mount = nautilus_file_get_mount (file); 4444 4445 if (mount == NULL) { 4446 return; 4447 } 4448 4449 x_content_types = nautilus_get_cached_x_content_types_for_mount (mount); 4450 if (x_content_types != NULL) { 4451 for (n = 0; x_content_types[n] != NULL; n++) { 4452 char *x_content_type = x_content_types[n]; 4453 GList *app_info_for_x_content_type; 4454 4455 app_info_for_x_content_type = g_app_info_get_all_for_type (x_content_type); 4456 *applications = g_list_concat (*applications, app_info_for_x_content_type); 4457 } 4458 g_strfreev (x_content_types); 4459 } else { 4460 nautilus_get_x_content_types_for_mount_async (mount, 4461 get_x_content_async_callback, 4462 NULL, 4463 g_object_ref (view)); 4464 4465 } 4466 4467 g_object_unref (mount); 4468 } 4469 4470 static void 4471 reset_open_with_menu (NautilusView *view, GList *selection) 4472 { 4473 GList *applications, *node; 4474 NautilusFile *file; 4475 gboolean submenu_visible, filter_default; 4476 int num_applications; 4477 int index; 4478 gboolean other_applications_visible; 4479 gboolean open_with_chooser_visible; 4480 GtkUIManager *ui_manager; 4481 GtkAction *action; 4482 GAppInfo *default_app; 4483 4484 /* Clear any previous inserted items in the applications and viewers placeholders */ 4485 4486 ui_manager = nautilus_view_get_ui_manager (view); 4487 nautilus_ui_unmerge_ui (ui_manager, 4488 &view->details->open_with_merge_id, 4489 &view->details->open_with_action_group); 4490 4491 nautilus_ui_prepare_merge_ui (ui_manager, 4492 "OpenWithGroup", 4493 &view->details->open_with_merge_id, 4494 &view->details->open_with_action_group); 4495 4496 other_applications_visible = (selection != NULL); 4497 filter_default = (selection != NULL); 4498 4499 for (node = selection; node != NULL; node = node->next) { 4500 4501 file = NAUTILUS_FILE (node->data); 4502 4503 other_applications_visible &= (!nautilus_mime_file_opens_in_view (file) && 4504 !nautilus_file_is_nautilus_link (file)); 4505 } 4506 4507 default_app = NULL; 4508 if (filter_default) { 4509 default_app = nautilus_mime_get_default_application_for_files (selection); 4510 } 4511 4512 applications = NULL; 4513 if (other_applications_visible) { 4514 applications = nautilus_mime_get_applications_for_files (selection); 4515 } 4516 4517 if (g_list_length (selection) == 1) { 4518 add_x_content_apps (view, NAUTILUS_FILE (selection->data), &applications); 4519 } 4520 4521 4522 num_applications = g_list_length (applications); 4523 4524 submenu_visible = (num_applications > 1); 4525 4526 for (node = applications, index = 0; node != NULL; node = node->next, index++) { 4527 GAppInfo *application; 4528 char *menu_path; 4529 char *popup_path; 4530 4531 application = node->data; 4532 4533 if (default_app != NULL && g_app_info_equal (default_app, application)) { 4534 continue; 4535 } 4536 4537 if (submenu_visible) { 4538 menu_path = NAUTILUS_VIEW_MENU_PATH_APPLICATIONS_SUBMENU_PLACEHOLDER; 4539 popup_path = NAUTILUS_VIEW_POPUP_PATH_APPLICATIONS_SUBMENU_PLACEHOLDER; 4540 } else { 4541 menu_path = NAUTILUS_VIEW_MENU_PATH_APPLICATIONS_PLACEHOLDER; 4542 popup_path = NAUTILUS_VIEW_POPUP_PATH_APPLICATIONS_PLACEHOLDER; 4543 } 4544 4545 gtk_ui_manager_add_ui (nautilus_view_get_ui_manager (view), 4546 view->details->open_with_merge_id, 4547 menu_path, 4548 "separator", 4549 NULL, 4550 GTK_UI_MANAGER_SEPARATOR, 4551 FALSE); 4552 4553 add_application_to_open_with_menu (view, 4554 node->data, 4555 selection, 4556 index, 4557 menu_path, popup_path, submenu_visible); 4558 } 4559 g_list_free_full (applications, g_object_unref); 4560 if (default_app != NULL) { 4561 g_object_unref (default_app); 4562 } 4563 4564 open_with_chooser_visible = other_applications_visible && 4565 g_list_length (selection) == 1; 4566 4567 if (submenu_visible) { 4568 action = gtk_action_group_get_action (view->details->dir_action_group, 4569 NAUTILUS_ACTION_OTHER_APPLICATION1); 4570 gtk_action_set_visible (action, open_with_chooser_visible); 4571 action = gtk_action_group_get_action (view->details->dir_action_group, 4572 NAUTILUS_ACTION_OTHER_APPLICATION2); 4573 gtk_action_set_visible (action, FALSE); 4574 } else { 4575 action = gtk_action_group_get_action (view->details->dir_action_group, 4576 NAUTILUS_ACTION_OTHER_APPLICATION1); 4577 gtk_action_set_visible (action, FALSE); 4578 action = gtk_action_group_get_action (view->details->dir_action_group, 4579 NAUTILUS_ACTION_OTHER_APPLICATION2); 4580 gtk_action_set_visible (action, open_with_chooser_visible); 4581 } 4582 } 4583 4584 static GList * 4585 get_all_extension_menu_items (GtkWidget *window, 4586 GList *selection) 4587 { 4588 GList *items; 4589 GList *providers; 4590 GList *l; 4591 4592 providers = nautilus_module_get_extensions_for_type (NAUTILUS_TYPE_MENU_PROVIDER); 4593 items = NULL; 4594 4595 for (l = providers; l != NULL; l = l->next) { 4596 NautilusMenuProvider *provider; 4597 GList *file_items; 4598 4599 provider = NAUTILUS_MENU_PROVIDER (l->data); 4600 file_items = nautilus_menu_provider_get_file_items (provider, 4601 window, 4602 selection); 4603 items = g_list_concat (items, file_items); 4604 } 4605 4606 nautilus_module_extension_list_free (providers); 4607 4608 return items; 4609 } 4610 4611 typedef struct 4612 { 4613 NautilusMenuItem *item; 4614 NautilusView *view; 4615 GList *selection; 4616 GtkAction *action; 4617 } ExtensionActionCallbackData; 4618 4619 4620 static void 4621 extension_action_callback_data_free (ExtensionActionCallbackData *data) 4622 { 4623 g_object_unref (data->item); 4624 nautilus_file_list_free (data->selection); 4625 4626 g_free (data); 4627 } 4628 4629 static gboolean 4630 search_in_menu_items (GList* items, const char *item_name) 4631 { 4632 GList* list; 4633 4634 for (list = items; list != NULL; list = list->next) { 4635 NautilusMenu* menu; 4636 char *name; 4637 4638 g_object_get (list->data, "name", &name, NULL); 4639 if (strcmp (name, item_name) == 0) { 4640 g_free (name); 4641 return TRUE; 4642 } 4643 g_free (name); 4644 4645 menu = NULL; 4646 g_object_get (list->data, "menu", &menu, NULL); 4647 if (menu != NULL) { 4648 gboolean ret; 4649 GList* submenus; 4650 4651 submenus = nautilus_menu_get_items (menu); 4652 ret = search_in_menu_items (submenus, item_name); 4653 nautilus_menu_item_list_free (submenus); 4654 g_object_unref (menu); 4655 if (ret) { 4656 return TRUE; 4657 } 4658 } 4659 } 4660 return FALSE; 4661 } 4662 4663 static void 4664 extension_action_callback (GtkAction *action, 4665 gpointer callback_data) 4666 { 4667 ExtensionActionCallbackData *data; 4668 char *item_name; 4669 gboolean is_valid; 4670 GList *l; 4671 GList *items; 4672 4673 data = callback_data; 4674 4675 /* Make sure the selected menu item is valid for the final sniffed 4676 * mime type */ 4677 g_object_get (data->item, "name", &item_name, NULL); 4678 items = get_all_extension_menu_items (gtk_widget_get_toplevel (GTK_WIDGET (data->view)), 4679 data->selection); 4680 4681 is_valid = search_in_menu_items (items, item_name); 4682 4683 for (l = items; l != NULL; l = l->next) { 4684 g_object_unref (l->data); 4685 } 4686 g_list_free (items); 4687 4688 g_free (item_name); 4689 4690 if (is_valid) { 4691 nautilus_menu_item_activate (data->item); 4692 } 4693 } 4694 4695 static GdkPixbuf * 4696 get_menu_icon_for_file (NautilusFile *file) 4697 { 4698 NautilusIconInfo *info; 4699 GdkPixbuf *pixbuf; 4700 int size; 4701 4702 size = nautilus_get_icon_size_for_stock_size (GTK_ICON_SIZE_MENU); 4703 4704 info = nautilus_file_get_icon (file, size, 0); 4705 pixbuf = nautilus_icon_info_get_pixbuf_nodefault_at_size (info, size); 4706 g_object_unref (info); 4707 4708 return pixbuf; 4709 } 4710 4711 static GtkAction * 4712 add_extension_action_for_files (NautilusView *view, 4713 NautilusMenuItem *item, 4714 GList *files) 4715 { 4716 char *name, *label, *tip, *icon; 4717 gboolean sensitive, priority; 4718 GtkAction *action; 4719 GdkPixbuf *pixbuf; 4720 ExtensionActionCallbackData *data; 4721 4722 g_object_get (G_OBJECT (item), 4723 "name", &name, "label", &label, 4724 "tip", &tip, "icon", &icon, 4725 "sensitive", &sensitive, 4726 "priority", &priority, 4727 NULL); 4728 4729 action = gtk_action_new (name, 4730 label, 4731 tip, 4732 NULL); 4733 4734 if (icon != NULL) { 4735 pixbuf = nautilus_ui_get_menu_icon (icon); 4736 if (pixbuf != NULL) { 4737 gtk_action_set_gicon (action, G_ICON (pixbuf)); 4738 g_object_unref (pixbuf); 4739 } 4740 } 4741 4742 gtk_action_set_sensitive (action, sensitive); 4743 g_object_set (action, "is-important", priority, NULL); 4744 4745 data = g_new0 (ExtensionActionCallbackData, 1); 4746 data->item = g_object_ref (item); 4747 data->view = view; 4748 data->selection = nautilus_file_list_copy (files); 4749 data->action = action; 4750 4751 g_signal_connect_data (action, "activate", 4752 G_CALLBACK (extension_action_callback), 4753 data, 4754 (GClosureNotify)extension_action_callback_data_free, 0); 4755 4756 gtk_action_group_add_action (view->details->extensions_menu_action_group, 4757 GTK_ACTION (action)); 4758 g_object_unref (action); 4759 4760 g_free (name); 4761 g_free (label); 4762 g_free (tip); 4763 g_free (icon); 4764 4765 return action; 4766 } 4767 4768 static void 4769 add_extension_menu_items (NautilusView *view, 4770 GList *files, 4771 GList *menu_items, 4772 const char *subdirectory) 4773 { 4774 GtkUIManager *ui_manager; 4775 GList *l; 4776 4777 ui_manager = nautilus_view_get_ui_manager (view); 4778 4779 for (l = menu_items; l; l = l->next) { 4780 NautilusMenuItem *item; 4781 NautilusMenu *menu; 4782 GtkAction *action; 4783 char *path; 4784 4785 item = NAUTILUS_MENU_ITEM (l->data); 4786 4787 g_object_get (item, "menu", &menu, NULL); 4788 4789 action = add_extension_action_for_files (view, item, files); 4790 4791 path = g_build_path ("/", NAUTILUS_VIEW_POPUP_PATH_EXTENSION_ACTIONS, subdirectory, NULL); 4792 gtk_ui_manager_add_ui (ui_manager, 4793 view->details->extensions_menu_merge_id, 4794 path, 4795 gtk_action_get_name (action), 4796 gtk_action_get_name (action), 4797 (menu != NULL) ? GTK_UI_MANAGER_MENU : GTK_UI_MANAGER_MENUITEM, 4798 FALSE); 4799 g_free (path); 4800 4801 path = g_build_path ("/", NAUTILUS_VIEW_MENU_PATH_EXTENSION_ACTIONS_PLACEHOLDER, subdirectory, NULL); 4802 gtk_ui_manager_add_ui (ui_manager, 4803 view->details->extensions_menu_merge_id, 4804 path, 4805 gtk_action_get_name (action), 4806 gtk_action_get_name (action), 4807 (menu != NULL) ? GTK_UI_MANAGER_MENU : GTK_UI_MANAGER_MENUITEM, 4808 FALSE); 4809 g_free (path); 4810 4811 /* recursively fill the menu */ 4812 if (menu != NULL) { 4813 char *subdir; 4814 GList *children; 4815 4816 children = nautilus_menu_get_items (menu); 4817 4818 subdir = g_build_path ("/", subdirectory, gtk_action_get_name (action), NULL); 4819 add_extension_menu_items (view, 4820 files, 4821 children, 4822 subdir); 4823 4824 nautilus_menu_item_list_free (children); 4825 g_free (subdir); 4826 } 4827 } 4828 } 4829 4830 static void 4831 reset_extension_actions_menu (NautilusView *view, GList *selection) 4832 { 4833 GList *items; 4834 GtkUIManager *ui_manager; 4835 4836 /* Clear any previous inserted items in the extension actions placeholder */ 4837 ui_manager = nautilus_view_get_ui_manager (view); 4838 4839 nautilus_ui_unmerge_ui (ui_manager, 4840 &view->details->extensions_menu_merge_id, 4841 &view->details->extensions_menu_action_group); 4842 4843 nautilus_ui_prepare_merge_ui (ui_manager, 4844 "DirExtensionsMenuGroup", 4845 &view->details->extensions_menu_merge_id, 4846 &view->details->extensions_menu_action_group); 4847 4848 items = get_all_extension_menu_items (gtk_widget_get_toplevel (GTK_WIDGET (view)), 4849 selection); 4850 if (items != NULL) { 4851 add_extension_menu_items (view, selection, items, ""); 4852 4853 g_list_foreach (items, (GFunc) g_object_unref, NULL); 4854 g_list_free (items); 4855 } 4856 } 4857 4858 static char * 4859 change_to_view_directory (NautilusView *view) 4860 { 4861 char *path; 4862 char *old_path; 4863 4864 old_path = g_get_current_dir (); 4865 4866 path = get_view_directory (view); 4867 4868 /* FIXME: What to do about non-local directories? */ 4869 if (path != NULL) { 4870 g_chdir (path); 4871 } 4872 4873 g_free (path); 4874 4875 return old_path; 4876 } 4877 4878 static char ** 4879 get_file_names_as_parameter_array (GList *selection, 4880 NautilusDirectory *model) 4881 { 4882 NautilusFile *file; 4883 char **parameters; 4884 GList *node; 4885 GFile *file_location; 4886 GFile *model_location; 4887 int i; 4888 4889 if (model == NULL) { 4890 return NULL; 4891 } 4892 4893 parameters = g_new (char *, g_list_length (selection) + 1); 4894 4895 model_location = nautilus_directory_get_location (model); 4896 4897 for (node = selection, i = 0; node != NULL; node = node->next, i++) { 4898 file = NAUTILUS_FILE (node->data); 4899 4900 if (!nautilus_file_is_local (file)) { 4901 parameters[i] = NULL; 4902 g_strfreev (parameters); 4903 return NULL; 4904 } 4905 4906 file_location = nautilus_file_get_location (NAUTILUS_FILE (node->data)); 4907 parameters[i] = g_file_get_relative_path (model_location, file_location); 4908 if (parameters[i] == NULL) { 4909 parameters[i] = g_file_get_path (file_location); 4910 } 4911 g_object_unref (file_location); 4912 } 4913 4914 g_object_unref (model_location); 4915 4916 parameters[i] = NULL; 4917 return parameters; 4918 } 4919 4920 static char * 4921 get_file_paths_or_uris_as_newline_delimited_string (GList *selection, gboolean get_paths) 4922 { 4923 char *path; 4924 char *uri; 4925 char *result; 4926 NautilusDesktopLink *link; 4927 GString *expanding_string; 4928 GList *node; 4929 GFile *location; 4930 4931 expanding_string = g_string_new (""); 4932 for (node = selection; node != NULL; node = node->next) { 4933 uri = NULL; 4934 if (NAUTILUS_IS_DESKTOP_ICON_FILE (node->data)) { 4935 link = nautilus_desktop_icon_file_get_link (NAUTILUS_DESKTOP_ICON_FILE (node->data)); 4936 if (link != NULL) { 4937 location = nautilus_desktop_link_get_activation_location (link); 4938 uri = g_file_get_uri (location); 4939 g_object_unref (location); 4940 g_object_unref (G_OBJECT (link)); 4941 } 4942 } else { 4943 uri = nautilus_file_get_uri (NAUTILUS_FILE (node->data)); 4944 } 4945 if (uri == NULL) { 4946 continue; 4947 } 4948 4949 if (get_paths) { 4950 path = g_filename_from_uri (uri, NULL, NULL); 4951 if (path != NULL) { 4952 g_string_append (expanding_string, path); 4953 g_free (path); 4954 g_string_append (expanding_string, "\n"); 4955 } 4956 } else { 4957 g_string_append (expanding_string, uri); 4958 g_string_append (expanding_string, "\n"); 4959 } 4960 g_free (uri); 4961 } 4962 4963 result = expanding_string->str; 4964 g_string_free (expanding_string, FALSE); 4965 4966 return result; 4967 } 4968 4969 static char * 4970 get_file_paths_as_newline_delimited_string (GList *selection) 4971 { 4972 return get_file_paths_or_uris_as_newline_delimited_string (selection, TRUE); 4973 } 4974 4975 static char * 4976 get_file_uris_as_newline_delimited_string (GList *selection) 4977 { 4978 return get_file_paths_or_uris_as_newline_delimited_string (selection, FALSE); 4979 } 4980 4981 /* returns newly allocated strings for setting the environment variables */ 4982 static void 4983 get_strings_for_environment_variables (NautilusView *view, GList *selected_files, 4984 char **file_paths, char **uris, char **uri) 4985 { 4986 char *directory_uri; 4987 4988 /* We need to check that the directory uri starts with "file:" since 4989 * nautilus_directory_is_local returns FALSE for nfs. 4990 */ 4991 directory_uri = nautilus_directory_get_uri (view->details->model); 4992 if (g_str_has_prefix (directory_uri, "file:") || 4993 eel_uri_is_desktop (directory_uri) || 4994 eel_uri_is_trash (directory_uri)) { 4995 *file_paths = get_file_paths_as_newline_delimited_string (selected_files); 4996 } else { 4997 *file_paths = g_strdup (""); 4998 } 4999 g_free (directory_uri); 5000 5001 *uris = get_file_uris_as_newline_delimited_string (selected_files); 5002 5003 *uri = nautilus_directory_get_uri (view->details->model); 5004 if (eel_uri_is_desktop (*uri)) { 5005 g_free (*uri); 5006 *uri = nautilus_get_desktop_directory_uri (); 5007 } 5008 } 5009 5010 /* 5011 * Set up some environment variables that scripts can use 5012 * to take advantage of the current Nautilus state. 5013 */ 5014 static void 5015 set_script_environment_variables (NautilusView *view, GList *selected_files) 5016 { 5017 char *file_paths; 5018 char *uris; 5019 char *uri; 5020 char *geometry_string; 5021 5022 get_strings_for_environment_variables (view, selected_files, 5023 &file_paths, &uris, &uri); 5024 5025 g_setenv ("NAUTILUS_SCRIPT_SELECTED_FILE_PATHS", file_paths, TRUE); 5026 g_free (file_paths); 5027 5028 g_setenv ("NAUTILUS_SCRIPT_SELECTED_URIS", uris, TRUE); 5029 g_free (uris); 5030 5031 g_setenv ("NAUTILUS_SCRIPT_CURRENT_URI", uri, TRUE); 5032 g_free (uri); 5033 5034 geometry_string = eel_gtk_window_get_geometry_string 5035 (GTK_WINDOW (nautilus_view_get_containing_window (view))); 5036 g_setenv ("NAUTILUS_SCRIPT_WINDOW_GEOMETRY", geometry_string, TRUE); 5037 g_free (geometry_string); 5038 } 5039 5040 /* Unset all the special script environment variables. */ 5041 static void 5042 unset_script_environment_variables (void) 5043 { 5044 g_unsetenv ("NAUTILUS_SCRIPT_SELECTED_FILE_PATHS"); 5045 g_unsetenv ("NAUTILUS_SCRIPT_SELECTED_URIS"); 5046 g_unsetenv ("NAUTILUS_SCRIPT_CURRENT_URI"); 5047 g_unsetenv ("NAUTILUS_SCRIPT_WINDOW_GEOMETRY"); 5048 } 5049 5050 static void 5051 run_script_callback (GtkAction *action, gpointer callback_data) 5052 { 5053 ScriptLaunchParameters *launch_parameters; 5054 GdkScreen *screen; 5055 GList *selected_files; 5056 char *file_uri; 5057 char *local_file_path; 5058 char *quoted_path; 5059 char *old_working_dir; 5060 char **parameters; 5061 5062 launch_parameters = (ScriptLaunchParameters *) callback_data; 5063 5064 file_uri = nautilus_file_get_uri (launch_parameters->file); 5065 local_file_path = g_filename_from_uri (file_uri, NULL, NULL); 5066 g_assert (local_file_path != NULL); 5067 g_free (file_uri); 5068 5069 quoted_path = g_shell_quote (local_file_path); 5070 g_free (local_file_path); 5071 5072 old_working_dir = change_to_view_directory (launch_parameters->directory_view); 5073 5074 selected_files = nautilus_view_get_selection (launch_parameters->directory_view); 5075 set_script_environment_variables (launch_parameters->directory_view, selected_files); 5076 5077 parameters = get_file_names_as_parameter_array (selected_files, 5078 launch_parameters->directory_view->details->model); 5079 5080 screen = gtk_widget_get_screen (GTK_WIDGET (launch_parameters->directory_view)); 5081 5082 DEBUG ("run_script_callback, script_path=“%s” (omitting script parameters)", 5083 local_file_path); 5084 5085 nautilus_launch_application_from_command_array (screen, quoted_path, FALSE, 5086 (const char * const *) parameters); 5087 g_strfreev (parameters); 5088 5089 nautilus_file_list_free (selected_files); 5090 unset_script_environment_variables (); 5091 g_chdir (old_working_dir); 5092 g_free (old_working_dir); 5093 g_free (quoted_path); 5094 } 5095 5096 static void 5097 add_script_to_scripts_menus (NautilusView *directory_view, 5098 NautilusFile *file, 5099 const char *menu_path, 5100 const char *popup_path, 5101 const char *popup_bg_path) 5102 { 5103 ScriptLaunchParameters *launch_parameters; 5104 char *tip; 5105 char *name; 5106 char *uri; 5107 char *action_name; 5108 char *escaped_label; 5109 GdkPixbuf *pixbuf; 5110 GtkUIManager *ui_manager; 5111 GtkAction *action; 5112 5113 name = nautilus_file_get_display_name (file); 5114 uri = nautilus_file_get_uri (file); 5115 tip = g_strdup_printf (_("Run “%s” on any selected items"), name); 5116 5117 launch_parameters = script_launch_parameters_new (file, directory_view); 5118 5119 action_name = nautilus_escape_action_name (uri, "script_"); 5120 escaped_label = eel_str_double_underscores (name); 5121 5122 action = gtk_action_new (action_name, 5123 escaped_label, 5124 tip, 5125 NULL); 5126 5127 pixbuf = get_menu_icon_for_file (file); 5128 if (pixbuf != NULL) { 5129 gtk_action_set_gicon (action, G_ICON (pixbuf)); 5130 g_object_unref (pixbuf); 5131 } 5132 5133 g_signal_connect_data (action, "activate", 5134 G_CALLBACK (run_script_callback), 5135 launch_parameters, 5136 (GClosureNotify)script_launch_parameters_free, 0); 5137 5138 gtk_action_group_add_action_with_accel (directory_view->details->scripts_action_group, 5139 action, NULL); 5140 g_object_unref (action); 5141 5142 ui_manager = nautilus_view_get_ui_manager (directory_view); 5143 5144 gtk_ui_manager_add_ui (ui_manager, 5145 directory_view->details->scripts_merge_id, 5146 menu_path, 5147 action_name, 5148 action_name, 5149 GTK_UI_MANAGER_MENUITEM, 5150 FALSE); 5151 gtk_ui_manager_add_ui (ui_manager, 5152 directory_view->details->scripts_merge_id, 5153 popup_path, 5154 action_name, 5155 action_name, 5156 GTK_UI_MANAGER_MENUITEM, 5157 FALSE); 5158 gtk_ui_manager_add_ui (ui_manager, 5159 directory_view->details->scripts_merge_id, 5160 popup_bg_path, 5161 action_name, 5162 action_name, 5163 GTK_UI_MANAGER_MENUITEM, 5164 FALSE); 5165 5166 menu_item_show_image (ui_manager, menu_path, action_name); 5167 menu_item_show_image (ui_manager, popup_path, action_name); 5168 menu_item_show_image (ui_manager, popup_bg_path, action_name); 5169 5170 g_free (name); 5171 g_free (uri); 5172 g_free (tip); 5173 g_free (action_name); 5174 g_free (escaped_label); 5175 } 5176 5177 static void 5178 add_submenu_to_directory_menus (NautilusView *directory_view, 5179 GtkActionGroup *action_group, 5180 guint merge_id, 5181 NautilusFile *file, 5182 const char *menu_path, 5183 const char *popup_path, 5184 const char *popup_bg_path) 5185 { 5186 char *name; 5187 GdkPixbuf *pixbuf; 5188 char *uri; 5189 GtkUIManager *ui_manager; 5190 5191 ui_manager = nautilus_view_get_ui_manager (directory_view); 5192 uri = nautilus_file_get_uri (file); 5193 name = nautilus_file_get_display_name (file); 5194 pixbuf = get_menu_icon_for_file (file); 5195 add_submenu (ui_manager, action_group, merge_id, menu_path, uri, name, pixbuf, TRUE); 5196 add_submenu (ui_manager, action_group, merge_id, popup_path, uri, name, pixbuf, FALSE); 5197 add_submenu (ui_manager, action_group, merge_id, popup_bg_path, uri, name, pixbuf, FALSE); 5198 if (pixbuf) { 5199 g_object_unref (pixbuf); 5200 } 5201 g_free (name); 5202 g_free (uri); 5203 } 5204 5205 static gboolean 5206 directory_belongs_in_scripts_menu (const char *uri) 5207 { 5208 int num_levels; 5209 int i; 5210 5211 if (!g_str_has_prefix (uri, scripts_directory_uri)) { 5212 return FALSE; 5213 } 5214 5215 num_levels = 0; 5216 for (i = scripts_directory_uri_length; uri[i] != '\0'; i++) { 5217 if (uri[i] == '/') { 5218 num_levels++; 5219 } 5220 } 5221 5222 if (num_levels > MAX_MENU_LEVELS) { 5223 return FALSE; 5224 } 5225 5226 return TRUE; 5227 } 5228 5229 static gboolean 5230 update_directory_in_scripts_menu (NautilusView *view, NautilusDirectory *directory) 5231 { 5232 char *menu_path, *popup_path, *popup_bg_path; 5233 GList *file_list, *filtered, *node; 5234 gboolean any_scripts; 5235 NautilusFile *file; 5236 NautilusDirectory *dir; 5237 char *uri; 5238 char *escaped_path; 5239 5240 uri = nautilus_directory_get_uri (directory); 5241 escaped_path = escape_action_path (uri + scripts_directory_uri_length); 5242 g_free (uri); 5243 menu_path = g_strconcat (NAUTILUS_VIEW_MENU_PATH_SCRIPTS_PLACEHOLDER, 5244 escaped_path, 5245 NULL); 5246 popup_path = g_strconcat (NAUTILUS_VIEW_POPUP_PATH_SCRIPTS_PLACEHOLDER, 5247 escaped_path, 5248 NULL); 5249 popup_bg_path = g_strconcat (NAUTILUS_VIEW_POPUP_PATH_BACKGROUND_SCRIPTS_PLACEHOLDER, 5250 escaped_path, 5251 NULL); 5252 g_free (escaped_path); 5253 5254 file_list = nautilus_directory_get_file_list (directory); 5255 filtered = nautilus_file_list_filter_hidden (file_list, FALSE); 5256 nautilus_file_list_free (file_list); 5257 5258 file_list = nautilus_file_list_sort_by_display_name (filtered); 5259 5260 any_scripts = FALSE; 5261 for (node = file_list; node != NULL; node = node->next) { 5262 file = node->data; 5263 5264 if (nautilus_file_is_launchable (file)) { 5265 add_script_to_scripts_menus (view, file, menu_path, popup_path, popup_bg_path); 5266 any_scripts = TRUE; 5267 } else if (nautilus_file_is_directory (file)) { 5268 uri = nautilus_file_get_uri (file); 5269 if (directory_belongs_in_scripts_menu (uri)) { 5270 dir = nautilus_directory_get_by_uri (uri); 5271 add_directory_to_scripts_directory_list (view, dir); 5272 nautilus_directory_unref (dir); 5273 5274 add_submenu_to_directory_menus (view, 5275 view->details->scripts_action_group, 5276 view->details->scripts_merge_id, 5277 file, menu_path, popup_path, popup_bg_path); 5278 5279 any_scripts = TRUE; 5280 } 5281 g_free (uri); 5282 } 5283 } 5284 5285 nautilus_file_list_free (file_list); 5286 5287 g_free (popup_path); 5288 g_free (popup_bg_path); 5289 g_free (menu_path); 5290 5291 return any_scripts; 5292 } 5293 5294 static void 5295 update_scripts_menu (NautilusView *view) 5296 { 5297 gboolean any_scripts; 5298 GList *sorted_copy, *node; 5299 NautilusDirectory *directory; 5300 char *uri; 5301 GtkUIManager *ui_manager; 5302 GtkAction *action; 5303 5304 /* There is a race condition here. If we don't mark the scripts menu as 5305 valid before we begin our task then we can lose script menu updates that 5306 occur before we finish. */ 5307 view->details->scripts_invalid = FALSE; 5308 5309 ui_manager = nautilus_view_get_ui_manager (view); 5310 nautilus_ui_unmerge_ui (ui_manager, 5311 &view->details->scripts_merge_id, 5312 &view->details->scripts_action_group); 5313 5314 nautilus_ui_prepare_merge_ui (ui_manager, 5315 "ScriptsGroup", 5316 &view->details->scripts_merge_id, 5317 &view->details->scripts_action_group); 5318 5319 /* As we walk through the directories, remove any that no longer belong. */ 5320 any_scripts = FALSE; 5321 sorted_copy = nautilus_directory_list_sort_by_uri 5322 (nautilus_directory_list_copy (view->details->scripts_directory_list)); 5323 for (node = sorted_copy; node != NULL; node = node->next) { 5324 directory = node->data; 5325 5326 uri = nautilus_directory_get_uri (directory); 5327 if (!directory_belongs_in_scripts_menu (uri)) { 5328 remove_directory_from_scripts_directory_list (view, directory); 5329 } else if (update_directory_in_scripts_menu (view, directory)) { 5330 any_scripts = TRUE; 5331 } 5332 g_free (uri); 5333 } 5334 nautilus_directory_list_free (sorted_copy); 5335 5336 action = gtk_action_group_get_action (view->details->dir_action_group, NAUTILUS_ACTION_SCRIPTS); 5337 gtk_action_set_visible (action, any_scripts); 5338 } 5339 5340 static void 5341 create_template_callback (GtkAction *action, gpointer callback_data) 5342 { 5343 CreateTemplateParameters *parameters; 5344 5345 parameters = callback_data; 5346 5347 nautilus_view_new_file (parameters->directory_view, NULL, parameters->file); 5348 } 5349 5350 static void 5351 add_template_to_templates_menus (NautilusView *directory_view, 5352 NautilusFile *file, 5353 const char *menu_path, 5354 const char *popup_bg_path) 5355 { 5356 char *tmp, *tip, *uri, *name; 5357 char *escaped_label; 5358 GdkPixbuf *pixbuf; 5359 char *action_name; 5360 CreateTemplateParameters *parameters; 5361 GtkUIManager *ui_manager; 5362 GtkAction *action; 5363 5364 tmp = nautilus_file_get_display_name (file); 5365 name = eel_filename_strip_extension (tmp); 5366 g_free (tmp); 5367 5368 uri = nautilus_file_get_uri (file); 5369 tip = g_strdup_printf (_("Create a new document from template “%s”"), name); 5370 5371 action_name = nautilus_escape_action_name (uri, "template_"); 5372 escaped_label = eel_str_double_underscores (name); 5373 5374 parameters = create_template_parameters_new (file, directory_view); 5375 5376 action = gtk_action_new (action_name, 5377 escaped_label, 5378 tip, 5379 NULL); 5380 5381 pixbuf = get_menu_icon_for_file (file); 5382 if (pixbuf != NULL) { 5383 gtk_action_set_gicon (action, G_ICON (pixbuf)); 5384 g_object_unref (pixbuf); 5385 } 5386 5387 g_signal_connect_data (action, "activate", 5388 G_CALLBACK (create_template_callback), 5389 parameters, 5390 (GClosureNotify)create_templates_parameters_free, 0); 5391 5392 gtk_action_group_add_action (directory_view->details->templates_action_group, 5393 action); 5394 g_object_unref (action); 5395 5396 ui_manager = nautilus_view_get_ui_manager (directory_view); 5397 5398 gtk_ui_manager_add_ui (ui_manager, 5399 directory_view->details->templates_merge_id, 5400 menu_path, 5401 action_name, 5402 action_name, 5403 GTK_UI_MANAGER_MENUITEM, 5404 FALSE); 5405 5406 gtk_ui_manager_add_ui (ui_manager, 5407 directory_view->details->templates_merge_id, 5408 popup_bg_path, 5409 action_name, 5410 action_name, 5411 GTK_UI_MANAGER_MENUITEM, 5412 FALSE); 5413 5414 menu_item_show_image (ui_manager, menu_path, action_name); 5415 menu_item_show_image (ui_manager, popup_bg_path, action_name); 5416 5417 g_free (escaped_label); 5418 g_free (name); 5419 g_free (tip); 5420 g_free (uri); 5421 g_free (action_name); 5422 } 5423 5424 static void 5425 update_templates_directory (NautilusView *view) 5426 { 5427 NautilusDirectory *templates_directory; 5428 GList *node, *next; 5429 char *templates_uri; 5430 5431 for (node = view->details->templates_directory_list; node != NULL; node = next) { 5432 next = node->next; 5433 remove_directory_from_templates_directory_list (view, node->data); 5434 } 5435 5436 if (nautilus_should_use_templates_directory ()) { 5437 templates_uri = nautilus_get_templates_directory_uri (); 5438 templates_directory = nautilus_directory_get_by_uri (templates_uri); 5439 g_free (templates_uri); 5440 add_directory_to_templates_directory_list (view, templates_directory); 5441 nautilus_directory_unref (templates_directory); 5442 } 5443 } 5444 5445 static void 5446 user_dirs_changed (NautilusView *view) 5447 { 5448 update_templates_directory (view); 5449 view->details->templates_invalid = TRUE; 5450 schedule_update_menus (view); 5451 } 5452 5453 static gboolean 5454 directory_belongs_in_templates_menu (const char *templates_directory_uri, 5455 const char *uri) 5456 { 5457 int num_levels; 5458 int i; 5459 5460 if (templates_directory_uri == NULL) { 5461 return FALSE; 5462 } 5463 5464 if (!g_str_has_prefix (uri, templates_directory_uri)) { 5465 return FALSE; 5466 } 5467 5468 num_levels = 0; 5469 for (i = strlen (templates_directory_uri); uri[i] != '\0'; i++) { 5470 if (uri[i] == '/') { 5471 num_levels++; 5472 } 5473 } 5474 5475 if (num_levels > MAX_MENU_LEVELS) { 5476 return FALSE; 5477 } 5478 5479 return TRUE; 5480 } 5481 5482 static gboolean 5483 update_directory_in_templates_menu (NautilusView *view, 5484 const char *templates_directory_uri, 5485 NautilusDirectory *directory) 5486 { 5487 char *menu_path, *popup_bg_path; 5488 GList *file_list, *filtered, *node; 5489 gboolean any_templates; 5490 NautilusFile *file; 5491 NautilusDirectory *dir; 5492 char *escaped_path; 5493 char *uri; 5494 int num; 5495 5496 /* We know this directory belongs to the template dir, so it must exist */ 5497 g_assert (templates_directory_uri); 5498 5499 uri = nautilus_directory_get_uri (directory); 5500 escaped_path = escape_action_path (uri + strlen (templates_directory_uri)); 5501 g_free (uri); 5502 menu_path = g_strconcat (NAUTILUS_VIEW_MENU_PATH_NEW_DOCUMENTS_PLACEHOLDER, 5503 escaped_path, 5504 NULL); 5505 popup_bg_path = g_strconcat (NAUTILUS_VIEW_POPUP_PATH_BACKGROUND_NEW_DOCUMENTS_PLACEHOLDER, 5506 escaped_path, 5507 NULL); 5508 g_free (escaped_path); 5509 5510 file_list = nautilus_directory_get_file_list (directory); 5511 filtered = nautilus_file_list_filter_hidden (file_list, FALSE); 5512 nautilus_file_list_free (file_list); 5513 5514 file_list = nautilus_file_list_sort_by_display_name (filtered); 5515 5516 num = 0; 5517 any_templates = FALSE; 5518 for (node = file_list; num < TEMPLATE_LIMIT && node != NULL; node = node->next, num++) { 5519 file = node->data; 5520 5521 if (nautilus_file_is_directory (file)) { 5522 uri = nautilus_file_get_uri (file); 5523 if (directory_belongs_in_templates_menu (templates_directory_uri, uri)) { 5524 dir = nautilus_directory_get_by_uri (uri); 5525 add_directory_to_templates_directory_list (view, dir); 5526 nautilus_directory_unref (dir); 5527 5528 add_submenu_to_directory_menus (view, 5529 view->details->templates_action_group, 5530 view->details->templates_merge_id, 5531 file, menu_path, NULL, popup_bg_path); 5532 5533 any_templates = TRUE; 5534 } 5535 g_free (uri); 5536 } else if (nautilus_file_can_read (file)) { 5537 add_template_to_templates_menus (view, file, menu_path, popup_bg_path); 5538 any_templates = TRUE; 5539 } 5540 } 5541 5542 nautilus_file_list_free (file_list); 5543 5544 g_free (popup_bg_path); 5545 g_free (menu_path); 5546 5547 return any_templates; 5548 } 5549 5550 5551 5552 static void 5553 update_templates_menu (NautilusView *view) 5554 { 5555 gboolean any_templates; 5556 GList *sorted_copy, *node; 5557 NautilusDirectory *directory; 5558 GtkUIManager *ui_manager; 5559 char *uri; 5560 char *templates_directory_uri; 5561 5562 if (nautilus_should_use_templates_directory ()) { 5563 templates_directory_uri = nautilus_get_templates_directory_uri (); 5564 } else { 5565 templates_directory_uri = NULL; 5566 } 5567 5568 /* There is a race condition here. If we don't mark the scripts menu as 5569 valid before we begin our task then we can lose template menu updates that 5570 occur before we finish. */ 5571 view->details->templates_invalid = FALSE; 5572 5573 ui_manager = nautilus_view_get_ui_manager (view); 5574 nautilus_ui_unmerge_ui (ui_manager, 5575 &view->details->templates_merge_id, 5576 &view->details->templates_action_group); 5577 5578 nautilus_ui_prepare_merge_ui (ui_manager, 5579 "TemplatesGroup", 5580 &view->details->templates_merge_id, 5581 &view->details->templates_action_group); 5582 5583 /* As we walk through the directories, remove any that no longer belong. */ 5584 any_templates = FALSE; 5585 sorted_copy = nautilus_directory_list_sort_by_uri 5586 (nautilus_directory_list_copy (view->details->templates_directory_list)); 5587 for (node = sorted_copy; node != NULL; node = node->next) { 5588 directory = node->data; 5589 5590 uri = nautilus_directory_get_uri (directory); 5591 if (!directory_belongs_in_templates_menu (templates_directory_uri, uri)) { 5592 remove_directory_from_templates_directory_list (view, directory); 5593 } else if (update_directory_in_templates_menu (view, 5594 templates_directory_uri, 5595 directory)) { 5596 any_templates = TRUE; 5597 } 5598 g_free (uri); 5599 } 5600 nautilus_directory_list_free (sorted_copy); 5601 5602 view->details->templates_present = any_templates; 5603 5604 g_free (templates_directory_uri); 5605 } 5606 5607 5608 static void 5609 action_open_scripts_folder_callback (GtkAction *action, 5610 gpointer callback_data) 5611 { 5612 NautilusView *view; 5613 static GFile *location = NULL; 5614 5615 if (location == NULL) { 5616 location = g_file_new_for_uri (scripts_directory_uri); 5617 } 5618 5619 view = NAUTILUS_VIEW (callback_data); 5620 nautilus_window_slot_open_location (view->details->slot, location, 0); 5621 } 5622 5623 static GtkMenu * 5624 create_popup_menu (NautilusView *view, const char *popup_path) 5625 { 5626 GtkWidget *menu; 5627 5628 menu = gtk_ui_manager_get_widget (nautilus_view_get_ui_manager (view), 5629 popup_path); 5630 gtk_menu_set_screen (GTK_MENU (menu), 5631 gtk_widget_get_screen (GTK_WIDGET (view))); 5632 gtk_widget_show (GTK_WIDGET (menu)); 5633 5634 return GTK_MENU (menu); 5635 } 5636 5637 typedef struct _CopyCallbackData { 5638 NautilusView *view; 5639 GtkFileChooser *chooser; 5640 GHashTable *locations; 5641 GList *selection; 5642 gboolean is_move; 5643 } CopyCallbackData; 5644 5645 static void 5646 add_bookmark_for_uri (CopyCallbackData *data, 5647 const char *uri) 5648 { 5649 GError *error = NULL; 5650 int count; 5651 5652 count = GPOINTER_TO_INT (g_hash_table_lookup (data->locations, uri)); 5653 if (count == 0) { 5654 gtk_file_chooser_add_shortcut_folder_uri (data->chooser, 5655 uri, 5656 &error); 5657 if (error != NULL) { 5658 DEBUG ("Unable to add location '%s' to file selector: %s", uri, error->message); 5659 g_clear_error (&error); 5660 } 5661 } 5662 g_hash_table_replace (data->locations, g_strdup (uri), GINT_TO_POINTER (count + 1)); 5663 } 5664 5665 static void 5666 remove_bookmark_for_uri (CopyCallbackData *data, 5667 const char *uri) 5668 { 5669 GError *error = NULL; 5670 int count; 5671 5672 count = GPOINTER_TO_INT (g_hash_table_lookup (data->locations, uri)); 5673 if (count == 1) { 5674 gtk_file_chooser_remove_shortcut_folder_uri (data->chooser, 5675 uri, 5676 &error); 5677 if (error != NULL) { 5678 DEBUG ("Unable to remove location '%s' to file selector: %s", uri, error->message); 5679 g_clear_error (&error); 5680 } 5681 g_hash_table_remove (data->locations, uri); 5682 } else { 5683 g_hash_table_replace (data->locations, g_strdup (uri), GINT_TO_POINTER (count - 1)); 5684 } 5685 } 5686 5687 static void 5688 add_bookmarks_for_window_slot (CopyCallbackData *data, 5689 NautilusWindowSlot *slot) 5690 { 5691 char *uri; 5692 5693 uri = nautilus_window_slot_get_location_uri (slot); 5694 if (uri != NULL) { 5695 add_bookmark_for_uri (data, uri); 5696 } 5697 g_free (uri); 5698 } 5699 5700 static void 5701 remove_bookmarks_for_window_slot (CopyCallbackData *data, 5702 NautilusWindowSlot *slot) 5703 { 5704 char *uri; 5705 5706 uri = nautilus_window_slot_get_location_uri (slot); 5707 if (uri != NULL) { 5708 remove_bookmark_for_uri (data, uri); 5709 } 5710 g_free (uri); 5711 } 5712 5713 static void 5714 on_slot_location_changed (NautilusWindowSlot *slot, 5715 const char *from, 5716 const char *to, 5717 CopyCallbackData *data) 5718 { 5719 if (from != NULL) { 5720 remove_bookmark_for_uri (data, from); 5721 } 5722 5723 if (to != NULL) { 5724 add_bookmark_for_uri (data, to); 5725 } 5726 } 5727 5728 static void 5729 on_slot_added (NautilusWindow *window, 5730 NautilusWindowSlot *slot, 5731 CopyCallbackData *data) 5732 { 5733 add_bookmarks_for_window_slot (data, slot); 5734 g_signal_connect (slot, "location-changed", G_CALLBACK (on_slot_location_changed), data); 5735 } 5736 5737 static void 5738 on_slot_removed (NautilusWindow *window, 5739 NautilusWindowSlot *slot, 5740 CopyCallbackData *data) 5741 { 5742 remove_bookmarks_for_window_slot (data, slot); 5743 g_signal_handlers_disconnect_by_func (slot, 5744 G_CALLBACK (on_slot_location_changed), 5745 data); 5746 } 5747 5748 static void 5749 add_bookmarks_for_window (CopyCallbackData *data, 5750 NautilusWindow *window) 5751 { 5752 GList *s; 5753 GList *slots; 5754 5755 slots = nautilus_window_get_slots (window); 5756 for (s = slots; s != NULL; s = s->next) { 5757 NautilusWindowSlot *slot = s->data; 5758 add_bookmarks_for_window_slot (data, slot); 5759 g_signal_connect (slot, "location-changed", G_CALLBACK (on_slot_location_changed), data); 5760 } 5761 g_signal_connect (window, "slot-added", G_CALLBACK (on_slot_added), data); 5762 g_signal_connect (window, "slot-removed", G_CALLBACK (on_slot_removed), data); 5763 } 5764 5765 static void 5766 remove_bookmarks_for_window (CopyCallbackData *data, 5767 NautilusWindow *window) 5768 { 5769 GList *s; 5770 GList *slots; 5771 5772 slots = nautilus_window_get_slots (window); 5773 for (s = slots; s != NULL; s = s->next) { 5774 NautilusWindowSlot *slot = s->data; 5775 remove_bookmarks_for_window_slot (data, slot); 5776 g_signal_handlers_disconnect_by_func (slot, 5777 G_CALLBACK (on_slot_location_changed), 5778 data); 5779 } 5780 g_signal_handlers_disconnect_by_func (window, 5781 G_CALLBACK (on_slot_added), 5782 data); 5783 g_signal_handlers_disconnect_by_func (window, 5784 G_CALLBACK (on_slot_removed), 5785 data); 5786 } 5787 5788 static void 5789 on_app_window_added (GtkApplication *application, 5790 GtkWindow *window, 5791 CopyCallbackData *data) 5792 { 5793 add_bookmarks_for_window (data, NAUTILUS_WINDOW (window)); 5794 } 5795 5796 static void 5797 on_app_window_removed (GtkApplication *application, 5798 GtkWindow *window, 5799 CopyCallbackData *data) 5800 { 5801 remove_bookmarks_for_window (data, NAUTILUS_WINDOW (window)); 5802 } 5803 5804 static void 5805 copy_data_free (CopyCallbackData *data) 5806 { 5807 GtkApplication *application; 5808 GList *windows; 5809 GList *w; 5810 5811 application = GTK_APPLICATION (g_application_get_default ()); 5812 g_signal_handlers_disconnect_by_func (application, 5813 G_CALLBACK (on_app_window_added), 5814 data); 5815 g_signal_handlers_disconnect_by_func (application, 5816 G_CALLBACK (on_app_window_removed), 5817 data); 5818 5819 windows = gtk_application_get_windows (application); 5820 for (w = windows; w != NULL; w = w->next) { 5821 NautilusWindow *window = w->data; 5822 GList *slots; 5823 GList *s; 5824 5825 slots = nautilus_window_get_slots (window); 5826 for (s = slots; s != NULL; s = s->next) { 5827 NautilusWindowSlot *slot = s->data; 5828 g_signal_handlers_disconnect_by_func (slot, G_CALLBACK (on_slot_location_changed), data); 5829 } 5830 g_signal_handlers_disconnect_by_func (window, G_CALLBACK (on_slot_added), data); 5831 g_signal_handlers_disconnect_by_func (window, G_CALLBACK (on_slot_removed), data); 5832 } 5833 5834 nautilus_file_list_free (data->selection); 5835 g_hash_table_destroy (data->locations); 5836 g_free (data); 5837 } 5838 5839 static gboolean 5840 uri_is_parent_of_selection (GList *selection, 5841 const char *uri) 5842 { 5843 gboolean found; 5844 GList *l; 5845 GFile *file; 5846 5847 found = FALSE; 5848 5849 file = g_file_new_for_uri (uri); 5850 for (l = selection; !found && l != NULL; l = l->next) { 5851 GFile *parent; 5852 parent = nautilus_file_get_parent_location (l->data); 5853 found = g_file_equal (file, parent); 5854 g_object_unref (parent); 5855 } 5856 g_object_unref (file); 5857 return found; 5858 } 5859 5860 static void 5861 on_destination_dialog_folder_changed (GtkFileChooser *chooser, 5862 gpointer user_data) 5863 { 5864 CopyCallbackData *copy_data = user_data; 5865 char *uri; 5866 gboolean found; 5867 5868 uri = gtk_file_chooser_get_current_folder_uri (chooser); 5869 found = uri_is_parent_of_selection (copy_data->selection, uri); 5870 gtk_dialog_set_response_sensitive (GTK_DIALOG (chooser), GTK_RESPONSE_OK, !found); 5871 g_free (uri); 5872 } 5873 5874 static void 5875 on_destination_dialog_response (GtkDialog *dialog, 5876 gint response_id, 5877 gpointer user_data) 5878 { 5879 CopyCallbackData *copy_data = user_data; 5880 5881 if (response_id == GTK_RESPONSE_OK) { 5882 char *target_uri; 5883 GList *uris, *l; 5884 5885 target_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog)); 5886 5887 uris = NULL; 5888 for (l = copy_data->selection; l != NULL; l = l->next) { 5889 uris = g_list_prepend (uris, 5890 nautilus_file_get_uri ((NautilusFile *) l->data)); 5891 } 5892 uris = g_list_reverse (uris); 5893 5894 nautilus_view_move_copy_items (copy_data->view, uris, NULL, target_uri, 5895 copy_data->is_move ? GDK_ACTION_MOVE : GDK_ACTION_COPY, 5896 0, 0); 5897 5898 g_list_free_full (uris, g_free); 5899 g_free (target_uri); 5900 } 5901 5902 copy_data_free (copy_data); 5903 gtk_widget_destroy (GTK_WIDGET (dialog)); 5904 } 5905 5906 static gboolean 5907 destination_dialog_filter_cb (const GtkFileFilterInfo *filter_info, 5908 gpointer user_data) 5909 { 5910 GList *selection = user_data; 5911 GList *l; 5912 5913 for (l = selection; l != NULL; l = l->next) { 5914 char *uri; 5915 uri = nautilus_file_get_uri (l->data); 5916 if (strcmp (uri, filter_info->uri) == 0) { 5917 g_free (uri); 5918 return FALSE; 5919 } 5920 g_free (uri); 5921 } 5922 5923 return TRUE; 5924 } 5925 5926 static GList * 5927 get_selected_folders (GList *selection) 5928 { 5929 GList *folders; 5930 GList *l; 5931 5932 folders = NULL; 5933 for (l = selection; l != NULL; l = l->next) { 5934 if (nautilus_file_is_directory (l->data)) 5935 folders = g_list_prepend (folders, nautilus_file_ref (l->data)); 5936 } 5937 return g_list_reverse (folders); 5938 } 5939 5940 static void 5941 add_window_location_bookmarks (CopyCallbackData *data) 5942 { 5943 GtkApplication *application; 5944 GList *windows; 5945 GList *w; 5946 5947 application = GTK_APPLICATION (g_application_get_default ()); 5948 windows = gtk_application_get_windows (application); 5949 g_signal_connect (application, "window-added", G_CALLBACK (on_app_window_added), data); 5950 g_signal_connect (application, "window-removed", G_CALLBACK (on_app_window_removed), data); 5951 5952 for (w = windows; w != NULL; w = w->next) { 5953 NautilusWindow *window = w->data; 5954 add_bookmarks_for_window (data, window); 5955 } 5956 } 5957 5958 static void 5959 copy_or_move_selection (NautilusView *view, 5960 gboolean is_move) 5961 { 5962 GtkWidget *dialog; 5963 char *uri; 5964 CopyCallbackData *copy_data; 5965 GList *selection; 5966 5967 selection = nautilus_view_get_selection_for_file_transfer (view); 5968 5969 dialog = gtk_file_chooser_dialog_new (_("Select Destination"), 5970 GTK_WINDOW (nautilus_view_get_window (view)), 5971 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, 5972 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, 5973 _("_Select"), GTK_RESPONSE_OK, 5974 NULL); 5975 gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE); 5976 gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); 5977 5978 copy_data = g_new0 (CopyCallbackData, 1); 5979 copy_data->view = view; 5980 copy_data->selection = selection; 5981 copy_data->is_move = is_move; 5982 copy_data->chooser = GTK_FILE_CHOOSER (dialog); 5983 copy_data->locations = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); 5984 5985 add_window_location_bookmarks (copy_data); 5986 5987 if (selection != NULL) { 5988 GtkFileFilter *filter; 5989 GList *folders; 5990 5991 folders = get_selected_folders (selection); 5992 5993 filter = gtk_file_filter_new (); 5994 gtk_file_filter_add_custom (filter, 5995 GTK_FILE_FILTER_URI, 5996 destination_dialog_filter_cb, 5997 folders, 5998 (GDestroyNotify)nautilus_file_list_free); 5999 gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), filter); 6000 } 6001 6002 uri = nautilus_directory_get_uri (view->details->model); 6003 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dialog), uri); 6004 g_free (uri); 6005 g_signal_connect (dialog, "current-folder-changed", 6006 G_CALLBACK (on_destination_dialog_folder_changed), 6007 copy_data); 6008 g_signal_connect (dialog, "response", 6009 G_CALLBACK (on_destination_dialog_response), 6010 copy_data); 6011 6012 gtk_widget_show_all (dialog); 6013 } 6014 6015 static void 6016 copy_or_cut_files (NautilusView *view, 6017 GList *clipboard_contents, 6018 gboolean cut) 6019 { 6020 NautilusClipboardInfo info; 6021 GtkTargetList *target_list; 6022 GtkTargetEntry *targets; 6023 int n_targets; 6024 6025 info.files = clipboard_contents; 6026 info.cut = cut; 6027 6028 target_list = gtk_target_list_new (NULL, 0); 6029 gtk_target_list_add (target_list, copied_files_atom, 0, 0); 6030 gtk_target_list_add_uri_targets (target_list, 0); 6031 gtk_target_list_add_text_targets (target_list, 0); 6032 6033 targets = gtk_target_table_new_from_list (target_list, &n_targets); 6034 gtk_target_list_unref (target_list); 6035 6036 gtk_clipboard_set_with_data (nautilus_clipboard_get (GTK_WIDGET (view)), 6037 targets, n_targets, 6038 nautilus_get_clipboard_callback, nautilus_clear_clipboard_callback, 6039 NULL); 6040 gtk_target_table_free (targets, n_targets); 6041 6042 nautilus_clipboard_monitor_set_clipboard_info (nautilus_clipboard_monitor_get (), &info); 6043 } 6044 6045 static void 6046 action_copy_files_callback (GtkAction *action, 6047 gpointer callback_data) 6048 { 6049 NautilusView *view; 6050 GList *selection; 6051 6052 view = NAUTILUS_VIEW (callback_data); 6053 6054 selection = nautilus_view_get_selection_for_file_transfer (view); 6055 copy_or_cut_files (view, selection, FALSE); 6056 nautilus_file_list_free (selection); 6057 } 6058 6059 static void 6060 action_cut_files_callback (GtkAction *action, 6061 gpointer callback_data) 6062 { 6063 NautilusView *view; 6064 GList *selection; 6065 6066 view = NAUTILUS_VIEW (callback_data); 6067 6068 selection = nautilus_view_get_selection_for_file_transfer (view); 6069 copy_or_cut_files (view, selection, TRUE); 6070 nautilus_file_list_free (selection); 6071 } 6072 6073 static void 6074 action_copy_to_callback (GtkAction *action, 6075 gpointer callback_data) 6076 { 6077 NautilusView *view; 6078 6079 view = NAUTILUS_VIEW (callback_data); 6080 copy_or_move_selection (view, FALSE); 6081 } 6082 6083 static void 6084 action_move_to_callback (GtkAction *action, 6085 gpointer callback_data) 6086 { 6087 NautilusView *view; 6088 6089 view = NAUTILUS_VIEW (callback_data); 6090 copy_or_move_selection (view, TRUE); 6091 } 6092 6093 static void 6094 paste_clipboard_data (NautilusView *view, 6095 GtkSelectionData *selection_data, 6096 char *destination_uri) 6097 { 6098 gboolean cut; 6099 GList *item_uris; 6100 6101 cut = FALSE; 6102 item_uris = nautilus_clipboard_get_uri_list_from_selection_data (selection_data, &cut, 6103 copied_files_atom); 6104 6105 if (item_uris != NULL && destination_uri != NULL) { 6106 nautilus_view_move_copy_items (view, item_uris, NULL, destination_uri, 6107 cut ? GDK_ACTION_MOVE : GDK_ACTION_COPY, 6108 0, 0); 6109 6110 /* If items are cut then remove from clipboard */ 6111 if (cut) { 6112 gtk_clipboard_clear (nautilus_clipboard_get (GTK_WIDGET (view))); 6113 } 6114 6115 g_list_free_full (item_uris, g_free); 6116 } 6117 } 6118 6119 static void 6120 paste_clipboard_received_callback (GtkClipboard *clipboard, 6121 GtkSelectionData *selection_data, 6122 gpointer data) 6123 { 6124 NautilusView *view; 6125 char *view_uri; 6126 6127 view = NAUTILUS_VIEW (data); 6128 6129 view_uri = nautilus_view_get_backing_uri (view); 6130 6131 if (view->details->slot != NULL) { 6132 paste_clipboard_data (view, selection_data, view_uri); 6133 } 6134 6135 g_free (view_uri); 6136 6137 g_object_unref (view); 6138 } 6139 6140 typedef struct { 6141 NautilusView *view; 6142 NautilusFile *target; 6143 } PasteIntoData; 6144 6145 static void 6146 paste_into_clipboard_received_callback (GtkClipboard *clipboard, 6147 GtkSelectionData *selection_data, 6148 gpointer callback_data) 6149 { 6150 PasteIntoData *data; 6151 NautilusView *view; 6152 char *directory_uri; 6153 6154 data = (PasteIntoData *) callback_data; 6155 6156 view = NAUTILUS_VIEW (data->view); 6157 6158 if (view->details->slot != NULL) { 6159 directory_uri = nautilus_file_get_activation_uri (data->target); 6160 6161 paste_clipboard_data (view, selection_data, directory_uri); 6162 6163 g_free (directory_uri); 6164 } 6165 6166 g_object_unref (view); 6167 nautilus_file_unref (data->target); 6168 g_free (data); 6169 } 6170 6171 static void 6172 action_paste_files_callback (GtkAction *action, 6173 gpointer callback_data) 6174 { 6175 NautilusView *view; 6176 6177 view = NAUTILUS_VIEW (callback_data); 6178 6179 g_object_ref (view); 6180 gtk_clipboard_request_contents (nautilus_clipboard_get (GTK_WIDGET (view)), 6181 copied_files_atom, 6182 paste_clipboard_received_callback, 6183 view); 6184 } 6185 6186 static void 6187 paste_into (NautilusView *view, 6188 NautilusFile *target) 6189 { 6190 PasteIntoData *data; 6191 6192 g_assert (NAUTILUS_IS_VIEW (view)); 6193 g_assert (NAUTILUS_IS_FILE (target)); 6194 6195 data = g_new (PasteIntoData, 1); 6196 6197 data->view = g_object_ref (view); 6198 data->target = nautilus_file_ref (target); 6199 6200 gtk_clipboard_request_contents (nautilus_clipboard_get (GTK_WIDGET (view)), 6201 copied_files_atom, 6202 paste_into_clipboard_received_callback, 6203 data); 6204 } 6205 6206 static void 6207 action_paste_files_into_callback (GtkAction *action, 6208 gpointer callback_data) 6209 { 6210 NautilusView *view; 6211 GList *selection; 6212 6213 view = NAUTILUS_VIEW (callback_data); 6214 selection = nautilus_view_get_selection (view); 6215 if (selection != NULL) { 6216 paste_into (view, NAUTILUS_FILE (selection->data)); 6217 nautilus_file_list_free (selection); 6218 } 6219 6220 } 6221 6222 static void 6223 invoke_external_bulk_rename_utility (NautilusView *view, 6224 GList *selection) 6225 { 6226 GString *cmd; 6227 char *parameter; 6228 char *quoted_parameter; 6229 char *bulk_rename_tool; 6230 GList *walk; 6231 NautilusFile *file; 6232 6233 /* assemble command line */ 6234 bulk_rename_tool = get_bulk_rename_tool (); 6235 cmd = g_string_new (bulk_rename_tool); 6236 g_free (bulk_rename_tool); 6237 for (walk = selection; walk; walk = walk->next) { 6238 file = walk->data; 6239 parameter = nautilus_file_get_uri (file); 6240 quoted_parameter = g_shell_quote (parameter); 6241 g_free (parameter); 6242 cmd = g_string_append (cmd, " "); 6243 cmd = g_string_append (cmd, quoted_parameter); 6244 g_free (quoted_parameter); 6245 } 6246 6247 /* spawning and error handling */ 6248 nautilus_launch_application_from_command (gtk_widget_get_screen (GTK_WIDGET (view)), 6249 cmd->str, FALSE, NULL); 6250 g_string_free (cmd, TRUE); 6251 } 6252 6253 static void 6254 real_action_undo (NautilusView *view) 6255 { 6256 GtkWidget *toplevel; 6257 6258 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (view)); 6259 nautilus_file_undo_manager_undo (GTK_WINDOW (toplevel)); 6260 } 6261 6262 static void 6263 real_action_redo (NautilusView *view) 6264 { 6265 GtkWidget *toplevel; 6266 6267 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (view)); 6268 nautilus_file_undo_manager_redo (GTK_WINDOW (toplevel)); 6269 } 6270 6271 static void 6272 action_undo_callback (GtkAction *action, 6273 gpointer callback_data) 6274 { 6275 real_action_undo (NAUTILUS_VIEW (callback_data)); 6276 } 6277 6278 static void 6279 action_redo_callback (GtkAction *action, 6280 gpointer callback_data) 6281 { 6282 real_action_redo (NAUTILUS_VIEW (callback_data)); 6283 } 6284 6285 static void 6286 real_action_rename (NautilusView *view, 6287 gboolean select_all) 6288 { 6289 NautilusFile *file; 6290 GList *selection; 6291 6292 g_assert (NAUTILUS_IS_VIEW (view)); 6293 6294 selection = nautilus_view_get_selection (view); 6295 6296 if (selection_not_empty_in_menu_callback (view, selection)) { 6297 /* If there is more than one file selected, invoke a batch renamer */ 6298 if (selection->next != NULL) { 6299 if (have_bulk_rename_tool ()) { 6300 invoke_external_bulk_rename_utility (view, selection); 6301 } 6302 } else { 6303 file = NAUTILUS_FILE (selection->data); 6304 if (!select_all) { 6305 /* directories don't have a file extension, so 6306 * they are always pre-selected as a whole */ 6307 select_all = nautilus_file_is_directory (file); 6308 } 6309 NAUTILUS_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->start_renaming_file (view, file, select_all); 6310 } 6311 } 6312 6313 nautilus_file_list_free (selection); 6314 } 6315 6316 static void 6317 action_rename_callback (GtkAction *action, 6318 gpointer callback_data) 6319 { 6320 real_action_rename (NAUTILUS_VIEW (callback_data), FALSE); 6321 } 6322 6323 static void 6324 action_rename_select_all_callback (GtkAction *action, 6325 gpointer callback_data) 6326 { 6327 real_action_rename (NAUTILUS_VIEW (callback_data), TRUE); 6328 } 6329 6330 #define BG_KEY_DRAW_BACKGROUND "draw-background" 6331 #define BG_KEY_PRIMARY_COLOR "primary-color" 6332 #define BG_KEY_SECONDARY_COLOR "secondary-color" 6333 #define BG_KEY_COLOR_TYPE "color-shading-type" 6334 #define BG_KEY_PICTURE_PLACEMENT "picture-options" 6335 #define BG_KEY_PICTURE_URI "picture-uri" 6336 6337 static void 6338 set_uri_as_wallpaper (const char *uri) 6339 { 6340 GSettings *settings; 6341 6342 settings = gnome_background_preferences; 6343 6344 g_settings_delay (settings); 6345 6346 if (uri == NULL) 6347 uri = ""; 6348 6349 g_settings_set_boolean (settings, BG_KEY_DRAW_BACKGROUND, TRUE); 6350 g_settings_set_string (settings, BG_KEY_PICTURE_URI, uri); 6351 g_settings_set_string (settings, BG_KEY_PRIMARY_COLOR, "#000000"); 6352 g_settings_set_string (settings, BG_KEY_SECONDARY_COLOR, "#000000"); 6353 g_settings_set_enum (settings, BG_KEY_COLOR_TYPE, G_DESKTOP_BACKGROUND_SHADING_SOLID); 6354 g_settings_set_enum (settings, BG_KEY_PICTURE_PLACEMENT, G_DESKTOP_BACKGROUND_STYLE_ZOOM); 6355 6356 /* Apply changes atomically. */ 6357 g_settings_apply (settings); 6358 } 6359 6360 static void 6361 wallpaper_copy_done_callback (GHashTable *debuting_files, 6362 gboolean success, 6363 gpointer data) 6364 { 6365 GHashTableIter iter; 6366 gpointer key, value; 6367 6368 g_hash_table_iter_init (&iter, debuting_files); 6369 while (g_hash_table_iter_next (&iter, &key, &value)) { 6370 char *uri; 6371 uri = g_file_get_uri (G_FILE (key)); 6372 set_uri_as_wallpaper (uri); 6373 g_free (uri); 6374 break; 6375 } 6376 } 6377 6378 static gboolean 6379 can_set_wallpaper (GList *selection) 6380 { 6381 NautilusFile *file; 6382 6383 if (g_list_length (selection) != 1) { 6384 return FALSE; 6385 } 6386 6387 file = NAUTILUS_FILE (selection->data); 6388 if (!nautilus_file_is_mime_type (file, "image/*")) { 6389 return FALSE; 6390 } 6391 6392 /* FIXME: check file size? */ 6393 6394 return TRUE; 6395 } 6396 6397 static void 6398 action_set_as_wallpaper_callback (GtkAction *action, 6399 NautilusView *view) 6400 { 6401 GList *selection; 6402 6403 /* Copy the item to Pictures/Wallpaper since it may be 6404 remote. Then set it as the current wallpaper. */ 6405 6406 g_assert (NAUTILUS_IS_VIEW (view)); 6407 6408 selection = nautilus_view_get_selection (view); 6409 6410 if (can_set_wallpaper (selection) 6411 && selection_not_empty_in_menu_callback (view, selection)) { 6412 NautilusFile *file; 6413 char *target_uri; 6414 GList *uris; 6415 GFile *parent; 6416 GFile *target; 6417 6418 file = NAUTILUS_FILE (selection->data); 6419 6420 parent = g_file_new_for_path (g_get_user_special_dir (G_USER_DIRECTORY_PICTURES)); 6421 target = g_file_get_child (parent, "Wallpapers"); 6422 g_object_unref (parent); 6423 g_file_make_directory_with_parents (target, NULL, NULL); 6424 target_uri = g_file_get_uri (target); 6425 g_object_unref (target); 6426 uris = g_list_prepend (NULL, nautilus_file_get_uri (file)); 6427 nautilus_file_operations_copy_move (uris, 6428 NULL, 6429 target_uri, 6430 GDK_ACTION_COPY, 6431 GTK_WIDGET (view), 6432 wallpaper_copy_done_callback, 6433 NULL); 6434 g_free (target_uri); 6435 g_list_free_full (uris, g_free); 6436 } 6437 6438 nautilus_file_list_free (selection); 6439 } 6440 6441 static void 6442 file_mount_callback (NautilusFile *file, 6443 GFile *result_location, 6444 GError *error, 6445 gpointer callback_data) 6446 { 6447 NautilusView *view; 6448 6449 view = NAUTILUS_VIEW (callback_data); 6450 6451 if (error != NULL && 6452 (error->domain != G_IO_ERROR || 6453 (error->code != G_IO_ERROR_CANCELLED && 6454 error->code != G_IO_ERROR_FAILED_HANDLED && 6455 error->code != G_IO_ERROR_ALREADY_MOUNTED))) { 6456 char *text; 6457 char *name; 6458 name = nautilus_file_get_display_name (file); 6459 /* Translators: %s is a file name formatted for display */ 6460 text = g_strdup_printf (_("Unable to access “%s”"), name); 6461 eel_show_error_dialog (text, error->message, 6462 GTK_WINDOW (nautilus_view_get_window (view))); 6463 g_free (text); 6464 g_free (name); 6465 } 6466 } 6467 6468 static void 6469 file_unmount_callback (NautilusFile *file, 6470 GFile *result_location, 6471 GError *error, 6472 gpointer callback_data) 6473 { 6474 NautilusView *view; 6475 6476 view = NAUTILUS_VIEW (callback_data); 6477 g_object_unref (view); 6478 6479 if (error != NULL && 6480 (error->domain != G_IO_ERROR || 6481 (error->code != G_IO_ERROR_CANCELLED && 6482 error->code != G_IO_ERROR_FAILED_HANDLED))) { 6483 char *text; 6484 char *name; 6485 name = nautilus_file_get_display_name (file); 6486 /* Translators: %s is a file name formatted for display */ 6487 text = g_strdup_printf (_("Unable to remove “%s”"), name); 6488 eel_show_error_dialog (text, error->message, 6489 GTK_WINDOW (nautilus_view_get_window (view))); 6490 g_free (text); 6491 g_free (name); 6492 } 6493 } 6494 6495 static void 6496 file_eject_callback (NautilusFile *file, 6497 GFile *result_location, 6498 GError *error, 6499 gpointer callback_data) 6500 { 6501 NautilusView *view; 6502 6503 view = NAUTILUS_VIEW (callback_data); 6504 g_object_unref (view); 6505 6506 if (error != NULL && 6507 (error->domain != G_IO_ERROR || 6508 (error->code != G_IO_ERROR_CANCELLED && 6509 error->code != G_IO_ERROR_FAILED_HANDLED))) { 6510 char *text; 6511 char *name; 6512 name = nautilus_file_get_display_name (file); 6513 /* Translators: %s is a file name formatted for display */ 6514 text = g_strdup_printf (_("Unable to eject “%s”"), name); 6515 eel_show_error_dialog (text, error->message, 6516 GTK_WINDOW (nautilus_view_get_window (view))); 6517 g_free (text); 6518 g_free (name); 6519 } 6520 } 6521 6522 static void 6523 file_stop_callback (NautilusFile *file, 6524 GFile *result_location, 6525 GError *error, 6526 gpointer callback_data) 6527 { 6528 NautilusView *view; 6529 6530 view = NAUTILUS_VIEW (callback_data); 6531 6532 if (error != NULL && 6533 (error->domain != G_IO_ERROR || 6534 (error->code != G_IO_ERROR_CANCELLED && 6535 error->code != G_IO_ERROR_FAILED_HANDLED))) { 6536 eel_show_error_dialog (_("Unable to stop drive"), 6537 error->message, 6538 GTK_WINDOW (nautilus_view_get_window (view))); 6539 } 6540 } 6541 6542 static void 6543 action_mount_volume_callback (GtkAction *action, 6544 gpointer data) 6545 { 6546 NautilusFile *file; 6547 GList *selection, *l; 6548 NautilusView *view; 6549 GMountOperation *mount_op; 6550 6551 view = NAUTILUS_VIEW (data); 6552 6553 selection = nautilus_view_get_selection (view); 6554 for (l = selection; l != NULL; l = l->next) { 6555 file = NAUTILUS_FILE (l->data); 6556 6557 if (nautilus_file_can_mount (file)) { 6558 mount_op = gtk_mount_operation_new (nautilus_view_get_containing_window (view)); 6559 g_mount_operation_set_password_save (mount_op, G_PASSWORD_SAVE_FOR_SESSION); 6560 nautilus_file_mount (file, mount_op, NULL, 6561 file_mount_callback, 6562 view); 6563 g_object_unref (mount_op); 6564 } 6565 } 6566 nautilus_file_list_free (selection); 6567 } 6568 6569 static void 6570 action_unmount_volume_callback (GtkAction *action, 6571 gpointer data) 6572 { 6573 NautilusFile *file; 6574 GList *selection, *l; 6575 NautilusView *view; 6576 6577 view = NAUTILUS_VIEW (data); 6578 6579 selection = nautilus_view_get_selection (view); 6580 6581 for (l = selection; l != NULL; l = l->next) { 6582 file = NAUTILUS_FILE (l->data); 6583 if (nautilus_file_can_unmount (file)) { 6584 GMountOperation *mount_op; 6585 mount_op = gtk_mount_operation_new (nautilus_view_get_containing_window (view)); 6586 nautilus_file_unmount (file, mount_op, NULL, 6587 file_unmount_callback, g_object_ref (view)); 6588 g_object_unref (mount_op); 6589 } 6590 } 6591 nautilus_file_list_free (selection); 6592 } 6593 6594 static void 6595 action_eject_volume_callback (GtkAction *action, 6596 gpointer data) 6597 { 6598 NautilusFile *file; 6599 GList *selection, *l; 6600 NautilusView *view; 6601 6602 view = NAUTILUS_VIEW (data); 6603 6604 selection = nautilus_view_get_selection (view); 6605 for (l = selection; l != NULL; l = l->next) { 6606 file = NAUTILUS_FILE (l->data); 6607 6608 if (nautilus_file_can_eject (file)) { 6609 GMountOperation *mount_op; 6610 mount_op = gtk_mount_operation_new (nautilus_view_get_containing_window (view)); 6611 nautilus_file_eject (file, mount_op, NULL, 6612 file_eject_callback, g_object_ref (view)); 6613 g_object_unref (mount_op); 6614 } 6615 } 6616 nautilus_file_list_free (selection); 6617 } 6618 6619 static void 6620 file_start_callback (NautilusFile *file, 6621 GFile *result_location, 6622 GError *error, 6623 gpointer callback_data) 6624 { 6625 NautilusView *view; 6626 6627 view = NAUTILUS_VIEW (callback_data); 6628 6629 if (error != NULL && 6630 (error->domain != G_IO_ERROR || 6631 (error->code != G_IO_ERROR_CANCELLED && 6632 error->code != G_IO_ERROR_FAILED_HANDLED && 6633 error->code != G_IO_ERROR_ALREADY_MOUNTED))) { 6634 char *text; 6635 char *name; 6636 name = nautilus_file_get_display_name (file); 6637 /* Translators: %s is a file name formatted for display */ 6638 text = g_strdup_printf (_("Unable to start “%s”"), name); 6639 eel_show_error_dialog (text, error->message, 6640 GTK_WINDOW (nautilus_view_get_window (view))); 6641 g_free (text); 6642 g_free (name); 6643 } 6644 } 6645 6646 static void 6647 action_start_volume_callback (GtkAction *action, 6648 gpointer data) 6649 { 6650 NautilusFile *file; 6651 GList *selection, *l; 6652 NautilusView *view; 6653 GMountOperation *mount_op; 6654 6655 view = NAUTILUS_VIEW (data); 6656 6657 selection = nautilus_view_get_selection (view); 6658 for (l = selection; l != NULL; l = l->next) { 6659 file = NAUTILUS_FILE (l->data); 6660 6661 if (nautilus_file_can_start (file) || nautilus_file_can_start_degraded (file)) { 6662 mount_op = gtk_mount_operation_new (nautilus_view_get_containing_window (view)); 6663 nautilus_file_start (file, mount_op, NULL, 6664 file_start_callback, view); 6665 g_object_unref (mount_op); 6666 } 6667 } 6668 nautilus_file_list_free (selection); 6669 } 6670 6671 static void 6672 action_stop_volume_callback (GtkAction *action, 6673 gpointer data) 6674 { 6675 NautilusFile *file; 6676 GList *selection, *l; 6677 NautilusView *view; 6678 6679 view = NAUTILUS_VIEW (data); 6680 6681 selection = nautilus_view_get_selection (view); 6682 for (l = selection; l != NULL; l = l->next) { 6683 file = NAUTILUS_FILE (l->data); 6684 6685 if (nautilus_file_can_stop (file)) { 6686 GMountOperation *mount_op; 6687 mount_op = gtk_mount_operation_new (nautilus_view_get_containing_window (view)); 6688 nautilus_file_stop (file, mount_op, NULL, 6689 file_stop_callback, view); 6690 g_object_unref (mount_op); 6691 } 6692 } 6693 nautilus_file_list_free (selection); 6694 } 6695 6696 static void 6697 action_detect_media_callback (GtkAction *action, 6698 gpointer data) 6699 { 6700 NautilusFile *file; 6701 GList *selection, *l; 6702 NautilusView *view; 6703 6704 view = NAUTILUS_VIEW (data); 6705 6706 selection = nautilus_view_get_selection (view); 6707 for (l = selection; l != NULL; l = l->next) { 6708 file = NAUTILUS_FILE (l->data); 6709 6710 if (nautilus_file_can_poll_for_media (file) && !nautilus_file_is_media_check_automatic (file)) { 6711 nautilus_file_poll_for_media (file); 6712 } 6713 } 6714 nautilus_file_list_free (selection); 6715 } 6716 6717 static void 6718 action_self_mount_volume_callback (GtkAction *action, 6719 gpointer data) 6720 { 6721 NautilusFile *file; 6722 NautilusView *view; 6723 GMountOperation *mount_op; 6724 6725 view = NAUTILUS_VIEW (data); 6726 6727 file = nautilus_view_get_directory_as_file (view); 6728 if (file == NULL) { 6729 return; 6730 } 6731 6732 mount_op = gtk_mount_operation_new (nautilus_view_get_containing_window (view)); 6733 g_mount_operation_set_password_save (mount_op, G_PASSWORD_SAVE_FOR_SESSION); 6734 nautilus_file_mount (file, mount_op, NULL, file_mount_callback, view); 6735 g_object_unref (mount_op); 6736 } 6737 6738 static void 6739 action_self_unmount_volume_callback (GtkAction *action, 6740 gpointer data) 6741 { 6742 NautilusFile *file; 6743 NautilusView *view; 6744 GMountOperation *mount_op; 6745 6746 view = NAUTILUS_VIEW (data); 6747 6748 file = nautilus_view_get_directory_as_file (view); 6749 if (file == NULL) { 6750 return; 6751 } 6752 6753 mount_op = gtk_mount_operation_new (nautilus_view_get_containing_window (view)); 6754 nautilus_file_unmount (file, mount_op, NULL, file_unmount_callback, g_object_ref (view)); 6755 g_object_unref (mount_op); 6756 } 6757 6758 static void 6759 action_self_eject_volume_callback (GtkAction *action, 6760 gpointer data) 6761 { 6762 NautilusFile *file; 6763 NautilusView *view; 6764 GMountOperation *mount_op; 6765 6766 view = NAUTILUS_VIEW (data); 6767 6768 file = nautilus_view_get_directory_as_file (view); 6769 if (file == NULL) { 6770 return; 6771 } 6772 6773 mount_op = gtk_mount_operation_new (nautilus_view_get_containing_window (view)); 6774 nautilus_file_eject (file, mount_op, NULL, file_eject_callback, g_object_ref (view)); 6775 g_object_unref (mount_op); 6776 } 6777 6778 static void 6779 action_self_start_volume_callback (GtkAction *action, 6780 gpointer data) 6781 { 6782 NautilusFile *file; 6783 NautilusView *view; 6784 GMountOperation *mount_op; 6785 6786 view = NAUTILUS_VIEW (data); 6787 6788 file = nautilus_view_get_directory_as_file (view); 6789 if (file == NULL) { 6790 return; 6791 } 6792 6793 mount_op = gtk_mount_operation_new (nautilus_view_get_containing_window (view)); 6794 nautilus_file_start (file, mount_op, NULL, file_start_callback, view); 6795 g_object_unref (mount_op); 6796 } 6797 6798 static void 6799 action_self_stop_volume_callback (GtkAction *action, 6800 gpointer data) 6801 { 6802 NautilusFile *file; 6803 NautilusView *view; 6804 GMountOperation *mount_op; 6805 6806 view = NAUTILUS_VIEW (data); 6807 6808 file = nautilus_view_get_directory_as_file (view); 6809 if (file == NULL) { 6810 return; 6811 } 6812 6813 mount_op = gtk_mount_operation_new (nautilus_view_get_containing_window (view)); 6814 nautilus_file_stop (file, mount_op, NULL, 6815 file_stop_callback, view); 6816 g_object_unref (mount_op); 6817 } 6818 6819 static void 6820 action_self_detect_media_callback (GtkAction *action, 6821 gpointer data) 6822 { 6823 NautilusFile *file; 6824 NautilusView *view; 6825 6826 view = NAUTILUS_VIEW (data); 6827 6828 file = nautilus_view_get_directory_as_file (view); 6829 if (file == NULL) { 6830 return; 6831 } 6832 6833 nautilus_file_poll_for_media (file); 6834 } 6835 6836 static void 6837 action_location_mount_volume_callback (GtkAction *action, 6838 gpointer data) 6839 { 6840 NautilusFile *file; 6841 NautilusView *view; 6842 GMountOperation *mount_op; 6843 6844 view = NAUTILUS_VIEW (data); 6845 6846 file = view->details->location_popup_directory_as_file; 6847 if (file == NULL) { 6848 return; 6849 } 6850 6851 mount_op = gtk_mount_operation_new (nautilus_view_get_containing_window (view)); 6852 g_mount_operation_set_password_save (mount_op, G_PASSWORD_SAVE_FOR_SESSION); 6853 nautilus_file_mount (file, mount_op, NULL, file_mount_callback, view); 6854 g_object_unref (mount_op); 6855 } 6856 6857 static void 6858 action_location_unmount_volume_callback (GtkAction *action, 6859 gpointer data) 6860 { 6861 NautilusFile *file; 6862 NautilusView *view; 6863 GMountOperation *mount_op; 6864 6865 view = NAUTILUS_VIEW (data); 6866 6867 file = view->details->location_popup_directory_as_file; 6868 if (file == NULL) { 6869 return; 6870 } 6871 6872 mount_op = gtk_mount_operation_new (nautilus_view_get_containing_window (view)); 6873 nautilus_file_unmount (file, mount_op, NULL, 6874 file_unmount_callback, g_object_ref (view)); 6875 g_object_unref (mount_op); 6876 } 6877 6878 static void 6879 action_location_eject_volume_callback (GtkAction *action, 6880 gpointer data) 6881 { 6882 NautilusFile *file; 6883 NautilusView *view; 6884 GMountOperation *mount_op; 6885 6886 view = NAUTILUS_VIEW (data); 6887 6888 file = view->details->location_popup_directory_as_file; 6889 if (file == NULL) { 6890 return; 6891 } 6892 6893 mount_op = gtk_mount_operation_new (nautilus_view_get_containing_window (view)); 6894 nautilus_file_eject (file, mount_op, NULL, 6895 file_eject_callback, g_object_ref (view)); 6896 g_object_unref (mount_op); 6897 } 6898 6899 static void 6900 action_location_start_volume_callback (GtkAction *action, 6901 gpointer data) 6902 { 6903 NautilusFile *file; 6904 NautilusView *view; 6905 GMountOperation *mount_op; 6906 6907 view = NAUTILUS_VIEW (data); 6908 6909 file = view->details->location_popup_directory_as_file; 6910 if (file == NULL) { 6911 return; 6912 } 6913 6914 mount_op = gtk_mount_operation_new (nautilus_view_get_containing_window (view)); 6915 nautilus_file_start (file, mount_op, NULL, file_start_callback, view); 6916 g_object_unref (mount_op); 6917 } 6918 6919 static void 6920 action_location_stop_volume_callback (GtkAction *action, 6921 gpointer data) 6922 { 6923 NautilusFile *file; 6924 NautilusView *view; 6925 GMountOperation *mount_op; 6926 6927 view = NAUTILUS_VIEW (data); 6928 6929 file = view->details->location_popup_directory_as_file; 6930 if (file == NULL) { 6931 return; 6932 } 6933 6934 mount_op = gtk_mount_operation_new (nautilus_view_get_containing_window (view)); 6935 nautilus_file_stop (file, mount_op, NULL, 6936 file_stop_callback, view); 6937 g_object_unref (mount_op); 6938 } 6939 6940 static void 6941 action_location_detect_media_callback (GtkAction *action, 6942 gpointer data) 6943 { 6944 NautilusFile *file; 6945 NautilusView *view; 6946 6947 view = NAUTILUS_VIEW (data); 6948 6949 file = view->details->location_popup_directory_as_file; 6950 if (file == NULL) { 6951 return; 6952 } 6953 6954 nautilus_file_poll_for_media (file); 6955 } 6956 6957 static void 6958 action_location_open_alternate_callback (GtkAction *action, 6959 gpointer callback_data) 6960 { 6961 NautilusView *view; 6962 NautilusFile *file; 6963 6964 view = NAUTILUS_VIEW (callback_data); 6965 6966 file = view->details->location_popup_directory_as_file; 6967 if (file == NULL) { 6968 return; 6969 } 6970 nautilus_view_activate_file (view, 6971 file, 6972 NAUTILUS_WINDOW_OPEN_FLAG_NEW_WINDOW); 6973 } 6974 6975 static void 6976 action_location_open_in_new_tab_callback (GtkAction *action, 6977 gpointer callback_data) 6978 { 6979 NautilusView *view; 6980 NautilusFile *file; 6981 6982 view = NAUTILUS_VIEW (callback_data); 6983 6984 file = view->details->location_popup_directory_as_file; 6985 if (file == NULL) { 6986 return; 6987 } 6988 6989 nautilus_view_activate_file (view, 6990 file, 6991 NAUTILUS_WINDOW_OPEN_FLAG_NEW_TAB); 6992 } 6993 6994 static void 6995 action_location_cut_callback (GtkAction *action, 6996 gpointer callback_data) 6997 { 6998 NautilusView *view; 6999 NautilusFile *file; 7000 GList *files; 7001 7002 view = NAUTILUS_VIEW (callback_data); 7003 7004 file = view->details->location_popup_directory_as_file; 7005 g_return_if_fail (file != NULL); 7006 7007 files = g_list_append (NULL, file); 7008 copy_or_cut_files (view, files, TRUE); 7009 g_list_free (files); 7010 } 7011 7012 static void 7013 action_location_copy_callback (GtkAction *action, 7014 gpointer callback_data) 7015 { 7016 NautilusView *view; 7017 NautilusFile *file; 7018 GList *files; 7019 7020 view = NAUTILUS_VIEW (callback_data); 7021 7022 file = view->details->location_popup_directory_as_file; 7023 g_return_if_fail (file != NULL); 7024 7025 files = g_list_append (NULL, file); 7026 copy_or_cut_files (view, files, FALSE); 7027 g_list_free (files); 7028 } 7029 7030 static void 7031 action_location_paste_files_into_callback (GtkAction *action, 7032 gpointer callback_data) 7033 { 7034 NautilusView *view; 7035 NautilusFile *file; 7036 7037 view = NAUTILUS_VIEW (callback_data); 7038 7039 file = view->details->location_popup_directory_as_file; 7040 g_return_if_fail (file != NULL); 7041 7042 paste_into (view, file); 7043 } 7044 7045 static void 7046 action_location_trash_callback (GtkAction *action, 7047 gpointer callback_data) 7048 { 7049 NautilusView *view; 7050 NautilusFile *file; 7051 GList *files; 7052 7053 view = NAUTILUS_VIEW (callback_data); 7054 7055 file = view->details->location_popup_directory_as_file; 7056 g_return_if_fail (file != NULL); 7057 7058 files = g_list_append (NULL, file); 7059 trash_or_delete_files (nautilus_view_get_containing_window (view), 7060 files, TRUE, 7061 view); 7062 g_list_free (files); 7063 } 7064 7065 static void 7066 action_location_delete_callback (GtkAction *action, 7067 gpointer callback_data) 7068 { 7069 NautilusView *view; 7070 NautilusFile *file; 7071 GFile *location; 7072 GList *files; 7073 7074 view = NAUTILUS_VIEW (callback_data); 7075 7076 file = view->details->location_popup_directory_as_file; 7077 g_return_if_fail (file != NULL); 7078 7079 location = nautilus_file_get_location (file); 7080 7081 files = g_list_append (NULL, location); 7082 nautilus_file_operations_delete (files, nautilus_view_get_containing_window (view), 7083 NULL, NULL); 7084 7085 g_list_free_full (files, g_object_unref); 7086 } 7087 7088 static void 7089 action_location_restore_from_trash_callback (GtkAction *action, 7090 gpointer callback_data) 7091 { 7092 NautilusView *view; 7093 NautilusFile *file; 7094 GList l; 7095 7096 view = NAUTILUS_VIEW (callback_data); 7097 file = view->details->location_popup_directory_as_file; 7098 7099 l.prev = NULL; 7100 l.next = NULL; 7101 l.data = file; 7102 nautilus_restore_files_from_trash (&l, 7103 nautilus_view_get_containing_window (view)); 7104 } 7105 7106 gboolean 7107 nautilus_view_get_show_hidden_files (NautilusView *view) 7108 { 7109 return view->details->show_hidden_files; 7110 } 7111 7112 static void 7113 nautilus_view_set_show_hidden_files (NautilusView *view, 7114 gboolean show_hidden) 7115 { 7116 if (view->details->ignore_hidden_file_preferences) { 7117 return; 7118 } 7119 7120 if (show_hidden != view->details->show_hidden_files) { 7121 view->details->show_hidden_files = show_hidden; 7122 if (view->details->model != NULL) { 7123 load_directory (view, view->details->model); 7124 } 7125 } 7126 } 7127 7128 static const GtkActionEntry directory_view_entries[] = { 7129 /* name, stock id, label */ { NAUTILUS_ACTION_NEW_DOCUMENTS, "document-new", N_("New _Document") }, 7130 /* name, stock id, label */ { NAUTILUS_ACTION_OPEN_WITH, NULL, N_("Open Wit_h"), 7131 NULL, N_("Choose a program with which to open the selected item") }, 7132 /* name, stock id */ { NAUTILUS_ACTION_PROPERTIES, GTK_STOCK_PROPERTIES, 7133 /* label, accelerator */ N_("P_roperties"), "<alt>Return", 7134 /* tooltip */ N_("View or modify the properties of each selected item"), 7135 G_CALLBACK (action_properties_callback) }, 7136 /* name, stock id */ { "PropertiesAccel", NULL, 7137 /* label, accelerator */ "PropertiesAccel", "<control>I", 7138 /* tooltip */ NULL, 7139 G_CALLBACK (action_properties_callback) }, 7140 /* name, stock id */ { NAUTILUS_ACTION_NEW_FOLDER, "folder-new", 7141 /* label, accelerator */ N_("New _Folder"), "<control><shift>N", 7142 /* tooltip */ N_("Create a new empty folder inside this folder"), 7143 G_CALLBACK (action_new_folder_callback) }, 7144 /* name, stock id */ { NAUTILUS_ACTION_NEW_FOLDER_WITH_SELECTION, NULL, 7145 /* label, accelerator */ N_("New Folder with Selection"), NULL, 7146 /* tooltip */ N_("Create a new folder containing the selected items"), 7147 G_CALLBACK (action_new_folder_with_selection_callback) }, 7148 /* name, stock id */ { NAUTILUS_ACTION_NEW_EMPTY_DOCUMENT, NULL, 7149 /* translators: this is used to indicate that a document doesn't contain anything */ 7150 /* label, accelerator */ N_("_Empty Document"), NULL, 7151 /* tooltip */ N_("Create a new empty document inside this folder"), 7152 G_CALLBACK (action_new_empty_file_callback) }, 7153 /* name, stock id */ { NAUTILUS_ACTION_OPEN, NULL, 7154 /* label, accelerator */ N_("_Open"), "<control>o", 7155 /* tooltip */ N_("Open the selected item in this window"), 7156 G_CALLBACK (action_open_callback) }, 7157 /* name, stock id */ { "OpenAccel", NULL, 7158 /* label, accelerator */ "OpenAccel", "<alt>Down", 7159 /* tooltip */ NULL, 7160 G_CALLBACK (action_open_callback) }, 7161 /* name, stock id */ { NAUTILUS_ACTION_OPEN_ALTERNATE, NULL, 7162 /* label, accelerator */ N_("Open in Navigation Window"), "<control><shift>o", 7163 /* tooltip */ N_("Open each selected item in a navigation window"), 7164 G_CALLBACK (action_open_alternate_callback) }, 7165 /* name, stock id */ { NAUTILUS_ACTION_OPEN_IN_NEW_TAB, NULL, 7166 /* label, accelerator */ N_("Open in New _Tab"), "<control><shift>t", 7167 /* tooltip */ N_("Open each selected item in a new tab"), 7168 G_CALLBACK (action_open_new_tab_callback) }, 7169 /* name, stock id */ { NAUTILUS_ACTION_OTHER_APPLICATION1, NULL, 7170 /* label, accelerator */ N_("Other _Application..."), NULL, 7171 /* tooltip */ N_("Choose another application with which to open the selected item"), 7172 G_CALLBACK (action_other_application_callback) }, 7173 /* name, stock id */ { NAUTILUS_ACTION_OTHER_APPLICATION2, NULL, 7174 /* label, accelerator */ N_("Open With Other _Application..."), NULL, 7175 /* tooltip */ N_("Choose another application with which to open the selected item"), 7176 G_CALLBACK (action_other_application_callback) }, 7177 /* name, stock id */ { NAUTILUS_ACTION_OPEN_SCRIPTS_FOLDER, NULL, 7178 /* label, accelerator */ N_("_Open Scripts Folder"), NULL, 7179 /* tooltip */ N_("Show the folder containing the scripts that appear in this menu"), 7180 G_CALLBACK (action_open_scripts_folder_callback) }, 7181 /* name, stock id */ { NAUTILUS_ACTION_EMPTY_TRASH, NULL, 7182 /* label, accelerator */ N_("E_mpty Trash"), NULL, 7183 /* tooltip */ N_("Delete all items in the Trash"), 7184 G_CALLBACK (action_empty_trash_callback) }, 7185 /* name, stock id */ { NAUTILUS_ACTION_CUT, GTK_STOCK_CUT, 7186 /* label, accelerator */ NULL, NULL, 7187 /* tooltip */ N_("Prepare the selected files to be moved with a Paste command"), 7188 G_CALLBACK (action_cut_files_callback) }, 7189 /* name, stock id */ { NAUTILUS_ACTION_COPY, GTK_STOCK_COPY, 7190 /* label, accelerator */ NULL, NULL, 7191 /* tooltip */ N_("Prepare the selected files to be copied with a Paste command"), 7192 G_CALLBACK (action_copy_files_callback) }, 7193 /* name, stock id */ { NAUTILUS_ACTION_PASTE, GTK_STOCK_PASTE, 7194 /* label, accelerator */ NULL, NULL, 7195 /* tooltip */ N_("Move or copy files previously selected by a Cut or Copy command"), 7196 G_CALLBACK (action_paste_files_callback) }, 7197 /* We make accelerator "" instead of null here to not inherit the stock 7198 accelerator for paste */ 7199 /* name, stock id */ { NAUTILUS_ACTION_PASTE_FILES_INTO, GTK_STOCK_PASTE, 7200 /* label, accelerator */ N_("_Paste Into Folder"), "", 7201 /* tooltip */ N_("Move or copy files previously selected by a Cut or Copy command into the selected folder"), 7202 G_CALLBACK (action_paste_files_into_callback) }, 7203 /* name, stock id */ { NAUTILUS_ACTION_COPY_TO, NULL, 7204 /* label, accelerator */ N_("Copy To..."), NULL, 7205 /* tooltip */ N_("Copy selected files to another location"), 7206 G_CALLBACK (action_copy_to_callback) }, 7207 /* name, stock id */ { NAUTILUS_ACTION_MOVE_TO, NULL, 7208 /* label, accelerator */ N_("Move To..."), NULL, 7209 /* tooltip */ N_("Move selected files to another location"), 7210 G_CALLBACK (action_move_to_callback) }, 7211 /* name, stock id */ { NAUTILUS_ACTION_SELECT_ALL, NULL, 7212 /* label, accelerator */ N_("Select _All"), "<control>A", 7213 /* tooltip */ N_("Select all items in this window"), 7214 G_CALLBACK (action_select_all_callback) }, 7215 /* name, stock id */ { NAUTILUS_ACTION_SELECT_PATTERN, NULL, 7216 /* label, accelerator */ N_("Select I_tems Matching..."), "<control>S", 7217 /* tooltip */ N_("Select items in this window matching a given pattern"), 7218 G_CALLBACK (action_select_pattern_callback) }, 7219 /* name, stock id */ { NAUTILUS_ACTION_INVERT_SELECTION, NULL, 7220 /* label, accelerator */ N_("_Invert Selection"), "<control><shift>I", 7221 /* tooltip */ N_("Select all and only the items that are not currently selected"), 7222 G_CALLBACK (action_invert_selection_callback) }, 7223 /* name, stock id */ { NAUTILUS_ACTION_CREATE_LINK, NULL, 7224 /* label, accelerator */ N_("Ma_ke Link"), "<control>M", 7225 /* tooltip */ N_("Create a symbolic link for each selected item"), 7226 G_CALLBACK (action_create_link_callback) }, 7227 /* name, stock id */ { NAUTILUS_ACTION_RENAME, NULL, 7228 /* label, accelerator */ N_("Rena_me..."), "F2", 7229 /* tooltip */ N_("Rename selected item"), 7230 G_CALLBACK (action_rename_callback) }, 7231 /* name, stock id */ { NAUTILUS_ACTION_SET_AS_WALLPAPER, NULL, 7232 /* label, accelerator */ N_("Set as Wallpaper"), NULL, 7233 /* tooltip */ N_("Make item the wallpaper"), 7234 G_CALLBACK (action_set_as_wallpaper_callback) }, 7235 /* name, stock id */ { "RenameSelectAll", NULL, 7236 /* label, accelerator */ "RenameSelectAll", "<shift>F2", 7237 /* tooltip */ NULL, 7238 G_CALLBACK (action_rename_select_all_callback) }, 7239 /* name, stock id */ { NAUTILUS_ACTION_TRASH, NULL, 7240 /* label, accelerator */ N_("Mo_ve to Trash"), "<control>Delete", 7241 /* tooltip */ N_("Move each selected item to the Trash"), 7242 G_CALLBACK (action_trash_callback) }, 7243 /* name, stock id */ { NAUTILUS_ACTION_DELETE, NULL, 7244 /* label, accelerator */ N_("_Delete"), "<shift>Delete", 7245 /* tooltip */ N_("Delete each selected item, without moving to the Trash"), 7246 G_CALLBACK (action_delete_callback) }, 7247 /* name, stock id */ { NAUTILUS_ACTION_RESTORE_FROM_TRASH, NULL, 7248 /* label, accelerator */ N_("_Restore"), NULL, 7249 NULL, 7250 G_CALLBACK (action_restore_from_trash_callback) }, 7251 /* name, stock id */ { NAUTILUS_ACTION_UNDO, GTK_STOCK_UNDO, 7252 /* label, accelerator */ N_("_Undo"), "<control>Z", 7253 /* tooltip */ N_("Undo the last action"), 7254 G_CALLBACK (action_undo_callback) }, 7255 /* name, stock id */ { NAUTILUS_ACTION_REDO, GTK_STOCK_REDO, 7256 /* label, accelerator */ N_("_Redo"), "<control>Y", 7257 /* tooltip */ N_("Redo the last undone action"), 7258 G_CALLBACK (action_redo_callback) }, 7259 /* 7260 * multiview-TODO: decide whether "Reset to Defaults" should 7261 * be window-wide, and not just view-wide. 7262 * Since this also resets the "Show hidden files" mode, 7263 * it is a mixture of both ATM. 7264 */ 7265 /* name, stock id */ { NAUTILUS_ACTION_RESET_TO_DEFAULTS, NULL, 7266 /* label, accelerator */ N_("Reset View to _Defaults"), NULL, 7267 /* tooltip */ N_("Reset sorting order and zoom level to match preferences for this view"), 7268 G_CALLBACK (action_reset_to_defaults_callback) }, 7269 /* name, stock id */ { NAUTILUS_ACTION_MOUNT_VOLUME, NULL, 7270 /* label, accelerator */ N_("_Mount"), NULL, 7271 /* tooltip */ N_("Mount the selected volume"), 7272 G_CALLBACK (action_mount_volume_callback) }, 7273 /* name, stock id */ { NAUTILUS_ACTION_UNMOUNT_VOLUME, NULL, 7274 /* label, accelerator */ N_("_Unmount"), NULL, 7275 /* tooltip */ N_("Unmount the selected volume"), 7276 G_CALLBACK (action_unmount_volume_callback) }, 7277 /* name, stock id */ { NAUTILUS_ACTION_EJECT_VOLUME, NULL, 7278 /* label, accelerator */ N_("_Eject"), NULL, 7279 /* tooltip */ N_("Eject the selected volume"), 7280 G_CALLBACK (action_eject_volume_callback) }, 7281 /* name, stock id */ { NAUTILUS_ACTION_START_VOLUME, NULL, 7282 /* label, accelerator */ N_("_Start"), NULL, 7283 /* tooltip */ N_("Start the selected volume"), 7284 G_CALLBACK (action_start_volume_callback) }, 7285 /* name, stock id */ { NAUTILUS_ACTION_STOP_VOLUME, NULL, 7286 /* label, accelerator */ N_("_Stop"), NULL, 7287 /* tooltip */ N_("Stop the selected volume"), 7288 G_CALLBACK (action_stop_volume_callback) }, 7289 /* name, stock id */ { NAUTILUS_ACTION_POLL, NULL, 7290 /* label, accelerator */ N_("_Detect Media"), NULL, 7291 /* tooltip */ N_("Detect media in the selected drive"), 7292 G_CALLBACK (action_detect_media_callback) }, 7293 /* name, stock id */ { NAUTILUS_ACTION_SELF_MOUNT_VOLUME, NULL, 7294 /* label, accelerator */ N_("_Mount"), NULL, 7295 /* tooltip */ N_("Mount the volume associated with the open folder"), 7296 G_CALLBACK (action_self_mount_volume_callback) }, 7297 /* name, stock id */ { NAUTILUS_ACTION_SELF_UNMOUNT_VOLUME, NULL, 7298 /* label, accelerator */ N_("_Unmount"), NULL, 7299 /* tooltip */ N_("Unmount the volume associated with the open folder"), 7300 G_CALLBACK (action_self_unmount_volume_callback) }, 7301 /* name, stock id */ { NAUTILUS_ACTION_SELF_EJECT_VOLUME, NULL, 7302 /* label, accelerator */ N_("_Eject"), NULL, 7303 /* tooltip */ N_("Eject the volume associated with the open folder"), 7304 G_CALLBACK (action_self_eject_volume_callback) }, 7305 /* name, stock id */ { NAUTILUS_ACTION_SELF_START_VOLUME, NULL, 7306 /* label, accelerator */ N_("_Start"), NULL, 7307 /* tooltip */ N_("Start the volume associated with the open folder"), 7308 G_CALLBACK (action_self_start_volume_callback) }, 7309 /* name, stock id */ { NAUTILUS_ACTION_SELF_STOP_VOLUME, NULL, 7310 /* label, accelerator */ N_("_Stop"), NULL, 7311 /* tooltip */ N_("Stop the volume associated with the open folder"), 7312 G_CALLBACK (action_self_stop_volume_callback) }, 7313 /* name, stock id */ { NAUTILUS_ACTION_SELF_POLL, NULL, 7314 /* label, accelerator */ N_("_Detect Media"), NULL, 7315 /* tooltip */ N_("Detect media in the selected drive"), 7316 G_CALLBACK (action_self_detect_media_callback) }, 7317 /* name, stock id */ { "OpenCloseParent", NULL, 7318 /* label, accelerator */ N_("Open File and Close window"), "<alt><shift>Down", 7319 /* tooltip */ NULL, 7320 G_CALLBACK (action_open_close_parent_callback) }, 7321 /* name, stock id */ { NAUTILUS_ACTION_SAVE_SEARCH, NULL, 7322 /* label, accelerator */ N_("Sa_ve Search"), NULL, 7323 /* tooltip */ N_("Save the edited search"), 7324 G_CALLBACK (action_save_search_callback) }, 7325 /* name, stock id */ { NAUTILUS_ACTION_SAVE_SEARCH_AS, NULL, 7326 /* label, accelerator */ N_("Sa_ve Search As..."), NULL, 7327 /* tooltip */ N_("Save the current search as a file"), 7328 G_CALLBACK (action_save_search_as_callback) }, 7329 7330 /* Location-specific actions */ 7331 /* name, stock id */ { NAUTILUS_ACTION_LOCATION_OPEN_ALTERNATE, NULL, 7332 /* label, accelerator */ N_("Open in Navigation Window"), "", 7333 /* tooltip */ N_("Open this folder in a navigation window"), 7334 G_CALLBACK (action_location_open_alternate_callback) }, 7335 /* name, stock id */ { NAUTILUS_ACTION_LOCATION_OPEN_IN_NEW_TAB, NULL, 7336 /* label, accelerator */ N_("Open in New _Tab"), "", 7337 /* tooltip */ N_("Open this folder in a new tab"), 7338 G_CALLBACK (action_location_open_in_new_tab_callback) }, 7339 7340 /* name, stock id */ { NAUTILUS_ACTION_LOCATION_CUT, GTK_STOCK_CUT, 7341 /* label, accelerator */ NULL, "", 7342 /* tooltip */ N_("Prepare this folder to be moved with a Paste command"), 7343 G_CALLBACK (action_location_cut_callback) }, 7344 /* name, stock id */ { NAUTILUS_ACTION_LOCATION_COPY, GTK_STOCK_COPY, 7345 /* label, accelerator */ NULL, "", 7346 /* tooltip */ N_("Prepare this folder to be copied with a Paste command"), 7347 G_CALLBACK (action_location_copy_callback) }, 7348 /* name, stock id */ { NAUTILUS_ACTION_LOCATION_PASTE_FILES_INTO, GTK_STOCK_PASTE, 7349 /* label, accelerator */ N_("_Paste Into Folder"), "", 7350 /* tooltip */ N_("Move or copy files previously selected by a Cut or Copy command into this folder"), 7351 G_CALLBACK (action_location_paste_files_into_callback) }, 7352 7353 /* name, stock id */ { NAUTILUS_ACTION_LOCATION_TRASH, NULL, 7354 /* label, accelerator */ N_("Mo_ve to Trash"), "", 7355 /* tooltip */ N_("Move this folder to the Trash"), 7356 G_CALLBACK (action_location_trash_callback) }, 7357 /* name, stock id */ { NAUTILUS_ACTION_LOCATION_DELETE, NAUTILUS_ICON_DELETE, 7358 /* label, accelerator */ N_("_Delete"), "", 7359 /* tooltip */ N_("Delete this folder, without moving to the Trash"), 7360 G_CALLBACK (action_location_delete_callback) }, 7361 /* name, stock id */ { NAUTILUS_ACTION_LOCATION_RESTORE_FROM_TRASH, NULL, 7362 /* label, accelerator */ N_("_Restore"), NULL, NULL, 7363 G_CALLBACK (action_location_restore_from_trash_callback) }, 7364 7365 /* name, stock id */ { NAUTILUS_ACTION_LOCATION_MOUNT_VOLUME, NULL, 7366 /* label, accelerator */ N_("_Mount"), NULL, 7367 /* tooltip */ N_("Mount the volume associated with this folder"), 7368 G_CALLBACK (action_location_mount_volume_callback) }, 7369 /* name, stock id */ { NAUTILUS_ACTION_LOCATION_UNMOUNT_VOLUME, NULL, 7370 /* label, accelerator */ N_("_Unmount"), NULL, 7371 /* tooltip */ N_("Unmount the volume associated with this folder"), 7372 G_CALLBACK (action_location_unmount_volume_callback) }, 7373 /* name, stock id */ { NAUTILUS_ACTION_LOCATION_EJECT_VOLUME, NULL, 7374 /* label, accelerator */ N_("_Eject"), NULL, 7375 /* tooltip */ N_("Eject the volume associated with this folder"), 7376 G_CALLBACK (action_location_eject_volume_callback) }, 7377 /* name, stock id */ { NAUTILUS_ACTION_LOCATION_START_VOLUME, NULL, 7378 /* label, accelerator */ N_("_Start"), NULL, 7379 /* tooltip */ N_("Start the volume associated with this folder"), 7380 G_CALLBACK (action_location_start_volume_callback) }, 7381 /* name, stock id */ { NAUTILUS_ACTION_LOCATION_STOP_VOLUME, NULL, 7382 /* label, accelerator */ N_("_Stop"), NULL, 7383 /* tooltip */ N_("Stop the volume associated with this folder"), 7384 G_CALLBACK (action_location_stop_volume_callback) }, 7385 /* name, stock id */ { NAUTILUS_ACTION_LOCATION_POLL, NULL, 7386 /* label, accelerator */ N_("_Detect Media"), NULL, 7387 /* tooltip */ N_("Detect media in the selected drive"), 7388 G_CALLBACK (action_location_detect_media_callback) }, 7389 7390 /* name, stock id */ { NAUTILUS_ACTION_LOCATION_PROPERTIES, GTK_STOCK_PROPERTIES, 7391 /* label, accelerator */ N_("P_roperties"), NULL, 7392 /* tooltip */ N_("View or modify the properties of this folder"), 7393 G_CALLBACK (action_location_properties_callback) }, 7394 }; 7395 7396 static const GtkToggleActionEntry directory_view_toggle_entries[] = { 7397 /* name, stock id */ { NAUTILUS_ACTION_SHOW_HIDDEN_FILES, NULL, 7398 /* label, accelerator */ N_("Show _Hidden Files"), "<control>H", 7399 /* tooltip */ N_("Toggle the display of hidden files in the current window"), 7400 G_CALLBACK (action_show_hidden_files_callback), 7401 TRUE }, 7402 }; 7403 7404 static void 7405 connect_proxy (NautilusView *view, 7406 GtkAction *action, 7407 GtkWidget *proxy, 7408 GtkActionGroup *action_group) 7409 { 7410 GdkPixbuf *pixbuf; 7411 GtkWidget *image; 7412 7413 if (strcmp (gtk_action_get_name (action), NAUTILUS_ACTION_NEW_EMPTY_DOCUMENT) == 0 && 7414 GTK_IS_IMAGE_MENU_ITEM (proxy)) { 7415 pixbuf = nautilus_ui_get_menu_icon ("text-x-generic"); 7416 if (pixbuf != NULL) { 7417 image = gtk_image_new_from_pixbuf (pixbuf); 7418 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (proxy), image); 7419 7420 g_object_unref (pixbuf); 7421 } 7422 } 7423 } 7424 7425 static void 7426 pre_activate (NautilusView *view, 7427 GtkAction *action, 7428 GtkActionGroup *action_group) 7429 { 7430 GdkEvent *event; 7431 GtkWidget *proxy; 7432 gboolean activated_from_popup; 7433 7434 /* check whether action was activated through a popup menu. 7435 * If not, unset the last stored context menu popup position */ 7436 activated_from_popup = FALSE; 7437 7438 event = gtk_get_current_event (); 7439 proxy = gtk_get_event_widget (event); 7440 7441 if (proxy != NULL) { 7442 GtkWidget *toplevel; 7443 GdkWindowTypeHint hint; 7444 7445 toplevel = gtk_widget_get_toplevel (proxy); 7446 7447 if (GTK_IS_WINDOW (toplevel)) { 7448 hint = gtk_window_get_type_hint (GTK_WINDOW (toplevel)); 7449 7450 if (hint == GDK_WINDOW_TYPE_HINT_POPUP_MENU) { 7451 activated_from_popup = TRUE; 7452 } 7453 } 7454 } 7455 7456 if (!activated_from_popup) { 7457 update_context_menu_position_from_event (view, NULL); 7458 } 7459 } 7460 7461 static void 7462 real_merge_menus (NautilusView *view) 7463 { 7464 GtkActionGroup *action_group; 7465 GtkUIManager *ui_manager; 7466 GtkAction *action; 7467 char *tooltip; 7468 7469 ui_manager = nautilus_view_get_ui_manager (view); 7470 7471 action_group = gtk_action_group_new ("DirViewActions"); 7472 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE); 7473 view->details->dir_action_group = action_group; 7474 gtk_action_group_add_actions (action_group, 7475 directory_view_entries, G_N_ELEMENTS (directory_view_entries), 7476 view); 7477 gtk_action_group_add_toggle_actions (action_group, 7478 directory_view_toggle_entries, G_N_ELEMENTS (directory_view_toggle_entries), 7479 view); 7480 7481 tooltip = g_strdup (_("Run or manage scripts")); 7482 /* Create a script action here specially because its tooltip is dynamic */ 7483 action = gtk_action_new ("Scripts", _("_Scripts"), tooltip, NULL); 7484 gtk_action_group_add_action (action_group, action); 7485 g_object_unref (action); 7486 g_free (tooltip); 7487 7488 g_signal_connect_object (action_group, "connect-proxy", 7489 G_CALLBACK (connect_proxy), G_OBJECT (view), 7490 G_CONNECT_SWAPPED); 7491 g_signal_connect_object (action_group, "pre-activate", 7492 G_CALLBACK (pre_activate), G_OBJECT (view), 7493 G_CONNECT_SWAPPED); 7494 7495 /* Insert action group at end so clipboard action group ends up before it */ 7496 gtk_ui_manager_insert_action_group (ui_manager, action_group, -1); 7497 g_object_unref (action_group); /* owned by ui manager */ 7498 7499 view->details->dir_merge_id = gtk_ui_manager_add_ui_from_resource (ui_manager, "/org/gnome/nautilus/nautilus-directory-view-ui.xml", NULL); 7500 7501 view->details->scripts_invalid = TRUE; 7502 view->details->templates_invalid = TRUE; 7503 } 7504 7505 7506 static gboolean 7507 can_paste_into_file (NautilusFile *file) 7508 { 7509 if (nautilus_file_is_directory (file) && 7510 nautilus_file_can_write (file)) { 7511 return TRUE; 7512 } 7513 if (nautilus_file_has_activation_uri (file)) { 7514 GFile *location; 7515 NautilusFile *activation_file; 7516 gboolean res; 7517 7518 location = nautilus_file_get_activation_location (file); 7519 activation_file = nautilus_file_get (location); 7520 g_object_unref (location); 7521 7522 /* The target location might not have data for it read yet, 7523 and we can't want to do sync I/O, so treat the unknown 7524 case as can-write */ 7525 res = (nautilus_file_get_file_type (activation_file) == G_FILE_TYPE_UNKNOWN) || 7526 (nautilus_file_get_file_type (activation_file) == G_FILE_TYPE_DIRECTORY && 7527 nautilus_file_can_write (activation_file)); 7528 7529 nautilus_file_unref (activation_file); 7530 7531 return res; 7532 } 7533 7534 return FALSE; 7535 } 7536 7537 static void 7538 clipboard_targets_received (GtkClipboard *clipboard, 7539 GdkAtom *targets, 7540 int n_targets, 7541 gpointer user_data) 7542 { 7543 NautilusView *view; 7544 gboolean can_paste; 7545 int i; 7546 GList *selection; 7547 int count; 7548 GtkAction *action; 7549 7550 view = NAUTILUS_VIEW (user_data); 7551 can_paste = FALSE; 7552 7553 if (view->details->slot == NULL || 7554 !view->details->active) { 7555 /* We've been destroyed or became inactive since call */ 7556 g_object_unref (view); 7557 return; 7558 } 7559 7560 if (targets) { 7561 for (i=0; i < n_targets; i++) { 7562 if (targets[i] == copied_files_atom) { 7563 can_paste = TRUE; 7564 } 7565 } 7566 } 7567 7568 7569 selection = nautilus_view_get_selection (view); 7570 count = g_list_length (selection); 7571 7572 action = gtk_action_group_get_action (view->details->dir_action_group, 7573 NAUTILUS_ACTION_PASTE); 7574 gtk_action_set_sensitive (action, 7575 can_paste && !nautilus_view_is_read_only (view)); 7576 7577 action = gtk_action_group_get_action (view->details->dir_action_group, 7578 NAUTILUS_ACTION_PASTE_FILES_INTO); 7579 gtk_action_set_sensitive (action, 7580 can_paste && count == 1 && 7581 can_paste_into_file (NAUTILUS_FILE (selection->data))); 7582 7583 action = gtk_action_group_get_action (view->details->dir_action_group, 7584 NAUTILUS_ACTION_LOCATION_PASTE_FILES_INTO); 7585 g_object_set_data (G_OBJECT (action), 7586 "can-paste-according-to-clipboard", 7587 GINT_TO_POINTER (can_paste)); 7588 gtk_action_set_sensitive (action, 7589 GPOINTER_TO_INT (g_object_get_data (G_OBJECT (action), 7590 "can-paste-according-to-clipboard")) && 7591 GPOINTER_TO_INT (g_object_get_data (G_OBJECT (action), 7592 "can-paste-according-to-destination"))); 7593 7594 nautilus_file_list_free (selection); 7595 7596 g_object_unref (view); 7597 } 7598 7599 static gboolean 7600 should_show_empty_trash (NautilusView *view) 7601 { 7602 return (showing_trash_directory (view)); 7603 } 7604 7605 static gboolean 7606 file_list_all_are_folders (GList *file_list) 7607 { 7608 GList *l; 7609 NautilusFile *file, *linked_file; 7610 char *activation_uri; 7611 gboolean is_dir; 7612 7613 for (l = file_list; l != NULL; l = l->next) { 7614 file = NAUTILUS_FILE (l->data); 7615 if (nautilus_file_is_nautilus_link (file) && 7616 !NAUTILUS_IS_DESKTOP_ICON_FILE (file)) { 7617 if (nautilus_file_is_launcher (file)) { 7618 return FALSE; 7619 } 7620 7621 activation_uri = nautilus_file_get_activation_uri (file); 7622 7623 if (activation_uri == NULL) { 7624 g_free (activation_uri); 7625 return FALSE; 7626 } 7627 7628 linked_file = nautilus_file_get_existing_by_uri (activation_uri); 7629 7630 /* We might not actually know the type of the linked file yet, 7631 * however we don't want to schedule a read, since that might do things 7632 * like ask for password etc. This is a bit unfortunate, but I don't 7633 * know any way around it, so we do various heuristics here 7634 * to get things mostly right 7635 */ 7636 is_dir = 7637 (linked_file != NULL && 7638 nautilus_file_is_directory (linked_file)) || 7639 (activation_uri != NULL && 7640 activation_uri[strlen (activation_uri) - 1] == '/'); 7641 7642 nautilus_file_unref (linked_file); 7643 g_free (activation_uri); 7644 7645 if (!is_dir) { 7646 return FALSE; 7647 } 7648 } else if (!(nautilus_file_is_directory (file) || 7649 NAUTILUS_IS_DESKTOP_ICON_FILE (file))) { 7650 return FALSE; 7651 } 7652 } 7653 return TRUE; 7654 } 7655 7656 static void 7657 file_should_show_foreach (NautilusFile *file, 7658 gboolean *show_mount, 7659 gboolean *show_unmount, 7660 gboolean *show_eject, 7661 gboolean *show_start, 7662 gboolean *show_stop, 7663 gboolean *show_poll, 7664 GDriveStartStopType *start_stop_type) 7665 { 7666 *show_mount = FALSE; 7667 *show_unmount = FALSE; 7668 *show_eject = FALSE; 7669 *show_start = FALSE; 7670 *show_stop = FALSE; 7671 *show_poll = FALSE; 7672 7673 if (nautilus_file_can_eject (file)) { 7674 *show_eject = TRUE; 7675 } 7676 7677 if (nautilus_file_can_mount (file)) { 7678 *show_mount = TRUE; 7679 } 7680 7681 if (nautilus_file_can_start (file) || nautilus_file_can_start_degraded (file)) { 7682 *show_start = TRUE; 7683 } 7684 7685 if (nautilus_file_can_stop (file)) { 7686 *show_stop = TRUE; 7687 } 7688 7689 /* Dot not show both Unmount and Eject/Safe Removal; too confusing to 7690 * have too many menu entries */ 7691 if (nautilus_file_can_unmount (file) && !*show_eject && !*show_stop) { 7692 *show_unmount = TRUE; 7693 } 7694 7695 if (nautilus_file_can_poll_for_media (file) && !nautilus_file_is_media_check_automatic (file)) { 7696 *show_poll = TRUE; 7697 } 7698 7699 *start_stop_type = nautilus_file_get_start_stop_type (file); 7700 } 7701 7702 static void 7703 file_should_show_self (NautilusFile *file, 7704 gboolean *show_mount, 7705 gboolean *show_unmount, 7706 gboolean *show_eject, 7707 gboolean *show_start, 7708 gboolean *show_stop, 7709 gboolean *show_poll, 7710 GDriveStartStopType *start_stop_type) 7711 { 7712 *show_mount = FALSE; 7713 *show_unmount = FALSE; 7714 *show_eject = FALSE; 7715 *show_start = FALSE; 7716 *show_stop = FALSE; 7717 *show_poll = FALSE; 7718 7719 if (file == NULL) { 7720 return; 7721 } 7722 7723 if (nautilus_file_can_eject (file)) { 7724 *show_eject = TRUE; 7725 } 7726 7727 if (nautilus_file_can_mount (file)) { 7728 *show_mount = TRUE; 7729 } 7730 7731 if (nautilus_file_can_start (file) || nautilus_file_can_start_degraded (file)) { 7732 *show_start = TRUE; 7733 } 7734 7735 if (nautilus_file_can_stop (file)) { 7736 *show_stop = TRUE; 7737 } 7738 7739 /* Dot not show both Unmount and Eject/Safe Removal; too confusing to 7740 * have too many menu entries */ 7741 if (nautilus_file_can_unmount (file) && !*show_eject && !*show_stop) { 7742 *show_unmount = TRUE; 7743 } 7744 7745 if (nautilus_file_can_poll_for_media (file) && !nautilus_file_is_media_check_automatic (file)) { 7746 *show_poll = TRUE; 7747 } 7748 7749 *start_stop_type = nautilus_file_get_start_stop_type (file); 7750 7751 } 7752 7753 static gboolean 7754 files_are_all_directories (GList *files) 7755 { 7756 NautilusFile *file; 7757 GList *l; 7758 gboolean all_directories; 7759 7760 all_directories = TRUE; 7761 7762 for (l = files; l != NULL; l = l->next) { 7763 file = NAUTILUS_FILE (l->data); 7764 all_directories &= nautilus_file_is_directory (file); 7765 } 7766 7767 return all_directories; 7768 } 7769 7770 static gboolean 7771 files_is_none_directory (GList *files) 7772 { 7773 NautilusFile *file; 7774 GList *l; 7775 gboolean no_directory; 7776 7777 no_directory = TRUE; 7778 7779 for (l = files; l != NULL; l = l->next) { 7780 file = NAUTILUS_FILE (l->data); 7781 no_directory &= !nautilus_file_is_directory (file); 7782 } 7783 7784 return no_directory; 7785 } 7786 7787 static void 7788 update_restore_from_trash_action (GtkAction *action, 7789 GList *files, 7790 gboolean is_self) 7791 { 7792 NautilusFile *original_file; 7793 NautilusFile *original_dir; 7794 GHashTable *original_dirs_hash; 7795 GList *original_dirs; 7796 GFile *original_location; 7797 char *tooltip, *original_name; 7798 7799 original_file = NULL; 7800 original_dir = NULL; 7801 original_dirs = NULL; 7802 original_dirs_hash = NULL; 7803 original_location = NULL; 7804 original_name = NULL; 7805 7806 if (files != NULL) { 7807 if (g_list_length (files) == 1) { 7808 original_file = nautilus_file_get_trash_original_file (files->data); 7809 } else { 7810 original_dirs_hash = nautilus_trashed_files_get_original_directories (files, NULL); 7811 if (original_dirs_hash != NULL) { 7812 original_dirs = g_hash_table_get_keys (original_dirs_hash); 7813 if (g_list_length (original_dirs) == 1) { 7814 original_dir = nautilus_file_ref (NAUTILUS_FILE (original_dirs->data)); 7815 } 7816 } 7817 } 7818 } 7819 7820 if (original_file != NULL || original_dirs != NULL) { 7821 gtk_action_set_visible (action, TRUE); 7822 7823 if (original_file != NULL) { 7824 original_location = nautilus_file_get_location (original_file); 7825 } else if (original_dir != NULL) { 7826 original_location = nautilus_file_get_location (original_dir); 7827 } 7828 7829 if (original_location != NULL) { 7830 original_name = g_file_get_parse_name (original_location); 7831 } 7832 7833 if (is_self) { 7834 g_assert (g_list_length (files) == 1); 7835 g_assert (original_location != NULL); 7836 tooltip = g_strdup_printf (_("Move the open folder out of the trash to “%s”"), original_name); 7837 } else if (files_are_all_directories (files)) { 7838 if (original_name != NULL) { 7839 if (g_list_length (files) == 1) { 7840 tooltip = g_strdup_printf (_("Move the selected folder out of the trash to “%s”"), 7841 original_name); 7842 } else { 7843 tooltip = g_strdup_printf (_("Move the selected folders out of the trash to “%s”"), 7844 original_name); 7845 } 7846 } else { 7847 if (g_list_length (files) == 1) { 7848 tooltip = g_strdup (_("Move the selected folder out of the trash")); 7849 } else { 7850 tooltip = g_strdup (_("Move the selected folders out of the trash")); 7851 } 7852 } 7853 } else if (files_is_none_directory (files)) { 7854 if (original_name != NULL) { 7855 if (g_list_length (files) == 1) { 7856 tooltip = g_strdup_printf (_("Move the selected file out of the trash to “%s”"), 7857 original_name); 7858 } else { 7859 tooltip = g_strdup_printf (_("Move the selected files out of the trash to “%s”"), 7860 original_name); 7861 } 7862 } else { 7863 if (g_list_length (files) == 1) { 7864 tooltip = g_strdup (_("Move the selected file out of the trash")); 7865 } else { 7866 tooltip = g_strdup (_("Move the selected files out of the trash")); 7867 } 7868 } 7869 } else { 7870 if (original_name != NULL) { 7871 if (g_list_length (files) == 1) { 7872 tooltip = g_strdup_printf (_("Move the selected item out of the trash to “%s”"), 7873 original_name); 7874 } else { 7875 tooltip = g_strdup_printf (_("Move the selected items out of the trash to “%s”"), 7876 original_name); 7877 } 7878 } else { 7879 if (g_list_length (files) == 1) { 7880 tooltip = g_strdup (_("Move the selected item out of the trash")); 7881 } else { 7882 tooltip = g_strdup (_("Move the selected items out of the trash")); 7883 } 7884 } 7885 } 7886 g_free (original_name); 7887 7888 g_object_set (action, "tooltip", tooltip, NULL); 7889 g_free (tooltip); 7890 7891 if (original_location != NULL) { 7892 g_object_unref (original_location); 7893 } 7894 } else { 7895 gtk_action_set_visible (action, FALSE); 7896 } 7897 7898 nautilus_file_unref (original_file); 7899 nautilus_file_unref (original_dir); 7900 g_list_free (original_dirs); 7901 7902 if (original_dirs_hash != NULL) { 7903 g_hash_table_destroy (original_dirs_hash); 7904 } 7905 } 7906 7907 static void 7908 real_update_menus_volumes (NautilusView *view, 7909 GList *selection, 7910 gint selection_count) 7911 { 7912 GList *l; 7913 NautilusFile *file; 7914 gboolean show_mount; 7915 gboolean show_unmount; 7916 gboolean show_eject; 7917 gboolean show_start; 7918 gboolean show_stop; 7919 gboolean show_poll; 7920 GDriveStartStopType start_stop_type; 7921 gboolean show_self_mount; 7922 gboolean show_self_unmount; 7923 gboolean show_self_eject; 7924 gboolean show_self_start; 7925 gboolean show_self_stop; 7926 gboolean show_self_poll; 7927 GDriveStartStopType self_start_stop_type; 7928 GtkAction *action; 7929 7930 show_mount = (selection != NULL); 7931 show_unmount = (selection != NULL); 7932 show_eject = (selection != NULL); 7933 show_start = (selection != NULL && selection_count == 1); 7934 show_stop = (selection != NULL && selection_count == 1); 7935 show_poll = (selection != NULL && selection_count == 1); 7936 start_stop_type = G_DRIVE_START_STOP_TYPE_UNKNOWN; 7937 self_start_stop_type = G_DRIVE_START_STOP_TYPE_UNKNOWN; 7938 7939 for (l = selection; l != NULL && (show_mount || show_unmount 7940 || show_eject 7941 || show_start || show_stop 7942 || show_poll); 7943 l = l->next) { 7944 gboolean show_mount_one; 7945 gboolean show_unmount_one; 7946 gboolean show_eject_one; 7947 gboolean show_start_one; 7948 gboolean show_stop_one; 7949 gboolean show_poll_one; 7950 7951 file = NAUTILUS_FILE (l->data); 7952 file_should_show_foreach (file, 7953 &show_mount_one, 7954 &show_unmount_one, 7955 &show_eject_one, 7956 &show_start_one, 7957 &show_stop_one, 7958 &show_poll_one, 7959 &start_stop_type); 7960 7961 show_mount &= show_mount_one; 7962 show_unmount &= show_unmount_one; 7963 show_eject &= show_eject_one; 7964 show_start &= show_start_one; 7965 show_stop &= show_stop_one; 7966 show_poll &= show_poll_one; 7967 } 7968 7969 action = gtk_action_group_get_action (view->details->dir_action_group, 7970 NAUTILUS_ACTION_MOUNT_VOLUME); 7971 gtk_action_set_visible (action, show_mount); 7972 7973 action = gtk_action_group_get_action (view->details->dir_action_group, 7974 NAUTILUS_ACTION_UNMOUNT_VOLUME); 7975 gtk_action_set_visible (action, show_unmount); 7976 7977 action = gtk_action_group_get_action (view->details->dir_action_group, 7978 NAUTILUS_ACTION_EJECT_VOLUME); 7979 gtk_action_set_visible (action, show_eject); 7980 7981 action = gtk_action_group_get_action (view->details->dir_action_group, 7982 NAUTILUS_ACTION_START_VOLUME); 7983 gtk_action_set_visible (action, show_start); 7984 if (show_start) { 7985 switch (start_stop_type) { 7986 default: 7987 case G_DRIVE_START_STOP_TYPE_UNKNOWN: 7988 gtk_action_set_label (action, _("_Start")); 7989 gtk_action_set_tooltip (action, _("Start the selected drive")); 7990 break; 7991 case G_DRIVE_START_STOP_TYPE_SHUTDOWN: 7992 gtk_action_set_label (action, _("_Start")); 7993 gtk_action_set_tooltip (action, _("Start the selected drive")); 7994 break; 7995 case G_DRIVE_START_STOP_TYPE_NETWORK: 7996 gtk_action_set_label (action, _("_Connect")); 7997 gtk_action_set_tooltip (action, _("Connect to the selected drive")); 7998 break; 7999 case G_DRIVE_START_STOP_TYPE_MULTIDISK: 8000 gtk_action_set_label (action, _("_Start Multi-disk Drive")); 8001 gtk_action_set_tooltip (action, _("Start the selected multi-disk drive")); 8002 break; 8003 case G_DRIVE_START_STOP_TYPE_PASSWORD: 8004 gtk_action_set_label (action, _("U_nlock Drive")); 8005 gtk_action_set_tooltip (action, _("Unlock the selected drive")); 8006 break; 8007 } 8008 } 8009 8010 action = gtk_action_group_get_action (view->details->dir_action_group, 8011 NAUTILUS_ACTION_STOP_VOLUME); 8012 gtk_action_set_visible (action, show_stop); 8013 if (show_stop) { 8014 switch (start_stop_type) { 8015 default: 8016 case G_DRIVE_START_STOP_TYPE_UNKNOWN: 8017 gtk_action_set_label (action, _("_Stop")); 8018 gtk_action_set_tooltip (action, _("Stop the selected drive")); 8019 break; 8020 case G_DRIVE_START_STOP_TYPE_SHUTDOWN: 8021 gtk_action_set_label (action, _("_Safely Remove Drive")); 8022 gtk_action_set_tooltip (action, _("Safely remove the selected drive")); 8023 break; 8024 case G_DRIVE_START_STOP_TYPE_NETWORK: 8025 gtk_action_set_label (action, _("_Disconnect")); 8026 gtk_action_set_tooltip (action, _("Disconnect the selected drive")); 8027 break; 8028 case G_DRIVE_START_STOP_TYPE_MULTIDISK: 8029 gtk_action_set_label (action, _("_Stop Multi-disk Drive")); 8030 gtk_action_set_tooltip (action, _("Stop the selected multi-disk drive")); 8031 break; 8032 case G_DRIVE_START_STOP_TYPE_PASSWORD: 8033 gtk_action_set_label (action, _("_Lock Drive")); 8034 gtk_action_set_tooltip (action, _("Lock the selected drive")); 8035 break; 8036 } 8037 } 8038 8039 action = gtk_action_group_get_action (view->details->dir_action_group, 8040 NAUTILUS_ACTION_POLL); 8041 gtk_action_set_visible (action, show_poll); 8042 8043 show_self_mount = show_self_unmount = show_self_eject = 8044 show_self_start = show_self_stop = show_self_poll = FALSE; 8045 8046 file = nautilus_view_get_directory_as_file (view); 8047 file_should_show_self (file, 8048 &show_self_mount, 8049 &show_self_unmount, 8050 &show_self_eject, 8051 &show_self_start, 8052 &show_self_stop, 8053 &show_self_poll, 8054 &self_start_stop_type); 8055 8056 action = gtk_action_group_get_action (view->details->dir_action_group, 8057 NAUTILUS_ACTION_SELF_MOUNT_VOLUME); 8058 gtk_action_set_visible (action, show_self_mount); 8059 8060 action = gtk_action_group_get_action (view->details->dir_action_group, 8061 NAUTILUS_ACTION_SELF_UNMOUNT_VOLUME); 8062 gtk_action_set_visible (action, show_self_unmount); 8063 8064 action = gtk_action_group_get_action (view->details->dir_action_group, 8065 NAUTILUS_ACTION_SELF_EJECT_VOLUME); 8066 gtk_action_set_visible (action, show_self_eject); 8067 8068 action = gtk_action_group_get_action (view->details->dir_action_group, 8069 NAUTILUS_ACTION_SELF_START_VOLUME); 8070 gtk_action_set_visible (action, show_self_start); 8071 if (show_self_start) { 8072 switch (self_start_stop_type) { 8073 default: 8074 case G_DRIVE_START_STOP_TYPE_UNKNOWN: 8075 gtk_action_set_label (action, _("_Start")); 8076 gtk_action_set_tooltip (action, _("Start the drive associated with the open folder")); 8077 break; 8078 case G_DRIVE_START_STOP_TYPE_SHUTDOWN: 8079 gtk_action_set_label (action, _("_Start")); 8080 gtk_action_set_tooltip (action, _("Start the drive associated with the open folder")); 8081 break; 8082 case G_DRIVE_START_STOP_TYPE_NETWORK: 8083 gtk_action_set_label (action, _("_Connect")); 8084 gtk_action_set_tooltip (action, _("Connect to the drive associated with the open folder")); 8085 break; 8086 case G_DRIVE_START_STOP_TYPE_MULTIDISK: 8087 gtk_action_set_label (action, _("_Start Multi-disk Drive")); 8088 gtk_action_set_tooltip (action, _("Start the multi-disk drive associated with the open folder")); 8089 break; 8090 case G_DRIVE_START_STOP_TYPE_PASSWORD: 8091 gtk_action_set_label (action, _("_Unlock Drive")); 8092 gtk_action_set_tooltip (action, _("Unlock the drive associated with the open folder")); 8093 break; 8094 } 8095 } 8096 8097 action = gtk_action_group_get_action (view->details->dir_action_group, 8098 NAUTILUS_ACTION_SELF_STOP_VOLUME); 8099 gtk_action_set_visible (action, show_self_stop); 8100 if (show_self_stop) { 8101 switch (self_start_stop_type) { 8102 default: 8103 case G_DRIVE_START_STOP_TYPE_UNKNOWN: 8104 gtk_action_set_label (action, _("_Stop")); 8105 gtk_action_set_tooltip (action, _("_Stop the drive associated with the open folder")); 8106 break; 8107 case G_DRIVE_START_STOP_TYPE_SHUTDOWN: 8108 gtk_action_set_label (action, _("_Safely Remove Drive")); 8109 gtk_action_set_tooltip (action, _("Safely remove the drive associated with the open folder")); 8110 break; 8111 case G_DRIVE_START_STOP_TYPE_NETWORK: 8112 gtk_action_set_label (action, _("_Disconnect")); 8113 gtk_action_set_tooltip (action, _("Disconnect the drive associated with the open folder")); 8114 break; 8115 case G_DRIVE_START_STOP_TYPE_MULTIDISK: 8116 gtk_action_set_label (action, _("_Stop Multi-disk Drive")); 8117 gtk_action_set_tooltip (action, _("Stop the multi-disk drive associated with the open folder")); 8118 break; 8119 case G_DRIVE_START_STOP_TYPE_PASSWORD: 8120 gtk_action_set_label (action, _("_Lock Drive")); 8121 gtk_action_set_tooltip (action, _("Lock the drive associated with the open folder")); 8122 break; 8123 } 8124 } 8125 8126 action = gtk_action_group_get_action (view->details->dir_action_group, 8127 NAUTILUS_ACTION_SELF_POLL); 8128 gtk_action_set_visible (action, show_self_poll); 8129 8130 } 8131 8132 static void 8133 real_update_location_menu_volumes (NautilusView *view) 8134 { 8135 GtkAction *action; 8136 NautilusFile *file; 8137 gboolean show_mount; 8138 gboolean show_unmount; 8139 gboolean show_eject; 8140 gboolean show_start; 8141 gboolean show_stop; 8142 gboolean show_poll; 8143 GDriveStartStopType start_stop_type; 8144 8145 g_assert (NAUTILUS_IS_VIEW (view)); 8146 g_assert (NAUTILUS_IS_FILE (view->details->location_popup_directory_as_file)); 8147 8148 file = NAUTILUS_FILE (view->details->location_popup_directory_as_file); 8149 file_should_show_foreach (file, 8150 &show_mount, 8151 &show_unmount, 8152 &show_eject, 8153 &show_start, 8154 &show_stop, 8155 &show_poll, 8156 &start_stop_type); 8157 8158 action = gtk_action_group_get_action (view->details->dir_action_group, 8159 NAUTILUS_ACTION_LOCATION_MOUNT_VOLUME); 8160 gtk_action_set_visible (action, show_mount); 8161 8162 action = gtk_action_group_get_action (view->details->dir_action_group, 8163 NAUTILUS_ACTION_LOCATION_UNMOUNT_VOLUME); 8164 gtk_action_set_visible (action, show_unmount); 8165 8166 action = gtk_action_group_get_action (view->details->dir_action_group, 8167 NAUTILUS_ACTION_LOCATION_EJECT_VOLUME); 8168 gtk_action_set_visible (action, show_eject); 8169 8170 action = gtk_action_group_get_action (view->details->dir_action_group, 8171 NAUTILUS_ACTION_LOCATION_START_VOLUME); 8172 gtk_action_set_visible (action, show_start); 8173 if (show_start) { 8174 switch (start_stop_type) { 8175 default: 8176 case G_DRIVE_START_STOP_TYPE_UNKNOWN: 8177 gtk_action_set_label (action, _("_Start")); 8178 gtk_action_set_tooltip (action, _("Start the selected drive")); 8179 break; 8180 case G_DRIVE_START_STOP_TYPE_SHUTDOWN: 8181 gtk_action_set_label (action, _("_Start")); 8182 gtk_action_set_tooltip (action, _("Start the selected drive")); 8183 break; 8184 case G_DRIVE_START_STOP_TYPE_NETWORK: 8185 gtk_action_set_label (action, _("_Connect")); 8186 gtk_action_set_tooltip (action, _("Connect to the selected drive")); 8187 break; 8188 case G_DRIVE_START_STOP_TYPE_MULTIDISK: 8189 gtk_action_set_label (action, _("_Start Multi-disk Drive")); 8190 gtk_action_set_tooltip (action, _("Start the selected multi-disk drive")); 8191 break; 8192 case G_DRIVE_START_STOP_TYPE_PASSWORD: 8193 gtk_action_set_label (action, _("_Unlock Drive")); 8194 gtk_action_set_tooltip (action, _("Unlock the selected drive")); 8195 break; 8196 } 8197 } 8198 8199 action = gtk_action_group_get_action (view->details->dir_action_group, 8200 NAUTILUS_ACTION_LOCATION_STOP_VOLUME); 8201 gtk_action_set_visible (action, show_stop); 8202 if (show_stop) { 8203 switch (start_stop_type) { 8204 default: 8205 case G_DRIVE_START_STOP_TYPE_UNKNOWN: 8206 gtk_action_set_label (action, _("_Stop")); 8207 gtk_action_set_tooltip (action, _("Stop the selected volume")); 8208 break; 8209 case G_DRIVE_START_STOP_TYPE_SHUTDOWN: 8210 gtk_action_set_label (action, _("_Safely Remove Drive")); 8211 gtk_action_set_tooltip (action, _("Safely remove the selected drive")); 8212 break; 8213 case G_DRIVE_START_STOP_TYPE_NETWORK: 8214 gtk_action_set_label (action, _("_Disconnect")); 8215 gtk_action_set_tooltip (action, _("Disconnect the selected drive")); 8216 break; 8217 case G_DRIVE_START_STOP_TYPE_MULTIDISK: 8218 gtk_action_set_label (action, _("_Stop Multi-disk Drive")); 8219 gtk_action_set_tooltip (action, _("Stop the selected multi-disk drive")); 8220 break; 8221 case G_DRIVE_START_STOP_TYPE_PASSWORD: 8222 gtk_action_set_label (action, _("_Lock Drive")); 8223 gtk_action_set_tooltip (action, _("Lock the selected drive")); 8224 break; 8225 } 8226 } 8227 8228 action = gtk_action_group_get_action (view->details->dir_action_group, 8229 NAUTILUS_ACTION_LOCATION_POLL); 8230 gtk_action_set_visible (action, show_poll); 8231 } 8232 8233 /* TODO: we should split out this routine into two functions: 8234 * Update on clipboard changes 8235 * Update on selection changes 8236 */ 8237 static void 8238 real_update_paste_menu (NautilusView *view, 8239 GList *selection, 8240 gint selection_count) 8241 { 8242 gboolean can_paste_files_into; 8243 gboolean selection_is_read_only; 8244 gboolean selection_contains_recent; 8245 gboolean is_read_only; 8246 GtkAction *action; 8247 8248 selection_is_read_only = selection_count == 1 && 8249 (!nautilus_file_can_write (NAUTILUS_FILE (selection->data)) && 8250 !nautilus_file_has_activation_uri (NAUTILUS_FILE (selection->data))); 8251 8252 is_read_only = nautilus_view_is_read_only (view); 8253 selection_contains_recent = showing_recent_directory (view); 8254 8255 can_paste_files_into = (!selection_contains_recent && 8256 selection_count == 1 && 8257 can_paste_into_file (NAUTILUS_FILE (selection->data))); 8258 8259 action = gtk_action_group_get_action (view->details->dir_action_group, 8260 NAUTILUS_ACTION_PASTE); 8261 gtk_action_set_sensitive (action, !is_read_only); 8262 gtk_action_set_visible (action, !selection_contains_recent); 8263 8264 action = gtk_action_group_get_action (view->details->dir_action_group, 8265 NAUTILUS_ACTION_PASTE_FILES_INTO); 8266 gtk_action_set_visible (action, can_paste_files_into); 8267 gtk_action_set_sensitive (action, !selection_is_read_only); 8268 8269 /* Ask the clipboard */ 8270 g_object_ref (view); /* Need to keep the object alive until we get the reply */ 8271 gtk_clipboard_request_targets (nautilus_clipboard_get (GTK_WIDGET (view)), 8272 clipboard_targets_received, 8273 view); 8274 } 8275 8276 static void 8277 real_update_location_menu (NautilusView *view) 8278 { 8279 GtkAction *action; 8280 NautilusFile *file; 8281 gboolean is_special_link; 8282 gboolean is_desktop_or_home_dir; 8283 gboolean is_recent; 8284 gboolean can_delete_file, show_delete; 8285 gboolean show_separate_delete_command; 8286 GList l; 8287 char *label; 8288 char *tip; 8289 8290 action = gtk_action_group_get_action (view->details->dir_action_group, 8291 NAUTILUS_ACTION_LOCATION_OPEN_ALTERNATE); 8292 8293 label = _("Open in New _Window"); 8294 g_object_set (action, 8295 "label", label, 8296 NULL); 8297 8298 action = gtk_action_group_get_action (view->details->dir_action_group, 8299 NAUTILUS_ACTION_LOCATION_OPEN_IN_NEW_TAB); 8300 8301 label = _("Open in New _Tab"); 8302 g_object_set (action, 8303 "label", label, 8304 NULL); 8305 8306 file = view->details->location_popup_directory_as_file; 8307 g_assert (NAUTILUS_IS_FILE (file)); 8308 g_assert (nautilus_file_check_if_ready (file, NAUTILUS_FILE_ATTRIBUTE_INFO | 8309 NAUTILUS_FILE_ATTRIBUTE_MOUNT | 8310 NAUTILUS_FILE_ATTRIBUTE_FILESYSTEM_INFO)); 8311 8312 is_special_link = NAUTILUS_IS_DESKTOP_ICON_FILE (file); 8313 is_desktop_or_home_dir = nautilus_file_is_home (file) 8314 || nautilus_file_is_desktop_directory (file); 8315 is_recent = nautilus_file_is_in_recent (file); 8316 8317 can_delete_file = 8318 nautilus_file_can_delete (file) && 8319 !is_special_link && 8320 !is_desktop_or_home_dir; 8321 8322 action = gtk_action_group_get_action (view->details->dir_action_group, 8323 NAUTILUS_ACTION_LOCATION_CUT); 8324 gtk_action_set_sensitive (action, !is_recent && can_delete_file); 8325 gtk_action_set_visible (action, !is_recent); 8326 8327 action = gtk_action_group_get_action (view->details->dir_action_group, 8328 NAUTILUS_ACTION_LOCATION_PASTE_FILES_INTO); 8329 g_object_set_data (G_OBJECT (action), 8330 "can-paste-according-to-destination", 8331 GINT_TO_POINTER (can_paste_into_file (file))); 8332 gtk_action_set_sensitive (action, 8333 !is_recent && 8334 GPOINTER_TO_INT (g_object_get_data (G_OBJECT (action), 8335 "can-paste-according-to-clipboard")) && 8336 GPOINTER_TO_INT (g_object_get_data (G_OBJECT (action), 8337 "can-paste-according-to-destination"))); 8338 gtk_action_set_visible (action, !is_recent); 8339 8340 show_delete = TRUE; 8341 8342 if (file != NULL && 8343 nautilus_file_is_in_trash (file)) { 8344 if (nautilus_file_is_self_owned (file)) { 8345 show_delete = FALSE; 8346 } 8347 8348 label = _("_Delete Permanently"); 8349 tip = _("Delete the open folder permanently"); 8350 show_separate_delete_command = FALSE; 8351 } else { 8352 label = _("Mo_ve to Trash"); 8353 tip = _("Move the open folder to the Trash"); 8354 show_separate_delete_command = g_settings_get_boolean (nautilus_preferences, NAUTILUS_PREFERENCES_ENABLE_DELETE); 8355 } 8356 8357 action = gtk_action_group_get_action (view->details->dir_action_group, 8358 NAUTILUS_ACTION_LOCATION_TRASH); 8359 g_object_set (action, 8360 "label", label, 8361 "tooltip", tip, 8362 "icon-name", (file != NULL && 8363 nautilus_file_is_in_trash (file)) ? 8364 NAUTILUS_ICON_DELETE : NAUTILUS_ICON_TRASH_FULL, 8365 NULL); 8366 gtk_action_set_sensitive (action, can_delete_file); 8367 gtk_action_set_visible (action, show_delete); 8368 8369 action = gtk_action_group_get_action (view->details->dir_action_group, 8370 NAUTILUS_ACTION_LOCATION_DELETE); 8371 gtk_action_set_visible (action, show_separate_delete_command); 8372 if (show_separate_delete_command) { 8373 gtk_action_set_sensitive (action, can_delete_file); 8374 g_object_set (action, 8375 "icon-name", NAUTILUS_ICON_DELETE, 8376 "sensitive", can_delete_file, 8377 NULL); 8378 } 8379 8380 action = gtk_action_group_get_action (view->details->dir_action_group, 8381 NAUTILUS_ACTION_LOCATION_RESTORE_FROM_TRASH); 8382 l.prev = NULL; 8383 l.next = NULL; 8384 l.data = file; 8385 update_restore_from_trash_action (action, &l, TRUE); 8386 8387 real_update_location_menu_volumes (view); 8388 } 8389 8390 static void 8391 clipboard_changed_callback (NautilusClipboardMonitor *monitor, NautilusView *view) 8392 { 8393 GList *selection; 8394 gint selection_count; 8395 8396 if (!view->details->active) { 8397 return; 8398 } 8399 8400 selection = nautilus_view_get_selection (view); 8401 selection_count = g_list_length (selection); 8402 8403 real_update_paste_menu (view, selection, selection_count); 8404 8405 nautilus_file_list_free (selection); 8406 8407 } 8408 8409 static gboolean 8410 can_delete_all (GList *files) 8411 { 8412 NautilusFile *file; 8413 GList *l; 8414 8415 for (l = files; l != NULL; l = l->next) { 8416 file = l->data; 8417 if (!nautilus_file_can_delete (file)) { 8418 return FALSE; 8419 } 8420 } 8421 return TRUE; 8422 } 8423 8424 static gboolean 8425 can_trash_all (GList *files) 8426 { 8427 NautilusFile *file; 8428 GList *l; 8429 8430 for (l = files; l != NULL; l = l->next) { 8431 file = l->data; 8432 if (!nautilus_file_can_trash (file)) { 8433 return FALSE; 8434 } 8435 } 8436 return TRUE; 8437 } 8438 8439 static void 8440 real_update_menus (NautilusView *view) 8441 { 8442 GList *selection, *l; 8443 gint selection_count; 8444 const char *tip, *label; 8445 char *label_with_underscore; 8446 gboolean selection_contains_special_link; 8447 gboolean selection_contains_desktop_or_home_dir; 8448 gboolean selection_contains_recent; 8449 gboolean can_create_files; 8450 gboolean can_delete_files; 8451 gboolean can_trash_files; 8452 gboolean can_copy_files; 8453 gboolean can_link_files; 8454 gboolean show_separate_delete_command; 8455 gboolean show_open_alternate; 8456 gboolean show_open_in_new_tab; 8457 gboolean can_open; 8458 gboolean show_app; 8459 gboolean show_save_search; 8460 gboolean save_search_sensitive; 8461 gboolean show_save_search_as; 8462 GtkAction *action; 8463 GAppInfo *app; 8464 GIcon *app_icon; 8465 GtkWidget *menuitem; 8466 gboolean show_properties; 8467 8468 selection = nautilus_view_get_selection (view); 8469 selection_count = g_list_length (selection); 8470 8471 selection_contains_special_link = special_link_in_selection (view); 8472 selection_contains_desktop_or_home_dir = desktop_or_home_dir_in_selection (view); 8473 selection_contains_recent = showing_recent_directory (view); 8474 8475 can_create_files = nautilus_view_supports_creating_files (view); 8476 can_delete_files = 8477 can_delete_all (selection) && 8478 selection_count != 0 && 8479 !selection_contains_special_link && 8480 !selection_contains_desktop_or_home_dir; 8481 can_trash_files = 8482 can_trash_all (selection) && 8483 selection_count != 0 && 8484 !selection_contains_special_link && 8485 !selection_contains_desktop_or_home_dir; 8486 can_copy_files = selection_count != 0 8487 && !selection_contains_recent 8488 && !selection_contains_special_link; 8489 8490 can_link_files = can_create_files && can_copy_files; 8491 8492 action = gtk_action_group_get_action (view->details->dir_action_group, 8493 NAUTILUS_ACTION_RENAME); 8494 /* rename sensitivity depending on selection */ 8495 if (selection_count > 1) { 8496 /* If multiple files are selected, sensitivity depends on whether a bulk renamer is registered. */ 8497 gtk_action_set_sensitive (action, have_bulk_rename_tool ()); 8498 } else { 8499 gtk_action_set_sensitive (action, 8500 selection_count == 1 && 8501 nautilus_view_can_rename_file (view, selection->data)); 8502 } 8503 gtk_action_set_visible (action, !selection_contains_recent); 8504 8505 action = gtk_action_group_get_action (view->details->dir_action_group, 8506 NAUTILUS_ACTION_SET_AS_WALLPAPER); 8507 /* rename sensitivity depending on selection */ 8508 if (can_set_wallpaper (selection)) { 8509 gtk_action_set_visible (action, TRUE); 8510 } else { 8511 gtk_action_set_visible (action, FALSE); 8512 } 8513 8514 action = gtk_action_group_get_action (view->details->dir_action_group, 8515 NAUTILUS_ACTION_NEW_FOLDER); 8516 gtk_action_set_sensitive (action, can_create_files); 8517 gtk_action_set_visible (action, !selection_contains_recent); 8518 8519 action = gtk_action_group_get_action (view->details->dir_action_group, 8520 NAUTILUS_ACTION_NEW_FOLDER_WITH_SELECTION); 8521 gtk_action_set_sensitive (action, can_create_files && can_delete_files && (selection_count > 1)); 8522 gtk_action_set_visible (action, !selection_contains_recent && (selection_count > 1)); 8523 label_with_underscore = g_strdup_printf (ngettext("New Folder with Selection (%'d Item)", 8524 "New Folder with Selection (%'d Items)", 8525 selection_count), 8526 selection_count); 8527 g_object_set (action, "label", label_with_underscore, NULL); 8528 g_free (label_with_underscore); 8529 8530 action = gtk_action_group_get_action (view->details->dir_action_group, 8531 NAUTILUS_ACTION_OPEN); 8532 gtk_action_set_sensitive (action, selection_count != 0); 8533 8534 can_open = show_app = selection_count != 0; 8535 8536 for (l = selection; l != NULL; l = l->next) { 8537 NautilusFile *file; 8538 8539 file = NAUTILUS_FILE (selection->data); 8540 8541 if (!nautilus_mime_file_opens_in_external_app (file)) { 8542 show_app = FALSE; 8543 } 8544 8545 if (!show_app) { 8546 break; 8547 } 8548 } 8549 8550 label_with_underscore = NULL; 8551 8552 app = NULL; 8553 app_icon = NULL; 8554 8555 if (can_open && show_app) { 8556 app = nautilus_mime_get_default_application_for_files (selection); 8557 } 8558 8559 if (app != NULL) { 8560 char *escaped_app; 8561 8562 escaped_app = eel_str_double_underscores (g_app_info_get_display_name (app)); 8563 label_with_underscore = g_strdup_printf (_("_Open With %s"), 8564 escaped_app); 8565 8566 app_icon = g_app_info_get_icon (app); 8567 if (app_icon != NULL) { 8568 g_object_ref (app_icon); 8569 } 8570 8571 g_free (escaped_app); 8572 g_object_unref (app); 8573 } 8574 8575 g_object_set (action, "label", 8576 label_with_underscore ? label_with_underscore : _("_Open"), 8577 NULL); 8578 8579 menuitem = gtk_ui_manager_get_widget ( 8580 nautilus_view_get_ui_manager (view), 8581 NAUTILUS_VIEW_POPUP_PATH_OPEN); 8582 8583 /* Only force displaying the icon if it is an application icon */ 8584 gtk_image_menu_item_set_always_show_image ( 8585 GTK_IMAGE_MENU_ITEM (menuitem), app_icon != NULL); 8586 8587 if (app_icon == NULL) { 8588 app_icon = g_themed_icon_new (GTK_STOCK_OPEN); 8589 } 8590 8591 gtk_action_set_gicon (action, app_icon); 8592 g_object_unref (app_icon); 8593 8594 gtk_action_set_visible (action, can_open); 8595 8596 g_free (label_with_underscore); 8597 8598 show_open_alternate = file_list_all_are_folders (selection) && 8599 selection_count > 0 && 8600 !NAUTILUS_IS_DESKTOP_CANVAS_VIEW (view); 8601 8602 action = gtk_action_group_get_action (view->details->dir_action_group, 8603 NAUTILUS_ACTION_OPEN_ALTERNATE); 8604 8605 gtk_action_set_sensitive (action, selection_count != 0); 8606 gtk_action_set_visible (action, show_open_alternate); 8607 8608 if (selection_count == 0 || selection_count == 1) { 8609 label_with_underscore = g_strdup (_("Open in New _Window")); 8610 } else { 8611 label_with_underscore = g_strdup_printf (ngettext("Open in %'d New _Window", 8612 "Open in %'d New _Windows", 8613 selection_count), 8614 selection_count); 8615 } 8616 8617 g_object_set (action, "label", 8618 label_with_underscore, 8619 NULL); 8620 g_free (label_with_underscore); 8621 8622 show_open_in_new_tab = show_open_alternate; 8623 action = gtk_action_group_get_action (view->details->dir_action_group, 8624 NAUTILUS_ACTION_OPEN_IN_NEW_TAB); 8625 gtk_action_set_sensitive (action, selection_count != 0); 8626 gtk_action_set_visible (action, show_open_in_new_tab); 8627 8628 if (selection_count == 0 || selection_count == 1) { 8629 label_with_underscore = g_strdup (_("Open in New _Tab")); 8630 } else { 8631 label_with_underscore = g_strdup_printf (ngettext("Open in %'d New _Tab", 8632 "Open in %'d New _Tabs", 8633 selection_count), 8634 selection_count); 8635 } 8636 8637 g_object_set (action, "label", 8638 label_with_underscore, 8639 NULL); 8640 g_free (label_with_underscore); 8641 8642 /* Broken into its own function just for convenience */ 8643 reset_open_with_menu (view, selection); 8644 reset_extension_actions_menu (view, selection); 8645 8646 if (all_selected_items_in_trash (view)) { 8647 label = _("_Delete Permanently"); 8648 tip = _("Delete all selected items permanently"); 8649 show_separate_delete_command = FALSE; 8650 } else { 8651 label = _("Mo_ve to Trash"); 8652 tip = _("Move each selected item to the Trash"); 8653 show_separate_delete_command = g_settings_get_boolean (nautilus_preferences, NAUTILUS_PREFERENCES_ENABLE_DELETE); 8654 } 8655 8656 action = gtk_action_group_get_action (view->details->dir_action_group, 8657 NAUTILUS_ACTION_TRASH); 8658 g_object_set (action, 8659 "label", label, 8660 "tooltip", tip, 8661 "icon-name", all_selected_items_in_trash (view) ? 8662 NAUTILUS_ICON_DELETE : NAUTILUS_ICON_TRASH_FULL, 8663 NULL); 8664 /* if the backend supports delete but not trash then don't show trash */ 8665 if (!can_trash_files && can_delete_files) { 8666 gtk_action_set_visible (action, FALSE); 8667 } else { 8668 gtk_action_set_visible (action, TRUE); 8669 gtk_action_set_sensitive (action, can_trash_files); 8670 } 8671 8672 action = gtk_action_group_get_action (view->details->dir_action_group, 8673 NAUTILUS_ACTION_DELETE); 8674 /* if the backend doesn't support trash but supports delete 8675 show the delete option. or if the user set this pref */ 8676 gtk_action_set_visible (action, (!can_trash_files && can_delete_files) || show_separate_delete_command); 8677 8678 if ((!can_trash_files && can_delete_files) || show_separate_delete_command) { 8679 g_object_set (action, 8680 "label", _("_Delete"), 8681 "icon-name", NAUTILUS_ICON_DELETE, 8682 NULL); 8683 } 8684 gtk_action_set_sensitive (action, can_delete_files); 8685 8686 8687 action = gtk_action_group_get_action (view->details->dir_action_group, 8688 NAUTILUS_ACTION_RESTORE_FROM_TRASH); 8689 update_restore_from_trash_action (action, selection, FALSE); 8690 8691 action = gtk_action_group_get_action (view->details->dir_action_group, 8692 NAUTILUS_ACTION_CREATE_LINK); 8693 gtk_action_set_sensitive (action, can_link_files); 8694 gtk_action_set_visible (action, !selection_contains_recent); 8695 g_object_set (action, "label", 8696 ngettext ("Ma_ke Link", 8697 "Ma_ke Links", 8698 selection_count), 8699 NULL); 8700 8701 show_properties = !showing_network_directory (view) 8702 && (!NAUTILUS_IS_DESKTOP_CANVAS_VIEW (view) || selection_count > 0); 8703 8704 action = gtk_action_group_get_action (view->details->dir_action_group, 8705 NAUTILUS_ACTION_PROPERTIES); 8706 8707 gtk_action_set_sensitive (action, show_properties); 8708 gtk_action_set_visible (action, show_properties); 8709 8710 if (selection_count == 0) { 8711 gtk_action_set_tooltip (action, _("View or modify the properties of the open folder")); 8712 } else { 8713 gtk_action_set_tooltip (action, _("View or modify the properties of each selected item")); 8714 } 8715 8716 action = gtk_action_group_get_action (view->details->dir_action_group, 8717 NAUTILUS_ACTION_PROPERTIES_ACCEL); 8718 8719 gtk_action_set_sensitive (action, show_properties); 8720 gtk_action_set_visible (action, show_properties); 8721 8722 action = gtk_action_group_get_action (view->details->dir_action_group, 8723 NAUTILUS_ACTION_EMPTY_TRASH); 8724 g_object_set (action, 8725 "label", _("E_mpty Trash"), 8726 NULL); 8727 gtk_action_set_sensitive (action, !nautilus_trash_monitor_is_empty ()); 8728 gtk_action_set_visible (action, should_show_empty_trash (view)); 8729 8730 show_save_search = FALSE; 8731 save_search_sensitive = FALSE; 8732 show_save_search_as = FALSE; 8733 if (view->details->model && 8734 NAUTILUS_IS_SEARCH_DIRECTORY (view->details->model)) { 8735 NautilusSearchDirectory *search; 8736 8737 search = NAUTILUS_SEARCH_DIRECTORY (view->details->model); 8738 if (nautilus_search_directory_is_saved_search (search)) { 8739 show_save_search = TRUE; 8740 save_search_sensitive = nautilus_search_directory_is_modified (search); 8741 } else { 8742 show_save_search_as = TRUE; 8743 } 8744 } 8745 action = gtk_action_group_get_action (view->details->dir_action_group, 8746 NAUTILUS_ACTION_SAVE_SEARCH); 8747 gtk_action_set_visible (action, show_save_search); 8748 gtk_action_set_sensitive (action, save_search_sensitive); 8749 action = gtk_action_group_get_action (view->details->dir_action_group, 8750 NAUTILUS_ACTION_SAVE_SEARCH_AS); 8751 gtk_action_set_visible (action, show_save_search_as); 8752 8753 8754 action = gtk_action_group_get_action (view->details->dir_action_group, 8755 NAUTILUS_ACTION_SELECT_ALL); 8756 gtk_action_set_sensitive (action, !nautilus_view_is_empty (view)); 8757 8758 action = gtk_action_group_get_action (view->details->dir_action_group, 8759 NAUTILUS_ACTION_SELECT_PATTERN); 8760 gtk_action_set_sensitive (action, !nautilus_view_is_empty (view)); 8761 8762 action = gtk_action_group_get_action (view->details->dir_action_group, 8763 NAUTILUS_ACTION_INVERT_SELECTION); 8764 gtk_action_set_sensitive (action, !nautilus_view_is_empty (view)); 8765 8766 action = gtk_action_group_get_action (view->details->dir_action_group, 8767 NAUTILUS_ACTION_CUT); 8768 gtk_action_set_sensitive (action, can_delete_files); 8769 gtk_action_set_visible (action, !selection_contains_recent); 8770 8771 action = gtk_action_group_get_action (view->details->dir_action_group, 8772 NAUTILUS_ACTION_COPY); 8773 gtk_action_set_sensitive (action, can_copy_files); 8774 8775 real_update_paste_menu (view, selection, selection_count); 8776 8777 real_update_menus_volumes (view, selection, selection_count); 8778 8779 update_undo_actions (view); 8780 8781 nautilus_file_list_free (selection); 8782 8783 if (view->details->scripts_invalid) { 8784 update_scripts_menu (view); 8785 } 8786 8787 if (can_create_files 8788 && !selection_contains_recent 8789 && view->details->templates_invalid) { 8790 update_templates_menu (view); 8791 } 8792 action = gtk_action_group_get_action (view->details->dir_action_group, 8793 NAUTILUS_ACTION_NEW_DOCUMENTS); 8794 gtk_action_set_sensitive (action, can_create_files); 8795 gtk_action_set_visible (action, !selection_contains_recent && view->details->templates_present); 8796 8797 action = gtk_action_group_get_action (view->details->dir_action_group, 8798 NAUTILUS_ACTION_COPY_TO); 8799 gtk_action_set_sensitive (action, can_copy_files); 8800 gtk_action_set_visible (action, !selection_contains_recent); 8801 action = gtk_action_group_get_action (view->details->dir_action_group, 8802 NAUTILUS_ACTION_MOVE_TO); 8803 gtk_action_set_sensitive (action, can_delete_files); 8804 gtk_action_set_visible (action, !selection_contains_recent); 8805 8806 action = gtk_action_group_get_action (view->details->dir_action_group, NAUTILUS_ACTION_SHOW_HIDDEN_FILES); 8807 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), view->details->show_hidden_files); 8808 } 8809 8810 /** 8811 * nautilus_view_pop_up_selection_context_menu 8812 * 8813 * Pop up a context menu appropriate to the selected items. 8814 * @view: NautilusView of interest. 8815 * @event: The event that triggered this context menu. 8816 * 8817 * Return value: NautilusDirectory for this view. 8818 * 8819 **/ 8820 void 8821 nautilus_view_pop_up_selection_context_menu (NautilusView *view, 8822 GdkEventButton *event) 8823 { 8824 g_assert (NAUTILUS_IS_VIEW (view)); 8825 8826 /* Make the context menu items not flash as they update to proper disabled, 8827 * etc. states by forcing menus to update now. 8828 */ 8829 update_menus_if_pending (view); 8830 8831 update_context_menu_position_from_event (view, event); 8832 8833 eel_pop_up_context_menu (create_popup_menu 8834 (view, NAUTILUS_VIEW_POPUP_PATH_SELECTION), 8835 event); 8836 } 8837 8838 /** 8839 * nautilus_view_pop_up_background_context_menu 8840 * 8841 * Pop up a context menu appropriate to the view globally at the last right click location. 8842 * @view: NautilusView of interest. 8843 * 8844 * Return value: NautilusDirectory for this view. 8845 * 8846 **/ 8847 void 8848 nautilus_view_pop_up_background_context_menu (NautilusView *view, 8849 GdkEventButton *event) 8850 { 8851 g_assert (NAUTILUS_IS_VIEW (view)); 8852 8853 /* Make the context menu items not flash as they update to proper disabled, 8854 * etc. states by forcing menus to update now. 8855 */ 8856 update_menus_if_pending (view); 8857 8858 update_context_menu_position_from_event (view, event); 8859 8860 8861 eel_pop_up_context_menu (create_popup_menu 8862 (view, NAUTILUS_VIEW_POPUP_PATH_BACKGROUND), 8863 event); 8864 } 8865 8866 static void 8867 real_pop_up_location_context_menu (NautilusView *view) 8868 { 8869 /* always update the menu before showing it. Shouldn't be too expensive. */ 8870 real_update_location_menu (view); 8871 8872 update_context_menu_position_from_event (view, view->details->location_popup_event); 8873 8874 eel_pop_up_context_menu (create_popup_menu 8875 (view, NAUTILUS_VIEW_POPUP_PATH_LOCATION), 8876 view->details->location_popup_event); 8877 } 8878 8879 static void 8880 location_popup_file_attributes_ready (NautilusFile *file, 8881 gpointer data) 8882 { 8883 NautilusView *view; 8884 8885 view = NAUTILUS_VIEW (data); 8886 g_assert (NAUTILUS_IS_VIEW (view)); 8887 8888 g_assert (file == view->details->location_popup_directory_as_file); 8889 8890 real_pop_up_location_context_menu (view); 8891 } 8892 8893 static void 8894 unschedule_pop_up_location_context_menu (NautilusView *view) 8895 { 8896 if (view->details->location_popup_directory_as_file != NULL) { 8897 g_assert (NAUTILUS_IS_FILE (view->details->location_popup_directory_as_file)); 8898 nautilus_file_cancel_call_when_ready (view->details->location_popup_directory_as_file, 8899 location_popup_file_attributes_ready, 8900 view); 8901 nautilus_file_unref (view->details->location_popup_directory_as_file); 8902 view->details->location_popup_directory_as_file = NULL; 8903 } 8904 } 8905 8906 static void 8907 schedule_pop_up_location_context_menu (NautilusView *view, 8908 GdkEventButton *event, 8909 NautilusFile *file) 8910 { 8911 g_assert (NAUTILUS_IS_FILE (file)); 8912 8913 if (view->details->location_popup_event != NULL) { 8914 gdk_event_free ((GdkEvent *) view->details->location_popup_event); 8915 } 8916 view->details->location_popup_event = (GdkEventButton *) gdk_event_copy ((GdkEvent *)event); 8917 8918 if (file == view->details->location_popup_directory_as_file) { 8919 if (nautilus_file_check_if_ready (file, NAUTILUS_FILE_ATTRIBUTE_INFO | 8920 NAUTILUS_FILE_ATTRIBUTE_MOUNT | 8921 NAUTILUS_FILE_ATTRIBUTE_FILESYSTEM_INFO)) { 8922 real_pop_up_location_context_menu (view); 8923 } 8924 } else { 8925 unschedule_pop_up_location_context_menu (view); 8926 8927 view->details->location_popup_directory_as_file = nautilus_file_ref (file); 8928 nautilus_file_call_when_ready (view->details->location_popup_directory_as_file, 8929 NAUTILUS_FILE_ATTRIBUTE_INFO | 8930 NAUTILUS_FILE_ATTRIBUTE_MOUNT | 8931 NAUTILUS_FILE_ATTRIBUTE_FILESYSTEM_INFO, 8932 location_popup_file_attributes_ready, 8933 view); 8934 } 8935 } 8936 8937 /** 8938 * nautilus_view_pop_up_location_context_menu 8939 * 8940 * Pop up a context menu appropriate to the view globally. 8941 * @view: NautilusView of interest. 8942 * @event: GdkEventButton triggering the popup. 8943 * @location: The location the popup-menu should be created for, 8944 * or NULL for the currently displayed location. 8945 * 8946 **/ 8947 void 8948 nautilus_view_pop_up_location_context_menu (NautilusView *view, 8949 GdkEventButton *event, 8950 const char *location) 8951 { 8952 NautilusFile *file; 8953 8954 g_assert (NAUTILUS_IS_VIEW (view)); 8955 8956 if (location != NULL) { 8957 file = nautilus_file_get_by_uri (location); 8958 } else { 8959 file = nautilus_file_ref (view->details->directory_as_file); 8960 } 8961 8962 if (file != NULL) { 8963 schedule_pop_up_location_context_menu (view, event, file); 8964 nautilus_file_unref (file); 8965 } 8966 } 8967 8968 static void 8969 schedule_update_menus (NautilusView *view) 8970 { 8971 g_assert (NAUTILUS_IS_VIEW (view)); 8972 8973 /* Don't schedule updates after destroy (#349551), 8974 * or if we are not active. 8975 */ 8976 if (view->details->slot == NULL || 8977 !view->details->active) { 8978 return; 8979 } 8980 8981 view->details->menu_states_untrustworthy = TRUE; 8982 8983 /* Schedule a menu update with the current update interval */ 8984 if (view->details->update_menus_timeout_id == 0) { 8985 view->details->update_menus_timeout_id 8986 = g_timeout_add (view->details->update_interval, update_menus_timeout_callback, view); 8987 } 8988 } 8989 8990 static void 8991 remove_update_status_idle_callback (NautilusView *view) 8992 { 8993 if (view->details->update_status_idle_id != 0) { 8994 g_source_remove (view->details->update_status_idle_id); 8995 view->details->update_status_idle_id = 0; 8996 } 8997 } 8998 8999 static gboolean 9000 update_status_idle_callback (gpointer data) 9001 { 9002 NautilusView *view; 9003 9004 view = NAUTILUS_VIEW (data); 9005 nautilus_view_display_selection_info (view); 9006 view->details->update_status_idle_id = 0; 9007 return FALSE; 9008 } 9009 9010 static void 9011 schedule_update_status (NautilusView *view) 9012 { 9013 g_assert (NAUTILUS_IS_VIEW (view)); 9014 9015 /* Make sure we haven't already destroyed it */ 9016 if (view->details->slot == NULL) { 9017 return; 9018 } 9019 9020 if (view->details->loading) { 9021 /* Don't update status bar while loading the dir */ 9022 return; 9023 } 9024 9025 if (view->details->update_status_idle_id == 0) { 9026 view->details->update_status_idle_id = 9027 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE - 20, 9028 update_status_idle_callback, view, NULL); 9029 } 9030 } 9031 9032 /** 9033 * nautilus_view_notify_selection_changed: 9034 * 9035 * Notify this view that the selection has changed. This is normally 9036 * called only by subclasses. 9037 * @view: NautilusView whose selection has changed. 9038 * 9039 **/ 9040 void 9041 nautilus_view_notify_selection_changed (NautilusView *view) 9042 { 9043 GtkWindow *window; 9044 GList *selection; 9045 9046 g_return_if_fail (NAUTILUS_IS_VIEW (view)); 9047 9048 selection = nautilus_view_get_selection (view); 9049 window = nautilus_view_get_containing_window (view); 9050 DEBUG_FILES (selection, "Selection changed in window %p", window); 9051 nautilus_file_list_free (selection); 9052 9053 view->details->selection_was_removed = FALSE; 9054 9055 if (!view->details->selection_change_is_due_to_shell) { 9056 view->details->send_selection_change_to_shell = TRUE; 9057 } 9058 9059 /* Schedule a display of the new selection. */ 9060 if (view->details->display_selection_idle_id == 0) { 9061 view->details->display_selection_idle_id 9062 = g_idle_add (display_selection_info_idle_callback, 9063 view); 9064 } 9065 9066 if (view->details->batching_selection_level != 0) { 9067 view->details->selection_changed_while_batched = TRUE; 9068 } else { 9069 /* Here is the work we do only when we're not 9070 * batching selection changes. In other words, it's the slower 9071 * stuff that we don't want to slow down selection techniques 9072 * such as rubberband-selecting in icon view. 9073 */ 9074 9075 /* Schedule an update of menu item states to match selection */ 9076 schedule_update_menus (view); 9077 } 9078 } 9079 9080 static void 9081 file_changed_callback (NautilusFile *file, gpointer callback_data) 9082 { 9083 NautilusView *view = NAUTILUS_VIEW (callback_data); 9084 9085 schedule_changes (view); 9086 9087 schedule_update_menus (view); 9088 schedule_update_status (view); 9089 } 9090 9091 /** 9092 * load_directory: 9093 * 9094 * Switch the displayed location to a new uri. If the uri is not valid, 9095 * the location will not be switched; user feedback will be provided instead. 9096 * @view: NautilusView whose location will be changed. 9097 * @uri: A string representing the uri to switch to. 9098 * 9099 **/ 9100 static void 9101 load_directory (NautilusView *view, 9102 NautilusDirectory *directory) 9103 { 9104 NautilusDirectory *old_directory; 9105 NautilusFile *old_file; 9106 NautilusFileAttributes attributes; 9107 9108 g_assert (NAUTILUS_IS_VIEW (view)); 9109 g_assert (NAUTILUS_IS_DIRECTORY (directory)); 9110 9111 nautilus_profile_start (NULL); 9112 9113 nautilus_view_stop_loading (view); 9114 g_signal_emit (view, signals[CLEAR], 0); 9115 9116 view->details->loading = TRUE; 9117 9118 /* Update menus when directory is empty, before going to new 9119 * location, so they won't have any false lingering knowledge 9120 * of old selection. 9121 */ 9122 schedule_update_menus (view); 9123 9124 while (view->details->subdirectory_list != NULL) { 9125 nautilus_view_remove_subdirectory (view, 9126 view->details->subdirectory_list->data); 9127 } 9128 9129 old_directory = view->details->model; 9130 disconnect_model_handlers (view); 9131 9132 nautilus_directory_ref (directory); 9133 view->details->model = directory; 9134 nautilus_directory_unref (old_directory); 9135 9136 old_file = view->details->directory_as_file; 9137 view->details->directory_as_file = 9138 nautilus_directory_get_corresponding_file (directory); 9139 nautilus_file_unref (old_file); 9140 9141 view->details->reported_load_error = FALSE; 9142 9143 /* FIXME bugzilla.gnome.org 45062: In theory, we also need to monitor metadata here (as 9144 * well as doing a call when ready), in case external forces 9145 * change the directory's file metadata. 9146 */ 9147 attributes = 9148 NAUTILUS_FILE_ATTRIBUTE_INFO | 9149 NAUTILUS_FILE_ATTRIBUTE_MOUNT | 9150 NAUTILUS_FILE_ATTRIBUTE_FILESYSTEM_INFO; 9151 view->details->metadata_for_directory_as_file_pending = TRUE; 9152 view->details->metadata_for_files_in_directory_pending = TRUE; 9153 nautilus_file_call_when_ready 9154 (view->details->directory_as_file, 9155 attributes, 9156 metadata_for_directory_as_file_ready_callback, view); 9157 nautilus_directory_call_when_ready 9158 (view->details->model, 9159 attributes, 9160 FALSE, 9161 metadata_for_files_in_directory_ready_callback, view); 9162 9163 /* If capabilities change, then we need to update the menus 9164 * because of New Folder, and relative emblems. 9165 */ 9166 attributes = 9167 NAUTILUS_FILE_ATTRIBUTE_INFO | 9168 NAUTILUS_FILE_ATTRIBUTE_FILESYSTEM_INFO; 9169 nautilus_file_monitor_add (view->details->directory_as_file, 9170 &view->details->directory_as_file, 9171 attributes); 9172 9173 view->details->file_changed_handler_id = g_signal_connect 9174 (view->details->directory_as_file, "changed", 9175 G_CALLBACK (file_changed_callback), view); 9176 9177 nautilus_profile_end (NULL); 9178 } 9179 9180 static void 9181 finish_loading (NautilusView *view) 9182 { 9183 NautilusFileAttributes attributes; 9184 NautilusWindow *window; 9185 9186 nautilus_profile_start (NULL); 9187 9188 window = nautilus_view_get_window (view); 9189 nautilus_window_report_load_underway (window, NAUTILUS_VIEW (view)); 9190 9191 /* Tell interested parties that we've begun loading this directory now. 9192 * Subclasses use this to know that the new metadata is now available. 9193 */ 9194 nautilus_profile_start ("BEGIN_LOADING"); 9195 g_signal_emit (view, signals[BEGIN_LOADING], 0); 9196 nautilus_profile_end ("BEGIN_LOADING"); 9197 9198 /* Assume we have now all information to show window */ 9199 nautilus_window_view_visible (window, NAUTILUS_VIEW (view)); 9200 9201 if (nautilus_directory_are_all_files_seen (view->details->model)) { 9202 /* Unschedule a pending update and schedule a new one with the minimal 9203 * update interval. This gives the view a short chance at gathering the 9204 * (cached) deep counts. 9205 */ 9206 unschedule_display_of_pending_files (view); 9207 schedule_timeout_display_of_pending_files (view, UPDATE_INTERVAL_MIN); 9208 } 9209 9210 /* Start loading. */ 9211 9212 /* Connect handlers to learn about loading progress. */ 9213 view->details->done_loading_handler_id = g_signal_connect 9214 (view->details->model, "done_loading", 9215 G_CALLBACK (done_loading_callback), view); 9216 view->details->load_error_handler_id = g_signal_connect 9217 (view->details->model, "load_error", 9218 G_CALLBACK (load_error_callback), view); 9219 9220 /* Monitor the things needed to get the right icon. Also 9221 * monitor a directory's item count because the "size" 9222 * attribute is based on that, and the file's metadata 9223 * and possible custom name. 9224 */ 9225 attributes = 9226 NAUTILUS_FILE_ATTRIBUTES_FOR_ICON | 9227 NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT | 9228 NAUTILUS_FILE_ATTRIBUTE_INFO | 9229 NAUTILUS_FILE_ATTRIBUTE_LINK_INFO | 9230 NAUTILUS_FILE_ATTRIBUTE_MOUNT | 9231 NAUTILUS_FILE_ATTRIBUTE_EXTENSION_INFO; 9232 9233 nautilus_directory_file_monitor_add (view->details->model, 9234 &view->details->model, 9235 view->details->show_hidden_files, 9236 attributes, 9237 files_added_callback, view); 9238 9239 view->details->files_added_handler_id = g_signal_connect 9240 (view->details->model, "files_added", 9241 G_CALLBACK (files_added_callback), view); 9242 view->details->files_changed_handler_id = g_signal_connect 9243 (view->details->model, "files_changed", 9244 G_CALLBACK (files_changed_callback), view); 9245 9246 nautilus_profile_end (NULL); 9247 } 9248 9249 static void 9250 finish_loading_if_all_metadata_loaded (NautilusView *view) 9251 { 9252 if (!view->details->metadata_for_directory_as_file_pending && 9253 !view->details->metadata_for_files_in_directory_pending) { 9254 finish_loading (view); 9255 } 9256 } 9257 9258 static void 9259 metadata_for_directory_as_file_ready_callback (NautilusFile *file, 9260 gpointer callback_data) 9261 { 9262 NautilusView *view; 9263 9264 view = callback_data; 9265 9266 g_assert (NAUTILUS_IS_VIEW (view)); 9267 g_assert (view->details->directory_as_file == file); 9268 g_assert (view->details->metadata_for_directory_as_file_pending); 9269 9270 nautilus_profile_start (NULL); 9271 9272 view->details->metadata_for_directory_as_file_pending = FALSE; 9273 9274 finish_loading_if_all_metadata_loaded (view); 9275 nautilus_profile_end (NULL); 9276 } 9277 9278 static void 9279 metadata_for_files_in_directory_ready_callback (NautilusDirectory *directory, 9280 GList *files, 9281 gpointer callback_data) 9282 { 9283 NautilusView *view; 9284 9285 view = callback_data; 9286 9287 g_assert (NAUTILUS_IS_VIEW (view)); 9288 g_assert (view->details->model == directory); 9289 g_assert (view->details->metadata_for_files_in_directory_pending); 9290 9291 nautilus_profile_start (NULL); 9292 9293 view->details->metadata_for_files_in_directory_pending = FALSE; 9294 9295 finish_loading_if_all_metadata_loaded (view); 9296 nautilus_profile_end (NULL); 9297 } 9298 9299 static void 9300 disconnect_handler (GObject *object, guint *id) 9301 { 9302 if (*id != 0) { 9303 g_signal_handler_disconnect (object, *id); 9304 *id = 0; 9305 } 9306 } 9307 9308 static void 9309 disconnect_directory_handler (NautilusView *view, guint *id) 9310 { 9311 disconnect_handler (G_OBJECT (view->details->model), id); 9312 } 9313 9314 static void 9315 disconnect_directory_as_file_handler (NautilusView *view, guint *id) 9316 { 9317 disconnect_handler (G_OBJECT (view->details->directory_as_file), id); 9318 } 9319 9320 static void 9321 disconnect_model_handlers (NautilusView *view) 9322 { 9323 if (view->details->model == NULL) { 9324 return; 9325 } 9326 disconnect_directory_handler (view, &view->details->files_added_handler_id); 9327 disconnect_directory_handler (view, &view->details->files_changed_handler_id); 9328 disconnect_directory_handler (view, &view->details->done_loading_handler_id); 9329 disconnect_directory_handler (view, &view->details->load_error_handler_id); 9330 disconnect_directory_as_file_handler (view, &view->details->file_changed_handler_id); 9331 nautilus_file_cancel_call_when_ready (view->details->directory_as_file, 9332 metadata_for_directory_as_file_ready_callback, 9333 view); 9334 nautilus_directory_cancel_callback (view->details->model, 9335 metadata_for_files_in_directory_ready_callback, 9336 view); 9337 nautilus_directory_file_monitor_remove (view->details->model, 9338 &view->details->model); 9339 nautilus_file_monitor_remove (view->details->directory_as_file, 9340 &view->details->directory_as_file); 9341 } 9342 9343 static void 9344 nautilus_view_select_file (NautilusView *view, NautilusFile *file) 9345 { 9346 GList file_list; 9347 9348 file_list.data = file; 9349 file_list.next = NULL; 9350 file_list.prev = NULL; 9351 nautilus_view_call_set_selection (view, &file_list); 9352 } 9353 9354 static gboolean 9355 remove_all (gpointer key, gpointer value, gpointer callback_data) 9356 { 9357 return TRUE; 9358 } 9359 9360 /** 9361 * nautilus_view_stop_loading: 9362 * 9363 * Stop the current ongoing process, such as switching to a new uri. 9364 * @view: NautilusView in question. 9365 * 9366 **/ 9367 void 9368 nautilus_view_stop_loading (NautilusView *view) 9369 { 9370 g_return_if_fail (NAUTILUS_IS_VIEW (view)); 9371 9372 unschedule_display_of_pending_files (view); 9373 reset_update_interval (view); 9374 9375 /* Free extra undisplayed files */ 9376 file_and_directory_list_free (view->details->new_added_files); 9377 view->details->new_added_files = NULL; 9378 9379 file_and_directory_list_free (view->details->new_changed_files); 9380 view->details->new_changed_files = NULL; 9381 9382 g_hash_table_foreach_remove (view->details->non_ready_files, remove_all, NULL); 9383 9384 file_and_directory_list_free (view->details->old_added_files); 9385 view->details->old_added_files = NULL; 9386 9387 file_and_directory_list_free (view->details->old_changed_files); 9388 view->details->old_changed_files = NULL; 9389 9390 g_list_free_full (view->details->pending_selection, g_object_unref); 9391 view->details->pending_selection = NULL; 9392 9393 if (view->details->model != NULL) { 9394 nautilus_directory_file_monitor_remove (view->details->model, view); 9395 } 9396 done_loading (view, FALSE); 9397 } 9398 9399 gboolean 9400 nautilus_view_is_editable (NautilusView *view) 9401 { 9402 NautilusDirectory *directory; 9403 9404 directory = nautilus_view_get_model (view); 9405 9406 if (directory != NULL) { 9407 return nautilus_directory_is_editable (directory); 9408 } 9409 9410 return TRUE; 9411 } 9412 9413 static gboolean 9414 real_is_read_only (NautilusView *view) 9415 { 9416 NautilusFile *file; 9417 9418 if (!nautilus_view_is_editable (view)) { 9419 return TRUE; 9420 } 9421 9422 file = nautilus_view_get_directory_as_file (view); 9423 if (file != NULL) { 9424 return !nautilus_file_can_write (file); 9425 } 9426 return FALSE; 9427 } 9428 9429 /** 9430 * nautilus_view_should_show_file 9431 * 9432 * Returns whether or not this file should be displayed based on 9433 * current filtering options. 9434 */ 9435 gboolean 9436 nautilus_view_should_show_file (NautilusView *view, NautilusFile *file) 9437 { 9438 return nautilus_file_should_show (file, 9439 view->details->show_hidden_files, 9440 view->details->show_foreign_files); 9441 } 9442 9443 static gboolean 9444 real_using_manual_layout (NautilusView *view) 9445 { 9446 g_return_val_if_fail (NAUTILUS_IS_VIEW (view), FALSE); 9447 9448 return FALSE; 9449 } 9450 9451 void 9452 nautilus_view_ignore_hidden_file_preferences (NautilusView *view) 9453 { 9454 g_return_if_fail (view->details->model == NULL); 9455 9456 if (view->details->ignore_hidden_file_preferences) { 9457 return; 9458 } 9459 9460 view->details->show_hidden_files = FALSE; 9461 view->details->ignore_hidden_file_preferences = TRUE; 9462 } 9463 9464 void 9465 nautilus_view_set_show_foreign (NautilusView *view, 9466 gboolean show_foreign) 9467 { 9468 view->details->show_foreign_files = show_foreign; 9469 } 9470 9471 char * 9472 nautilus_view_get_uri (NautilusView *view) 9473 { 9474 g_return_val_if_fail (NAUTILUS_IS_VIEW (view), NULL); 9475 if (view->details->model == NULL) { 9476 return NULL; 9477 } 9478 return nautilus_directory_get_uri (view->details->model); 9479 } 9480 9481 void 9482 nautilus_view_move_copy_items (NautilusView *view, 9483 const GList *item_uris, 9484 GArray *relative_item_points, 9485 const char *target_uri, 9486 int copy_action, 9487 int x, int y) 9488 { 9489 NautilusFile *target_file; 9490 9491 g_assert (relative_item_points == NULL 9492 || relative_item_points->len == 0 9493 || g_list_length ((GList *)item_uris) == relative_item_points->len); 9494 9495 /* add the drop location to the icon offsets */ 9496 offset_drop_points (relative_item_points, x, y); 9497 9498 target_file = nautilus_file_get_existing_by_uri (target_uri); 9499 /* special-case "command:" here instead of starting a move/copy */ 9500 if (target_file != NULL && nautilus_file_is_launcher (target_file)) { 9501 nautilus_file_unref (target_file); 9502 nautilus_launch_desktop_file ( 9503 gtk_widget_get_screen (GTK_WIDGET (view)), 9504 target_uri, item_uris, 9505 nautilus_view_get_containing_window (view)); 9506 return; 9507 } else if (copy_action == GDK_ACTION_COPY && 9508 nautilus_is_file_roller_installed () && 9509 target_file != NULL && 9510 nautilus_file_is_archive (target_file)) { 9511 char *command, *quoted_uri, *tmp; 9512 const GList *l; 9513 GdkScreen *screen; 9514 9515 /* Handle dropping onto a file-roller archiver file, instead of starting a move/copy */ 9516 9517 nautilus_file_unref (target_file); 9518 9519 quoted_uri = g_shell_quote (target_uri); 9520 command = g_strconcat ("file-roller -a ", quoted_uri, NULL); 9521 g_free (quoted_uri); 9522 9523 for (l = item_uris; l != NULL; l = l->next) { 9524 quoted_uri = g_shell_quote ((char *) l->data); 9525 9526 tmp = g_strconcat (command, " ", quoted_uri, NULL); 9527 g_free (command); 9528 command = tmp; 9529 9530 g_free (quoted_uri); 9531 } 9532 9533 screen = gtk_widget_get_screen (GTK_WIDGET (view)); 9534 if (screen == NULL) { 9535 screen = gdk_screen_get_default (); 9536 } 9537 9538 nautilus_launch_application_from_command (screen, command, FALSE, NULL); 9539 g_free (command); 9540 9541 return; 9542 } 9543 nautilus_file_unref (target_file); 9544 9545 nautilus_file_operations_copy_move 9546 (item_uris, relative_item_points, 9547 target_uri, copy_action, GTK_WIDGET (view), 9548 copy_move_done_callback, pre_copy_move (view)); 9549 } 9550 9551 static void 9552 nautilus_view_trash_state_changed_callback (NautilusTrashMonitor *trash_monitor, 9553 gboolean state, gpointer callback_data) 9554 { 9555 NautilusView *view; 9556 9557 view = (NautilusView *) callback_data; 9558 g_assert (NAUTILUS_IS_VIEW (view)); 9559 9560 schedule_update_menus (view); 9561 } 9562 9563 void 9564 nautilus_view_start_batching_selection_changes (NautilusView *view) 9565 { 9566 g_return_if_fail (NAUTILUS_IS_VIEW (view)); 9567 9568 ++view->details->batching_selection_level; 9569 view->details->selection_changed_while_batched = FALSE; 9570 } 9571 9572 void 9573 nautilus_view_stop_batching_selection_changes (NautilusView *view) 9574 { 9575 g_return_if_fail (NAUTILUS_IS_VIEW (view)); 9576 g_return_if_fail (view->details->batching_selection_level > 0); 9577 9578 if (--view->details->batching_selection_level == 0) { 9579 if (view->details->selection_changed_while_batched) { 9580 nautilus_view_notify_selection_changed (view); 9581 } 9582 } 9583 } 9584 9585 gboolean 9586 nautilus_view_get_active (NautilusView *view) 9587 { 9588 g_assert (NAUTILUS_IS_VIEW (view)); 9589 return view->details->active; 9590 } 9591 9592 static GArray * 9593 real_get_selected_icon_locations (NautilusView *view) 9594 { 9595 /* By default, just return an empty list. */ 9596 return g_array_new (FALSE, TRUE, sizeof (GdkPoint)); 9597 } 9598 9599 static void 9600 nautilus_view_set_property (GObject *object, 9601 guint prop_id, 9602 const GValue *value, 9603 GParamSpec *pspec) 9604 { 9605 NautilusView *directory_view; 9606 NautilusWindowSlot *slot; 9607 9608 directory_view = NAUTILUS_VIEW (object); 9609 9610 switch (prop_id) { 9611 case PROP_WINDOW_SLOT: 9612 g_assert (directory_view->details->slot == NULL); 9613 9614 slot = NAUTILUS_WINDOW_SLOT (g_value_get_object (value)); 9615 directory_view->details->slot = slot; 9616 9617 g_signal_connect_object (directory_view->details->slot, 9618 "active", G_CALLBACK (slot_active), 9619 directory_view, 0); 9620 g_signal_connect_object (directory_view->details->slot, 9621 "inactive", G_CALLBACK (slot_inactive), 9622 directory_view, 0); 9623 break; 9624 case PROP_SUPPORTS_ZOOMING: 9625 directory_view->details->supports_zooming = g_value_get_boolean (value); 9626 break; 9627 default: 9628 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); 9629 break; 9630 } 9631 } 9632 9633 9634 gboolean 9635 nautilus_view_handle_scroll_event (NautilusView *directory_view, 9636 GdkEventScroll *event) 9637 { 9638 static gdouble total_delta_y = 0; 9639 gdouble delta_x, delta_y; 9640 9641 if (event->state & GDK_CONTROL_MASK) { 9642 switch (event->direction) { 9643 case GDK_SCROLL_UP: 9644 /* Zoom In */ 9645 nautilus_view_bump_zoom_level (directory_view, 1); 9646 return TRUE; 9647 9648 case GDK_SCROLL_DOWN: 9649 /* Zoom Out */ 9650 nautilus_view_bump_zoom_level (directory_view, -1); 9651 return TRUE; 9652 9653 case GDK_SCROLL_SMOOTH: 9654 gdk_event_get_scroll_deltas ((const GdkEvent *) event, 9655 &delta_x, &delta_y); 9656 9657 /* try to emulate a normal scrolling event by summing deltas */ 9658 total_delta_y += delta_y; 9659 9660 if (total_delta_y >= 1) { 9661 total_delta_y = 0; 9662 /* emulate scroll down */ 9663 nautilus_view_bump_zoom_level (directory_view, -1); 9664 return TRUE; 9665 } else if (total_delta_y <= - 1) { 9666 total_delta_y = 0; 9667 /* emulate scroll up */ 9668 nautilus_view_bump_zoom_level (directory_view, 1); 9669 return TRUE; 9670 } else { 9671 /* eat event */ 9672 return TRUE; 9673 } 9674 9675 case GDK_SCROLL_LEFT: 9676 case GDK_SCROLL_RIGHT: 9677 break; 9678 9679 default: 9680 g_assert_not_reached (); 9681 } 9682 } 9683 9684 return FALSE; 9685 } 9686 9687 /* handle Shift+Scroll, which will cause a zoom-in/out */ 9688 static gboolean 9689 nautilus_view_scroll_event (GtkWidget *widget, 9690 GdkEventScroll *event) 9691 { 9692 NautilusView *directory_view; 9693 9694 directory_view = NAUTILUS_VIEW (widget); 9695 if (nautilus_view_handle_scroll_event (directory_view, event)) { 9696 return TRUE; 9697 } 9698 9699 return GTK_WIDGET_CLASS (parent_class)->scroll_event (widget, event); 9700 } 9701 9702 9703 static void 9704 nautilus_view_parent_set (GtkWidget *widget, 9705 GtkWidget *old_parent) 9706 { 9707 NautilusView *view; 9708 GtkWidget *parent; 9709 9710 view = NAUTILUS_VIEW (widget); 9711 9712 parent = gtk_widget_get_parent (widget); 9713 g_assert (parent == NULL || old_parent == NULL); 9714 9715 if (GTK_WIDGET_CLASS (parent_class)->parent_set != NULL) { 9716 GTK_WIDGET_CLASS (parent_class)->parent_set (widget, old_parent); 9717 } 9718 9719 if (parent != NULL) { 9720 g_assert (old_parent == NULL); 9721 9722 if (view->details->slot == 9723 nautilus_window_get_active_slot (nautilus_view_get_window (view))) { 9724 view->details->active = TRUE; 9725 9726 nautilus_view_merge_menus (view); 9727 schedule_update_menus (view); 9728 } 9729 } else { 9730 nautilus_view_unmerge_menus (view); 9731 remove_update_menus_timeout_callback (view); 9732 } 9733 } 9734 9735 static void 9736 nautilus_view_class_init (NautilusViewClass *klass) 9737 { 9738 GObjectClass *oclass; 9739 GtkWidgetClass *widget_class; 9740 GtkScrolledWindowClass *scrolled_window_class; 9741 GtkBindingSet *binding_set; 9742 9743 widget_class = GTK_WIDGET_CLASS (klass); 9744 scrolled_window_class = GTK_SCROLLED_WINDOW_CLASS (klass); 9745 oclass = G_OBJECT_CLASS (klass); 9746 9747 oclass->finalize = nautilus_view_finalize; 9748 oclass->set_property = nautilus_view_set_property; 9749 9750 widget_class->destroy = nautilus_view_destroy; 9751 widget_class->scroll_event = nautilus_view_scroll_event; 9752 widget_class->parent_set = nautilus_view_parent_set; 9753 9754 g_type_class_add_private (klass, sizeof (NautilusViewDetails)); 9755 9756 /* Get rid of the strange 3-pixel gap that GtkScrolledWindow 9757 * uses by default. It does us no good. 9758 */ 9759 scrolled_window_class->scrollbar_spacing = 0; 9760 9761 signals[ADD_FILE] = 9762 g_signal_new ("add_file", 9763 G_TYPE_FROM_CLASS (klass), 9764 G_SIGNAL_RUN_LAST, 9765 G_STRUCT_OFFSET (NautilusViewClass, add_file), 9766 NULL, NULL, 9767 g_cclosure_marshal_generic, 9768 G_TYPE_NONE, 2, NAUTILUS_TYPE_FILE, NAUTILUS_TYPE_DIRECTORY); 9769 signals[BEGIN_FILE_CHANGES] = 9770 g_signal_new ("begin_file_changes", 9771 G_TYPE_FROM_CLASS (klass), 9772 G_SIGNAL_RUN_LAST, 9773 G_STRUCT_OFFSET (NautilusViewClass, begin_file_changes), 9774 NULL, NULL, 9775 g_cclosure_marshal_VOID__VOID, 9776 G_TYPE_NONE, 0); 9777 signals[BEGIN_LOADING] = 9778 g_signal_new ("begin_loading", 9779 G_TYPE_FROM_CLASS (klass), 9780 G_SIGNAL_RUN_LAST, 9781 G_STRUCT_OFFSET (NautilusViewClass, begin_loading), 9782 NULL, NULL, 9783 g_cclosure_marshal_VOID__VOID, 9784 G_TYPE_NONE, 0); 9785 signals[CLEAR] = 9786 g_signal_new ("clear", 9787 G_TYPE_FROM_CLASS (klass), 9788 G_SIGNAL_RUN_LAST, 9789 G_STRUCT_OFFSET (NautilusViewClass, clear), 9790 NULL, NULL, 9791 g_cclosure_marshal_VOID__VOID, 9792 G_TYPE_NONE, 0); 9793 signals[END_FILE_CHANGES] = 9794 g_signal_new ("end_file_changes", 9795 G_TYPE_FROM_CLASS (klass), 9796 G_SIGNAL_RUN_LAST, 9797 G_STRUCT_OFFSET (NautilusViewClass, end_file_changes), 9798 NULL, NULL, 9799 g_cclosure_marshal_VOID__VOID, 9800 G_TYPE_NONE, 0); 9801 signals[END_LOADING] = 9802 g_signal_new ("end_loading", 9803 G_TYPE_FROM_CLASS (klass), 9804 G_SIGNAL_RUN_LAST, 9805 G_STRUCT_OFFSET (NautilusViewClass, end_loading), 9806 NULL, NULL, 9807 g_cclosure_marshal_VOID__BOOLEAN, 9808 G_TYPE_NONE, 1, G_TYPE_BOOLEAN); 9809 signals[FILE_CHANGED] = 9810 g_signal_new ("file_changed", 9811 G_TYPE_FROM_CLASS (klass), 9812 G_SIGNAL_RUN_LAST, 9813 G_STRUCT_OFFSET (NautilusViewClass, file_changed), 9814 NULL, NULL, 9815 g_cclosure_marshal_generic, 9816 G_TYPE_NONE, 2, NAUTILUS_TYPE_FILE, NAUTILUS_TYPE_DIRECTORY); 9817 signals[LOAD_ERROR] = 9818 g_signal_new ("load_error", 9819 G_TYPE_FROM_CLASS (klass), 9820 G_SIGNAL_RUN_LAST, 9821 G_STRUCT_OFFSET (NautilusViewClass, load_error), 9822 NULL, NULL, 9823 g_cclosure_marshal_VOID__POINTER, 9824 G_TYPE_NONE, 1, G_TYPE_POINTER); 9825 signals[REMOVE_FILE] = 9826 g_signal_new ("remove_file", 9827 G_TYPE_FROM_CLASS (klass), 9828 G_SIGNAL_RUN_LAST, 9829 G_STRUCT_OFFSET (NautilusViewClass, remove_file), 9830 NULL, NULL, 9831 g_cclosure_marshal_generic, 9832 G_TYPE_NONE, 2, NAUTILUS_TYPE_FILE, NAUTILUS_TYPE_DIRECTORY); 9833 signals[ZOOM_LEVEL_CHANGED] = 9834 g_signal_new ("zoom-level-changed", 9835 G_TYPE_FROM_CLASS (klass), 9836 G_SIGNAL_RUN_LAST, 9837 0, NULL, NULL, 9838 g_cclosure_marshal_VOID__VOID, 9839 G_TYPE_NONE, 0); 9840 signals[SELECTION_CHANGED] = 9841 g_signal_new ("selection-changed", 9842 G_TYPE_FROM_CLASS (klass), 9843 G_SIGNAL_RUN_LAST, 9844 0, 9845 NULL, NULL, 9846 g_cclosure_marshal_VOID__VOID, 9847 G_TYPE_NONE, 0); 9848 signals[TRASH] = 9849 g_signal_new ("trash", 9850 G_TYPE_FROM_CLASS (klass), 9851 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, 9852 G_STRUCT_OFFSET (NautilusViewClass, trash), 9853 g_signal_accumulator_true_handled, NULL, 9854 g_cclosure_marshal_generic, 9855 G_TYPE_BOOLEAN, 0); 9856 signals[DELETE] = 9857 g_signal_new ("delete", 9858 G_TYPE_FROM_CLASS (klass), 9859 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, 9860 G_STRUCT_OFFSET (NautilusViewClass, delete), 9861 g_signal_accumulator_true_handled, NULL, 9862 g_cclosure_marshal_generic, 9863 G_TYPE_BOOLEAN, 0); 9864 9865 klass->get_selected_icon_locations = real_get_selected_icon_locations; 9866 klass->is_read_only = real_is_read_only; 9867 klass->load_error = real_load_error; 9868 klass->can_rename_file = can_rename_file; 9869 klass->start_renaming_file = start_renaming_file; 9870 klass->get_backing_uri = real_get_backing_uri; 9871 klass->using_manual_layout = real_using_manual_layout; 9872 klass->merge_menus = real_merge_menus; 9873 klass->unmerge_menus = real_unmerge_menus; 9874 klass->update_menus = real_update_menus; 9875 klass->trash = real_trash; 9876 klass->delete = real_delete; 9877 9878 copied_files_atom = gdk_atom_intern ("x-special/gnome-copied-files", FALSE); 9879 9880 properties[PROP_WINDOW_SLOT] = 9881 g_param_spec_object ("window-slot", 9882 "Window Slot", 9883 "The parent window slot reference", 9884 NAUTILUS_TYPE_WINDOW_SLOT, 9885 G_PARAM_WRITABLE | 9886 G_PARAM_CONSTRUCT_ONLY); 9887 properties[PROP_SUPPORTS_ZOOMING] = 9888 g_param_spec_boolean ("supports-zooming", 9889 "Supports zooming", 9890 "Whether the view supports zooming", 9891 TRUE, 9892 G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | 9893 G_PARAM_STATIC_STRINGS); 9894 9895 g_object_class_install_properties (oclass, NUM_PROPERTIES, properties); 9896 9897 binding_set = gtk_binding_set_by_class (klass); 9898 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, GDK_CONTROL_MASK, 9899 "trash", 0); 9900 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Delete, GDK_CONTROL_MASK, 9901 "trash", 0); 9902 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Delete, GDK_SHIFT_MASK, 9903 "delete", 0); 9904 }