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);