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