1 /* nautilus-files-view.c
2 *
3 * Copyright (C) 1999, 2000 Free Software Foundation
4 * Copyright (C) 2000, 2001 Eazel, Inc.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public
17 * License along with this program; if not, see <http://www.gnu.org/licenses/>.
18 *
19 * Authors: Ettore Perazzoli,
20 * John Sullivan <sullivan@eazel.com>,
21 * Darin Adler <darin@bentspoon.com>,
22 * Pavel Cisler <pavel@eazel.com>,
23 * David Emory Watson <dwatson@cs.ucr.edu>
24 */
25
26 #include "nautilus-files-view.h"
27
28 #include <eel/eel-glib-extensions.h>
29 #include <eel/eel-gtk-extensions.h>
30 #include <eel/eel-stock-dialogs.h>
31 #include <eel/eel-string.h>
32 #include <eel/eel-vfs-extensions.h>
33 #include <fcntl.h>
34 #include <gdesktop-enums.h>
35 #include <gdk/gdkkeysyms.h>
36 #include <gdk/gdk.h>
37 #include <gio/gio.h>
38 #include <glib/gi18n.h>
39 #include <glib/gstdio.h>
40 #include <gtk/gtk.h>
41 #include <gnome-autoar/gnome-autoar.h>
42 #include <math.h>
43 #include <nautilus-extension.h>
44 #include <string.h>
45 #include <sys/types.h>
46 #include <sys/stat.h>
47
48 #define DEBUG_FLAG NAUTILUS_DEBUG_DIRECTORY_VIEW
49 #include "nautilus-debug.h"
50
51 #include "nautilus-application.h"
52 #include "nautilus-batch-rename-dialog.h"
53 #include "nautilus-batch-rename-utilities.h"
54 #include "nautilus-canvas-view.h"
55 #include "nautilus-clipboard.h"
56 #include "nautilus-compress-dialog-controller.h"
57 #include "nautilus-directory.h"
58 #include "nautilus-dnd.h"
59 #include "nautilus-enums.h"
60 #include "nautilus-error-reporting.h"
61 #include "nautilus-file-changes-queue.h"
62 #include "nautilus-file-name-widget-controller.h"
63 #include "nautilus-file-operations.h"
64 #include "nautilus-file-private.h"
65 #include "nautilus-file-undo-manager.h"
66 #include "nautilus-file-utilities.h"
67 #include "nautilus-file.h"
68 #include "nautilus-floating-bar.h"
69 #include "nautilus-global-preferences.h"
70 #include "nautilus-icon-info.h"
71 #include "nautilus-icon-names.h"
72 #include "nautilus-list-view.h"
73 #include "nautilus-metadata.h"
74 #include "nautilus-mime-actions.h"
75 #include "nautilus-module.h"
76 #include "nautilus-new-folder-dialog-controller.h"
77 #include "nautilus-previewer.h"
78 #include "nautilus-profile.h"
79 #include "nautilus-program-choosing.h"
80 #include "nautilus-properties-window.h"
81 #include "nautilus-rename-file-popover-controller.h"
82 #include "nautilus-search-directory.h"
83 #include "nautilus-signaller.h"
84 #include "nautilus-tag-manager.h"
85 #include "nautilus-toolbar.h"
86 #include "nautilus-trash-monitor.h"
87 #include "nautilus-ui-utilities.h"
88 #include "nautilus-view.h"
89 #include "nautilus-view-icon-controller.h"
90 #include "nautilus-window.h"
91 #include "nautilus-tracker-utilities.h"
92
93 #ifdef HAVE_LIBPORTAL
94 #include <libportal/portal.h>
95 #include <libportal-gtk3/portal-gtk3.h>
96 #endif
97
98 /* Minimum starting update inverval */
99 #define UPDATE_INTERVAL_MIN 100
100 /* Maximum update interval */
101 #define UPDATE_INTERVAL_MAX 2000
102 /* Amount of miliseconds the update interval is increased */
103 #define UPDATE_INTERVAL_INC 250
104 /* Interval at which the update interval is increased */
105 #define UPDATE_INTERVAL_TIMEOUT_INTERVAL 250
106 /* Milliseconds that have to pass without a change to reset the update interval */
107 #define UPDATE_INTERVAL_RESET 1000
108
109 #define SILENT_WINDOW_OPEN_LIMIT 5
110
111 #define DUPLICATE_HORIZONTAL_ICON_OFFSET 70
112 #define DUPLICATE_VERTICAL_ICON_OFFSET 30
113
114 #define MAX_QUEUED_UPDATES 500
115
116 #define MAX_MENU_LEVELS 5
117 #define TEMPLATE_LIMIT 30
118
119 #define SHORTCUTS_PATH "/nautilus/scripts-accels"
120
121 /* Delay to show the Loading... floating bar */
122 #define FLOATING_BAR_LOADING_DELAY 200 /* ms */
123
124 #define MIN_COMMON_FILENAME_PREFIX_LENGTH 4
125
126 enum
127 {
128 ADD_FILES,
129 BEGIN_FILE_CHANGES,
130 BEGIN_LOADING,
131 CLEAR,
132 END_FILE_CHANGES,
133 END_LOADING,
134 FILE_CHANGED,
135 MOVE_COPY_ITEMS,
136 REMOVE_FILE,
137 SELECTION_CHANGED,
138 TRASH,
139 DELETE,
140 LAST_SIGNAL
141 };
142
143 enum
144 {
145 PROP_WINDOW_SLOT = 1,
146 PROP_SUPPORTS_ZOOMING,
147 PROP_ICON,
148 PROP_SEARCHING,
149 PROP_LOADING,
150 PROP_SELECTION,
151 PROP_LOCATION,
152 PROP_SEARCH_QUERY,
153 PROP_EXTENSIONS_BACKGROUND_MENU,
154 PROP_TEMPLATES_MENU,
155 NUM_PROPERTIES
156 };
157
158 static guint signals[LAST_SIGNAL];
159
160 static char *scripts_directory_uri = NULL;
161 static int scripts_directory_uri_length;
162
163 static GHashTable *script_accels = NULL;
164
165 typedef struct
166 {
167 /* Main components */
168 GtkWidget *overlay;
169
170 NautilusWindowSlot *slot;
171 NautilusDirectory *model;
172 NautilusFile *directory_as_file;
173 GFile *location;
174 guint dir_merge_id;
175
176 NautilusQuery *search_query;
177
178 NautilusRenameFilePopoverController *rename_file_controller;
179 NautilusNewFolderDialogController *new_folder_controller;
180 NautilusCompressDialogController *compress_controller;
181
182 gboolean supports_zooming;
183
184 GList *scripts_directory_list;
185 GList *templates_directory_list;
186 gboolean scripts_menu_updated;
187 gboolean templates_menu_updated;
188
189 guint display_selection_idle_id;
190 guint update_context_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 gulong files_added_handler_id;
201 gulong files_changed_handler_id;
202 gulong load_error_handler_id;
203 gulong done_loading_handler_id;
204 gulong file_changed_handler_id;
205
206 /* Containers with FileAndDirectory* elements */
207 GList *new_added_files;
208 GList *new_changed_files;
209 GHashTable *non_ready_files;
210 GList *old_added_files;
211 GList *old_changed_files;
212
213 GList *pending_selection;
214 GHashTable *pending_reveal;
215
216 /* whether we are in the active slot */
217 gboolean active;
218
219 /* loading indicates whether this view has begun loading a directory.
220 * This flag should need not be set inside subclasses. NautilusFilesView automatically
221 * sets 'loading' to TRUE before it begins loading a directory's contents and to FALSE
222 * after it finishes loading the directory and its view.
223 */
224 gboolean loading;
225
226 gboolean in_destruction;
227
228 gboolean sort_directories_first;
229
230 gboolean show_hidden_files;
231 gboolean ignore_hidden_file_preferences;
232
233 gboolean batching_selection_level;
234 gboolean selection_changed_while_batched;
235
236 gboolean selection_was_removed;
237
238 gboolean metadata_for_directory_as_file_pending;
239 gboolean metadata_for_files_in_directory_pending;
240
241 GList *subdirectory_list;
242
243 GMenu *selection_menu_model;
244 GMenu *background_menu_model;
245
246 GtkWidget *selection_menu;
247 GtkWidget *background_menu;
248
249 GActionGroup *view_action_group;
250
251 GtkWidget *scrolled_window;
252
253 /* Empty states */
254 GtkWidget *folder_is_empty_widget;
255 GtkWidget *trash_is_empty_widget;
256 GtkWidget *no_search_results_widget;
257 GtkWidget *starred_is_empty_widget;
258
259 /* Floating bar */
260 guint floating_bar_set_status_timeout_id;
261 guint floating_bar_loading_timeout_id;
262 guint floating_bar_set_passthrough_timeout_id;
263 GtkWidget *floating_bar;
264
265 /* Toolbar menu */
266 NautilusToolbarMenuSections *toolbar_menu_sections;
267 GtkWidget *sort_menu;
268 GtkWidget *sort_trash_time;
269 GtkWidget *visible_columns;
270 GtkWidget *stop;
271 GtkWidget *reload;
272 GtkWidget *zoom_controls_box;
273 GtkWidget *zoom_level_label;
274
275 /* Exposed menus, for the path bar etc. */
276 GMenuModel *extensions_background_menu;
277 GMenuModel *templates_menu;
278
279 /* Non exported menu, only for caching */
280 GMenuModel *scripts_menu;
281
282 gulong stop_signal_handler;
283 gulong reload_signal_handler;
284
285 GCancellable *starred_cancellable;
286 NautilusTagManager *tag_manager;
287
288 gulong name_accepted_handler_id;
289 gulong cancelled_handler_id;
290 } NautilusFilesViewPrivate;
291
292 /**
293 * FileAndDirectory:
294 * @file: A #NautilusFile
295 * @directory: A #NautilusDirectory where @file is present.
296 *
297 * The #FileAndDirectory struct is used to relate files to the directories they
298 * are displayed in. This is necessary because the same file can appear multiple
299 * times in the same view, by expanding folders as a tree in a list of search
300 * results. (Adapted from commit 671e4bdaa4d07b039015bedfcb5d42026e5d099e)
301 */
302 typedef struct
303 {
304 NautilusFile *file;
305 NautilusDirectory *directory;
306 } FileAndDirectory;
307
308 typedef struct
309 {
310 NautilusFilesView *view;
311 GList *selection;
312 } CompressCallbackData;
313
314 /* forward declarations */
315
316 static gboolean display_selection_info_idle_callback (gpointer data);
317 static void trash_or_delete_files (GtkWindow *parent_window,
318 const GList *files,
319 NautilusFilesView *view);
320 static void load_directory (NautilusFilesView *view,
321 NautilusDirectory *directory);
322 static void on_clipboard_owner_changed (GtkClipboard *clipboard,
323 GdkEvent *event,
324 gpointer user_data);
325 static void open_one_in_new_window (gpointer data,
326 gpointer callback_data);
327 static void schedule_update_context_menus (NautilusFilesView *view);
328 static void remove_update_context_menus_timeout_callback (NautilusFilesView *view);
329 static void schedule_update_status (NautilusFilesView *view);
330 static void remove_update_status_idle_callback (NautilusFilesView *view);
331 static void reset_update_interval (NautilusFilesView *view);
332 static void schedule_idle_display_of_pending_files (NautilusFilesView *view);
333 static void unschedule_display_of_pending_files (NautilusFilesView *view);
334 static void disconnect_model_handlers (NautilusFilesView *view);
335 static void metadata_for_directory_as_file_ready_callback (NautilusFile *file,
336 gpointer callback_data);
337 static void metadata_for_files_in_directory_ready_callback (NautilusDirectory *directory,
338 GList *files,
339 gpointer callback_data);
340 static void nautilus_files_view_trash_state_changed_callback (NautilusTrashMonitor *trash,
341 gboolean state,
342 gpointer callback_data);
343 static void nautilus_files_view_select_file (NautilusFilesView *view,
344 NautilusFile *file);
345
346 static void update_templates_directory (NautilusFilesView *view);
347
348 static void extract_files (NautilusFilesView *view,
349 GList *files,
350 GFile *destination_directory);
351 static void extract_files_to_chosen_location (NautilusFilesView *view,
352 GList *files);
353
354 static void nautilus_files_view_check_empty_states (NautilusFilesView *view);
355
356 static gboolean nautilus_files_view_is_searching (NautilusView *view);
357
358 static void nautilus_files_view_iface_init (NautilusViewInterface *view);
359
360 static void set_search_query_internal (NautilusFilesView *files_view,
361 NautilusQuery *query,
362 NautilusDirectory *base_model);
363
364 static gboolean nautilus_files_view_is_read_only (NautilusFilesView *view);
365 static void set_wallpaper_fallback (NautilusFile *file,
366 gpointer user_data);
367
368 G_DEFINE_TYPE_WITH_CODE (NautilusFilesView,
369 nautilus_files_view,
370 GTK_TYPE_GRID,
371 G_IMPLEMENT_INTERFACE (NAUTILUS_TYPE_VIEW, nautilus_files_view_iface_init)
372 G_ADD_PRIVATE (NautilusFilesView));
373
374 static const struct
375 {
376 unsigned int keyval;
377 const char *action;
378 } extra_view_keybindings [] =
379 {
380 /* View actions */
381 { GDK_KEY_ZoomIn, "zoom-in" },
382 { GDK_KEY_ZoomOut, "zoom-out" },
383 };
384
385 /*
386 * Floating Bar code
387 */
388 static void
remove_loading_floating_bar(NautilusFilesView * view)389 remove_loading_floating_bar (NautilusFilesView *view)
390 {
391 NautilusFilesViewPrivate *priv;
392
393 priv = nautilus_files_view_get_instance_private (view);
394
395 if (priv->floating_bar_loading_timeout_id != 0)
396 {
397 g_source_remove (priv->floating_bar_loading_timeout_id);
398 priv->floating_bar_loading_timeout_id = 0;
399 }
400
401 gtk_widget_hide (priv->floating_bar);
402 nautilus_floating_bar_cleanup_actions (NAUTILUS_FLOATING_BAR (priv->floating_bar));
403 }
404
405 static void
real_setup_loading_floating_bar(NautilusFilesView * view)406 real_setup_loading_floating_bar (NautilusFilesView *view)
407 {
408 NautilusFilesViewPrivate *priv;
409
410 priv = nautilus_files_view_get_instance_private (view);
411
412 nautilus_floating_bar_cleanup_actions (NAUTILUS_FLOATING_BAR (priv->floating_bar));
413 nautilus_floating_bar_set_primary_label (NAUTILUS_FLOATING_BAR (priv->floating_bar),
414 nautilus_view_is_searching (NAUTILUS_VIEW (view)) ? _("Searching…") : _("Loading…"));
415 nautilus_floating_bar_set_details_label (NAUTILUS_FLOATING_BAR (priv->floating_bar), NULL);
416 nautilus_floating_bar_set_show_spinner (NAUTILUS_FLOATING_BAR (priv->floating_bar), priv->loading);
417 nautilus_floating_bar_add_action (NAUTILUS_FLOATING_BAR (priv->floating_bar),
418 "process-stop-symbolic",
419 NAUTILUS_FLOATING_BAR_ACTION_ID_STOP);
420
421 gtk_widget_set_halign (priv->floating_bar, GTK_ALIGN_END);
422 gtk_widget_show (priv->floating_bar);
423 }
424
425 static gboolean
setup_loading_floating_bar_timeout_cb(gpointer user_data)426 setup_loading_floating_bar_timeout_cb (gpointer user_data)
427 {
428 NautilusFilesView *view = user_data;
429 NautilusFilesViewPrivate *priv;
430
431 priv = nautilus_files_view_get_instance_private (view);
432
433 priv->floating_bar_loading_timeout_id = 0;
434 real_setup_loading_floating_bar (view);
435
436 return FALSE;
437 }
438
439 static void
setup_loading_floating_bar(NautilusFilesView * view)440 setup_loading_floating_bar (NautilusFilesView *view)
441 {
442 NautilusFilesViewPrivate *priv;
443
444 priv = nautilus_files_view_get_instance_private (view);
445
446 /* setup loading overlay */
447 if (priv->floating_bar_set_status_timeout_id != 0)
448 {
449 g_source_remove (priv->floating_bar_set_status_timeout_id);
450 priv->floating_bar_set_status_timeout_id = 0;
451 }
452
453 if (priv->floating_bar_loading_timeout_id != 0)
454 {
455 g_source_remove (priv->floating_bar_loading_timeout_id);
456 priv->floating_bar_loading_timeout_id = 0;
457 }
458
459 priv->floating_bar_loading_timeout_id =
460 g_timeout_add (FLOATING_BAR_LOADING_DELAY, setup_loading_floating_bar_timeout_cb, view);
461 }
462
463 static void
floating_bar_action_cb(NautilusFloatingBar * floating_bar,gint action,NautilusFilesView * view)464 floating_bar_action_cb (NautilusFloatingBar *floating_bar,
465 gint action,
466 NautilusFilesView *view)
467 {
468 NautilusFilesViewPrivate *priv;
469
470 priv = nautilus_files_view_get_instance_private (view);
471
472 if (action == NAUTILUS_FLOATING_BAR_ACTION_ID_STOP)
473 {
474 remove_loading_floating_bar (view);
475 nautilus_window_slot_stop_loading (priv->slot);
476 }
477 }
478
479 static void
real_floating_bar_set_short_status(NautilusFilesView * view,const gchar * primary_status,const gchar * detail_status)480 real_floating_bar_set_short_status (NautilusFilesView *view,
481 const gchar *primary_status,
482 const gchar *detail_status)
483 {
484 NautilusFilesViewPrivate *priv;
485
486 priv = nautilus_files_view_get_instance_private (view);
487
488 if (priv->loading)
489 {
490 return;
491 }
492
493 nautilus_floating_bar_cleanup_actions (NAUTILUS_FLOATING_BAR (priv->floating_bar));
494 nautilus_floating_bar_set_show_spinner (NAUTILUS_FLOATING_BAR (priv->floating_bar),
495 FALSE);
496
497 if (primary_status == NULL && detail_status == NULL)
498 {
499 gtk_widget_hide (priv->floating_bar);
500 nautilus_floating_bar_remove_hover_timeout (NAUTILUS_FLOATING_BAR (priv->floating_bar));
501 return;
502 }
503
504 nautilus_floating_bar_set_labels (NAUTILUS_FLOATING_BAR (priv->floating_bar),
505 primary_status,
506 detail_status);
507
508 gtk_widget_show (priv->floating_bar);
509 }
510
511 typedef struct
512 {
513 gchar *primary_status;
514 gchar *detail_status;
515 NautilusFilesView *view;
516 } FloatingBarSetStatusData;
517
518 static void
floating_bar_set_status_data_free(gpointer data)519 floating_bar_set_status_data_free (gpointer data)
520 {
521 FloatingBarSetStatusData *status_data = data;
522
523 g_free (status_data->primary_status);
524 g_free (status_data->detail_status);
525
526 g_slice_free (FloatingBarSetStatusData, data);
527 }
528
529 static gboolean
floating_bar_set_status_timeout_cb(gpointer data)530 floating_bar_set_status_timeout_cb (gpointer data)
531 {
532 NautilusFilesViewPrivate *priv;
533
534 FloatingBarSetStatusData *status_data = data;
535
536 priv = nautilus_files_view_get_instance_private (status_data->view);
537
538 priv->floating_bar_set_status_timeout_id = 0;
539 real_floating_bar_set_short_status (status_data->view,
540 status_data->primary_status,
541 status_data->detail_status);
542
543 return FALSE;
544 }
545
546 static gboolean
remove_floating_bar_passthrough(gpointer data)547 remove_floating_bar_passthrough (gpointer data)
548 {
549 NautilusFilesViewPrivate *priv;
550
551 priv = nautilus_files_view_get_instance_private (NAUTILUS_FILES_VIEW (data));
552 gtk_overlay_set_overlay_pass_through (GTK_OVERLAY (priv->overlay),
553 priv->floating_bar, FALSE);
554 priv->floating_bar_set_passthrough_timeout_id = 0;
555
556 return G_SOURCE_REMOVE;
557 }
558
559 static void
set_floating_bar_status(NautilusFilesView * view,const gchar * primary_status,const gchar * detail_status)560 set_floating_bar_status (NautilusFilesView *view,
561 const gchar *primary_status,
562 const gchar *detail_status)
563 {
564 GtkSettings *settings;
565 gint double_click_time;
566 FloatingBarSetStatusData *status_data;
567 NautilusFilesViewPrivate *priv;
568
569 priv = nautilus_files_view_get_instance_private (view);
570
571 if (priv->floating_bar_set_status_timeout_id != 0)
572 {
573 g_source_remove (priv->floating_bar_set_status_timeout_id);
574 priv->floating_bar_set_status_timeout_id = 0;
575 }
576
577 settings = gtk_settings_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (view)));
578 g_object_get (settings,
579 "gtk-double-click-time", &double_click_time,
580 NULL);
581
582 status_data = g_slice_new0 (FloatingBarSetStatusData);
583 status_data->primary_status = g_strdup (primary_status);
584 status_data->detail_status = g_strdup (detail_status);
585 status_data->view = view;
586
587 if (priv->floating_bar_set_passthrough_timeout_id != 0)
588 {
589 g_source_remove (priv->floating_bar_set_passthrough_timeout_id);
590 priv->floating_bar_set_passthrough_timeout_id = 0;
591 }
592 /* Activate passthrough on the floating bar just long enough for a
593 * potential double click to happen, so to not interfere with it */
594 gtk_overlay_set_overlay_pass_through (GTK_OVERLAY (priv->overlay),
595 priv->floating_bar, TRUE);
596 priv->floating_bar_set_passthrough_timeout_id = g_timeout_add ((guint) double_click_time,
597 remove_floating_bar_passthrough,
598 view);
599
600 /* waiting for half of the double-click-time before setting
601 * the status seems to be a good approximation of not setting it
602 * too often and not delaying the statusbar too much.
603 */
604 priv->floating_bar_set_status_timeout_id =
605 g_timeout_add_full (G_PRIORITY_DEFAULT,
606 (guint) (double_click_time / 2),
607 floating_bar_set_status_timeout_cb,
608 status_data,
609 floating_bar_set_status_data_free);
610 }
611
612 static char *
real_get_backing_uri(NautilusFilesView * view)613 real_get_backing_uri (NautilusFilesView *view)
614 {
615 NautilusFilesViewPrivate *priv;
616
617 g_return_val_if_fail (NAUTILUS_IS_FILES_VIEW (view), NULL);
618
619 priv = nautilus_files_view_get_instance_private (view);
620
621 if (priv->model == NULL)
622 {
623 return NULL;
624 }
625
626 return nautilus_directory_get_uri (priv->model);
627 }
628
629 /**
630 *
631 * nautilus_files_view_get_backing_uri:
632 *
633 * Returns the URI for the target location of new directory, new file, new
634 * link and paste operations.
635 */
636
637 char *
nautilus_files_view_get_backing_uri(NautilusFilesView * view)638 nautilus_files_view_get_backing_uri (NautilusFilesView *view)
639 {
640 g_return_val_if_fail (NAUTILUS_IS_FILES_VIEW (view), NULL);
641
642 return NAUTILUS_FILES_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_backing_uri (view);
643 }
644
645 /**
646 * nautilus_files_view_select_all:
647 *
648 * select all the items in the view
649 *
650 **/
651 static void
nautilus_files_view_select_all(NautilusFilesView * view)652 nautilus_files_view_select_all (NautilusFilesView *view)
653 {
654 g_return_if_fail (NAUTILUS_IS_FILES_VIEW (view));
655
656 NAUTILUS_FILES_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->select_all (view);
657 }
658
659 static void
nautilus_files_view_select_first(NautilusFilesView * view)660 nautilus_files_view_select_first (NautilusFilesView *view)
661 {
662 g_return_if_fail (NAUTILUS_IS_FILES_VIEW (view));
663
664 NAUTILUS_FILES_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->select_first (view);
665 }
666
667 static void
nautilus_files_view_call_set_selection(NautilusFilesView * view,GList * selection)668 nautilus_files_view_call_set_selection (NautilusFilesView *view,
669 GList *selection)
670 {
671 g_return_if_fail (NAUTILUS_IS_FILES_VIEW (view));
672
673 NAUTILUS_FILES_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->set_selection (view, selection);
674 }
675
676 static GList *
nautilus_files_view_get_selection_for_file_transfer(NautilusFilesView * view)677 nautilus_files_view_get_selection_for_file_transfer (NautilusFilesView *view)
678 {
679 g_return_val_if_fail (NAUTILUS_IS_FILES_VIEW (view), NULL);
680
681 return NAUTILUS_FILES_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_selection_for_file_transfer (view);
682 }
683
684 static void
nautilus_files_view_invert_selection(NautilusFilesView * view)685 nautilus_files_view_invert_selection (NautilusFilesView *view)
686 {
687 g_return_if_fail (NAUTILUS_IS_FILES_VIEW (view));
688
689 NAUTILUS_FILES_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->invert_selection (view);
690 }
691
692 /**
693 * nautilus_files_view_reveal_selection:
694 *
695 * Scroll as necessary to reveal the selected items.
696 **/
697 static void
nautilus_files_view_reveal_selection(NautilusFilesView * view)698 nautilus_files_view_reveal_selection (NautilusFilesView *view)
699 {
700 g_return_if_fail (NAUTILUS_IS_FILES_VIEW (view));
701
702 NAUTILUS_FILES_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->reveal_selection (view);
703 }
704
705 /**
706 * nautilus_files_view_get_toolbar_menu_sections:
707 * @view: a #NautilusFilesView
708 *
709 * Retrieves the menu sections that should be added to the toolbar menu when
710 * this view is active
711 *
712 * Returns: (transfer none): a #NautilusToolbarMenuSections with the details of
713 * which menu sections should be added to the menu
714 */
715 static NautilusToolbarMenuSections *
nautilus_files_view_get_toolbar_menu_sections(NautilusView * view)716 nautilus_files_view_get_toolbar_menu_sections (NautilusView *view)
717 {
718 NautilusFilesViewPrivate *priv;
719
720 g_return_val_if_fail (NAUTILUS_IS_FILES_VIEW (view), NULL);
721
722 priv = nautilus_files_view_get_instance_private (NAUTILUS_FILES_VIEW (view));
723
724 return priv->toolbar_menu_sections;
725 }
726
727 static GMenuModel *
nautilus_files_view_get_templates_menu(NautilusView * self)728 nautilus_files_view_get_templates_menu (NautilusView *self)
729 {
730 GMenuModel *menu;
731
732 g_object_get (self, "templates-menu", &menu, NULL);
733
734 return menu;
735 }
736
737 static GMenuModel *
nautilus_files_view_get_extensions_background_menu(NautilusView * self)738 nautilus_files_view_get_extensions_background_menu (NautilusView *self)
739 {
740 GMenuModel *menu;
741
742 g_object_get (self, "extensions-background-menu", &menu, NULL);
743
744 return menu;
745 }
746
747 static GMenuModel *
real_get_extensions_background_menu(NautilusView * view)748 real_get_extensions_background_menu (NautilusView *view)
749 {
750 NautilusFilesViewPrivate *priv;
751
752 g_return_val_if_fail (NAUTILUS_IS_FILES_VIEW (view), NULL);
753
754 priv = nautilus_files_view_get_instance_private (NAUTILUS_FILES_VIEW (view));
755
756 return priv->extensions_background_menu;
757 }
758
759 static GMenuModel *
real_get_templates_menu(NautilusView * view)760 real_get_templates_menu (NautilusView *view)
761 {
762 NautilusFilesViewPrivate *priv;
763
764 g_return_val_if_fail (NAUTILUS_IS_FILES_VIEW (view), NULL);
765
766 priv = nautilus_files_view_get_instance_private (NAUTILUS_FILES_VIEW (view));
767
768 return priv->templates_menu;
769 }
770
771 static void
nautilus_files_view_set_templates_menu(NautilusView * self,GMenuModel * menu)772 nautilus_files_view_set_templates_menu (NautilusView *self,
773 GMenuModel *menu)
774 {
775 g_object_set (self, "templates-menu", menu, NULL);
776 }
777
778 static void
nautilus_files_view_set_extensions_background_menu(NautilusView * self,GMenuModel * menu)779 nautilus_files_view_set_extensions_background_menu (NautilusView *self,
780 GMenuModel *menu)
781 {
782 g_object_set (self, "extensions-background-menu", menu, NULL);
783 }
784
785 static void
real_set_extensions_background_menu(NautilusView * view,GMenuModel * menu)786 real_set_extensions_background_menu (NautilusView *view,
787 GMenuModel *menu)
788 {
789 NautilusFilesViewPrivate *priv;
790
791 g_return_if_fail (NAUTILUS_IS_FILES_VIEW (view));
792
793 priv = nautilus_files_view_get_instance_private (NAUTILUS_FILES_VIEW (view));
794
795 g_set_object (&priv->extensions_background_menu, menu);
796 }
797
798 static void
real_set_templates_menu(NautilusView * view,GMenuModel * menu)799 real_set_templates_menu (NautilusView *view,
800 GMenuModel *menu)
801 {
802 NautilusFilesViewPrivate *priv;
803
804 g_return_if_fail (NAUTILUS_IS_FILES_VIEW (view));
805
806 priv = nautilus_files_view_get_instance_private (NAUTILUS_FILES_VIEW (view));
807
808 g_set_object (&priv->templates_menu, menu);
809 }
810
811 static gboolean
showing_trash_directory(NautilusFilesView * view)812 showing_trash_directory (NautilusFilesView *view)
813 {
814 NautilusFile *file;
815
816 file = nautilus_files_view_get_directory_as_file (view);
817 if (file != NULL)
818 {
819 return nautilus_file_is_in_trash (file);
820 }
821 return FALSE;
822 }
823
824 static gboolean
showing_recent_directory(NautilusFilesView * view)825 showing_recent_directory (NautilusFilesView *view)
826 {
827 NautilusFile *file;
828
829 file = nautilus_files_view_get_directory_as_file (view);
830 if (file != NULL)
831 {
832 return nautilus_file_is_in_recent (file);
833 }
834 return FALSE;
835 }
836
837 static gboolean
showing_starred_directory(NautilusFilesView * view)838 showing_starred_directory (NautilusFilesView *view)
839 {
840 NautilusFile *file;
841
842 file = nautilus_files_view_get_directory_as_file (view);
843 if (file != NULL)
844 {
845 return nautilus_file_is_in_starred (file);
846 }
847 return FALSE;
848 }
849
850 static gboolean
nautilus_files_view_supports_creating_files(NautilusFilesView * view)851 nautilus_files_view_supports_creating_files (NautilusFilesView *view)
852 {
853 g_return_val_if_fail (NAUTILUS_IS_FILES_VIEW (view), FALSE);
854
855 return !nautilus_files_view_is_read_only (view)
856 && !showing_trash_directory (view)
857 && !showing_recent_directory (view)
858 && !showing_starred_directory (view);
859 }
860
861 static gboolean
nautilus_files_view_supports_extract_here(NautilusFilesView * view)862 nautilus_files_view_supports_extract_here (NautilusFilesView *view)
863 {
864 g_return_val_if_fail (NAUTILUS_IS_FILES_VIEW (view), FALSE);
865
866 return nautilus_files_view_supports_creating_files (view)
867 && !nautilus_view_is_searching (NAUTILUS_VIEW (view));
868 }
869
870 static gboolean
nautilus_files_view_is_empty(NautilusFilesView * view)871 nautilus_files_view_is_empty (NautilusFilesView *view)
872 {
873 g_return_val_if_fail (NAUTILUS_IS_FILES_VIEW (view), FALSE);
874
875 return NAUTILUS_FILES_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->is_empty (view);
876 }
877
878 /**
879 * nautilus_files_view_bump_zoom_level:
880 *
881 * bump the current zoom level by invoking the relevant subclass through the slot
882 *
883 **/
884 void
nautilus_files_view_bump_zoom_level(NautilusFilesView * view,int zoom_increment)885 nautilus_files_view_bump_zoom_level (NautilusFilesView *view,
886 int zoom_increment)
887 {
888 g_return_if_fail (NAUTILUS_IS_FILES_VIEW (view));
889
890 if (!nautilus_files_view_supports_zooming (view))
891 {
892 return;
893 }
894
895 NAUTILUS_FILES_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->bump_zoom_level (view, zoom_increment);
896 }
897
898 /**
899 * nautilus_files_view_can_zoom_in:
900 *
901 * Determine whether the view can be zoomed any closer.
902 * @view: The zoomable NautilusFilesView.
903 *
904 * Return value: TRUE if @view can be zoomed any closer, FALSE otherwise.
905 *
906 **/
907 gboolean
nautilus_files_view_can_zoom_in(NautilusFilesView * view)908 nautilus_files_view_can_zoom_in (NautilusFilesView *view)
909 {
910 g_return_val_if_fail (NAUTILUS_IS_FILES_VIEW (view), FALSE);
911
912 if (!nautilus_files_view_supports_zooming (view))
913 {
914 return FALSE;
915 }
916
917 return NAUTILUS_FILES_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->can_zoom_in (view);
918 }
919
920 /**
921 * nautilus_files_view_can_zoom_out:
922 *
923 * Determine whether the view can be zoomed any further away.
924 * @view: The zoomable NautilusFilesView.
925 *
926 * Return value: TRUE if @view can be zoomed any further away, FALSE otherwise.
927 *
928 **/
929 gboolean
nautilus_files_view_can_zoom_out(NautilusFilesView * view)930 nautilus_files_view_can_zoom_out (NautilusFilesView *view)
931 {
932 g_return_val_if_fail (NAUTILUS_IS_FILES_VIEW (view), FALSE);
933
934 if (!nautilus_files_view_supports_zooming (view))
935 {
936 return FALSE;
937 }
938
939 return NAUTILUS_FILES_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->can_zoom_out (view);
940 }
941
942 gboolean
nautilus_files_view_supports_zooming(NautilusFilesView * view)943 nautilus_files_view_supports_zooming (NautilusFilesView *view)
944 {
945 NautilusFilesViewPrivate *priv;
946
947 priv = nautilus_files_view_get_instance_private (view);
948
949 g_return_val_if_fail (NAUTILUS_IS_FILES_VIEW (view), FALSE);
950
951 return priv->supports_zooming;
952 }
953
954 /**
955 * nautilus_files_view_restore_standard_zoom_level:
956 *
957 * Restore the zoom level to 100%
958 */
959 static void
nautilus_files_view_restore_standard_zoom_level(NautilusFilesView * view)960 nautilus_files_view_restore_standard_zoom_level (NautilusFilesView *view)
961 {
962 if (!nautilus_files_view_supports_zooming (view))
963 {
964 return;
965 }
966
967 NAUTILUS_FILES_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->restore_standard_zoom_level (view);
968 }
969
970 static gfloat
nautilus_files_view_get_zoom_level_percentage(NautilusFilesView * view)971 nautilus_files_view_get_zoom_level_percentage (NautilusFilesView *view)
972 {
973 g_return_val_if_fail (NAUTILUS_IS_FILES_VIEW (view), 1);
974
975 return NAUTILUS_FILES_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_zoom_level_percentage (view);
976 }
977
978 static gboolean
nautilus_files_view_is_zoom_level_default(NautilusFilesView * view)979 nautilus_files_view_is_zoom_level_default (NautilusFilesView *view)
980 {
981 g_return_val_if_fail (NAUTILUS_IS_FILES_VIEW (view), FALSE);
982
983 return NAUTILUS_FILES_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->is_zoom_level_default (view);
984 }
985
986 gboolean
nautilus_files_view_is_searching(NautilusView * view)987 nautilus_files_view_is_searching (NautilusView *view)
988 {
989 NautilusFilesView *files_view;
990 NautilusFilesViewPrivate *priv;
991
992 files_view = NAUTILUS_FILES_VIEW (view);
993 priv = nautilus_files_view_get_instance_private (files_view);
994
995 if (!priv->model)
996 {
997 return FALSE;
998 }
999
1000 return NAUTILUS_IS_SEARCH_DIRECTORY (priv->model);
1001 }
1002
1003 static guint
nautilus_files_view_get_view_id(NautilusView * view)1004 nautilus_files_view_get_view_id (NautilusView *view)
1005 {
1006 return NAUTILUS_FILES_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_view_id (NAUTILUS_FILES_VIEW (view));
1007 }
1008
1009 char *
nautilus_files_view_get_first_visible_file(NautilusFilesView * view)1010 nautilus_files_view_get_first_visible_file (NautilusFilesView *view)
1011 {
1012 return NAUTILUS_FILES_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_first_visible_file (view);
1013 }
1014
1015 void
nautilus_files_view_scroll_to_file(NautilusFilesView * view,const char * uri)1016 nautilus_files_view_scroll_to_file (NautilusFilesView *view,
1017 const char *uri)
1018 {
1019 NAUTILUS_FILES_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->scroll_to_file (view, uri);
1020 }
1021
1022 /**
1023 * nautilus_files_view_get_selection:
1024 *
1025 * Get a list of NautilusFile pointers that represents the
1026 * currently-selected items in this view. Subclasses must override
1027 * the signal handler for the 'get_selection' signal. Callers are
1028 * responsible for g_free-ing the list (and unrefing its data).
1029 * @view: NautilusFilesView whose selected items are of interest.
1030 *
1031 * Return value: GList of NautilusFile pointers representing the selection.
1032 *
1033 **/
1034 static GList *
nautilus_files_view_get_selection(NautilusView * view)1035 nautilus_files_view_get_selection (NautilusView *view)
1036 {
1037 g_return_val_if_fail (NAUTILUS_IS_FILES_VIEW (view), NULL);
1038
1039 return NAUTILUS_FILES_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->get_selection (NAUTILUS_FILES_VIEW (view));
1040 }
1041
1042 typedef struct
1043 {
1044 NautilusFile *file;
1045 NautilusFilesView *directory_view;
1046 } ScriptLaunchParameters;
1047
1048 typedef struct
1049 {
1050 NautilusFile *file;
1051 NautilusFilesView *directory_view;
1052 } CreateTemplateParameters;
1053
1054 static FileAndDirectory *
file_and_directory_new(NautilusFile * file,NautilusDirectory * directory)1055 file_and_directory_new (NautilusFile *file,
1056 NautilusDirectory *directory)
1057 {
1058 FileAndDirectory *fad;
1059
1060 fad = g_new0 (FileAndDirectory, 1);
1061 fad->directory = nautilus_directory_ref (directory);
1062 fad->file = nautilus_file_ref (file);
1063
1064 return fad;
1065 }
1066
1067 static NautilusFile *
file_and_directory_get_file(FileAndDirectory * fad)1068 file_and_directory_get_file (FileAndDirectory *fad)
1069 {
1070 g_return_val_if_fail (fad != NULL, NULL);
1071
1072 return nautilus_file_ref (fad->file);
1073 }
1074
1075 static void
file_and_directory_free(gpointer data)1076 file_and_directory_free (gpointer data)
1077 {
1078 FileAndDirectory *fad = data;
1079
1080 nautilus_directory_unref (fad->directory);
1081 nautilus_file_unref (fad->file);
1082 g_free (fad);
1083 }
1084
G_DEFINE_AUTOPTR_CLEANUP_FUNC(FileAndDirectory,file_and_directory_free)1085 G_DEFINE_AUTOPTR_CLEANUP_FUNC (FileAndDirectory, file_and_directory_free)
1086
1087 static gboolean
1088 file_and_directory_equal (gconstpointer v1,
1089 gconstpointer v2)
1090 {
1091 const FileAndDirectory *fad1, *fad2;
1092 fad1 = v1;
1093 fad2 = v2;
1094
1095 return (fad1->file == fad2->file &&
1096 fad1->directory == fad2->directory);
1097 }
1098
1099 static guint
file_and_directory_hash(gconstpointer v)1100 file_and_directory_hash (gconstpointer v)
1101 {
1102 const FileAndDirectory *fad;
1103
1104 fad = v;
1105 return GPOINTER_TO_UINT (fad->file) ^ GPOINTER_TO_UINT (fad->directory);
1106 }
1107
1108 static ScriptLaunchParameters *
script_launch_parameters_new(NautilusFile * file,NautilusFilesView * directory_view)1109 script_launch_parameters_new (NautilusFile *file,
1110 NautilusFilesView *directory_view)
1111 {
1112 ScriptLaunchParameters *result;
1113
1114 result = g_new0 (ScriptLaunchParameters, 1);
1115 result->directory_view = directory_view;
1116 nautilus_file_ref (file);
1117 result->file = file;
1118
1119 return result;
1120 }
1121
1122 static void
script_launch_parameters_free(ScriptLaunchParameters * parameters)1123 script_launch_parameters_free (ScriptLaunchParameters *parameters)
1124 {
1125 nautilus_file_unref (parameters->file);
1126 g_free (parameters);
1127 }
1128
1129 static CreateTemplateParameters *
create_template_parameters_new(NautilusFile * file,NautilusFilesView * directory_view)1130 create_template_parameters_new (NautilusFile *file,
1131 NautilusFilesView *directory_view)
1132 {
1133 CreateTemplateParameters *result;
1134
1135 result = g_new0 (CreateTemplateParameters, 1);
1136 result->directory_view = directory_view;
1137 nautilus_file_ref (file);
1138 result->file = file;
1139
1140 return result;
1141 }
1142
1143 static void
create_templates_parameters_free(CreateTemplateParameters * parameters)1144 create_templates_parameters_free (CreateTemplateParameters *parameters)
1145 {
1146 nautilus_file_unref (parameters->file);
1147 g_free (parameters);
1148 }
1149
1150 NautilusWindow *
nautilus_files_view_get_window(NautilusFilesView * view)1151 nautilus_files_view_get_window (NautilusFilesView *view)
1152 {
1153 NautilusFilesViewPrivate *priv;
1154
1155 priv = nautilus_files_view_get_instance_private (view);
1156
1157 return nautilus_window_slot_get_window (priv->slot);
1158 }
1159
1160 NautilusWindowSlot *
nautilus_files_view_get_nautilus_window_slot(NautilusFilesView * view)1161 nautilus_files_view_get_nautilus_window_slot (NautilusFilesView *view)
1162 {
1163 NautilusFilesViewPrivate *priv;
1164
1165 priv = nautilus_files_view_get_instance_private (view);
1166
1167 g_assert (priv->slot != NULL);
1168
1169 return priv->slot;
1170 }
1171
1172 /* Returns the GtkWindow that this directory view occupies, or NULL
1173 * if at the moment this directory view is not in a GtkWindow or the
1174 * GtkWindow cannot be determined. Primarily used for parenting dialogs.
1175 */
1176 static GtkWindow *
nautilus_files_view_get_containing_window(NautilusFilesView * view)1177 nautilus_files_view_get_containing_window (NautilusFilesView *view)
1178 {
1179 GtkWidget *window;
1180
1181 g_assert (NAUTILUS_IS_FILES_VIEW (view));
1182
1183 window = gtk_widget_get_ancestor (GTK_WIDGET (view), GTK_TYPE_WINDOW);
1184 if (window == NULL)
1185 {
1186 return NULL;
1187 }
1188
1189 return GTK_WINDOW (window);
1190 }
1191
1192 static gboolean
nautilus_files_view_confirm_multiple(GtkWindow * parent_window,int count,gboolean tabs)1193 nautilus_files_view_confirm_multiple (GtkWindow *parent_window,
1194 int count,
1195 gboolean tabs)
1196 {
1197 GtkDialog *dialog;
1198 char *prompt;
1199 char *detail;
1200 int response;
1201
1202 if (count <= SILENT_WINDOW_OPEN_LIMIT)
1203 {
1204 return TRUE;
1205 }
1206
1207 prompt = _("Are you sure you want to open all files?");
1208 if (tabs)
1209 {
1210 detail = g_strdup_printf (ngettext ("This will open %'d separate tab.",
1211 "This will open %'d separate tabs.", count), count);
1212 }
1213 else
1214 {
1215 detail = g_strdup_printf (ngettext ("This will open %'d separate window.",
1216 "This will open %'d separate windows.", count), count);
1217 }
1218 dialog = eel_show_yes_no_dialog (prompt, detail,
1219 _("_OK"), _("_Cancel"),
1220 parent_window);
1221 g_free (detail);
1222
1223 response = gtk_dialog_run (dialog);
1224 gtk_widget_destroy (GTK_WIDGET (dialog));
1225
1226 return response == GTK_RESPONSE_YES;
1227 }
1228
1229 static char *
get_view_directory(NautilusFilesView * view)1230 get_view_directory (NautilusFilesView *view)
1231 {
1232 NautilusFilesViewPrivate *priv;
1233 char *uri, *path;
1234 GFile *f;
1235
1236 priv = nautilus_files_view_get_instance_private (view);
1237
1238 uri = nautilus_directory_get_uri (priv->model);
1239 f = g_file_new_for_uri (uri);
1240 path = g_file_get_path (f);
1241 g_object_unref (f);
1242 g_free (uri);
1243
1244 return path;
1245 }
1246
1247 typedef struct
1248 {
1249 gchar *uri;
1250 gboolean is_update;
1251 } PreviewExportData;
1252
1253 static void
preview_export_data_free(gpointer _data)1254 preview_export_data_free (gpointer _data)
1255 {
1256 PreviewExportData *data = _data;
1257 g_free (data->uri);
1258 g_free (data);
1259 }
1260
G_DEFINE_AUTOPTR_CLEANUP_FUNC(PreviewExportData,preview_export_data_free)1261 G_DEFINE_AUTOPTR_CLEANUP_FUNC (PreviewExportData, preview_export_data_free)
1262
1263 static void
1264 on_window_handle_export (NautilusWindow *window,
1265 const char *handle,
1266 guint xid,
1267 gpointer user_data)
1268 {
1269 g_autoptr (PreviewExportData) data = user_data;
1270 nautilus_previewer_call_show_file (data->uri, handle, xid, !data->is_update);
1271 }
1272
1273 static void
nautilus_files_view_preview(NautilusFilesView * view,PreviewExportData * data)1274 nautilus_files_view_preview (NautilusFilesView *view,
1275 PreviewExportData *data)
1276 {
1277 if (!nautilus_window_export_handle (nautilus_files_view_get_window (view),
1278 on_window_handle_export,
1279 data))
1280 {
1281 /* Let's use a fallback, so at least a preview will be displayed */
1282 nautilus_previewer_call_show_file (data->uri, "x11:0", 0, !data->is_update);
1283 }
1284 }
1285
1286 void
nautilus_files_view_preview_files(NautilusFilesView * view,GList * files,GArray * locations)1287 nautilus_files_view_preview_files (NautilusFilesView *view,
1288 GList *files,
1289 GArray *locations)
1290 {
1291 PreviewExportData *data = g_new0 (PreviewExportData, 1);
1292
1293 data->uri = nautilus_file_get_uri (files->data);
1294 data->is_update = FALSE;
1295
1296 nautilus_files_view_preview (view, data);
1297 }
1298
1299 static void
nautilus_files_view_preview_update(NautilusFilesView * view)1300 nautilus_files_view_preview_update (NautilusFilesView *view)
1301 {
1302 NautilusFilesViewPrivate *priv = nautilus_files_view_get_instance_private (view);
1303 GtkApplication *app;
1304 GtkWindow *window;
1305 g_autolist (NautilusFile) selection = NULL;
1306 PreviewExportData *data;
1307
1308 if (!priv->active ||
1309 !nautilus_previewer_is_visible ())
1310 {
1311 return;
1312 }
1313
1314 app = GTK_APPLICATION (g_application_get_default ());
1315 window = GTK_WINDOW (nautilus_files_view_get_window (view));
1316 if (window == NULL || window != gtk_application_get_active_window (app))
1317 {
1318 return;
1319 }
1320
1321 selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
1322 if (selection == NULL)
1323 {
1324 return;
1325 }
1326
1327 data = g_new0 (PreviewExportData, 1);
1328 data->uri = nautilus_file_get_uri (selection->data);
1329 data->is_update = TRUE;
1330
1331 nautilus_files_view_preview (view, data);
1332 }
1333
1334 void
nautilus_files_view_preview_selection_event(NautilusFilesView * view,GtkDirectionType direction)1335 nautilus_files_view_preview_selection_event (NautilusFilesView *view,
1336 GtkDirectionType direction)
1337 {
1338 NAUTILUS_FILES_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->preview_selection_event (view, direction);
1339 }
1340
1341 void
nautilus_files_view_activate_selection(NautilusFilesView * view)1342 nautilus_files_view_activate_selection (NautilusFilesView *view)
1343 {
1344 g_autolist (NautilusFile) selection = NULL;
1345
1346 selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
1347 nautilus_files_view_activate_files (view,
1348 selection,
1349 0,
1350 TRUE);
1351 }
1352
1353 void
nautilus_files_view_activate_files(NautilusFilesView * view,GList * files,NautilusWindowOpenFlags flags,gboolean confirm_multiple)1354 nautilus_files_view_activate_files (NautilusFilesView *view,
1355 GList *files,
1356 NautilusWindowOpenFlags flags,
1357 gboolean confirm_multiple)
1358 {
1359 NautilusFilesViewPrivate *priv;
1360 GList *files_to_extract;
1361 GList *files_to_activate;
1362 char *path;
1363
1364 if (files == NULL)
1365 {
1366 return;
1367 }
1368
1369 priv = nautilus_files_view_get_instance_private (view);
1370
1371 files_to_extract = nautilus_file_list_filter (files,
1372 &files_to_activate,
1373 (NautilusFileFilterFunc) nautilus_mime_file_extracts,
1374 NULL);
1375
1376 if (nautilus_files_view_supports_extract_here (view))
1377 {
1378 g_autoptr (GFile) location = NULL;
1379 g_autoptr (GFile) parent = NULL;
1380
1381 location = nautilus_file_get_location (NAUTILUS_FILE (g_list_first (files)->data));
1382 /* Get a parent from a random file. We assume all files has a common parent.
1383 * But don't assume the parent is the view location, since that's not the
1384 * case in list view when expand-folder setting is set
1385 */
1386 parent = g_file_get_parent (location);
1387 extract_files (view, files_to_extract, parent);
1388 }
1389 else
1390 {
1391 extract_files_to_chosen_location (view, files_to_extract);
1392 }
1393
1394 path = get_view_directory (view);
1395 nautilus_mime_activate_files (nautilus_files_view_get_containing_window (view),
1396 priv->slot,
1397 files_to_activate,
1398 path,
1399 flags,
1400 confirm_multiple);
1401
1402 g_free (path);
1403 g_list_free (files_to_extract);
1404 g_list_free (files_to_activate);
1405 }
1406
1407 void
nautilus_files_view_activate_file(NautilusFilesView * view,NautilusFile * file,NautilusWindowOpenFlags flags)1408 nautilus_files_view_activate_file (NautilusFilesView *view,
1409 NautilusFile *file,
1410 NautilusWindowOpenFlags flags)
1411 {
1412 g_autoptr (GList) files = NULL;
1413
1414 files = g_list_append (files, file);
1415 nautilus_files_view_activate_files (view, files, flags, FALSE);
1416 }
1417
1418 static void
action_open_with_default_application(GSimpleAction * action,GVariant * state,gpointer user_data)1419 action_open_with_default_application (GSimpleAction *action,
1420 GVariant *state,
1421 gpointer user_data)
1422 {
1423 NautilusFilesView *view;
1424
1425 view = NAUTILUS_FILES_VIEW (user_data);
1426 nautilus_files_view_activate_selection (view);
1427 }
1428
1429 static void
action_open_item_location(GSimpleAction * action,GVariant * state,gpointer user_data)1430 action_open_item_location (GSimpleAction *action,
1431 GVariant *state,
1432 gpointer user_data)
1433 {
1434 NautilusFilesView *view;
1435 g_autolist (NautilusFile) selection = NULL;
1436 NautilusFile *item;
1437 GFile *activation_location;
1438 NautilusFile *activation_file;
1439 NautilusFile *parent;
1440 g_autoptr (GFile) parent_location = NULL;
1441
1442 view = NAUTILUS_FILES_VIEW (user_data);
1443 selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
1444
1445 if (!selection)
1446 {
1447 return;
1448 }
1449
1450 item = NAUTILUS_FILE (selection->data);
1451 activation_location = nautilus_file_get_activation_location (item);
1452 activation_file = nautilus_file_get (activation_location);
1453 parent = nautilus_file_get_parent (activation_file);
1454 parent_location = nautilus_file_get_location (parent);
1455
1456 if (nautilus_file_is_in_recent (item))
1457 {
1458 /* Selection logic will check against a NautilusFile of the
1459 * activation uri, not the recent:// one. Fixes bug 784516 */
1460 nautilus_file_unref (item);
1461 item = nautilus_file_ref (activation_file);
1462 selection->data = item;
1463 }
1464
1465 nautilus_application_open_location_full (NAUTILUS_APPLICATION (g_application_get_default ()),
1466 parent_location, 0, selection, NULL,
1467 nautilus_files_view_get_nautilus_window_slot (view));
1468
1469 nautilus_file_unref (parent);
1470 nautilus_file_unref (activation_file);
1471 g_object_unref (activation_location);
1472 }
1473
1474 static void
action_open_item_new_tab(GSimpleAction * action,GVariant * state,gpointer user_data)1475 action_open_item_new_tab (GSimpleAction *action,
1476 GVariant *state,
1477 gpointer user_data)
1478 {
1479 NautilusFilesView *view;
1480 g_autolist (NautilusFile) selection = NULL;
1481 GtkWindow *window;
1482
1483 view = NAUTILUS_FILES_VIEW (user_data);
1484 selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
1485
1486 window = nautilus_files_view_get_containing_window (view);
1487
1488 if (nautilus_files_view_confirm_multiple (window, g_list_length (selection), TRUE))
1489 {
1490 nautilus_files_view_activate_files (view,
1491 selection,
1492 NAUTILUS_WINDOW_OPEN_FLAG_NEW_TAB |
1493 NAUTILUS_WINDOW_OPEN_FLAG_DONT_MAKE_ACTIVE,
1494 FALSE);
1495 }
1496 }
1497
1498 static void
app_chooser_dialog_response_cb(GtkDialog * dialog,gint response_id,gpointer user_data)1499 app_chooser_dialog_response_cb (GtkDialog *dialog,
1500 gint response_id,
1501 gpointer user_data)
1502 {
1503 GtkWindow *parent_window;
1504 GList *files;
1505 GAppInfo *info;
1506
1507 parent_window = user_data;
1508 files = g_object_get_data (G_OBJECT (dialog), "directory-view:files");
1509
1510 if (response_id != GTK_RESPONSE_OK)
1511 {
1512 goto out;
1513 }
1514
1515 info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (dialog));
1516
1517 g_signal_emit_by_name (nautilus_signaller_get_current (), "mime-data-changed");
1518
1519 nautilus_launch_application (info, files, parent_window);
1520
1521 g_object_unref (info);
1522 out:
1523 gtk_widget_destroy (GTK_WIDGET (dialog));
1524 }
1525
1526 static void
choose_program(NautilusFilesView * view,GList * files)1527 choose_program (NautilusFilesView *view,
1528 GList *files)
1529 {
1530 GtkWidget *dialog;
1531 g_autofree gchar *mime_type = NULL;
1532 GtkWindow *parent_window;
1533
1534 g_assert (NAUTILUS_IS_FILES_VIEW (view));
1535
1536 mime_type = nautilus_file_get_mime_type (files->data);
1537 parent_window = nautilus_files_view_get_containing_window (view);
1538
1539 dialog = gtk_app_chooser_dialog_new_for_content_type (parent_window,
1540 GTK_DIALOG_MODAL |
1541 GTK_DIALOG_DESTROY_WITH_PARENT |
1542 GTK_DIALOG_USE_HEADER_BAR,
1543 mime_type);
1544 g_object_set_data_full (G_OBJECT (dialog),
1545 "directory-view:files",
1546 files,
1547 (GDestroyNotify) nautilus_file_list_free);
1548 gtk_widget_show (dialog);
1549
1550 g_signal_connect_object (dialog, "response",
1551 G_CALLBACK (app_chooser_dialog_response_cb),
1552 parent_window, 0);
1553 }
1554
1555 static void
open_with_other_program(NautilusFilesView * view)1556 open_with_other_program (NautilusFilesView *view)
1557 {
1558 g_autolist (NautilusFile) selection = NULL;
1559
1560 g_assert (NAUTILUS_IS_FILES_VIEW (view));
1561
1562 selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
1563 choose_program (view, g_steal_pointer (&selection));
1564 }
1565
1566 static void
action_open_with_other_application(GSimpleAction * action,GVariant * state,gpointer user_data)1567 action_open_with_other_application (GSimpleAction *action,
1568 GVariant *state,
1569 gpointer user_data)
1570 {
1571 g_assert (NAUTILUS_IS_FILES_VIEW (user_data));
1572
1573 open_with_other_program (NAUTILUS_FILES_VIEW (user_data));
1574 }
1575
1576 static void
trash_or_delete_selected_files(NautilusFilesView * view)1577 trash_or_delete_selected_files (NautilusFilesView *view)
1578 {
1579 NautilusFilesViewPrivate *priv;
1580 priv = nautilus_files_view_get_instance_private (view);
1581
1582 /* This might be rapidly called multiple times for the same selection
1583 * when using keybindings. So we remember if the current selection
1584 * was already removed (but the view doesn't know about it yet).
1585 */
1586 if (!priv->selection_was_removed)
1587 {
1588 g_autolist (NautilusFile) selection = NULL;
1589 selection = nautilus_files_view_get_selection_for_file_transfer (view);
1590 trash_or_delete_files (nautilus_files_view_get_containing_window (view),
1591 selection,
1592 view);
1593 priv->selection_was_removed = TRUE;
1594 }
1595 }
1596
1597 static void
action_move_to_trash(GSimpleAction * action,GVariant * state,gpointer user_data)1598 action_move_to_trash (GSimpleAction *action,
1599 GVariant *state,
1600 gpointer user_data)
1601 {
1602 trash_or_delete_selected_files (NAUTILUS_FILES_VIEW (user_data));
1603 }
1604
1605 static void
action_remove_from_recent(GSimpleAction * action,GVariant * state,gpointer user_data)1606 action_remove_from_recent (GSimpleAction *action,
1607 GVariant *state,
1608 gpointer user_data)
1609 {
1610 /* TODO:implement a set of functions for this, is very confusing to
1611 * call trash_or_delete_file to remove from recent, even if it does like
1612 * that not deleting/moving the files to trash */
1613 trash_or_delete_selected_files (NAUTILUS_FILES_VIEW (user_data));
1614 }
1615
1616 static void
delete_selected_files(NautilusFilesView * view)1617 delete_selected_files (NautilusFilesView *view)
1618 {
1619 GList *selection;
1620 GList *node;
1621 GList *locations;
1622
1623 selection = nautilus_files_view_get_selection_for_file_transfer (view);
1624 if (selection == NULL)
1625 {
1626 return;
1627 }
1628
1629 locations = NULL;
1630 for (node = selection; node != NULL; node = node->next)
1631 {
1632 locations = g_list_prepend (locations,
1633 nautilus_file_get_location ((NautilusFile *) node->data));
1634 }
1635 locations = g_list_reverse (locations);
1636
1637 nautilus_file_operations_delete_async (locations, nautilus_files_view_get_containing_window (view), NULL, NULL, NULL);
1638
1639 g_list_free_full (locations, g_object_unref);
1640 nautilus_file_list_free (selection);
1641 }
1642
1643 static void
action_delete(GSimpleAction * action,GVariant * state,gpointer user_data)1644 action_delete (GSimpleAction *action,
1645 GVariant *state,
1646 gpointer user_data)
1647 {
1648 delete_selected_files (NAUTILUS_FILES_VIEW (user_data));
1649 }
1650
1651 static void
action_star(GSimpleAction * action,GVariant * state,gpointer user_data)1652 action_star (GSimpleAction *action,
1653 GVariant *state,
1654 gpointer user_data)
1655 {
1656 NautilusFilesView *view;
1657 g_autolist (NautilusFile) selection = NULL;
1658 NautilusFilesViewPrivate *priv;
1659
1660 view = NAUTILUS_FILES_VIEW (user_data);
1661 priv = nautilus_files_view_get_instance_private (view);
1662 selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
1663
1664 nautilus_tag_manager_star_files (priv->tag_manager,
1665 G_OBJECT (view),
1666 selection,
1667 NULL,
1668 priv->starred_cancellable);
1669 }
1670
1671 static void
action_unstar(GSimpleAction * action,GVariant * state,gpointer user_data)1672 action_unstar (GSimpleAction *action,
1673 GVariant *state,
1674 gpointer user_data)
1675 {
1676 NautilusFilesView *view;
1677 g_autolist (NautilusFile) selection = NULL;
1678 NautilusFilesViewPrivate *priv;
1679
1680 view = NAUTILUS_FILES_VIEW (user_data);
1681 priv = nautilus_files_view_get_instance_private (view);
1682 selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
1683
1684 nautilus_tag_manager_unstar_files (priv->tag_manager,
1685 G_OBJECT (view),
1686 selection,
1687 NULL,
1688 priv->starred_cancellable);
1689 }
1690
1691 static void
action_restore_from_trash(GSimpleAction * action,GVariant * state,gpointer user_data)1692 action_restore_from_trash (GSimpleAction *action,
1693 GVariant *state,
1694 gpointer user_data)
1695 {
1696 NautilusFilesView *view;
1697 GList *selection;
1698
1699 view = NAUTILUS_FILES_VIEW (user_data);
1700
1701 selection = nautilus_files_view_get_selection_for_file_transfer (view);
1702 nautilus_restore_files_from_trash (selection,
1703 nautilus_files_view_get_containing_window (view));
1704
1705 nautilus_file_list_free (selection);
1706 }
1707
1708 static void
action_select_all(GSimpleAction * action,GVariant * state,gpointer user_data)1709 action_select_all (GSimpleAction *action,
1710 GVariant *state,
1711 gpointer user_data)
1712 {
1713 NautilusFilesView *view;
1714
1715 g_assert (NAUTILUS_IS_FILES_VIEW (user_data));
1716
1717 view = NAUTILUS_FILES_VIEW (user_data);
1718
1719 nautilus_files_view_select_all (view);
1720 }
1721
1722 static void
action_invert_selection(GSimpleAction * action,GVariant * state,gpointer user_data)1723 action_invert_selection (GSimpleAction *action,
1724 GVariant *state,
1725 gpointer user_data)
1726 {
1727 g_assert (NAUTILUS_IS_FILES_VIEW (user_data));
1728
1729 nautilus_files_view_invert_selection (user_data);
1730 }
1731
1732 static void
pattern_select_response_cb(GtkWidget * dialog,int response,gpointer user_data)1733 pattern_select_response_cb (GtkWidget *dialog,
1734 int response,
1735 gpointer user_data)
1736 {
1737 NautilusFilesView *view;
1738 NautilusDirectory *directory;
1739 GtkWidget *entry;
1740 GList *selection;
1741
1742 view = NAUTILUS_FILES_VIEW (user_data);
1743
1744 switch (response)
1745 {
1746 case GTK_RESPONSE_OK:
1747 {
1748 entry = g_object_get_data (G_OBJECT (dialog), "entry");
1749 directory = nautilus_files_view_get_model (view);
1750 selection = nautilus_directory_match_pattern (directory,
1751 gtk_entry_get_text (GTK_ENTRY (entry)));
1752
1753 nautilus_files_view_call_set_selection (view, selection);
1754 nautilus_files_view_reveal_selection (view);
1755
1756 if (selection)
1757 {
1758 nautilus_file_list_free (selection);
1759 }
1760 /* fall through */
1761 }
1762
1763 case GTK_RESPONSE_NONE:
1764 case GTK_RESPONSE_DELETE_EVENT:
1765 case GTK_RESPONSE_CANCEL:
1766 {
1767 gtk_widget_destroy (GTK_WIDGET (dialog));
1768 }
1769 break;
1770
1771 default:
1772 {
1773 g_assert_not_reached ();
1774 }
1775 }
1776 }
1777
1778 static void
select_pattern(NautilusFilesView * view)1779 select_pattern (NautilusFilesView *view)
1780 {
1781 GtkWidget *dialog;
1782 GtkWidget *label;
1783 GtkWidget *example;
1784 GtkWidget *grid;
1785 GtkWidget *entry;
1786 char *example_pattern;
1787
1788 dialog = gtk_dialog_new_with_buttons (_("Select Items Matching"),
1789 nautilus_files_view_get_containing_window (view),
1790 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_USE_HEADER_BAR,
1791 _("_Cancel"),
1792 GTK_RESPONSE_CANCEL,
1793 _("_Select"),
1794 GTK_RESPONSE_OK,
1795 NULL);
1796 gtk_dialog_set_default_response (GTK_DIALOG (dialog),
1797 GTK_RESPONSE_OK);
1798 gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
1799 gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 2);
1800
1801 label = gtk_label_new_with_mnemonic (_("_Pattern:"));
1802 gtk_widget_set_halign (label, GTK_ALIGN_START);
1803
1804 example = gtk_label_new (NULL);
1805 gtk_widget_set_halign (example, GTK_ALIGN_START);
1806 example_pattern = g_strdup_printf ("%s<i>%s</i> ",
1807 _("Examples: "),
1808 "*.png, file\?\?.txt, pict*.\?\?\?");
1809 gtk_label_set_markup (GTK_LABEL (example), example_pattern);
1810 g_free (example_pattern);
1811
1812 entry = gtk_entry_new ();
1813 gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
1814 gtk_widget_set_hexpand (entry, TRUE);
1815
1816 grid = gtk_grid_new ();
1817 g_object_set (grid,
1818 "orientation", GTK_ORIENTATION_VERTICAL,
1819 "border-width", 6,
1820 "row-spacing", 6,
1821 "column-spacing", 12,
1822 NULL);
1823
1824 gtk_container_add (GTK_CONTAINER (grid), label);
1825 gtk_grid_attach_next_to (GTK_GRID (grid), entry, label,
1826 GTK_POS_RIGHT, 1, 1);
1827 gtk_grid_attach_next_to (GTK_GRID (grid), example, entry,
1828 GTK_POS_BOTTOM, 1, 1);
1829
1830 gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
1831 gtk_widget_show_all (grid);
1832 gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), grid);
1833 g_object_set_data (G_OBJECT (dialog), "entry", entry);
1834 g_signal_connect (dialog, "response",
1835 G_CALLBACK (pattern_select_response_cb),
1836 view);
1837 gtk_widget_show_all (dialog);
1838 }
1839
1840 static void
action_select_pattern(GSimpleAction * action,GVariant * state,gpointer user_data)1841 action_select_pattern (GSimpleAction *action,
1842 GVariant *state,
1843 gpointer user_data)
1844 {
1845 g_assert (NAUTILUS_IS_FILES_VIEW (user_data));
1846
1847 select_pattern (user_data);
1848 }
1849
1850 typedef struct
1851 {
1852 NautilusFilesView *directory_view;
1853 GHashTable *added_locations;
1854 GList *selection;
1855 } NewFolderData;
1856
1857 typedef struct
1858 {
1859 NautilusFilesView *directory_view;
1860 GHashTable *to_remove_locations;
1861 NautilusFile *new_folder;
1862 } NewFolderSelectionData;
1863
1864 static void
track_newly_added_locations(NautilusFilesView * view,GList * new_files,gpointer user_data)1865 track_newly_added_locations (NautilusFilesView *view,
1866 GList *new_files,
1867 gpointer user_data)
1868 {
1869 GHashTable *added_locations;
1870
1871 added_locations = user_data;
1872
1873 while (new_files)
1874 {
1875 NautilusFile *new_file;
1876
1877 new_file = NAUTILUS_FILE (new_files->data);
1878
1879 g_hash_table_add (added_locations,
1880 nautilus_file_get_location (new_file));
1881
1882 new_files = new_files->next;
1883 }
1884 }
1885
1886 static void
new_folder_done(GFile * new_folder,gboolean success,gpointer user_data)1887 new_folder_done (GFile *new_folder,
1888 gboolean success,
1889 gpointer user_data)
1890 {
1891 NautilusFilesView *directory_view;
1892 NautilusFilesViewPrivate *priv;
1893 NautilusFile *file;
1894 NewFolderData *data;
1895
1896 data = (NewFolderData *) user_data;
1897
1898 directory_view = data->directory_view;
1899 priv = nautilus_files_view_get_instance_private (directory_view);
1900
1901 if (directory_view == NULL)
1902 {
1903 goto fail;
1904 }
1905
1906 g_signal_handlers_disconnect_by_func (directory_view,
1907 G_CALLBACK (track_newly_added_locations),
1908 data->added_locations);
1909
1910 if (new_folder == NULL)
1911 {
1912 goto fail;
1913 }
1914
1915 file = nautilus_file_get (new_folder);
1916
1917 if (data->selection != NULL)
1918 {
1919 GList *uris, *l;
1920 char *target_uri;
1921
1922 uris = NULL;
1923 for (l = data->selection; l != NULL; l = l->next)
1924 {
1925 uris = g_list_prepend (uris, nautilus_file_get_uri ((NautilusFile *) l->data));
1926 }
1927 uris = g_list_reverse (uris);
1928
1929 target_uri = nautilus_file_get_uri (file);
1930
1931 nautilus_files_view_move_copy_items (directory_view,
1932 uris,
1933 target_uri,
1934 GDK_ACTION_MOVE);
1935 g_list_free_full (uris, g_free);
1936 g_free (target_uri);
1937 }
1938
1939 if (g_hash_table_contains (data->added_locations, new_folder))
1940 {
1941 /* The file was already added */
1942 nautilus_files_view_select_file (directory_view, file);
1943 nautilus_files_view_reveal_selection (directory_view);
1944 }
1945 else
1946 {
1947 g_hash_table_insert (priv->pending_reveal,
1948 file,
1949 GUINT_TO_POINTER (TRUE));
1950 }
1951
1952 nautilus_file_unref (file);
1953
1954 fail:
1955 g_hash_table_destroy (data->added_locations);
1956
1957 if (data->directory_view != NULL)
1958 {
1959 g_object_remove_weak_pointer (G_OBJECT (data->directory_view),
1960 (gpointer *) &data->directory_view);
1961 }
1962
1963 nautilus_file_list_free (data->selection);
1964 g_free (data);
1965 }
1966
1967
1968 static NewFolderData *
new_folder_data_new(NautilusFilesView * directory_view,gboolean with_selection)1969 new_folder_data_new (NautilusFilesView *directory_view,
1970 gboolean with_selection)
1971 {
1972 NewFolderData *data;
1973
1974 data = g_new (NewFolderData, 1);
1975 data->directory_view = directory_view;
1976 data->added_locations = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal,
1977 g_object_unref, NULL);
1978 if (with_selection)
1979 {
1980 data->selection = nautilus_files_view_get_selection_for_file_transfer (directory_view);
1981 }
1982 else
1983 {
1984 data->selection = NULL;
1985 }
1986 g_object_add_weak_pointer (G_OBJECT (data->directory_view),
1987 (gpointer *) &data->directory_view);
1988
1989 return data;
1990 }
1991
1992 static GdkRectangle *
nautilus_files_view_compute_rename_popover_pointing_to(NautilusFilesView * view)1993 nautilus_files_view_compute_rename_popover_pointing_to (NautilusFilesView *view)
1994 {
1995 return NAUTILUS_FILES_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->compute_rename_popover_pointing_to (view);
1996 }
1997
1998 static void
disconnect_rename_controller_signals(NautilusFilesView * self)1999 disconnect_rename_controller_signals (NautilusFilesView *self)
2000 {
2001 NautilusFilesViewPrivate *priv;
2002
2003 g_assert (NAUTILUS_IS_FILES_VIEW (self));
2004
2005 priv = nautilus_files_view_get_instance_private (self);
2006
2007 g_clear_signal_handler (&priv->name_accepted_handler_id, priv->rename_file_controller);
2008 g_clear_signal_handler (&priv->cancelled_handler_id, priv->rename_file_controller);
2009 }
2010
2011 static void
rename_file_popover_controller_on_name_accepted(NautilusFileNameWidgetController * controller,gpointer user_data)2012 rename_file_popover_controller_on_name_accepted (NautilusFileNameWidgetController *controller,
2013 gpointer user_data)
2014 {
2015 NautilusFilesView *view;
2016 NautilusFile *target_file;
2017 g_autofree gchar *name = NULL;
2018 NautilusFilesViewPrivate *priv;
2019
2020 view = NAUTILUS_FILES_VIEW (user_data);
2021 priv = nautilus_files_view_get_instance_private (view);
2022
2023 name = nautilus_file_name_widget_controller_get_new_name (controller);
2024
2025 target_file =
2026 nautilus_rename_file_popover_controller_get_target_file (priv->rename_file_controller);
2027
2028 /* Put it on the queue for reveal after the view acknowledges the change */
2029 g_hash_table_insert (priv->pending_reveal,
2030 target_file,
2031 GUINT_TO_POINTER (FALSE));
2032
2033 nautilus_rename_file (target_file, name, NULL, NULL);
2034
2035 disconnect_rename_controller_signals (view);
2036 }
2037
2038 static void
rename_file_popover_controller_on_cancelled(NautilusFileNameWidgetController * controller,gpointer user_data)2039 rename_file_popover_controller_on_cancelled (NautilusFileNameWidgetController *controller,
2040 gpointer user_data)
2041 {
2042 NautilusFilesView *view;
2043
2044 view = NAUTILUS_FILES_VIEW (user_data);
2045
2046 disconnect_rename_controller_signals (view);
2047 }
2048
2049 static void
nautilus_files_view_rename_file_popover_new(NautilusFilesView * view,NautilusFile * target_file)2050 nautilus_files_view_rename_file_popover_new (NautilusFilesView *view,
2051 NautilusFile *target_file)
2052 {
2053 GdkRectangle *pointing_to;
2054 NautilusFilesViewPrivate *priv;
2055
2056 priv = nautilus_files_view_get_instance_private (view);
2057
2058 /* Make sure the whole item is visible. The selection is a single item, the
2059 * one to rename with the popover, so we can use reveal_selection() for this.
2060 */
2061 nautilus_files_view_reveal_selection (view);
2062
2063 pointing_to = nautilus_files_view_compute_rename_popover_pointing_to (view);
2064
2065 nautilus_rename_file_popover_controller_show_for_file (priv->rename_file_controller,
2066 target_file,
2067 pointing_to,
2068 GTK_WIDGET (view));
2069
2070 priv->name_accepted_handler_id = g_signal_connect (priv->rename_file_controller,
2071 "name-accepted",
2072 G_CALLBACK (rename_file_popover_controller_on_name_accepted),
2073 view);
2074 priv->cancelled_handler_id = g_signal_connect (priv->rename_file_controller,
2075 "cancelled",
2076 G_CALLBACK (rename_file_popover_controller_on_cancelled),
2077 view);
2078 }
2079
2080 static void
new_folder_dialog_controller_on_name_accepted(NautilusFileNameWidgetController * controller,gpointer user_data)2081 new_folder_dialog_controller_on_name_accepted (NautilusFileNameWidgetController *controller,
2082 gpointer user_data)
2083 {
2084 NautilusFilesView *view;
2085 NautilusFilesViewPrivate *priv;
2086 NewFolderData *data;
2087 g_autofree gchar *parent_uri = NULL;
2088 g_autofree gchar *name = NULL;
2089 NautilusFile *parent;
2090 gboolean with_selection;
2091
2092 view = NAUTILUS_FILES_VIEW (user_data);
2093 priv = nautilus_files_view_get_instance_private (view);
2094
2095 with_selection =
2096 nautilus_new_folder_dialog_controller_get_with_selection (priv->new_folder_controller);
2097
2098 data = new_folder_data_new (view, with_selection);
2099
2100 name = nautilus_file_name_widget_controller_get_new_name (controller);
2101 g_signal_connect_data (view,
2102 "add-files",
2103 G_CALLBACK (track_newly_added_locations),
2104 data->added_locations,
2105 (GClosureNotify) NULL,
2106 G_CONNECT_AFTER);
2107
2108 parent_uri = nautilus_files_view_get_backing_uri (view);
2109 parent = nautilus_file_get_by_uri (parent_uri);
2110 nautilus_file_operations_new_folder (GTK_WIDGET (view),
2111 NULL,
2112 parent_uri, name,
2113 new_folder_done, data);
2114
2115 g_clear_object (&priv->new_folder_controller);
2116
2117 /* After the dialog is destroyed the focus, is probably in the menu item
2118 * that created the dialog, but we want the focus to be in the newly created
2119 * folder.
2120 */
2121 gtk_widget_grab_focus (GTK_WIDGET (view));
2122
2123 g_object_unref (parent);
2124 }
2125
2126 static void
new_folder_dialog_controller_on_cancelled(NautilusNewFolderDialogController * controller,gpointer user_data)2127 new_folder_dialog_controller_on_cancelled (NautilusNewFolderDialogController *controller,
2128 gpointer user_data)
2129 {
2130 NautilusFilesView *view;
2131 NautilusFilesViewPrivate *priv;
2132
2133 view = NAUTILUS_FILES_VIEW (user_data);
2134 priv = nautilus_files_view_get_instance_private (view);
2135
2136 g_clear_object (&priv->new_folder_controller);
2137 }
2138
2139 static void
nautilus_files_view_new_folder_dialog_new(NautilusFilesView * view,gboolean with_selection)2140 nautilus_files_view_new_folder_dialog_new (NautilusFilesView *view,
2141 gboolean with_selection)
2142 {
2143 g_autoptr (NautilusDirectory) containing_directory = NULL;
2144 NautilusFilesViewPrivate *priv;
2145 g_autofree char *uri = NULL;
2146 g_autofree char *common_prefix = NULL;
2147
2148 priv = nautilus_files_view_get_instance_private (view);
2149
2150 if (priv->new_folder_controller != NULL)
2151 {
2152 return;
2153 }
2154
2155 uri = nautilus_files_view_get_backing_uri (view);
2156 containing_directory = nautilus_directory_get_by_uri (uri);
2157
2158 if (with_selection)
2159 {
2160 g_autolist (NautilusFile) selection = NULL;
2161 selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
2162 common_prefix = nautilus_get_common_filename_prefix (selection, MIN_COMMON_FILENAME_PREFIX_LENGTH);
2163 }
2164
2165 priv->new_folder_controller =
2166 nautilus_new_folder_dialog_controller_new (nautilus_files_view_get_containing_window (view),
2167 containing_directory,
2168 with_selection,
2169 common_prefix);
2170
2171 g_signal_connect (priv->new_folder_controller,
2172 "name-accepted",
2173 (GCallback) new_folder_dialog_controller_on_name_accepted,
2174 view);
2175 g_signal_connect (priv->new_folder_controller,
2176 "cancelled",
2177 (GCallback) new_folder_dialog_controller_on_cancelled,
2178 view);
2179 }
2180
2181 typedef struct
2182 {
2183 NautilusFilesView *view;
2184 GHashTable *added_locations;
2185 } CompressData;
2186
2187 static void
compress_done(GFile * new_file,gboolean success,gpointer user_data)2188 compress_done (GFile *new_file,
2189 gboolean success,
2190 gpointer user_data)
2191 {
2192 CompressData *data;
2193 NautilusFilesView *view;
2194 NautilusFilesViewPrivate *priv;
2195 NautilusFile *file;
2196
2197 data = user_data;
2198 view = data->view;
2199
2200 if (view == NULL)
2201 {
2202 goto out;
2203 }
2204
2205 priv = nautilus_files_view_get_instance_private (view);
2206
2207 g_signal_handlers_disconnect_by_func (view,
2208 G_CALLBACK (track_newly_added_locations),
2209 data->added_locations);
2210
2211 if (!success)
2212 {
2213 goto out;
2214 }
2215
2216 file = nautilus_file_get (new_file);
2217
2218 if (g_hash_table_contains (data->added_locations, new_file))
2219 {
2220 /* The file was already added */
2221 nautilus_files_view_select_file (view, file);
2222 nautilus_files_view_reveal_selection (view);
2223 }
2224 else
2225 {
2226 g_hash_table_insert (priv->pending_reveal,
2227 file,
2228 GUINT_TO_POINTER (TRUE));
2229 }
2230
2231 nautilus_file_unref (file);
2232 out:
2233 g_hash_table_destroy (data->added_locations);
2234
2235 if (data->view != NULL)
2236 {
2237 g_object_remove_weak_pointer (G_OBJECT (data->view),
2238 (gpointer *) &data->view);
2239 }
2240
2241 g_free (data);
2242 }
2243
2244 static void
compress_dialog_controller_on_name_accepted(NautilusFileNameWidgetController * controller,gpointer user_data)2245 compress_dialog_controller_on_name_accepted (NautilusFileNameWidgetController *controller,
2246 gpointer user_data)
2247 {
2248 CompressCallbackData *callback_data = user_data;
2249 NautilusFilesView *view;
2250 g_autofree gchar *name = NULL;
2251 GList *source_files = NULL;
2252 GList *l;
2253 CompressData *data;
2254 g_autoptr (GFile) output = NULL;
2255 g_autoptr (GFile) parent = NULL;
2256 NautilusCompressionFormat compression_format;
2257 NautilusFilesViewPrivate *priv;
2258 AutoarFormat format;
2259 AutoarFilter filter;
2260 const gchar *passphrase = NULL;
2261
2262 view = NAUTILUS_FILES_VIEW (callback_data->view);
2263 priv = nautilus_files_view_get_instance_private (view);
2264
2265 for (l = callback_data->selection; l != NULL; l = l->next)
2266 {
2267 source_files = g_list_prepend (source_files,
2268 nautilus_file_get_location (l->data));
2269 }
2270 source_files = g_list_reverse (source_files);
2271
2272 name = nautilus_file_name_widget_controller_get_new_name (controller);
2273 /* Get a parent from a random file. We assume all files has a common parent.
2274 * But don't assume the parent is the view location, since that's not the
2275 * case in list view when expand-folder setting is set
2276 */
2277 parent = g_file_get_parent (G_FILE (g_list_first (source_files)->data));
2278 output = g_file_get_child (parent, name);
2279
2280 data = g_new (CompressData, 1);
2281 data->view = view;
2282 data->added_locations = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal,
2283 g_object_unref, NULL);
2284 g_object_add_weak_pointer (G_OBJECT (data->view),
2285 (gpointer *) &data->view);
2286
2287 g_signal_connect_data (view,
2288 "add-files",
2289 G_CALLBACK (track_newly_added_locations),
2290 data->added_locations,
2291 NULL,
2292 G_CONNECT_AFTER);
2293
2294 compression_format = g_settings_get_enum (nautilus_compression_preferences,
2295 NAUTILUS_PREFERENCES_DEFAULT_COMPRESSION_FORMAT);
2296
2297 switch (compression_format)
2298 {
2299 case NAUTILUS_COMPRESSION_ZIP:
2300 {
2301 format = AUTOAR_FORMAT_ZIP;
2302 filter = AUTOAR_FILTER_NONE;
2303 }
2304 break;
2305
2306 case NAUTILUS_COMPRESSION_ENCRYPTED_ZIP:
2307 {
2308 format = AUTOAR_FORMAT_ZIP;
2309 filter = AUTOAR_FILTER_NONE;
2310 passphrase = nautilus_compress_dialog_controller_get_passphrase (priv->compress_controller);
2311 }
2312 break;
2313
2314 case NAUTILUS_COMPRESSION_TAR_XZ:
2315 {
2316 format = AUTOAR_FORMAT_TAR;
2317 filter = AUTOAR_FILTER_XZ;
2318 }
2319 break;
2320
2321 case NAUTILUS_COMPRESSION_7ZIP:
2322 {
2323 format = AUTOAR_FORMAT_7ZIP;
2324 filter = AUTOAR_FILTER_NONE;
2325 }
2326 break;
2327
2328 default:
2329 {
2330 g_assert_not_reached ();
2331 }
2332 }
2333
2334 nautilus_file_operations_compress (source_files, output,
2335 format,
2336 filter,
2337 passphrase,
2338 nautilus_files_view_get_containing_window (view),
2339 NULL,
2340 compress_done,
2341 data);
2342
2343 g_list_free_full (source_files, g_object_unref);
2344 g_clear_object (&priv->compress_controller);
2345 }
2346
2347 static void
compress_dialog_controller_on_cancelled(NautilusNewFolderDialogController * controller,gpointer user_data)2348 compress_dialog_controller_on_cancelled (NautilusNewFolderDialogController *controller,
2349 gpointer user_data)
2350 {
2351 NautilusFilesView *view;
2352 NautilusFilesViewPrivate *priv;
2353
2354 view = NAUTILUS_FILES_VIEW (user_data);
2355 priv = nautilus_files_view_get_instance_private (view);
2356
2357 g_clear_object (&priv->compress_controller);
2358 }
2359
2360 static void
compress_callback_data_free(CompressCallbackData * data)2361 compress_callback_data_free (CompressCallbackData *data)
2362 {
2363 nautilus_file_list_free (data->selection);
2364 g_free (data);
2365 }
2366
2367 static void
nautilus_files_view_compress_dialog_new(NautilusFilesView * view)2368 nautilus_files_view_compress_dialog_new (NautilusFilesView *view)
2369 {
2370 NautilusDirectory *containing_directory;
2371 NautilusFilesViewPrivate *priv;
2372 g_autolist (NautilusFile) selection = NULL;
2373 g_autofree char *common_prefix = NULL;
2374 CompressCallbackData *data;
2375
2376 priv = nautilus_files_view_get_instance_private (view);
2377
2378 if (priv->compress_controller != NULL)
2379 {
2380 return;
2381 }
2382
2383 containing_directory = nautilus_directory_get_by_uri (nautilus_files_view_get_backing_uri (view));
2384
2385 selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
2386
2387 if (g_list_length (selection) == 1)
2388 {
2389 g_autofree char *display_name = NULL;
2390
2391 display_name = nautilus_file_get_display_name (selection->data);
2392
2393 if (nautilus_file_is_directory (selection->data))
2394 {
2395 common_prefix = g_steal_pointer (&display_name);
2396 }
2397 else
2398 {
2399 common_prefix = eel_filename_strip_extension (display_name);
2400 }
2401 }
2402 else
2403 {
2404 common_prefix = nautilus_get_common_filename_prefix (selection,
2405 MIN_COMMON_FILENAME_PREFIX_LENGTH);
2406 }
2407
2408 priv->compress_controller = nautilus_compress_dialog_controller_new (nautilus_files_view_get_containing_window (view),
2409 containing_directory,
2410 common_prefix);
2411
2412 data = g_new0 (CompressCallbackData, 1);
2413 data->view = view;
2414 data->selection = nautilus_files_view_get_selection_for_file_transfer (view);
2415
2416 g_signal_connect_data (priv->compress_controller,
2417 "name-accepted",
2418 (GCallback) compress_dialog_controller_on_name_accepted,
2419 data,
2420 (GClosureNotify) compress_callback_data_free,
2421 G_CONNECT_AFTER);
2422
2423 g_signal_connect (priv->compress_controller,
2424 "cancelled",
2425 (GCallback) compress_dialog_controller_on_cancelled,
2426 view);
2427 }
2428
2429 static void
nautilus_files_view_new_folder(NautilusFilesView * directory_view,gboolean with_selection)2430 nautilus_files_view_new_folder (NautilusFilesView *directory_view,
2431 gboolean with_selection)
2432 {
2433 nautilus_files_view_new_folder_dialog_new (directory_view, with_selection);
2434 }
2435
2436 static NewFolderData *
setup_new_folder_data(NautilusFilesView * directory_view)2437 setup_new_folder_data (NautilusFilesView *directory_view)
2438 {
2439 NewFolderData *data;
2440
2441 data = new_folder_data_new (directory_view, FALSE);
2442
2443 g_signal_connect_data (directory_view,
2444 "add-files",
2445 G_CALLBACK (track_newly_added_locations),
2446 data->added_locations,
2447 (GClosureNotify) NULL,
2448 G_CONNECT_AFTER);
2449
2450 return data;
2451 }
2452
2453 void
nautilus_files_view_new_file_with_initial_contents(NautilusFilesView * view,const char * parent_uri,const char * filename,const char * initial_contents,int length)2454 nautilus_files_view_new_file_with_initial_contents (NautilusFilesView *view,
2455 const char *parent_uri,
2456 const char *filename,
2457 const char *initial_contents,
2458 int length)
2459 {
2460 NewFolderData *data;
2461
2462 g_assert (parent_uri != NULL);
2463
2464 data = setup_new_folder_data (view);
2465
2466 nautilus_file_operations_new_file (GTK_WIDGET (view),
2467 parent_uri, filename,
2468 initial_contents, length,
2469 new_folder_done, data);
2470 }
2471
2472 static void
nautilus_files_view_new_file(NautilusFilesView * directory_view,const char * parent_uri,NautilusFile * source)2473 nautilus_files_view_new_file (NautilusFilesView *directory_view,
2474 const char *parent_uri,
2475 NautilusFile *source)
2476 {
2477 NewFolderData *data;
2478 char *source_uri;
2479 char *container_uri;
2480
2481 container_uri = NULL;
2482 if (parent_uri == NULL)
2483 {
2484 container_uri = nautilus_files_view_get_backing_uri (directory_view);
2485 g_assert (container_uri != NULL);
2486 }
2487
2488 if (source == NULL)
2489 {
2490 nautilus_files_view_new_file_with_initial_contents (directory_view,
2491 parent_uri != NULL ? parent_uri : container_uri,
2492 NULL,
2493 NULL,
2494 0);
2495 g_free (container_uri);
2496 return;
2497 }
2498
2499 data = setup_new_folder_data (directory_view);
2500
2501 source_uri = nautilus_file_get_uri (source);
2502
2503 nautilus_file_operations_new_file_from_template (GTK_WIDGET (directory_view),
2504 parent_uri != NULL ? parent_uri : container_uri,
2505 NULL,
2506 source_uri,
2507 new_folder_done, data);
2508
2509 g_free (source_uri);
2510 g_free (container_uri);
2511 }
2512
2513 static void
action_new_folder(GSimpleAction * action,GVariant * state,gpointer user_data)2514 action_new_folder (GSimpleAction *action,
2515 GVariant *state,
2516 gpointer user_data)
2517 {
2518 g_assert (NAUTILUS_IS_FILES_VIEW (user_data));
2519
2520 nautilus_files_view_new_folder (NAUTILUS_FILES_VIEW (user_data), FALSE);
2521 }
2522
2523 static void
action_new_folder_with_selection(GSimpleAction * action,GVariant * state,gpointer user_data)2524 action_new_folder_with_selection (GSimpleAction *action,
2525 GVariant *state,
2526 gpointer user_data)
2527 {
2528 g_assert (NAUTILUS_IS_FILES_VIEW (user_data));
2529
2530 nautilus_files_view_new_folder (NAUTILUS_FILES_VIEW (user_data), TRUE);
2531 }
2532
2533 static void
action_properties(GSimpleAction * action,GVariant * state,gpointer user_data)2534 action_properties (GSimpleAction *action,
2535 GVariant *state,
2536 gpointer user_data)
2537 {
2538 NautilusFilesView *view;
2539 NautilusFilesViewPrivate *priv;
2540 g_autolist (NautilusFile) selection = NULL;
2541 GList *files;
2542
2543 g_assert (NAUTILUS_IS_FILES_VIEW (user_data));
2544
2545 view = NAUTILUS_FILES_VIEW (user_data);
2546 priv = nautilus_files_view_get_instance_private (view);
2547 selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
2548 if (g_list_length (selection) == 0)
2549 {
2550 if (priv->directory_as_file != NULL)
2551 {
2552 files = g_list_append (NULL, nautilus_file_ref (priv->directory_as_file));
2553
2554 nautilus_properties_window_present (files, GTK_WIDGET (view), NULL,
2555 NULL, NULL);
2556
2557 nautilus_file_list_free (files);
2558 }
2559 }
2560 else
2561 {
2562 nautilus_properties_window_present (selection, GTK_WIDGET (view), NULL,
2563 NULL, NULL);
2564 }
2565 }
2566
2567 static void
action_current_dir_properties(GSimpleAction * action,GVariant * state,gpointer user_data)2568 action_current_dir_properties (GSimpleAction *action,
2569 GVariant *state,
2570 gpointer user_data)
2571 {
2572 NautilusFilesView *view;
2573 NautilusFilesViewPrivate *priv;
2574 GList *files;
2575
2576 g_return_if_fail (NAUTILUS_IS_FILES_VIEW (user_data));
2577
2578 view = NAUTILUS_FILES_VIEW (user_data);
2579 priv = nautilus_files_view_get_instance_private (view);
2580
2581 if (priv->directory_as_file != NULL)
2582 {
2583 files = g_list_append (NULL, nautilus_file_ref (priv->directory_as_file));
2584
2585 nautilus_properties_window_present (files, GTK_WIDGET (view), NULL,
2586 NULL, NULL);
2587
2588 nautilus_file_list_free (files);
2589 }
2590 }
2591
2592 static void
nautilus_files_view_set_show_hidden_files(NautilusFilesView * view,gboolean show_hidden)2593 nautilus_files_view_set_show_hidden_files (NautilusFilesView *view,
2594 gboolean show_hidden)
2595 {
2596 NautilusFilesViewPrivate *priv;
2597
2598 priv = nautilus_files_view_get_instance_private (view);
2599
2600 if (priv->ignore_hidden_file_preferences)
2601 {
2602 return;
2603 }
2604
2605 if (show_hidden != priv->show_hidden_files)
2606 {
2607 priv->show_hidden_files = show_hidden;
2608
2609 g_settings_set_boolean (gtk_filechooser_preferences,
2610 NAUTILUS_PREFERENCES_SHOW_HIDDEN_FILES,
2611 show_hidden);
2612
2613 if (priv->model != NULL)
2614 {
2615 load_directory (view, priv->model);
2616 }
2617 }
2618 }
2619
2620 static void
action_show_hidden_files(GSimpleAction * action,GVariant * state,gpointer user_data)2621 action_show_hidden_files (GSimpleAction *action,
2622 GVariant *state,
2623 gpointer user_data)
2624 {
2625 gboolean show_hidden;
2626 NautilusFilesView *view;
2627
2628 g_assert (NAUTILUS_IS_FILES_VIEW (user_data));
2629
2630 view = NAUTILUS_FILES_VIEW (user_data);
2631 show_hidden = g_variant_get_boolean (state);
2632
2633 nautilus_files_view_set_show_hidden_files (view, show_hidden);
2634
2635 g_simple_action_set_state (action, state);
2636 }
2637
2638 static void
action_zoom_in(GSimpleAction * action,GVariant * state,gpointer user_data)2639 action_zoom_in (GSimpleAction *action,
2640 GVariant *state,
2641 gpointer user_data)
2642 {
2643 NautilusFilesView *view;
2644
2645 g_assert (NAUTILUS_IS_FILES_VIEW (user_data));
2646
2647 view = NAUTILUS_FILES_VIEW (user_data);
2648
2649 nautilus_files_view_bump_zoom_level (view, 1);
2650 }
2651
2652 static void
action_zoom_out(GSimpleAction * action,GVariant * state,gpointer user_data)2653 action_zoom_out (GSimpleAction *action,
2654 GVariant *state,
2655 gpointer user_data)
2656 {
2657 NautilusFilesView *view;
2658
2659 g_assert (NAUTILUS_IS_FILES_VIEW (user_data));
2660
2661 view = NAUTILUS_FILES_VIEW (user_data);
2662
2663 nautilus_files_view_bump_zoom_level (view, -1);
2664 }
2665
2666 static void
action_zoom_standard(GSimpleAction * action,GVariant * state,gpointer user_data)2667 action_zoom_standard (GSimpleAction *action,
2668 GVariant *state,
2669 gpointer user_data)
2670 {
2671 nautilus_files_view_restore_standard_zoom_level (user_data);
2672 }
2673
2674 static void
action_open_item_new_window(GSimpleAction * action,GVariant * state,gpointer user_data)2675 action_open_item_new_window (GSimpleAction *action,
2676 GVariant *state,
2677 gpointer user_data)
2678 {
2679 NautilusFilesView *view;
2680 GtkWindow *window;
2681 GList *selection;
2682
2683 view = NAUTILUS_FILES_VIEW (user_data);
2684 selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
2685 window = GTK_WINDOW (nautilus_files_view_get_containing_window (view));
2686
2687 if (nautilus_files_view_confirm_multiple (window, g_list_length (selection), TRUE))
2688 {
2689 g_list_foreach (selection, open_one_in_new_window, view);
2690 }
2691
2692 nautilus_file_list_free (selection);
2693 }
2694
2695 static void
handle_clipboard_data(NautilusFilesView * view,GtkSelectionData * selection_data,char * destination_uri,GdkDragAction action)2696 handle_clipboard_data (NautilusFilesView *view,
2697 GtkSelectionData *selection_data,
2698 char *destination_uri,
2699 GdkDragAction action)
2700 {
2701 GList *item_uris;
2702
2703 item_uris = nautilus_clipboard_get_uri_list_from_selection_data (selection_data);
2704
2705 if (item_uris != NULL && destination_uri != NULL)
2706 {
2707 nautilus_files_view_move_copy_items (view, item_uris, destination_uri,
2708 action);
2709
2710 /* If items are cut then remove from clipboard */
2711 if (action == GDK_ACTION_MOVE)
2712 {
2713 gtk_clipboard_clear (nautilus_clipboard_get (GTK_WIDGET (view)));
2714 }
2715
2716 g_list_free_full (item_uris, g_free);
2717 }
2718 }
2719
2720 static void
paste_clipboard_data(NautilusFilesView * view,GtkSelectionData * selection_data,char * destination_uri)2721 paste_clipboard_data (NautilusFilesView *view,
2722 GtkSelectionData *selection_data,
2723 char *destination_uri)
2724 {
2725 GdkDragAction action;
2726
2727 if (nautilus_clipboard_is_cut_from_selection_data (selection_data))
2728 {
2729 action = GDK_ACTION_MOVE;
2730 }
2731 else
2732 {
2733 action = GDK_ACTION_COPY;
2734 }
2735
2736 handle_clipboard_data (view, selection_data, destination_uri, action);
2737 }
2738
2739 static void
paste_clipboard_received_callback(GtkClipboard * clipboard,GtkSelectionData * selection_data,gpointer data)2740 paste_clipboard_received_callback (GtkClipboard *clipboard,
2741 GtkSelectionData *selection_data,
2742 gpointer data)
2743 {
2744 NautilusFilesView *view;
2745 NautilusFilesViewPrivate *priv;
2746 char *view_uri;
2747
2748 view = NAUTILUS_FILES_VIEW (data);
2749 priv = nautilus_files_view_get_instance_private (view);
2750
2751 view_uri = nautilus_files_view_get_backing_uri (view);
2752
2753 if (priv->slot != NULL)
2754 {
2755 paste_clipboard_data (view, selection_data, view_uri);
2756 }
2757
2758 g_free (view_uri);
2759
2760 g_object_unref (view);
2761 }
2762
2763 static void
paste_files(NautilusFilesView * view)2764 paste_files (NautilusFilesView *view)
2765 {
2766 GtkClipboard *clipboard;
2767
2768 clipboard = nautilus_clipboard_get (GTK_WIDGET (view));
2769
2770 /* Performing an async request of clipboard contents, corresponding unref
2771 * is in the callback.
2772 */
2773 g_object_ref (view);
2774 gtk_clipboard_request_contents (clipboard,
2775 nautilus_clipboard_get_atom (),
2776 paste_clipboard_received_callback,
2777 view);
2778 }
2779
2780 static void
action_paste_files(GSimpleAction * action,GVariant * state,gpointer user_data)2781 action_paste_files (GSimpleAction *action,
2782 GVariant *state,
2783 gpointer user_data)
2784 {
2785 NautilusFilesView *view;
2786
2787 view = NAUTILUS_FILES_VIEW (user_data);
2788
2789 paste_files (view);
2790 }
2791
2792 static void
action_paste_files_accel(GSimpleAction * action,GVariant * state,gpointer user_data)2793 action_paste_files_accel (GSimpleAction *action,
2794 GVariant *state,
2795 gpointer user_data)
2796 {
2797 NautilusFilesView *view;
2798
2799 view = NAUTILUS_FILES_VIEW (user_data);
2800
2801 if (nautilus_files_view_is_read_only (view))
2802 {
2803 show_dialog (_("Could not paste files"),
2804 _("Permissions do not allow pasting files in this directory"),
2805 nautilus_files_view_get_containing_window (view),
2806 GTK_MESSAGE_ERROR);
2807 }
2808 else
2809 {
2810 paste_files (view);
2811 }
2812 }
2813
2814 static void
create_links_clipboard_received_callback(GtkClipboard * clipboard,GtkSelectionData * selection_data,gpointer data)2815 create_links_clipboard_received_callback (GtkClipboard *clipboard,
2816 GtkSelectionData *selection_data,
2817 gpointer data)
2818 {
2819 NautilusFilesView *view;
2820 NautilusFilesViewPrivate *priv;
2821 char *view_uri;
2822
2823 view = NAUTILUS_FILES_VIEW (data);
2824 priv = nautilus_files_view_get_instance_private (view);
2825
2826 view_uri = nautilus_files_view_get_backing_uri (view);
2827
2828 if (priv->slot != NULL)
2829 {
2830 handle_clipboard_data (view, selection_data, view_uri, GDK_ACTION_LINK);
2831 }
2832
2833 g_free (view_uri);
2834
2835 g_object_unref (view);
2836 }
2837
2838 static void
action_create_links(GSimpleAction * action,GVariant * state,gpointer user_data)2839 action_create_links (GSimpleAction *action,
2840 GVariant *state,
2841 gpointer user_data)
2842 {
2843 NautilusFilesView *view;
2844
2845 g_assert (NAUTILUS_IS_FILES_VIEW (user_data));
2846
2847 view = NAUTILUS_FILES_VIEW (user_data);
2848
2849 g_object_ref (view);
2850 gtk_clipboard_request_contents (nautilus_clipboard_get (GTK_WIDGET (view)),
2851 nautilus_clipboard_get_atom (),
2852 create_links_clipboard_received_callback,
2853 view);
2854 }
2855
2856 static void
click_policy_changed_callback(gpointer callback_data)2857 click_policy_changed_callback (gpointer callback_data)
2858 {
2859 NautilusFilesView *view;
2860
2861 view = NAUTILUS_FILES_VIEW (callback_data);
2862
2863 NAUTILUS_FILES_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->click_policy_changed (view);
2864 }
2865
2866 gboolean
nautilus_files_view_should_sort_directories_first(NautilusFilesView * view)2867 nautilus_files_view_should_sort_directories_first (NautilusFilesView *view)
2868 {
2869 NautilusFilesViewPrivate *priv;
2870 gboolean is_search;
2871
2872 priv = nautilus_files_view_get_instance_private (view);
2873 is_search = nautilus_view_is_searching (NAUTILUS_VIEW (view));
2874
2875 return priv->sort_directories_first && !is_search;
2876 }
2877
2878 static void
sort_directories_first_changed_callback(gpointer callback_data)2879 sort_directories_first_changed_callback (gpointer callback_data)
2880 {
2881 NautilusFilesView *view;
2882 NautilusFilesViewPrivate *priv;
2883 gboolean preference_value;
2884
2885 view = NAUTILUS_FILES_VIEW (callback_data);
2886 priv = nautilus_files_view_get_instance_private (view);
2887
2888 preference_value =
2889 g_settings_get_boolean (gtk_filechooser_preferences, NAUTILUS_PREFERENCES_SORT_DIRECTORIES_FIRST);
2890
2891 if (preference_value != priv->sort_directories_first)
2892 {
2893 priv->sort_directories_first = preference_value;
2894 NAUTILUS_FILES_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->sort_directories_first_changed (view);
2895 }
2896 }
2897
2898 static void
show_hidden_files_changed_callback(gpointer callback_data)2899 show_hidden_files_changed_callback (gpointer callback_data)
2900 {
2901 NautilusFilesView *view;
2902 NautilusFilesViewPrivate *priv;
2903 gboolean preference_value;
2904
2905 view = NAUTILUS_FILES_VIEW (callback_data);
2906 priv = nautilus_files_view_get_instance_private (view);
2907
2908 preference_value =
2909 g_settings_get_boolean (gtk_filechooser_preferences, NAUTILUS_PREFERENCES_SHOW_HIDDEN_FILES);
2910
2911 nautilus_files_view_set_show_hidden_files (view, preference_value);
2912
2913 if (priv->active)
2914 {
2915 schedule_update_context_menus (view);
2916 }
2917 }
2918
2919 static gboolean
set_up_scripts_directory_global(void)2920 set_up_scripts_directory_global (void)
2921 {
2922 g_autofree gchar *old_scripts_directory_path = NULL;
2923 g_autoptr (GFile) old_scripts_directory = NULL;
2924 g_autofree gchar *scripts_directory_path = NULL;
2925 g_autoptr (GFile) scripts_directory = NULL;
2926 const char *override;
2927 GFileType file_type;
2928 g_autoptr (GError) error = NULL;
2929
2930 if (scripts_directory_uri != NULL)
2931 {
2932 return TRUE;
2933 }
2934
2935 scripts_directory_path = nautilus_get_scripts_directory_path ();
2936
2937 override = g_getenv ("GNOME22_USER_DIR");
2938
2939 if (override)
2940 {
2941 old_scripts_directory_path = g_build_filename (override,
2942 "nautilus-scripts",
2943 NULL);
2944 }
2945 else
2946 {
2947 old_scripts_directory_path = g_build_filename (g_get_home_dir (),
2948 ".gnome2",
2949 "nautilus-scripts",
2950 NULL);
2951 }
2952
2953 old_scripts_directory = g_file_new_for_path (old_scripts_directory_path);
2954 scripts_directory = g_file_new_for_path (scripts_directory_path);
2955
2956 file_type = g_file_query_file_type (old_scripts_directory,
2957 G_FILE_QUERY_INFO_NONE,
2958 NULL);
2959
2960 if (file_type == G_FILE_TYPE_DIRECTORY &&
2961 !g_file_query_exists (scripts_directory, NULL))
2962 {
2963 g_autoptr (GFile) updated = NULL;
2964 const char *message;
2965
2966 /* test if we already attempted to migrate first */
2967 updated = g_file_get_child (old_scripts_directory, "DEPRECATED-DIRECTORY");
2968 message = _("Nautilus 3.6 deprecated this directory and tried migrating "
2969 "this configuration to ~/.local/share/nautilus");
2970 if (!g_file_query_exists (updated, NULL))
2971 {
2972 g_autoptr (GFile) parent = NULL;
2973
2974 parent = g_file_get_parent (scripts_directory);
2975 g_file_make_directory_with_parents (parent, NULL, &error);
2976
2977 if (error == NULL ||
2978 g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS))
2979 {
2980 g_clear_error (&error);
2981
2982 g_file_set_attribute_uint32 (parent,
2983 G_FILE_ATTRIBUTE_UNIX_MODE,
2984 S_IRWXU,
2985 G_FILE_QUERY_INFO_NONE,
2986 NULL, NULL);
2987
2988 g_file_move (old_scripts_directory,
2989 scripts_directory,
2990 G_FILE_COPY_NONE,
2991 NULL, NULL, NULL,
2992 &error);
2993
2994 if (error == NULL)
2995 {
2996 g_file_replace_contents (updated,
2997 message, strlen (message),
2998 NULL,
2999 FALSE,
3000 G_FILE_CREATE_PRIVATE,
3001 NULL, NULL, NULL);
3002 }
3003 }
3004
3005 g_clear_error (&error);
3006 }
3007 }
3008
3009 g_file_make_directory_with_parents (scripts_directory, NULL, &error);
3010
3011 if (error == NULL ||
3012 g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS))
3013 {
3014 g_file_set_attribute_uint32 (scripts_directory,
3015 G_FILE_ATTRIBUTE_UNIX_MODE,
3016 S_IRWXU,
3017 G_FILE_QUERY_INFO_NONE,
3018 NULL, NULL);
3019
3020 scripts_directory_uri = g_file_get_uri (scripts_directory);
3021 scripts_directory_uri_length = strlen (scripts_directory_uri);
3022 }
3023
3024 return scripts_directory_uri != NULL;
3025 }
3026
3027 static void
scripts_added_or_changed_callback(NautilusDirectory * directory,GList * files,gpointer callback_data)3028 scripts_added_or_changed_callback (NautilusDirectory *directory,
3029 GList *files,
3030 gpointer callback_data)
3031 {
3032 NautilusFilesView *view;
3033 NautilusFilesViewPrivate *priv;
3034
3035 view = NAUTILUS_FILES_VIEW (callback_data);
3036 priv = nautilus_files_view_get_instance_private (view);
3037
3038 priv->scripts_menu_updated = FALSE;
3039 if (priv->active)
3040 {
3041 schedule_update_context_menus (view);
3042 }
3043 }
3044
3045 static void
templates_added_or_changed_callback(NautilusDirectory * directory,GList * files,gpointer callback_data)3046 templates_added_or_changed_callback (NautilusDirectory *directory,
3047 GList *files,
3048 gpointer callback_data)
3049 {
3050 NautilusFilesView *view;
3051 NautilusFilesViewPrivate *priv;
3052
3053 view = NAUTILUS_FILES_VIEW (callback_data);
3054 priv = nautilus_files_view_get_instance_private (view);
3055
3056 priv->templates_menu_updated = FALSE;
3057 if (priv->active)
3058 {
3059 schedule_update_context_menus (view);
3060 }
3061 }
3062
3063 static void
add_directory_to_directory_list(NautilusFilesView * view,NautilusDirectory * directory,GList ** directory_list,GCallback changed_callback)3064 add_directory_to_directory_list (NautilusFilesView *view,
3065 NautilusDirectory *directory,
3066 GList **directory_list,
3067 GCallback changed_callback)
3068 {
3069 NautilusFileAttributes attributes;
3070
3071 if (g_list_find (*directory_list, directory) == NULL)
3072 {
3073 nautilus_directory_ref (directory);
3074
3075 attributes =
3076 NAUTILUS_FILE_ATTRIBUTES_FOR_ICON |
3077 NAUTILUS_FILE_ATTRIBUTE_INFO |
3078 NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT;
3079
3080 nautilus_directory_file_monitor_add (directory, directory_list,
3081 FALSE, attributes,
3082 (NautilusDirectoryCallback) changed_callback, view);
3083
3084 g_signal_connect_object (directory, "files-added",
3085 G_CALLBACK (changed_callback), view, 0);
3086 g_signal_connect_object (directory, "files-changed",
3087 G_CALLBACK (changed_callback), view, 0);
3088
3089 *directory_list = g_list_append (*directory_list, directory);
3090 }
3091 }
3092
3093 static void
remove_directory_from_directory_list(NautilusFilesView * view,NautilusDirectory * directory,GList ** directory_list,GCallback changed_callback)3094 remove_directory_from_directory_list (NautilusFilesView *view,
3095 NautilusDirectory *directory,
3096 GList **directory_list,
3097 GCallback changed_callback)
3098 {
3099 *directory_list = g_list_remove (*directory_list, directory);
3100
3101 g_signal_handlers_disconnect_by_func (directory,
3102 G_CALLBACK (changed_callback),
3103 view);
3104
3105 nautilus_directory_file_monitor_remove (directory, directory_list);
3106
3107 nautilus_directory_unref (directory);
3108 }
3109
3110
3111 static void
add_directory_to_scripts_directory_list(NautilusFilesView * view,NautilusDirectory * directory)3112 add_directory_to_scripts_directory_list (NautilusFilesView *view,
3113 NautilusDirectory *directory)
3114 {
3115 NautilusFilesViewPrivate *priv;
3116
3117 priv = nautilus_files_view_get_instance_private (view);
3118
3119 add_directory_to_directory_list (view, directory,
3120 &priv->scripts_directory_list,
3121 G_CALLBACK (scripts_added_or_changed_callback));
3122 }
3123
3124 static void
remove_directory_from_scripts_directory_list(NautilusFilesView * view,NautilusDirectory * directory)3125 remove_directory_from_scripts_directory_list (NautilusFilesView *view,
3126 NautilusDirectory *directory)
3127 {
3128 NautilusFilesViewPrivate *priv;
3129
3130 priv = nautilus_files_view_get_instance_private (view);
3131
3132 remove_directory_from_directory_list (view, directory,
3133 &priv->scripts_directory_list,
3134 G_CALLBACK (scripts_added_or_changed_callback));
3135 }
3136
3137 static void
add_directory_to_templates_directory_list(NautilusFilesView * view,NautilusDirectory * directory)3138 add_directory_to_templates_directory_list (NautilusFilesView *view,
3139 NautilusDirectory *directory)
3140 {
3141 NautilusFilesViewPrivate *priv;
3142
3143 priv = nautilus_files_view_get_instance_private (view);
3144
3145 add_directory_to_directory_list (view, directory,
3146 &priv->templates_directory_list,
3147 G_CALLBACK (templates_added_or_changed_callback));
3148 }
3149
3150 static void
remove_directory_from_templates_directory_list(NautilusFilesView * view,NautilusDirectory * directory)3151 remove_directory_from_templates_directory_list (NautilusFilesView *view,
3152 NautilusDirectory *directory)
3153 {
3154 NautilusFilesViewPrivate *priv;
3155
3156 priv = nautilus_files_view_get_instance_private (view);
3157
3158 remove_directory_from_directory_list (view, directory,
3159 &priv->templates_directory_list,
3160 G_CALLBACK (templates_added_or_changed_callback));
3161 }
3162
3163 static void
slot_active_changed(NautilusWindowSlot * slot,GParamSpec * pspec,NautilusFilesView * view)3164 slot_active_changed (NautilusWindowSlot *slot,
3165 GParamSpec *pspec,
3166 NautilusFilesView *view)
3167 {
3168 NautilusFilesViewPrivate *priv;
3169
3170 priv = nautilus_files_view_get_instance_private (view);
3171
3172 if (priv->active == nautilus_window_slot_get_active (slot))
3173 {
3174 return;
3175 }
3176
3177 priv->active = nautilus_window_slot_get_active (slot);
3178
3179 if (priv->active)
3180 {
3181 /* Avoid updating the toolbar withouth making sure the toolbar
3182 * zoom slider has the correct adjustment that changes when the
3183 * view mode changes
3184 */
3185 nautilus_files_view_update_context_menus (view);
3186 nautilus_files_view_update_toolbar_menus (view);
3187
3188 schedule_update_context_menus (view);
3189
3190 gtk_widget_insert_action_group (GTK_WIDGET (nautilus_files_view_get_window (view)),
3191 "view",
3192 G_ACTION_GROUP (priv->view_action_group));
3193 }
3194 else
3195 {
3196 remove_update_context_menus_timeout_callback (view);
3197 gtk_widget_insert_action_group (GTK_WIDGET (nautilus_files_view_get_window (view)),
3198 "view",
3199 NULL);
3200 }
3201 }
3202
3203 static void
nautilus_files_view_grab_focus(GtkWidget * widget)3204 nautilus_files_view_grab_focus (GtkWidget *widget)
3205 {
3206 /* focus the child of the scrolled window if it exists */
3207 NautilusFilesView *view;
3208 NautilusFilesViewPrivate *priv;
3209 GtkWidget *child;
3210
3211 view = NAUTILUS_FILES_VIEW (widget);
3212 priv = nautilus_files_view_get_instance_private (view);
3213 child = gtk_bin_get_child (GTK_BIN (priv->scrolled_window));
3214
3215 GTK_WIDGET_CLASS (nautilus_files_view_parent_class)->grab_focus (widget);
3216
3217 if (child)
3218 {
3219 gtk_widget_grab_focus (GTK_WIDGET (child));
3220 }
3221 }
3222
3223 static void
nautilus_files_view_set_selection(NautilusView * nautilus_files_view,GList * selection)3224 nautilus_files_view_set_selection (NautilusView *nautilus_files_view,
3225 GList *selection)
3226 {
3227 NautilusFilesView *view;
3228 NautilusFilesViewPrivate *priv;
3229 GList *pending_selection;
3230
3231 view = NAUTILUS_FILES_VIEW (nautilus_files_view);
3232 priv = nautilus_files_view_get_instance_private (view);
3233
3234 if (!priv->loading)
3235 {
3236 /* If we aren't still loading, set the selection right now,
3237 * and reveal the new selection.
3238 */
3239 nautilus_files_view_call_set_selection (view, selection);
3240 nautilus_files_view_reveal_selection (view);
3241 }
3242 else
3243 {
3244 /* If we are still loading, set the list of pending URIs instead.
3245 * done_loading() will eventually select the pending URIs and reveal them.
3246 */
3247 pending_selection = g_list_copy_deep (selection,
3248 (GCopyFunc) g_object_ref, NULL);
3249 g_list_free_full (priv->pending_selection, g_object_unref);
3250
3251 priv->pending_selection = pending_selection;
3252 }
3253 }
3254
3255 static void
nautilus_files_view_destroy(GtkWidget * object)3256 nautilus_files_view_destroy (GtkWidget *object)
3257 {
3258 NautilusFilesView *view;
3259 NautilusFilesViewPrivate *priv;
3260 GtkClipboard *clipboard;
3261 GList *node, *next;
3262
3263 view = NAUTILUS_FILES_VIEW (object);
3264 priv = nautilus_files_view_get_instance_private (view);
3265
3266 priv->in_destruction = TRUE;
3267 nautilus_files_view_stop_loading (view);
3268
3269 if (priv->model)
3270 {
3271 nautilus_directory_unref (priv->model);
3272 priv->model = NULL;
3273 }
3274
3275 for (node = priv->scripts_directory_list; node != NULL; node = next)
3276 {
3277 next = node->next;
3278 remove_directory_from_scripts_directory_list (view, node->data);
3279 }
3280
3281 for (node = priv->templates_directory_list; node != NULL; node = next)
3282 {
3283 next = node->next;
3284 remove_directory_from_templates_directory_list (view, node->data);
3285 }
3286
3287 while (priv->subdirectory_list != NULL)
3288 {
3289 nautilus_files_view_remove_subdirectory (view,
3290 priv->subdirectory_list->data);
3291 }
3292
3293 remove_update_context_menus_timeout_callback (view);
3294 remove_update_status_idle_callback (view);
3295
3296 if (priv->display_selection_idle_id != 0)
3297 {
3298 g_source_remove (priv->display_selection_idle_id);
3299 priv->display_selection_idle_id = 0;
3300 }
3301
3302 if (priv->reveal_selection_idle_id != 0)
3303 {
3304 g_source_remove (priv->reveal_selection_idle_id);
3305 priv->reveal_selection_idle_id = 0;
3306 }
3307
3308 if (priv->floating_bar_set_status_timeout_id != 0)
3309 {
3310 g_source_remove (priv->floating_bar_set_status_timeout_id);
3311 priv->floating_bar_set_status_timeout_id = 0;
3312 }
3313
3314 if (priv->floating_bar_loading_timeout_id != 0)
3315 {
3316 g_source_remove (priv->floating_bar_loading_timeout_id);
3317 priv->floating_bar_loading_timeout_id = 0;
3318 }
3319
3320 if (priv->floating_bar_set_passthrough_timeout_id != 0)
3321 {
3322 g_source_remove (priv->floating_bar_set_passthrough_timeout_id);
3323 priv->floating_bar_set_passthrough_timeout_id = 0;
3324 }
3325
3326 g_signal_handlers_disconnect_by_func (nautilus_preferences,
3327 schedule_update_context_menus, view);
3328 g_signal_handlers_disconnect_by_func (nautilus_preferences,
3329 click_policy_changed_callback, view);
3330 g_signal_handlers_disconnect_by_func (gtk_filechooser_preferences,
3331 sort_directories_first_changed_callback, view);
3332 g_signal_handlers_disconnect_by_func (gtk_filechooser_preferences,
3333 show_hidden_files_changed_callback, view);
3334 g_signal_handlers_disconnect_by_func (nautilus_window_state,
3335 nautilus_files_view_display_selection_info, view);
3336 g_signal_handlers_disconnect_by_func (gnome_lockdown_preferences,
3337 schedule_update_context_menus, view);
3338 g_signal_handlers_disconnect_by_func (nautilus_trash_monitor_get (),
3339 nautilus_files_view_trash_state_changed_callback, view);
3340
3341 clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
3342 g_signal_handlers_disconnect_by_func (clipboard, on_clipboard_owner_changed, view);
3343
3344 nautilus_file_unref (priv->directory_as_file);
3345 priv->directory_as_file = NULL;
3346
3347 g_clear_object (&priv->search_query);
3348 g_clear_object (&priv->location);
3349
3350 /* We don't own the slot, so no unref */
3351 priv->slot = NULL;
3352
3353 GTK_WIDGET_CLASS (nautilus_files_view_parent_class)->destroy (object);
3354 }
3355
3356 static void
nautilus_files_view_finalize(GObject * object)3357 nautilus_files_view_finalize (GObject *object)
3358 {
3359 NautilusFilesView *view;
3360 NautilusFilesViewPrivate *priv;
3361
3362 view = NAUTILUS_FILES_VIEW (object);
3363 priv = nautilus_files_view_get_instance_private (view);
3364
3365 g_clear_object (&priv->view_action_group);
3366 g_clear_object (&priv->background_menu_model);
3367 g_clear_object (&priv->selection_menu_model);
3368 g_clear_object (&priv->toolbar_menu_sections->zoom_section);
3369 g_clear_object (&priv->toolbar_menu_sections->extended_section);
3370 g_clear_object (&priv->extensions_background_menu);
3371 g_clear_object (&priv->templates_menu);
3372 g_clear_object (&priv->rename_file_controller);
3373 g_clear_object (&priv->new_folder_controller);
3374 g_clear_object (&priv->compress_controller);
3375 g_free (priv->toolbar_menu_sections);
3376
3377 g_hash_table_destroy (priv->non_ready_files);
3378 g_hash_table_destroy (priv->pending_reveal);
3379
3380 g_cancellable_cancel (priv->starred_cancellable);
3381 g_clear_object (&priv->starred_cancellable);
3382 g_clear_object (&priv->tag_manager);
3383
3384 G_OBJECT_CLASS (nautilus_files_view_parent_class)->finalize (object);
3385 }
3386
3387 /**
3388 * nautilus_files_view_display_selection_info:
3389 *
3390 * Display information about the current selection, and notify the view frame of the changed selection.
3391 * @view: NautilusFilesView for which to display selection info.
3392 *
3393 **/
3394 void
nautilus_files_view_display_selection_info(NautilusFilesView * view)3395 nautilus_files_view_display_selection_info (NautilusFilesView *view)
3396 {
3397 g_autolist (NautilusFile) selection = NULL;
3398 goffset non_folder_size;
3399 gboolean non_folder_size_known;
3400 guint non_folder_count, folder_count, folder_item_count;
3401 gboolean folder_item_count_known;
3402 guint file_item_count;
3403 GList *p;
3404 char *first_item_name;
3405 char *non_folder_count_str;
3406 char *non_folder_item_count_str;
3407 char *non_folder_counts_str;
3408 char *folder_count_str;
3409 char *folder_item_count_str;
3410 char *folder_counts_str;
3411 char *primary_status;
3412 char *detail_status;
3413 NautilusFile *file;
3414
3415 g_return_if_fail (NAUTILUS_IS_FILES_VIEW (view));
3416
3417 selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
3418
3419 folder_item_count_known = TRUE;
3420 folder_count = 0;
3421 folder_item_count = 0;
3422 non_folder_count = 0;
3423 non_folder_size_known = FALSE;
3424 non_folder_size = 0;
3425 first_item_name = NULL;
3426 folder_count_str = NULL;
3427 folder_item_count_str = NULL;
3428 folder_counts_str = NULL;
3429 non_folder_count_str = NULL;
3430 non_folder_item_count_str = NULL;
3431 non_folder_counts_str = NULL;
3432
3433 for (p = selection; p != NULL; p = p->next)
3434 {
3435 file = p->data;
3436 if (nautilus_file_is_directory (file))
3437 {
3438 folder_count++;
3439 if (nautilus_file_get_directory_item_count (file, &file_item_count, NULL))
3440 {
3441 folder_item_count += file_item_count;
3442 }
3443 else
3444 {
3445 folder_item_count_known = FALSE;
3446 }
3447 }
3448 else
3449 {
3450 non_folder_count++;
3451 if (!nautilus_file_can_get_size (file))
3452 {
3453 non_folder_size_known = TRUE;
3454 non_folder_size += nautilus_file_get_size (file);
3455 }
3456 }
3457
3458 if (first_item_name == NULL)
3459 {
3460 first_item_name = nautilus_file_get_display_name (file);
3461 }
3462 }
3463
3464 /* Break out cases for localization's sake. But note that there are still pieces
3465 * being assembled in a particular order, which may be a problem for some localizers.
3466 */
3467
3468 if (folder_count != 0)
3469 {
3470 if (folder_count == 1 && non_folder_count == 0)
3471 {
3472 folder_count_str = g_strdup_printf (_("“%s” selected"), first_item_name);
3473 }
3474 else
3475 {
3476 folder_count_str = g_strdup_printf (ngettext ("%'d folder selected",
3477 "%'d folders selected",
3478 folder_count),
3479 folder_count);
3480 }
3481
3482 if (folder_count == 1)
3483 {
3484 if (!folder_item_count_known)
3485 {
3486 folder_item_count_str = g_strdup ("");
3487 }
3488 else
3489 {
3490 folder_item_count_str = g_strdup_printf (ngettext ("(containing %'d item)",
3491 "(containing %'d items)",
3492 folder_item_count),
3493 folder_item_count);
3494 }
3495 }
3496 else
3497 {
3498 if (!folder_item_count_known)
3499 {
3500 folder_item_count_str = g_strdup ("");
3501 }
3502 else
3503 {
3504 /* translators: this is preceded with a string of form 'N folders' (N more than 1) */
3505 folder_item_count_str = g_strdup_printf (ngettext ("(containing a total of %'d item)",
3506 "(containing a total of %'d items)",
3507 folder_item_count),
3508 folder_item_count);
3509 }
3510 }
3511 }
3512
3513 if (non_folder_count != 0)
3514 {
3515 if (folder_count == 0)
3516 {
3517 if (non_folder_count == 1)
3518 {
3519 non_folder_count_str = g_strdup_printf (_("“%s” selected"),
3520 first_item_name);
3521 }
3522 else
3523 {
3524 non_folder_count_str = g_strdup_printf (ngettext ("%'d item selected",
3525 "%'d items selected",
3526 non_folder_count),
3527 non_folder_count);
3528 }
3529 }
3530 else
3531 {
3532 /* Folders selected also, use "other" terminology */
3533 non_folder_count_str = g_strdup_printf (ngettext ("%'d other item selected",
3534 "%'d other items selected",
3535 non_folder_count),
3536 non_folder_count);
3537 }
3538
3539 if (non_folder_size_known)
3540 {
3541 char *size_string;
3542
3543 size_string = g_format_size (non_folder_size);
3544 /* This is marked for translation in case a localiser
3545 * needs to use something other than parentheses. The
3546 * the message in parentheses is the size of the selected items.
3547 */
3548 non_folder_item_count_str = g_strdup_printf (_("(%s)"), size_string);
3549 g_free (size_string);
3550 }
3551 else
3552 {
3553 non_folder_item_count_str = g_strdup ("");
3554 }
3555 }
3556
3557 if (folder_count == 0 && non_folder_count == 0)
3558 {
3559 primary_status = NULL;
3560 detail_status = NULL;
3561 }
3562 else if (folder_count == 0)
3563 {
3564 primary_status = g_strdup (non_folder_count_str);
3565 detail_status = g_strdup (non_folder_item_count_str);
3566 }
3567 else if (non_folder_count == 0)
3568 {
3569 primary_status = g_strdup (folder_count_str);
3570 detail_status = g_strdup (folder_item_count_str);
3571 }
3572 else
3573 {
3574 if (folder_item_count_known)
3575 {
3576 folder_counts_str = g_strconcat (folder_count_str, " ", folder_item_count_str, NULL);
3577 }
3578 else
3579 {
3580 folder_counts_str = g_strdup (folder_count_str);
3581 }
3582
3583 if (non_folder_size_known)
3584 {
3585 non_folder_counts_str = g_strconcat (non_folder_count_str, " ", non_folder_item_count_str, NULL);
3586 }
3587 else
3588 {
3589 non_folder_counts_str = g_strdup (non_folder_count_str);
3590 }
3591 /* This is marked for translation in case a localizer
3592 * needs to change ", " to something else. The comma
3593 * is between the message about the number of folders
3594 * and the number of items in those folders and the
3595 * message about the number of other items and the
3596 * total size of those items.
3597 */
3598 primary_status = g_strdup_printf (_("%s, %s"),
3599 folder_counts_str,
3600 non_folder_counts_str);
3601 detail_status = NULL;
3602 }
3603
3604 g_free (first_item_name);
3605 g_free (folder_count_str);
3606 g_free (folder_item_count_str);
3607 g_free (folder_counts_str);
3608 g_free (non_folder_count_str);
3609 g_free (non_folder_item_count_str);
3610 g_free (non_folder_counts_str);
3611
3612 set_floating_bar_status (view, primary_status, detail_status);
3613
3614 g_free (primary_status);
3615 g_free (detail_status);
3616 }
3617
3618 static void
nautilus_files_view_send_selection_change(NautilusFilesView * view)3619 nautilus_files_view_send_selection_change (NautilusFilesView *view)
3620 {
3621 g_signal_emit (view, signals[SELECTION_CHANGED], 0);
3622 g_object_notify (G_OBJECT (view), "selection");
3623 }
3624
3625 static void
nautilus_files_view_set_location(NautilusView * view,GFile * location)3626 nautilus_files_view_set_location (NautilusView *view,
3627 GFile *location)
3628 {
3629 NautilusDirectory *directory;
3630 NautilusFilesView *files_view;
3631
3632 nautilus_profile_start (NULL);
3633 files_view = NAUTILUS_FILES_VIEW (view);
3634 directory = nautilus_directory_get (location);
3635
3636 nautilus_files_view_stop_loading (files_view);
3637 /* In case we want to load a previous search we need to extract the real
3638 * location and the search location, and load the directory when everything
3639 * is ready. That's why we cannot use the nautilus_view_set_query, because
3640 * to set a query we need a previous location loaded, but to load a search
3641 * location we need to know the real location behind it. */
3642 if (NAUTILUS_IS_SEARCH_DIRECTORY (directory))
3643 {
3644 NautilusQuery *previous_query;
3645 NautilusDirectory *base_model;
3646
3647 base_model = nautilus_search_directory_get_base_model (NAUTILUS_SEARCH_DIRECTORY (directory));
3648 previous_query = nautilus_search_directory_get_query (NAUTILUS_SEARCH_DIRECTORY (directory));
3649 set_search_query_internal (files_view, previous_query, base_model);
3650 g_object_unref (previous_query);
3651 }
3652 else
3653 {
3654 load_directory (NAUTILUS_FILES_VIEW (view), directory);
3655 }
3656 nautilus_directory_unref (directory);
3657 nautilus_profile_end (NULL);
3658 }
3659
3660 static gboolean
reveal_selection_idle_callback(gpointer data)3661 reveal_selection_idle_callback (gpointer data)
3662 {
3663 NautilusFilesView *view;
3664 NautilusFilesViewPrivate *priv;
3665
3666 view = NAUTILUS_FILES_VIEW (data);
3667 priv = nautilus_files_view_get_instance_private (view);
3668
3669 priv->reveal_selection_idle_id = 0;
3670 nautilus_files_view_reveal_selection (view);
3671
3672 return FALSE;
3673 }
3674
3675 static void
nautilus_files_view_check_empty_states(NautilusFilesView * view)3676 nautilus_files_view_check_empty_states (NautilusFilesView *view)
3677 {
3678 NAUTILUS_FILES_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->check_empty_states (view);
3679 }
3680
3681 static void
real_check_empty_states(NautilusFilesView * view)3682 real_check_empty_states (NautilusFilesView *view)
3683 {
3684 NautilusFilesViewPrivate *priv;
3685 g_autofree gchar *uri = NULL;
3686
3687 priv = nautilus_files_view_get_instance_private (view);
3688
3689 gtk_widget_hide (priv->no_search_results_widget);
3690 gtk_widget_hide (priv->folder_is_empty_widget);
3691 gtk_widget_hide (priv->trash_is_empty_widget);
3692 gtk_widget_hide (priv->starred_is_empty_widget);
3693
3694 if (!priv->loading &&
3695 nautilus_files_view_is_empty (view))
3696 {
3697 uri = g_file_get_uri (priv->location);
3698
3699 if (nautilus_view_is_searching (NAUTILUS_VIEW (view)))
3700 {
3701 gtk_widget_show (priv->no_search_results_widget);
3702 }
3703 else if (eel_uri_is_trash_root (uri))
3704 {
3705 gtk_widget_show (priv->trash_is_empty_widget);
3706 }
3707 else if (eel_uri_is_starred (uri))
3708 {
3709 gtk_widget_show (priv->starred_is_empty_widget);
3710 }
3711 else
3712 {
3713 gtk_widget_show (priv->folder_is_empty_widget);
3714 }
3715 }
3716 }
3717
3718 static void
done_loading(NautilusFilesView * view,gboolean all_files_seen)3719 done_loading (NautilusFilesView *view,
3720 gboolean all_files_seen)
3721 {
3722 NautilusFilesViewPrivate *priv;
3723 g_autolist (NautilusFile) selection = NULL;
3724 gboolean do_reveal = FALSE;
3725
3726 priv = nautilus_files_view_get_instance_private (view);
3727
3728 if (!priv->loading)
3729 {
3730 return;
3731 }
3732
3733 nautilus_profile_start (NULL);
3734
3735 if (!priv->in_destruction)
3736 {
3737 remove_loading_floating_bar (view);
3738 schedule_update_context_menus (view);
3739 schedule_update_status (view);
3740 nautilus_files_view_update_toolbar_menus (view);
3741 reset_update_interval (view);
3742
3743 selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
3744
3745 if (nautilus_view_is_searching (NAUTILUS_VIEW (view)) &&
3746 all_files_seen && selection == NULL && priv->pending_selection == NULL)
3747 {
3748 nautilus_files_view_select_first (view);
3749 do_reveal = TRUE;
3750 }
3751 else if (priv->pending_selection != NULL && all_files_seen)
3752 {
3753 g_autolist (NautilusFile) pending_selection = NULL;
3754 pending_selection = g_steal_pointer (&priv->pending_selection);
3755
3756 nautilus_files_view_call_set_selection (view, pending_selection);
3757 do_reveal = TRUE;
3758 }
3759
3760 g_clear_pointer (&priv->pending_selection, nautilus_file_list_free);
3761
3762 if (do_reveal)
3763 {
3764 if (NAUTILUS_IS_LIST_VIEW (view) || NAUTILUS_IS_VIEW_ICON_CONTROLLER (view))
3765 {
3766 /* HACK: We should be able to directly call reveal_selection here,
3767 * but at this point the GtkTreeView hasn't allocated the new nodes
3768 * yet, and it has a bug in the scroll calculation dealing with this
3769 * special case. It would always make the selection the top row, even
3770 * if no scrolling would be neccessary to reveal it. So we let it
3771 * allocate before revealing.
3772 */
3773 if (priv->reveal_selection_idle_id != 0)
3774 {
3775 g_source_remove (priv->reveal_selection_idle_id);
3776 }
3777 priv->reveal_selection_idle_id =
3778 g_idle_add (reveal_selection_idle_callback, view);
3779 }
3780 else
3781 {
3782 nautilus_files_view_reveal_selection (view);
3783 }
3784 }
3785 nautilus_files_view_display_selection_info (view);
3786 }
3787
3788 priv->loading = FALSE;
3789 g_signal_emit (view, signals[END_LOADING], 0, all_files_seen);
3790 g_object_notify (G_OBJECT (view), "loading");
3791
3792 if (!priv->in_destruction)
3793 {
3794 nautilus_files_view_check_empty_states (view);
3795 }
3796
3797 nautilus_profile_end (NULL);
3798 }
3799
3800
3801 typedef struct
3802 {
3803 GHashTable *debuting_files;
3804 GList *added_files;
3805 } DebutingFilesData;
3806
3807 static void
debuting_files_data_free(DebutingFilesData * data)3808 debuting_files_data_free (DebutingFilesData *data)
3809 {
3810 g_hash_table_unref (data->debuting_files);
3811 nautilus_file_list_free (data->added_files);
3812 g_free (data);
3813 }
3814
3815 /* This signal handler watch for the arrival of the icons created
3816 * as the result of a file operation. Once the last one is detected
3817 * it selects and reveals them all.
3818 */
3819 static void
debuting_files_add_files_callback(NautilusFilesView * view,GList * new_files,DebutingFilesData * data)3820 debuting_files_add_files_callback (NautilusFilesView *view,
3821 GList *new_files,
3822 DebutingFilesData *data)
3823 {
3824 GFile *location;
3825 GList *l;
3826
3827 nautilus_profile_start (NULL);
3828
3829 for (l = new_files; l != NULL; l = l->next)
3830 {
3831 location = nautilus_file_get_location (NAUTILUS_FILE (l->data));
3832
3833 if (g_hash_table_remove (data->debuting_files, location))
3834 {
3835 nautilus_file_ref (NAUTILUS_FILE (l->data));
3836 data->added_files = g_list_prepend (data->added_files, NAUTILUS_FILE (l->data));
3837 }
3838 g_object_unref (location);
3839 }
3840
3841 if (g_hash_table_size (data->debuting_files) == 0)
3842 {
3843 nautilus_files_view_call_set_selection (view, data->added_files);
3844 nautilus_files_view_reveal_selection (view);
3845 g_signal_handlers_disconnect_by_func (view,
3846 G_CALLBACK (debuting_files_add_files_callback),
3847 data);
3848 }
3849
3850 nautilus_profile_end (NULL);
3851 }
3852
3853 typedef struct
3854 {
3855 GList *added_files;
3856 NautilusFilesView *directory_view;
3857 } CopyMoveDoneData;
3858
3859 static void
copy_move_done_data_free(CopyMoveDoneData * data)3860 copy_move_done_data_free (CopyMoveDoneData *data)
3861 {
3862 g_assert (data != NULL);
3863
3864 if (data->directory_view != NULL)
3865 {
3866 g_object_remove_weak_pointer (G_OBJECT (data->directory_view),
3867 (gpointer *) &data->directory_view);
3868 }
3869
3870 nautilus_file_list_free (data->added_files);
3871 g_free (data);
3872 }
3873
3874 static void
pre_copy_move_add_files_callback(NautilusFilesView * view,GList * new_files,CopyMoveDoneData * data)3875 pre_copy_move_add_files_callback (NautilusFilesView *view,
3876 GList *new_files,
3877 CopyMoveDoneData *data)
3878 {
3879 GList *l;
3880
3881 for (l = new_files; l != NULL; l = l->next)
3882 {
3883 nautilus_file_ref (NAUTILUS_FILE (l->data));
3884 data->added_files = g_list_prepend (data->added_files, l->data);
3885 }
3886 }
3887
3888 /* This needs to be called prior to nautilus_file_operations_copy_move.
3889 * It hooks up a signal handler to catch any icons that get added before
3890 * the copy_done_callback is invoked. The return value should be passed
3891 * as the data for uri_copy_move_done_callback.
3892 */
3893 static CopyMoveDoneData *
pre_copy_move(NautilusFilesView * directory_view)3894 pre_copy_move (NautilusFilesView *directory_view)
3895 {
3896 CopyMoveDoneData *copy_move_done_data;
3897
3898 copy_move_done_data = g_new0 (CopyMoveDoneData, 1);
3899 copy_move_done_data->directory_view = directory_view;
3900
3901 g_object_add_weak_pointer (G_OBJECT (copy_move_done_data->directory_view),
3902 (gpointer *) ©_move_done_data->directory_view);
3903
3904 /* We need to run after the default handler adds the folder we want to
3905 * operate on. The ADD_FILES signal is registered as G_SIGNAL_RUN_LAST, so we
3906 * must use connect_after.
3907 */
3908 g_signal_connect_after (directory_view, "add-files",
3909 G_CALLBACK (pre_copy_move_add_files_callback), copy_move_done_data);
3910
3911 return copy_move_done_data;
3912 }
3913
3914 /* This function is used to pull out any debuting uris that were added
3915 * and (as a side effect) remove them from the debuting uri hash table.
3916 */
3917 static gboolean
copy_move_done_partition_func(NautilusFile * file,gpointer callback_data)3918 copy_move_done_partition_func (NautilusFile *file,
3919 gpointer callback_data)
3920 {
3921 GFile *location;
3922 gboolean result;
3923
3924 location = nautilus_file_get_location (file);
3925 result = g_hash_table_remove ((GHashTable *) callback_data, location);
3926 g_object_unref (location);
3927
3928 return result;
3929 }
3930
3931 static gboolean
remove_not_really_moved_files(gpointer key,gpointer value,gpointer callback_data)3932 remove_not_really_moved_files (gpointer key,
3933 gpointer value,
3934 gpointer callback_data)
3935 {
3936 GList **added_files;
3937 GFile *loc;
3938
3939 loc = key;
3940
3941 if (GPOINTER_TO_INT (value))
3942 {
3943 return FALSE;
3944 }
3945
3946 added_files = callback_data;
3947 *added_files = g_list_prepend (*added_files,
3948 nautilus_file_get (loc));
3949 return TRUE;
3950 }
3951
3952 /* When this function is invoked, the file operation is over, but all
3953 * the icons may not have been added to the directory view yet, so
3954 * we can't select them yet.
3955 *
3956 * We're passed a hash table of the uri's to look out for, we hook
3957 * up a signal handler to await their arrival.
3958 */
3959 static void
copy_move_done_callback(GHashTable * debuting_files,gboolean success,gpointer data)3960 copy_move_done_callback (GHashTable *debuting_files,
3961 gboolean success,
3962 gpointer data)
3963 {
3964 NautilusFilesView *directory_view;
3965 CopyMoveDoneData *copy_move_done_data;
3966 DebutingFilesData *debuting_files_data;
3967 GList *failed_files;
3968
3969 copy_move_done_data = (CopyMoveDoneData *) data;
3970 directory_view = copy_move_done_data->directory_view;
3971
3972 if (directory_view != NULL)
3973 {
3974 g_assert (NAUTILUS_IS_FILES_VIEW (directory_view));
3975
3976 debuting_files_data = g_new (DebutingFilesData, 1);
3977 debuting_files_data->debuting_files = g_hash_table_ref (debuting_files);
3978 debuting_files_data->added_files = nautilus_file_list_filter (copy_move_done_data->added_files,
3979 &failed_files,
3980 copy_move_done_partition_func,
3981 debuting_files);
3982 nautilus_file_list_free (copy_move_done_data->added_files);
3983 copy_move_done_data->added_files = failed_files;
3984
3985 /* We're passed the same data used by pre_copy_move_add_files_callback, so disconnecting
3986 * it will free data. We've already siphoned off the added_files we need, and stashed the
3987 * directory_view pointer.
3988 */
3989 g_signal_handlers_disconnect_by_func (directory_view,
3990 G_CALLBACK (pre_copy_move_add_files_callback),
3991 data);
3992
3993 /* Any items in the debuting_files hash table that have
3994 * "FALSE" as their value aren't really being copied
3995 * or moved, so we can't wait for an add_files signal
3996 * to come in for those.
3997 */
3998 g_hash_table_foreach_remove (debuting_files,
3999 remove_not_really_moved_files,
4000 &debuting_files_data->added_files);
4001
4002 if (g_hash_table_size (debuting_files) == 0)
4003 {
4004 /* on the off-chance that all the icons have already been added */
4005 if (debuting_files_data->added_files != NULL)
4006 {
4007 nautilus_files_view_call_set_selection (directory_view,
4008 debuting_files_data->added_files);
4009 nautilus_files_view_reveal_selection (directory_view);
4010 }
4011 debuting_files_data_free (debuting_files_data);
4012 }
4013 else
4014 {
4015 /* We need to run after the default handler adds the folder we want to
4016 * operate on. The ADD_FILES signal is registered as G_SIGNAL_RUN_LAST, so we
4017 * must use connect_after.
4018 */
4019 g_signal_connect_data (directory_view,
4020 "add-files",
4021 G_CALLBACK (debuting_files_add_files_callback),
4022 debuting_files_data,
4023 (GClosureNotify) debuting_files_data_free,
4024 G_CONNECT_AFTER);
4025 }
4026 /* Schedule menu update for undo items */
4027 schedule_update_context_menus (directory_view);
4028 }
4029
4030 copy_move_done_data_free (copy_move_done_data);
4031 }
4032
4033 static gboolean
view_file_still_belongs(NautilusFilesView * view,FileAndDirectory * fad)4034 view_file_still_belongs (NautilusFilesView *view,
4035 FileAndDirectory *fad)
4036 {
4037 NautilusFilesViewPrivate *priv;
4038
4039 priv = nautilus_files_view_get_instance_private (view);
4040
4041 if (priv->model != fad->directory &&
4042 g_list_find (priv->subdirectory_list, fad->directory) == NULL)
4043 {
4044 return FALSE;
4045 }
4046
4047 return nautilus_directory_contains_file (fad->directory, fad->file);
4048 }
4049
4050 static gboolean
still_should_show_file(NautilusFilesView * view,FileAndDirectory * fad)4051 still_should_show_file (NautilusFilesView *view,
4052 FileAndDirectory *fad)
4053 {
4054 return nautilus_files_view_should_show_file (view, fad->file) &&
4055 view_file_still_belongs (view, fad);
4056 }
4057
4058 static gboolean
ready_to_load(NautilusFile * file)4059 ready_to_load (NautilusFile *file)
4060 {
4061 return nautilus_file_check_if_ready (file,
4062 NAUTILUS_FILE_ATTRIBUTES_FOR_ICON);
4063 }
4064
4065 static int
compare_files_cover(gconstpointer a,gconstpointer b,gpointer callback_data)4066 compare_files_cover (gconstpointer a,
4067 gconstpointer b,
4068 gpointer callback_data)
4069 {
4070 const FileAndDirectory *fad1, *fad2;
4071 NautilusFilesView *view;
4072
4073 view = callback_data;
4074 fad1 = a;
4075 fad2 = b;
4076
4077 if (fad1->directory < fad2->directory)
4078 {
4079 return -1;
4080 }
4081 else if (fad1->directory > fad2->directory)
4082 {
4083 return 1;
4084 }
4085 else
4086 {
4087 return NAUTILUS_FILES_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->compare_files (view, fad1->file, fad2->file);
4088 }
4089 }
4090 static void
sort_files(NautilusFilesView * view,GList ** list)4091 sort_files (NautilusFilesView *view,
4092 GList **list)
4093 {
4094 *list = g_list_sort_with_data (*list, compare_files_cover, view);
4095 }
4096
4097 /* Go through all the new added and changed files.
4098 * Put any that are not ready to load in the non_ready_files hash table.
4099 * Add all the rest to the old_added_files and old_changed_files lists.
4100 * Sort the old_*_files lists if anything was added to them.
4101 */
4102 static void
process_new_files(NautilusFilesView * view)4103 process_new_files (NautilusFilesView *view)
4104 {
4105 NautilusFilesViewPrivate *priv;
4106 g_autolist (FileAndDirectory) new_added_files = NULL;
4107 g_autolist (FileAndDirectory) new_changed_files = NULL;
4108 GList *old_added_files;
4109 GList *old_changed_files;
4110 GHashTable *non_ready_files;
4111 GList *node, *next;
4112 FileAndDirectory *pending;
4113 gboolean in_non_ready;
4114
4115 priv = nautilus_files_view_get_instance_private (view);
4116
4117 new_added_files = g_steal_pointer (&priv->new_added_files);
4118 new_changed_files = g_steal_pointer (&priv->new_changed_files);
4119
4120 non_ready_files = priv->non_ready_files;
4121
4122 old_added_files = priv->old_added_files;
4123 old_changed_files = priv->old_changed_files;
4124
4125 /* Newly added files go into the old_added_files list if they're
4126 * ready, and into the hash table if they're not.
4127 */
4128 for (node = new_added_files; node != NULL; node = next)
4129 {
4130 next = node->next;
4131 pending = (FileAndDirectory *) node->data;
4132 in_non_ready = g_hash_table_contains (non_ready_files, pending);
4133 if (nautilus_files_view_should_show_file (view, pending->file))
4134 {
4135 if (ready_to_load (pending->file))
4136 {
4137 if (in_non_ready)
4138 {
4139 g_hash_table_remove (non_ready_files, pending);
4140 }
4141 new_added_files = g_list_delete_link (new_added_files, node);
4142 old_added_files = g_list_prepend (old_added_files, pending);
4143 }
4144 else
4145 {
4146 if (!in_non_ready)
4147 {
4148 new_added_files = g_list_delete_link (new_added_files, node);
4149 g_hash_table_add (non_ready_files, pending);
4150 }
4151 }
4152 }
4153 }
4154
4155 /* Newly changed files go into the old_added_files list if they're ready
4156 * and were seen non-ready in the past, into the old_changed_files list
4157 * if they are read and were not seen non-ready in the past, and into
4158 * the hash table if they're not ready.
4159 */
4160 for (node = new_changed_files; node != NULL; node = next)
4161 {
4162 next = node->next;
4163 pending = (FileAndDirectory *) node->data;
4164 if (!still_should_show_file (view, pending) || ready_to_load (pending->file))
4165 {
4166 if (g_hash_table_contains (non_ready_files, pending))
4167 {
4168 g_hash_table_remove (non_ready_files, pending);
4169 if (still_should_show_file (view, pending))
4170 {
4171 new_changed_files = g_list_delete_link (new_changed_files, node);
4172 old_added_files = g_list_prepend (old_added_files, pending);
4173 }
4174 }
4175 else
4176 {
4177 new_changed_files = g_list_delete_link (new_changed_files, node);
4178 old_changed_files = g_list_prepend (old_changed_files, pending);
4179 }
4180 }
4181 }
4182
4183 /* If any files were added to old_added_files, then resort it. */
4184 if (old_added_files != priv->old_added_files)
4185 {
4186 priv->old_added_files = old_added_files;
4187 sort_files (view, &priv->old_added_files);
4188 }
4189
4190 /* Resort old_changed_files too, since file attributes
4191 * relevant to sorting could have changed.
4192 */
4193 if (old_changed_files != priv->old_changed_files)
4194 {
4195 priv->old_changed_files = old_changed_files;
4196 sort_files (view, &priv->old_changed_files);
4197 }
4198 }
4199
4200 static void
on_end_file_changes(NautilusFilesView * view)4201 on_end_file_changes (NautilusFilesView *view)
4202 {
4203 NautilusFilesViewPrivate *priv;
4204
4205 priv = nautilus_files_view_get_instance_private (view);
4206
4207 /* Addition and removal of files modify the empty state */
4208 nautilus_files_view_check_empty_states (view);
4209 /* If the view is empty, zoom slider and sort menu are insensitive */
4210 nautilus_files_view_update_toolbar_menus (view);
4211
4212 /* Reveal files that were pending to be revealed, only if all of them
4213 * were acknowledged by the view
4214 */
4215 if (g_hash_table_size (priv->pending_reveal) > 0)
4216 {
4217 GList *keys;
4218 GList *l;
4219 gboolean all_files_acknowledged = TRUE;
4220
4221 keys = g_hash_table_get_keys (priv->pending_reveal);
4222 for (l = keys; l && all_files_acknowledged; l = l->next)
4223 {
4224 all_files_acknowledged = GPOINTER_TO_UINT (g_hash_table_lookup (priv->pending_reveal,
4225 l->data));
4226 }
4227
4228 if (all_files_acknowledged)
4229 {
4230 nautilus_files_view_set_selection (NAUTILUS_VIEW (view), keys);
4231 nautilus_files_view_reveal_selection (view);
4232 g_hash_table_remove_all (priv->pending_reveal);
4233 }
4234
4235 g_list_free (keys);
4236 }
4237 }
4238
4239 static int
compare_pointers(gconstpointer pointer_1,gconstpointer pointer_2)4240 compare_pointers (gconstpointer pointer_1,
4241 gconstpointer pointer_2)
4242 {
4243 if (pointer_1 < pointer_2)
4244 {
4245 return -1;
4246 }
4247 else if (pointer_1 > pointer_2)
4248 {
4249 return +1;
4250 }
4251
4252 return 0;
4253 }
4254
4255 static gboolean
_g_lists_sort_and_check_for_intersection(GList ** list_1,GList ** list_2)4256 _g_lists_sort_and_check_for_intersection (GList **list_1,
4257 GList **list_2)
4258 {
4259 GList *node_1;
4260 GList *node_2;
4261 int compare_result;
4262
4263 *list_1 = g_list_sort (*list_1, compare_pointers);
4264 *list_2 = g_list_sort (*list_2, compare_pointers);
4265
4266 node_1 = *list_1;
4267 node_2 = *list_2;
4268
4269 while (node_1 != NULL && node_2 != NULL)
4270 {
4271 compare_result = compare_pointers (node_1->data, node_2->data);
4272 if (compare_result == 0)
4273 {
4274 return TRUE;
4275 }
4276 if (compare_result <= 0)
4277 {
4278 node_1 = node_1->next;
4279 }
4280 if (compare_result >= 0)
4281 {
4282 node_2 = node_2->next;
4283 }
4284 }
4285
4286 return FALSE;
4287 }
4288
4289 static void
process_old_files(NautilusFilesView * view)4290 process_old_files (NautilusFilesView *view)
4291 {
4292 NautilusFilesViewPrivate *priv;
4293 g_autolist (FileAndDirectory) files_added = NULL;
4294 g_autolist (FileAndDirectory) files_changed = NULL;
4295 FileAndDirectory *pending;
4296 GList *files;
4297 g_autoptr (GList) pending_additions = NULL;
4298
4299 priv = nautilus_files_view_get_instance_private (view);
4300 files_added = g_steal_pointer (&priv->old_added_files);
4301 files_changed = g_steal_pointer (&priv->old_changed_files);
4302
4303
4304 if (files_added != NULL || files_changed != NULL)
4305 {
4306 gboolean send_selection_change = FALSE;
4307
4308 g_signal_emit (view, signals[BEGIN_FILE_CHANGES], 0);
4309
4310 for (GList *node = files_added; node != NULL; node = node->next)
4311 {
4312 pending = node->data;
4313 pending_additions = g_list_prepend (pending_additions, pending->file);
4314 /* Acknowledge the files that were pending to be revealed */
4315 if (g_hash_table_contains (priv->pending_reveal, pending->file))
4316 {
4317 g_hash_table_insert (priv->pending_reveal,
4318 pending->file,
4319 GUINT_TO_POINTER (TRUE));
4320 }
4321 }
4322
4323 if (files_added != NULL)
4324 {
4325 g_signal_emit (view,
4326 signals[ADD_FILES], 0, pending_additions);
4327 }
4328
4329 for (GList *node = files_changed; node != NULL; node = node->next)
4330 {
4331 gboolean should_show_file;
4332 pending = node->data;
4333 should_show_file = still_should_show_file (view, pending);
4334 g_signal_emit (view,
4335 signals[should_show_file ? FILE_CHANGED : REMOVE_FILE], 0,
4336 pending->file, pending->directory);
4337
4338 /* Acknowledge the files that were pending to be revealed */
4339 if (g_hash_table_contains (priv->pending_reveal, pending->file))
4340 {
4341 if (should_show_file)
4342 {
4343 g_hash_table_insert (priv->pending_reveal,
4344 pending->file,
4345 GUINT_TO_POINTER (TRUE));
4346 }
4347 else
4348 {
4349 g_hash_table_remove (priv->pending_reveal,
4350 pending->file);
4351 }
4352 }
4353 }
4354
4355 if (files_changed != NULL)
4356 {
4357 g_autolist (NautilusFile) selection = NULL;
4358 selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
4359 files = g_list_copy_deep (files_changed, (GCopyFunc) file_and_directory_get_file, NULL);
4360 send_selection_change = _g_lists_sort_and_check_for_intersection
4361 (&files, &selection);
4362 nautilus_file_list_free (files);
4363 }
4364
4365 if (send_selection_change)
4366 {
4367 /* Send a selection change since some file names could
4368 * have changed.
4369 */
4370 nautilus_files_view_send_selection_change (view);
4371 }
4372
4373 g_signal_emit (view, signals[END_FILE_CHANGES], 0);
4374 }
4375 }
4376
4377 static void
display_pending_files(NautilusFilesView * view)4378 display_pending_files (NautilusFilesView *view)
4379 {
4380 NautilusFilesViewPrivate *priv;
4381 g_autolist (NautilusFile) selection = NULL;
4382
4383 process_new_files (view);
4384 process_old_files (view);
4385
4386 priv = nautilus_files_view_get_instance_private (view);
4387 selection = nautilus_files_view_get_selection (NAUTILUS_VIEW (view));
4388
4389 if (selection == NULL &&
4390 !priv->pending_selection &&
4391 nautilus_view_is_searching (NAUTILUS_VIEW (view)))
4392 {
4393 nautilus_files_view_select_first (view);
4394 }
4395
4396 if (priv->model != NULL
4397 && nautilus_directory_are_all_files_seen (priv->model)
4398 && g_hash_table_size (priv->non_ready_files) == 0)
4399 {
4400 done_loading (view, TRUE);
4401 }
4402 }
4403
4404 static gboolean
display_selection_info_idle_callback(gpointer data)4405 display_selection_info_idle_callback (gpointer data)
4406 {
4407 NautilusFilesView *view;
4408 NautilusFilesViewPrivate *priv;
4409
4410 view = NAUTILUS_FILES_VIEW (data);
4411 priv = nautilus_files_view_get_instance_private (view);
4412
4413 g_object_ref (G_OBJECT (view));
4414
4415 priv->display_selection_idle_id = 0;
4416 nautilus_files_view_display_selection_info (view);
4417 nautilus_files_view_send_selection_change (view);
4418
4419 g_object_unref (G_OBJECT (view));
4420
4421 return FALSE;
4422 }
4423
4424 static void
remove_update_context_menus_timeout_callback(NautilusFilesView * view)4425 remove_update_context_menus_timeout_callback (NautilusFilesView *view)
4426 {
4427 NautilusFilesViewPrivate *priv;
4428
4429 priv = nautilus_files_view_get_instance_private (view);
4430
4431 if (priv->update_context_menus_timeout_id != 0)
4432 {
4433 g_source_remove (priv->update_context_menus_timeout_id);
4434 priv->update_context_menus_timeout_id = 0;
4435 }
4436 }
4437
4438 static void
update_context_menus_if_pending(NautilusFilesView * view)4439 update_context_menus_if_pending (NautilusFilesView *view)
4440 {
4441 remove_update_context_menus_timeout_callback (view);
4442
4443 nautilus_files_view_update_context_menus (view);
4444 }
4445
4446 static gboolean
update_context_menus_timeout_callback(gpointer data)4447 update_context_menus_timeout_callback (gpointer data)
4448 {
4449 NautilusFilesView *view;
4450 NautilusFilesViewPrivate *priv;
4451
4452 view = NAUTILUS_FILES_VIEW (data);
4453 priv = nautilus_files_view_get_instance_private (view);
4454
4455 g_object_ref (G_OBJECT (view));
4456
4457 priv->update_context_menus_timeout_id = 0;
4458 nautilus_files_view_update_context_menus (view);
4459
4460 g_object_unref (G_OBJECT (view));
4461
4462 return FALSE;
4463 }
4464
4465 static gboolean
display_pending_callback(gpointer data)4466 display_pending_callback (gpointer data)
4467 {
4468 NautilusFilesView *view;
4469 NautilusFilesViewPrivate *priv;
4470
4471 view = NAUTILUS_FILES_VIEW (data);
4472 priv = nautilus_files_view_get_instance_private (view);
4473
4474 g_object_ref (G_OBJECT (view));
4475
4476 priv->display_pending_source_id = 0;
4477
4478 display_pending_files (view);
4479
4480 g_object_unref (G_OBJECT (view));
4481
4482 return FALSE;
4483 }
4484
4485 static void
schedule_idle_display_of_pending_files(NautilusFilesView * view)4486 schedule_idle_display_of_pending_files (NautilusFilesView *view)
4487 {
4488 NautilusFilesViewPrivate *priv;
4489
4490 priv = nautilus_files_view_get_instance_private (view);
4491
4492 /* Get rid of a pending source as it might be a timeout */
4493 unschedule_display_of_pending_files (view);
4494
4495 /* We want higher priority than the idle that handles the relayout
4496 * to avoid a resort on each add. But we still want to allow repaints
4497 * and other hight prio events while we have pending files to show. */
4498 priv->display_pending_source_id =
4499 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE - 20,
4500 display_pending_callback, view, NULL);
4501 }
4502
4503 static void
schedule_timeout_display_of_pending_files(NautilusFilesView * view,guint interval)4504 schedule_timeout_display_of_pending_files (NautilusFilesView *view,
4505 guint interval)
4506 {
4507 NautilusFilesViewPrivate *priv;
4508
4509 priv = nautilus_files_view_get_instance_private (view);
4510
4511 /* No need to schedule an update if there's already one pending. */
4512 if (priv->display_pending_source_id != 0)
4513 {
4514 return;
4515 }
4516
4517 priv->display_pending_source_id =
4518 g_timeout_add (interval, display_pending_callback, view);
4519 }
4520
4521 static void
unschedule_display_of_pending_files(NautilusFilesView * view)4522 unschedule_display_of_pending_files (NautilusFilesView *view)
4523 {
4524 NautilusFilesViewPrivate *priv;
4525
4526 priv = nautilus_files_view_get_instance_private (view);
4527
4528 /* Get rid of source if it's active. */
4529 if (priv->display_pending_source_id != 0)
4530 {
4531 g_source_remove (priv->display_pending_source_id);
4532 priv->display_pending_source_id = 0;
4533 }
4534 }
4535
4536 static void
queue_pending_files(NautilusFilesView * view,NautilusDirectory * directory,GList * files,GList ** pending_list)4537 queue_pending_files (NautilusFilesView *view,
4538 NautilusDirectory *directory,
4539 GList *files,
4540 GList **pending_list)
4541 {
4542 NautilusFilesViewPrivate *priv;
4543 GList *fad_list;
4544
4545 priv = nautilus_files_view_get_instance_private (view);
4546
4547 if (files == NULL)
4548 {
4549 return;
4550 }
4551
4552 fad_list = g_list_copy_deep (files, (GCopyFunc) file_and_directory_new, directory);
4553 *pending_list = g_list_concat (fad_list, *pending_list);
4554 /* Generally we don't want to show the files while the directory is loading
4555 * the files themselves, so we avoid jumping and oddities. However, for
4556 * search it can be a long wait, and we actually want to show files as
4557 * they are getting found. So for search is fine if not all files are
4558 * seen */
4559 if (!priv->loading ||
4560 (nautilus_directory_are_all_files_seen (directory) ||
4561 nautilus_view_is_searching (NAUTILUS_VIEW (view))))
4562 {
4563 schedule_timeout_display_of_pending_files (view, priv->update_interval);
4564 }
4565 }
4566
4567 static void
remove_changes_timeout_callback(NautilusFilesView * view)4568 remove_changes_timeout_callback (NautilusFilesView *view)
4569 {
4570 NautilusFilesViewPrivate *priv;
4571
4572 priv = nautilus_files_view_get_instance_private (view);
4573
4574 if (priv->changes_timeout_id != 0)
4575 {
4576 g_source_remove (priv->changes_timeout_id);
4577 priv->changes_timeout_id = 0;
4578 }
4579 }
4580
4581 static void
reset_update_interval(NautilusFilesView * view)4582 reset_update_interval (NautilusFilesView *view)
4583 {
4584 NautilusFilesViewPrivate *priv;
4585
4586 priv = nautilus_files_view_get_instance_private (view);
4587
4588 priv->update_interval = UPDATE_INTERVAL_MIN;
4589 remove_changes_timeout_callback (view);
4590 /* Reschedule a pending timeout to idle */
4591 if (priv->display_pending_source_id != 0)
4592 {
4593 schedule_idle_display_of_pending_files (view);
4594 }
4595 }
4596
4597 static gboolean
changes_timeout_callback(gpointer data)4598 changes_timeout_callback (gpointer data)
4599 {
4600 gint64 now;
4601 gint64 time_delta;
4602 gboolean ret;
4603 NautilusFilesView *view;
4604 NautilusFilesViewPrivate *priv;
4605
4606 view = NAUTILUS_FILES_VIEW (data);
4607 priv = nautilus_files_view_get_instance_private (view);
4608
4609 g_object_ref (G_OBJECT (view));
4610
4611 now = g_get_monotonic_time ();
4612 time_delta = now - priv->last_queued;
4613
4614 if (time_delta < UPDATE_INTERVAL_RESET * 1000)
4615 {
4616 if (priv->update_interval < UPDATE_INTERVAL_MAX &&
4617 priv->loading)
4618 {
4619 /* Increase */
4620 priv->update_interval += UPDATE_INTERVAL_INC;
4621 }
4622 ret = TRUE;
4623 }
4624 else
4625 {
4626 /* Reset */
4627 reset_update_interval (view);
4628 ret = FALSE;
4629 }
4630
4631 g_object_unref (G_OBJECT (view));
4632
4633 return ret;
4634 }
4635
4636 static void
schedule_changes(NautilusFilesView * view)4637 schedule_changes (NautilusFilesView *view)
4638 {
4639 NautilusFilesViewPrivate *priv;
4640
4641 priv = nautilus_files_view_get_instance_private (view);
4642 /* Remember when the change was queued */
4643 priv->last_queued = g_get_monotonic_time ();
4644
4645 /* No need to schedule if there are already changes pending or during loading */
4646 if (priv->changes_timeout_id != 0 ||
4647 priv->loading)
4648 {
4649 return;
4650 }
4651
4652 priv->changes_timeout_id =
4653 g_timeout_add (UPDATE_INTERVAL_TIMEOUT_INTERVAL, changes_timeout_callback, view);
4654 }
4655
4656 static void
files_added_callback(NautilusDirectory * directory,GList * files,gpointer callback_data)4657 files_added_callback (NautilusDirectory *directory,
4658 GList *files,
4659 gpointer callback_data)
4660 {
4661 NautilusFilesViewPrivate *priv;
4662 NautilusFilesView *view;
4663 GtkWindow *window;
4664 char *uri;
4665
4666 view = NAUTILUS_FILES_VIEW (callback_data);
4667 priv = nautilus_files_view_get_instance_private (view);
4668
4669 nautilus_profile_start (NULL);
4670
4671 window = nautilus_files_view_get_containing_window (view);
4672 uri = nautilus_files_view_get_uri (view);
4673 DEBUG_FILES (files, "Files added in window %p: %s",
4674 window, uri ? uri : "(no directory)");
4675 g_free (uri);
4676
4677 schedule_changes (view);
4678
4679 queue_pending_files (view, directory, files, &priv->new_added_files);
4680
4681 /* The number of items could have changed */
4682 schedule_update_status (view);
4683
4684 nautilus_profile_end (NULL);
4685 }
4686
4687 static void
files_changed_callback(NautilusDirectory * directory,GList * files,gpointer callback_data)4688 files_changed_callback (NautilusDirectory *directory,
4689 GList *files,
4690 gpointer callback_data)
4691 {
4692 NautilusFilesViewPrivate *priv;
4693 NautilusFilesView *view;
4694 GtkWindow *window;
4695 char *uri;
4696
4697 view = NAUTILUS_FILES_VIEW (callback_data);
4698 priv = nautilus_files_view_get_instance_private (view);
4699
4700 window = nautilus_files_view_get_containing_window (view);
4701 uri = nautilus_files_view_get_uri (view);
4702 DEBUG_FILES (files, "Files changed in window %p: %s",
4703 window, uri ? uri : "(no directory)");
4704 g_free (uri);
4705
4706 schedule_changes (view);
4707
4708 queue_pending_files (view, directory, files, &priv->new_changed_files);
4709
4710 /* The free space or the number of items could have changed */
4711 schedule_update_status (view);
4712
4713 /* A change in MIME type could affect the Open with menu, for
4714 * one thing, so we need to update menus when files change.
4715 */
4716 schedule_update_context_menus (view);
4717 }
4718
4719 static void
done_loading_callback(NautilusDirectory * directory,gpointer callback_data)4720 done_loading_callback (NautilusDirectory *directory,
4721 gpointer callback_data)
4722 {
4723 NautilusFilesView *view;
4724 NautilusFilesViewPrivate *priv;
4725
4726 view = NAUTILUS_FILES_VIEW (callback_data);
4727 priv = nautilus_files_view_get_instance_private (view);
4728
4729 nautilus_profile_start (NULL);
4730 process_new_files (view);
4731 if (g_hash_table_size (priv->non_ready_files) == 0)
4732 {
4733 /* Unschedule a pending update and schedule a new one with the minimal
4734 * update interval. This gives the view a short chance at gathering the
4735 * (cached) deep counts.
4736 */
4737 unschedule_display_of_pending_files (view);
4738 schedule_timeout_display_of_pending_files (view, UPDATE_INTERVAL_MIN);
4739
4740 remove_loading_floating_bar (view);
4741 }
4742 nautilus_profile_end (NULL);
4743 }
4744
4745 static void
load_error_callback(NautilusDirectory * directory,GError * error,gpointer callback_data)4746 load_error_callback (NautilusDirectory *directory,
4747 GError *error,
4748 gpointer callback_data)
4749 {
4750 NautilusFilesView *view;
4751
4752 view = NAUTILUS_FILES_VIEW (callback_data);
4753
4754 /* FIXME: By doing a stop, we discard some pending files. Is
4755 * that OK?
4756 */
4757 nautilus_files_view_stop_loading (view);
4758
4759 nautilus_report_error_loading_directory
4760 (nautilus_files_view_get_directory_as_file (view),
4761 error,
4762 nautilus_files_view_get_containing_window (view));
4763 }
4764
4765 void
nautilus_files_view_add_subdirectory(NautilusFilesView * view,NautilusDirectory * directory)4766 nautilus_files_view_add_subdirectory (NautilusFilesView *view,
4767 NautilusDirectory *directory)
4768 {
4769 NautilusFileAttributes attributes;
4770 NautilusFilesViewPrivate *priv;
4771
4772 priv = nautilus_files_view_get_instance_private (view);
4773
4774 g_assert (!g_list_find (priv->subdirectory_list, directory));
4775
4776 nautilus_directory_ref (directory);
4777
4778 attributes =
4779 NAUTILUS_FILE_ATTRIBUTES_FOR_ICON |
4780 NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT |
4781 NAUTILUS_FILE_ATTRIBUTE_INFO |
4782 NAUTILUS_FILE_ATTRIBUTE_MOUNT |
4783 NAUTILUS_FILE_ATTRIBUTE_EXTENSION_INFO;
4784
4785 nautilus_directory_file_monitor_add (directory,
4786 &priv->model,
4787 priv->show_hidden_files,
4788 attributes,
4789 files_added_callback, view);
4790
4791 g_signal_connect
4792 (directory, "files-added",
4793 G_CALLBACK (files_added_callback), view);
4794 g_signal_connect
4795 (directory, "files-changed",
4796 G_CALLBACK (files_changed_callback), view);
4797
4798 priv->subdirectory_list = g_list_prepend (
4799 priv->subdirectory_list, directory);
4800 }
4801
4802 void
nautilus_files_view_remove_subdirectory(NautilusFilesView * view,NautilusDirectory * directory)4803 nautilus_files_view_remove_subdirectory (NautilusFilesView *view,
4804 NautilusDirectory *directory)
4805 {
4806 NautilusFilesViewPrivate *priv;
4807 priv = nautilus_files_view_get_instance_private (view);
4808
4809 g_assert (g_list_find (priv->subdirectory_list, directory));
4810
4811 priv->subdirectory_list = g_list_remove (
4812 priv->subdirectory_list, directory);
4813
4814 g_signal_handlers_disconnect_by_func (directory,
4815 G_CALLBACK (files_added_callback),
4816 view);
4817 g_signal_handlers_disconnect_by_func (directory,
4818 G_CALLBACK (files_changed_callback),
4819 view);
4820
4821 nautilus_directory_file_monitor_remove (directory, &priv->model);
4822
4823 nautilus_directory_unref (directory);
4824 }
4825
4826 /**
4827 * nautilus_files_view_get_loading:
4828 * @view: an #NautilusFilesView.
4829 *
4830 * Return value: #gboolean inicating whether @view is currently loaded.
4831 *
4832 **/
4833 gboolean
nautilus_files_view_get_loading(NautilusFilesView * view)4834 nautilus_files_view_get_loading (NautilusFilesView *view)
4835 {
4836 NautilusFilesViewPrivate *priv;
4837
4838 g_return_val_if_fail (NAUTILUS_IS_FILES_VIEW (view), FALSE);
4839
4840 priv = nautilus_files_view_get_instance_private (view);
4841
4842 return priv->loading;
4843 }
4844
4845 /**
4846 * nautilus_files_view_get_model:
4847 *
4848 * Get the model for this NautilusFilesView.
4849 * @view: NautilusFilesView of interest.
4850 *
4851 * Return value: NautilusDirectory for this view.
4852 *
4853 **/
4854 NautilusDirectory *
nautilus_files_view_get_model(NautilusFilesView * view)4855 nautilus_files_view_get_model (NautilusFilesView *view)
4856 {
4857 NautilusFilesViewPrivate *priv;
4858
4859 g_return_val_if_fail (NAUTILUS_IS_FILES_VIEW (view), NULL);
4860
4861 priv = nautilus_files_view_get_instance_private (view);
4862
4863 return priv->model;
4864 }
4865
4866 GtkWidget *
nautilus_files_view_get_content_widget(NautilusFilesView * view)4867 nautilus_files_view_get_content_widget (NautilusFilesView *view)
4868 {
4869 NautilusFilesViewPrivate *priv;
4870
4871 g_return_val_if_fail (NAUTILUS_IS_FILES_VIEW (view), NULL);
4872
4873 priv = nautilus_files_view_get_instance_private (view);
4874
4875 return priv->scrolled_window;
4876 }
4877
4878 /* home_dir_in_selection()
4879 *
4880 * Return TRUE if the home directory is in the selection.
4881 */
4882
4883 static gboolean
home_dir_in_selection(GList * selection)4884 home_dir_in_selection (GList *selection)
4885 {
4886 for (GList *node = selection; node != NULL; node = node->next)
4887 {
4888 if (nautilus_file_is_home (NAUTILUS_FILE (node->data)))
4889 {
4890 return TRUE;
4891 }
4892 }
4893
4894 return FALSE;
4895 }
4896
4897 static void
trash_or_delete_done_cb(GHashTable * debuting_uris,gboolean user_cancel,NautilusFilesView * view)4898 trash_or_delete_done_cb (GHashTable *debuting_uris,
4899 gboolean user_cancel,
4900 NautilusFilesView *view)
4901 {
4902 NautilusFilesViewPrivate *priv;
4903
4904 priv = nautilus_files_view_get_instance_private (view);
4905 if (user_cancel)
4906 {
4907 priv->selection_was_removed = FALSE;
4908 }
4909 }
4910
4911 static void
trash_or_delete_files(GtkWindow * parent_window,const GList * files,NautilusFilesView * view)4912 trash_or_delete_files (GtkWindow *parent_window,
4913 const GList *files,
4914 NautilusFilesView *view)
4915 {
4916 GList *locations;
4917 const GList *node;
4918
4919 locations = NULL;
4920 for (node = files; node != NULL; node = node->next)
4921 {
4922 locations = g_list_prepend (locations,
4923 nautilus_file_get_location ((NautilusFile *) node->data));
4924 }
4925
4926 locations = g_list_reverse (locations);
4927
4928 nautilus_file_operations_trash_or_delete_async (locations,
4929 parent_window,
4930 NULL,
4931 (NautilusDeleteCallback) trash_or_delete_done_cb,
4932 view);
4933 g_list_free_full (locations, g_object_unref);
4934 }
4935
4936 static void
open_one_in_new_window(gpointer data,gpointer callback_data)4937 open_one_in_new_window (gpointer data,
4938 gpointer callback_data)
4939 {
4940 g_assert (NAUTILUS_IS_FILE (data));
4941 g_assert (NAUTILUS_IS_FILES_VIEW (callback_data));
4942
4943 nautilus_files_view_activate_file (NAUTILUS_FILES_VIEW (callback_data),
4944 NAUTILUS_FILE (data),
4945 NAUTILUS_WINDOW_OPEN_FLAG_NEW_WINDOW);
4946 }
4947
4948 NautilusFile *
nautilus_files_view_get_directory_as_file(NautilusFilesView * view)4949 nautilus_files_view_get_directory_as_file (NautilusFilesView *view)
4950 {
4951 NautilusFilesViewPrivate *priv;
4952
4953 g_assert (NAUTILUS_IS_FILES_VIEW (view));
4954
4955 priv = nautilus_files_view_get_instance_private (view);
4956
4957 return priv->directory_as_file;
4958 }
4959
4960 static GdkPixbuf *
get_menu_icon_for_file(NautilusFile * file,GtkWidget * widget)4961 get_menu_icon_for_file (NautilusFile *file,
4962 GtkWidget *widget)
4963 {
4964 NautilusIconInfo *info;
4965 GdkPixbuf *pixbuf;
4966 int size, scale;
4967
4968 size = nautilus_get_icon_size_for_stock_size (GTK_ICON_SIZE_MENU);
4969 scale = gtk_widget_get_scale_factor (widget);
4970
4971 info = nautilus_file_get_icon (file, size, scale, 0);
4972 pixbuf = nautilus_icon_info_get_pixbuf_nodefault_at_size (info, size);
4973 g_object_unref (info);
4974
4975 return pixbuf;
4976 }
4977
4978 static GList *
get_extension_selection_menu_items(NautilusFilesView * view)4979 get_extension_selection_menu_items (NautilusFilesView *view)
4980 {
4981 NautilusWindow *window;
4982 GList *items;
4983 GList *providers;
4984 GList *l;
4985 g_autolist (NautilusFile) selection = NULL;
4986
4987 window = nautilus_files_view_get_window (view);
4988 selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
4989 providers = nautilus_module_get_extensions_for_type (NAUTILUS_TYPE_MENU_PROVIDER);
4990 items = NULL;
4991
4992 for (l = providers; l != NULL; l = l->next)
4993 {
4994 NautilusMenuProvider *provider;
4995 GList *file_items;
4996
4997 provider = NAUTILUS_MENU_PROVIDER (l->data);
4998 file_items = nautilus_menu_provider_get_file_items (provider,
4999 GTK_WIDGET (window),
5000 selection);
5001 items = g_list_concat (items, file_items);
5002 }
5003
5004 nautilus_module_extension_list_free (providers);
5005
5006 return items;
5007 }
5008
5009 static GList *
get_extension_background_menu_items(NautilusFilesView * view)5010 get_extension_background_menu_items (NautilusFilesView *view)
5011 {
5012 NautilusFilesViewPrivate *priv;
5013 NautilusWindow *window;
5014 GList *items;
5015 GList *providers;
5016 GList *l;
5017
5018 priv = nautilus_files_view_get_instance_private (view);
5019 window = nautilus_files_view_get_window (view);
5020 providers = nautilus_module_get_extensions_for_type (NAUTILUS_TYPE_MENU_PROVIDER);
5021 items = NULL;
5022
5023 for (l = providers; l != NULL; l = l->next)
5024 {
5025 NautilusMenuProvider *provider;
5026 NautilusFileInfo *file_info;
5027 GList *file_items;
5028
5029 provider = NAUTILUS_MENU_PROVIDER (l->data);
5030 file_info = NAUTILUS_FILE_INFO (priv->directory_as_file);
5031 file_items = nautilus_menu_provider_get_background_items (provider,
5032 GTK_WIDGET (window),
5033 file_info);
5034 items = g_list_concat (items, file_items);
5035 }
5036
5037 nautilus_module_extension_list_free (providers);
5038
5039 return items;
5040 }
5041
5042 static void
extension_action_callback(GSimpleAction * action,GVariant * state,gpointer user_data)5043 extension_action_callback (GSimpleAction *action,
5044 GVariant *state,
5045 gpointer user_data)
5046 {
5047 NautilusMenuItem *item = user_data;
5048 nautilus_menu_item_activate (item);
5049 }
5050
5051 static void
add_extension_action(NautilusFilesView * view,NautilusMenuItem * item,const char * action_name)5052 add_extension_action (NautilusFilesView *view,
5053 NautilusMenuItem *item,
5054 const char *action_name)
5055 {
5056 NautilusFilesViewPrivate *priv;
5057 gboolean sensitive;
5058 GSimpleAction *action;
5059
5060 priv = nautilus_files_view_get_instance_private (view);
5061
5062 g_object_get (item,
5063 "sensitive", &sensitive,
5064 NULL);
5065
5066 action = g_simple_action_new (action_name, NULL);
5067 g_signal_connect_data (action, "activate",
5068 G_CALLBACK (extension_action_callback),
5069 g_object_ref (item),
5070 (GClosureNotify) g_object_unref, 0);
5071
5072 g_action_map_add_action (G_ACTION_MAP (priv->view_action_group),
5073 G_ACTION (action));
5074 g_simple_action_set_enabled (action, sensitive);
5075
5076 g_object_unref (action);
5077 }
5078
5079 static GMenuModel *
build_menu_for_extension_menu_items(NautilusFilesView * view,const gchar * extension_prefix,GList * menu_items)5080 build_menu_for_extension_menu_items (NautilusFilesView *view,
5081 const gchar *extension_prefix,
5082 GList *menu_items)
5083 {
5084 GList *l;
5085 GMenu *gmenu;
5086 gint idx = 0;
5087
5088 gmenu = g_menu_new ();
5089
5090 for (l = menu_items; l; l = l->next)
5091 {
5092 NautilusMenuItem *item;
5093 NautilusMenu *menu;
5094 GMenuItem *menu_item;
5095 char *name, *label;
5096 g_autofree gchar *escaped_name = NULL;
5097 char *extension_id, *detailed_action_name;
5098
5099 item = NAUTILUS_MENU_ITEM (l->data);
5100
5101 g_object_get (item,
5102 "label", &label,
5103 "menu", &menu,
5104 "name", &name,
5105 NULL);
5106
5107 escaped_name = g_uri_escape_string (name, NULL, TRUE);
5108 extension_id = g_strdup_printf ("extension_%s_%d_%s",
5109 extension_prefix, idx, escaped_name);
5110 add_extension_action (view, item, extension_id);
5111
5112 detailed_action_name = g_strconcat ("view.", extension_id, NULL);
5113 menu_item = g_menu_item_new (label, detailed_action_name);
5114
5115 if (menu != NULL)
5116 {
5117 GList *children;
5118 g_autoptr (GMenuModel) children_menu = NULL;
5119
5120 children = nautilus_menu_get_items (menu);
5121 children_menu = build_menu_for_extension_menu_items (view, extension_id, children);
5122 g_menu_item_set_submenu (menu_item, children_menu);
5123
5124 nautilus_menu_item_list_free (children);
5125 }
5126
5127 g_menu_append_item (gmenu, menu_item);
5128 idx++;
5129
5130 g_free (extension_id);
5131 g_free (detailed_action_name);
5132 g_free (name);
5133 g_free (label);
5134 g_object_unref (menu_item);
5135 }
5136
5137 return G_MENU_MODEL (gmenu);
5138 }
5139
5140 static void
update_extensions_menus(NautilusFilesView * view,GtkBuilder * builder)5141 update_extensions_menus (NautilusFilesView *view,
5142 GtkBuilder *builder)
5143 {
5144 GList *selection_items, *background_items;
5145 GObject *object;
5146 g_autoptr (GMenuModel) background_menu = NULL;
5147 g_autoptr (GMenuModel) selection_menu = NULL;
5148
5149 selection_items = get_extension_selection_menu_items (view);
5150 if (selection_items != NULL)
5151 {
5152 selection_menu = build_menu_for_extension_menu_items (view, "extensions",
5153 selection_items);
5154
5155 object = gtk_builder_get_object (builder, "selection-extensions-section");
5156 nautilus_gmenu_set_from_model (G_MENU (object), selection_menu);
5157
5158 nautilus_menu_item_list_free (selection_items);
5159 }
5160
5161 background_items = get_extension_background_menu_items (view);
5162 if (background_items != NULL)
5163 {
5164 background_menu = build_menu_for_extension_menu_items (view, "extensions",
5165 background_items);
5166
5167 object = gtk_builder_get_object (builder, "background-extensions-section");
5168 nautilus_gmenu_set_from_model (G_MENU (object), background_menu);
5169
5170 nautilus_menu_item_list_free (background_items);
5171 }
5172
5173 nautilus_view_set_extensions_background_menu (NAUTILUS_VIEW (view), background_menu);
5174 }
5175
5176 static char *
change_to_view_directory(NautilusFilesView * view)5177 change_to_view_directory (NautilusFilesView *view)
5178 {
5179 char *path;
5180 char *old_path;
5181
5182 old_path = g_get_current_dir ();
5183
5184 path = get_view_directory (view);
5185
5186 /* FIXME: What to do about non-local directories? */
5187 if (path != NULL)
5188 {
5189 g_chdir (path);
5190 }
5191
5192 g_free (path);
5193
5194 return old_path;
5195 }
5196
5197 static char **
get_file_names_as_parameter_array(GList * selection,NautilusDirectory * model)5198 get_file_names_as_parameter_array (GList *selection,
5199 NautilusDirectory *model)
5200 {
5201 char **parameters;
5202 g_autoptr (GFile) model_location = NULL;
5203 int i;
5204
5205 if (model == NULL)
5206 {
5207 return NULL;
5208 }
5209
5210 parameters = g_new (char *, g_list_length (selection) + 1);
5211
5212 model_location = nautilus_directory_get_location (model);
5213
5214 i = 0;
5215 for (GList *node = selection; node != NULL; node = node->next, i++)
5216 {
5217 g_autoptr (GFile) file_location = NULL;
5218 NautilusFile *file = NAUTILUS_FILE (node->data);
5219
5220 if (!nautilus_file_has_local_path (file))
5221 {
5222 parameters[i] = NULL;
5223 g_strfreev (parameters);
5224 return NULL;
5225 }
5226
5227 file_location = nautilus_file_get_location (file);
5228 parameters[i] = g_file_get_relative_path (model_location, file_location);
5229 if (parameters[i] == NULL)
5230 {
5231 parameters[i] = g_file_get_path (file_location);
5232 }
5233 }
5234
5235 parameters[i] = NULL;
5236 return parameters;
5237 }
5238
5239 static char *
get_file_paths_or_uris_as_newline_delimited_string(GList * selection,gboolean get_paths)5240 get_file_paths_or_uris_as_newline_delimited_string (GList *selection,
5241 gboolean get_paths)
5242 {
5243 GString *expanding_string;
5244
5245 expanding_string = g_string_new ("");
5246 for (GList *node = selection; node != NULL; node = node->next)
5247 {
5248 NautilusFile *file = NAUTILUS_FILE (node->data);
5249 g_autofree gchar *uri = NULL;
5250
5251 uri = nautilus_file_get_uri (file);
5252 if (uri == NULL)
5253 {
5254 continue;
5255 }
5256
5257 if (get_paths)
5258 {
5259 g_autofree gchar *path = NULL;
5260
5261 if (!nautilus_file_has_local_path (file))
5262 {
5263 g_string_free (expanding_string, TRUE);
5264 return g_strdup ("");
5265 }
5266
5267 path = g_filename_from_uri (uri, NULL, NULL);
5268 if (path != NULL)
5269 {
5270 g_string_append (expanding_string, path);
5271 g_string_append (expanding_string, "\n");
5272 }
5273 }
5274 else
5275 {
5276 g_string_append (expanding_string, uri);
5277 g_string_append (expanding_string, "\n");
5278 }
5279 }
5280
5281 return g_string_free (expanding_string, FALSE);
5282 }
5283
5284 static char *
get_file_paths_as_newline_delimited_string(GList * selection)5285 get_file_paths_as_newline_delimited_string (GList *selection)
5286 {
5287 return get_file_paths_or_uris_as_newline_delimited_string (selection, TRUE);
5288 }
5289
5290 static char *
get_file_uris_as_newline_delimited_string(GList * selection)5291 get_file_uris_as_newline_delimited_string (GList *selection)
5292 {
5293 return get_file_paths_or_uris_as_newline_delimited_string (selection, FALSE);
5294 }
5295
5296 /*
5297 * Set up some environment variables that scripts can use
5298 * to take advantage of the current Nautilus state.
5299 */
5300 static void
set_script_environment_variables(NautilusFilesView * view,GList * selected_files)5301 set_script_environment_variables (NautilusFilesView *view,
5302 GList *selected_files)
5303 {
5304 g_autofree gchar *file_paths = NULL;
5305 g_autofree gchar *uris = NULL;
5306 g_autofree gchar *uri = NULL;
5307 g_autofree gchar *geometry_string = NULL;
5308 NautilusFilesViewPrivate *priv;
5309
5310 priv = nautilus_files_view_get_instance_private (view);
5311
5312 file_paths = get_file_paths_as_newline_delimited_string (selected_files);
5313 g_setenv ("NAUTILUS_SCRIPT_SELECTED_FILE_PATHS", file_paths, TRUE);
5314
5315 uris = get_file_uris_as_newline_delimited_string (selected_files);
5316 g_setenv ("NAUTILUS_SCRIPT_SELECTED_URIS", uris, TRUE);
5317
5318 uri = nautilus_directory_get_uri (priv->model);
5319 g_setenv ("NAUTILUS_SCRIPT_CURRENT_URI", uri, TRUE);
5320
5321 geometry_string = eel_gtk_window_get_geometry_string
5322 (GTK_WINDOW (nautilus_files_view_get_containing_window (view)));
5323 g_setenv ("NAUTILUS_SCRIPT_WINDOW_GEOMETRY", geometry_string, TRUE);
5324 }
5325
5326 /* Unset all the special script environment variables. */
5327 static void
unset_script_environment_variables(void)5328 unset_script_environment_variables (void)
5329 {
5330 g_unsetenv ("NAUTILUS_SCRIPT_SELECTED_FILE_PATHS");
5331 g_unsetenv ("NAUTILUS_SCRIPT_SELECTED_URIS");
5332 g_unsetenv ("NAUTILUS_SCRIPT_CURRENT_URI");
5333 g_unsetenv ("NAUTILUS_SCRIPT_WINDOW_GEOMETRY");
5334 }
5335
5336 static void
run_script(GSimpleAction * action,GVariant * state,gpointer user_data)5337 run_script (GSimpleAction *action,
5338 GVariant *state,
5339 gpointer user_data)
5340 {
5341 ScriptLaunchParameters *launch_parameters;
5342 NautilusFilesViewPrivate *priv;
5343 g_autofree gchar *file_uri = NULL;
5344 g_autofree gchar *local_file_path = NULL;
5345 g_autofree gchar *quoted_path = NULL;
5346 g_autofree gchar *old_working_dir = NULL;
5347 g_autolist (NautilusFile) selection = NULL;
5348 g_auto (GStrv) parameters = NULL;
5349 GdkScreen *screen;
5350
5351 launch_parameters = (ScriptLaunchParameters *) user_data;
5352 priv = nautilus_files_view_get_instance_private (launch_parameters->directory_view);
5353
5354 file_uri = nautilus_file_get_uri (launch_parameters->file);
5355 local_file_path = g_filename_from_uri (file_uri, NULL, NULL);
5356 g_assert (local_file_path != NULL);
5357 quoted_path = g_shell_quote (local_file_path);
5358
5359 old_working_dir = change_to_view_directory (launch_parameters->directory_view);
5360
5361 selection = nautilus_view_get_selection (NAUTILUS_VIEW (launch_parameters->directory_view));
5362 set_script_environment_variables (launch_parameters->directory_view, selection);
5363
5364 parameters = get_file_names_as_parameter_array (selection, priv->model);
5365
5366 screen = gtk_widget_get_screen (GTK_WIDGET (launch_parameters->directory_view));
5367
5368 DEBUG ("run_script, script_path=“%s” (omitting script parameters)",
5369 local_file_path);
5370
5371 nautilus_launch_application_from_command_array (screen, quoted_path, FALSE,
5372 (const char * const *) parameters);
5373
5374 unset_script_environment_variables ();
5375 g_chdir (old_working_dir);
5376 }
5377
5378 static void
add_script_to_scripts_menus(NautilusFilesView * view,NautilusFile * file,GMenu * menu)5379 add_script_to_scripts_menus (NautilusFilesView *view,
5380 NautilusFile *file,
5381 GMenu *menu)
5382 {
5383 NautilusFilesViewPrivate *priv;
5384 gchar *name;
5385 g_autofree gchar *uri = NULL;
5386 g_autofree gchar *escaped_uri = NULL;
5387 GdkPixbuf *mimetype_icon;
5388 gchar *action_name, *detailed_action_name;
5389 ScriptLaunchParameters *launch_parameters;
5390 GAction *action;
5391 GMenuItem *menu_item;
5392 const gchar *shortcut;
5393
5394 priv = nautilus_files_view_get_instance_private (view);
5395 launch_parameters = script_launch_parameters_new (file, view);
5396
5397 name = nautilus_file_get_display_name (file);
5398
5399 uri = nautilus_file_get_uri (file);
5400 escaped_uri = g_uri_escape_string (uri, NULL, TRUE);
5401 action_name = g_strconcat ("script_", escaped_uri, NULL);
5402
5403 action = G_ACTION (g_simple_action_new (action_name, NULL));
5404
5405 g_signal_connect_data (action, "activate",
5406 G_CALLBACK (run_script),
5407 launch_parameters,
5408 (GClosureNotify) script_launch_parameters_free, 0);
5409
5410 g_action_map_add_action (G_ACTION_MAP (priv->view_action_group), action);
5411
5412 g_object_unref (action);
5413
5414 detailed_action_name = g_strconcat ("view.", action_name, NULL);
5415 menu_item = g_menu_item_new (name, detailed_action_name);
5416
5417 mimetype_icon = get_menu_icon_for_file (file, GTK_WIDGET (view));
5418 if (mimetype_icon != NULL)
5419 {
5420 g_menu_item_set_icon (menu_item, G_ICON (mimetype_icon));
5421 g_object_unref (mimetype_icon);
5422 }
5423
5424 g_menu_append_item (menu, menu_item);
5425
5426 if ((shortcut = g_hash_table_lookup (script_accels, name)))
5427 {
5428 nautilus_application_set_accelerator (g_application_get_default (),
5429 detailed_action_name, shortcut);
5430 }
5431
5432 g_free (name);
5433 g_free (action_name);
5434 g_free (detailed_action_name);
5435 g_object_unref (menu_item);
5436 }
5437
5438 static gboolean
directory_belongs_in_scripts_menu(const char * uri)5439 directory_belongs_in_scripts_menu (const char *uri)
5440 {
5441 int num_levels;
5442 int i;
5443
5444 if (!g_str_has_prefix (uri, scripts_directory_uri))
5445 {
5446 return FALSE;
5447 }
5448
5449 num_levels = 0;
5450 for (i = scripts_directory_uri_length; uri[i] != '\0'; i++)
5451 {
5452 if (uri[i] == '/')
5453 {
5454 num_levels++;
5455 }
5456 }
5457
5458 if (num_levels > MAX_MENU_LEVELS)
5459 {
5460 return FALSE;
5461 }
5462
5463 return TRUE;
5464 }
5465
5466 /* Expected format: accel script_name */
5467 static void
nautilus_load_custom_accel_for_scripts(void)5468 nautilus_load_custom_accel_for_scripts (void)
5469 {
5470 gchar *path, *contents;
5471 gchar **lines, **result;
5472 GError *error = NULL;
5473 const int max_len = 100;
5474 int i;
5475
5476 path = g_build_filename (g_get_user_config_dir (), SHORTCUTS_PATH, NULL);
5477
5478 if (g_file_get_contents (path, &contents, NULL, &error))
5479 {
5480 lines = g_strsplit (contents, "\n", -1);
5481 for (i = 0; lines[i] && (strstr (lines[i], " ") > 0); i++)
5482 {
5483 result = g_strsplit (lines[i], " ", 2);
5484 g_hash_table_insert (script_accels,
5485 g_strndup (result[1], max_len),
5486 g_strndup (result[0], max_len));
5487 g_strfreev (result);
5488 }
5489
5490 g_free (contents);
5491 g_strfreev (lines);
5492 }
5493 else
5494 {
5495 DEBUG ("Unable to open '%s', error message: %s", path, error->message);
5496 g_clear_error (&error);
5497 }
5498
5499 g_free (path);
5500 }
5501
5502 static GMenu *
update_directory_in_scripts_menu(NautilusFilesView * view,NautilusDirectory * directory)5503 update_directory_in_scripts_menu (NautilusFilesView *view,
5504 NautilusDirectory *directory)
5505 {
5506 GList *file_list, *filtered, *node;
5507 GMenu *menu, *children_menu;
5508 GMenuItem *menu_item;
5509 gboolean any_scripts;
5510 NautilusFile *file;
5511 NautilusDirectory *dir;
5512 char *uri;
5513 gchar *file_name;
5514 int num;
5515
5516 g_return_val_if_fail (NAUTILUS_IS_FILES_VIEW (view), NULL);
5517 g_return_val_if_fail (NAUTILUS_IS_DIRECTORY (directory), NULL);
5518
5519 if (script_accels == NULL)
5520 {
5521 script_accels = g_hash_table_new_full (g_str_hash, g_str_equal,
5522 g_free, g_free);
5523 nautilus_load_custom_accel_for_scripts ();
5524 }
5525
5526 file_list = nautilus_directory_get_file_list (directory);
5527 filtered = nautilus_file_list_filter_hidden (file_list, FALSE);
5528 nautilus_file_list_free (file_list);
5529 menu = g_menu_new ();
5530
5531 filtered = nautilus_file_list_sort_by_display_name (filtered);
5532
5533 num = 0;
5534 any_scripts = FALSE;
5535 for (node = filtered; num < TEMPLATE_LIMIT && node != NULL; node = node->next, num++)
5536 {
5537 file = node->data;
5538 if (nautilus_file_is_directory (file))
5539 {
5540 uri = nautilus_file_get_uri (file);
5541 if (directory_belongs_in_scripts_menu (uri))
5542 {
5543 dir = nautilus_directory_get_by_uri (uri);
5544 add_directory_to_scripts_directory_list (view, dir);
5545
5546 children_menu = update_directory_in_scripts_menu (view, dir);
5547
5548 if (children_menu != NULL)
5549 {
5550 file_name = nautilus_file_get_display_name (file);
5551 menu_item = g_menu_item_new_submenu (file_name,
5552 G_MENU_MODEL (children_menu));
5553 g_menu_append_item (menu, menu_item);
5554 any_scripts = TRUE;
5555 g_object_unref (menu_item);
5556 g_object_unref (children_menu);
5557 g_free (file_name);
5558 }
5559
5560 nautilus_directory_unref (dir);
5561 }
5562 g_free (uri);
5563 }
5564 else if (nautilus_file_is_launchable (file))
5565 {
5566 add_script_to_scripts_menus (view, file, menu);
5567 any_scripts = TRUE;
5568 }
5569 }
5570
5571 nautilus_file_list_free (filtered);
5572
5573 if (!any_scripts)
5574 {
5575 g_object_unref (menu);
5576 menu = NULL;
5577 }
5578
5579 return menu;
5580 }
5581
5582
5583
5584 static void
update_scripts_menu(NautilusFilesView * view,GtkBuilder * builder)5585 update_scripts_menu (NautilusFilesView *view,
5586 GtkBuilder *builder)
5587 {
5588 NautilusFilesViewPrivate *priv;
5589 g_autolist (NautilusDirectory) sorted_copy = NULL;
5590 g_autoptr (NautilusDirectory) directory = NULL;
5591 g_autoptr (GMenu) submenu = NULL;
5592
5593 priv = nautilus_files_view_get_instance_private (view);
5594
5595 sorted_copy = nautilus_directory_list_sort_by_uri
5596 (nautilus_directory_list_copy (priv->scripts_directory_list));
5597
5598 for (GList *dir_l = sorted_copy; dir_l != NULL; dir_l = dir_l->next)
5599 {
5600 g_autofree char *uri = nautilus_directory_get_uri (dir_l->data);
5601 if (!directory_belongs_in_scripts_menu (uri))
5602 {
5603 remove_directory_from_scripts_directory_list (view, dir_l->data);
5604 }
5605 }
5606
5607 directory = nautilus_directory_get_by_uri (scripts_directory_uri);
5608 submenu = update_directory_in_scripts_menu (view, directory);
5609 g_set_object (&priv->scripts_menu, G_MENU_MODEL (submenu));
5610 }
5611
5612 static void
create_template(GSimpleAction * action,GVariant * state,gpointer user_data)5613 create_template (GSimpleAction *action,
5614 GVariant *state,
5615 gpointer user_data)
5616 {
5617 CreateTemplateParameters *parameters;
5618
5619 parameters = user_data;
5620
5621 nautilus_files_view_new_file (parameters->directory_view, NULL, parameters->file);
5622 }
5623
5624 static void
add_template_to_templates_menus(NautilusFilesView * view,NautilusFile * file,GMenu * menu)5625 add_template_to_templates_menus (NautilusFilesView *view,
5626 NautilusFile *file,
5627 GMenu *menu)
5628 {
5629 NautilusFilesViewPrivate *priv;
5630 char *tmp, *uri, *name;
5631 g_autofree gchar *escaped_uri = NULL;
5632 GdkPixbuf *mimetype_icon;
5633 char *action_name, *detailed_action_name;
5634 CreateTemplateParameters *parameters;
5635 GAction *action;
5636 g_autofree char *label = NULL;
5637 GMenuItem *menu_item;
5638
5639 priv = nautilus_files_view_get_instance_private (view);
5640 tmp = nautilus_file_get_display_name (file);
5641 name = eel_filename_strip_extension (tmp);
5642 g_free (tmp);
5643
5644 uri = nautilus_file_get_uri (file);
5645 escaped_uri = g_uri_escape_string (uri, NULL, TRUE);
5646 action_name = g_strconcat ("template_", escaped_uri, NULL);
5647 action = G_ACTION (g_simple_action_new (action_name, NULL));
5648 parameters = create_template_parameters_new (file, view);
5649
5650 g_signal_connect_data (action, "activate",
5651 G_CALLBACK (create_template),
5652 parameters,
5653 (GClosureNotify) create_templates_parameters_free, 0);
5654
5655 g_action_map_add_action (G_ACTION_MAP (priv->view_action_group), action);
5656
5657 detailed_action_name = g_strconcat ("view.", action_name, NULL);
5658 label = eel_str_double_underscores (name);
5659 menu_item = g_menu_item_new (label, detailed_action_name);
5660
5661 mimetype_icon = get_menu_icon_for_file (file, GTK_WIDGET (view));
5662 if (mimetype_icon != NULL)
5663 {
5664 g_menu_item_set_icon (menu_item, G_ICON (mimetype_icon));
5665 g_object_unref (mimetype_icon);
5666 }
5667
5668 g_menu_append_item (menu, menu_item);
5669
5670 g_free (name);
5671 g_free (uri);
5672 g_free (action_name);
5673 g_free (detailed_action_name);
5674 g_object_unref (action);
5675 g_object_unref (menu_item);
5676 }
5677
5678 static void
update_templates_directory(NautilusFilesView * view)5679 update_templates_directory (NautilusFilesView *view)
5680 {
5681 NautilusFilesViewPrivate *priv;
5682 NautilusDirectory *templates_directory;
5683 GList *node, *next;
5684 char *templates_uri;
5685
5686 priv = nautilus_files_view_get_instance_private (view);
5687
5688 for (node = priv->templates_directory_list; node != NULL; node = next)
5689 {
5690 next = node->next;
5691 remove_directory_from_templates_directory_list (view, node->data);
5692 }
5693
5694 if (nautilus_should_use_templates_directory ())
5695 {
5696 templates_uri = nautilus_get_templates_directory_uri ();
5697 templates_directory = nautilus_directory_get_by_uri (templates_uri);
5698 g_free (templates_uri);
5699 add_directory_to_templates_directory_list (view, templates_directory);
5700 nautilus_directory_unref (templates_directory);
5701 }
5702 }
5703
5704 static gboolean
directory_belongs_in_templates_menu(const char * templates_directory_uri,const char * uri)5705 directory_belongs_in_templates_menu (const char *templates_directory_uri,
5706 const char *uri)
5707 {
5708 int num_levels;
5709 int i;
5710
5711 if (templates_directory_uri == NULL)
5712 {
5713 return FALSE;
5714 }
5715
5716 if (!g_str_has_prefix (uri, templates_directory_uri))
5717 {
5718 return FALSE;
5719 }
5720
5721 num_levels = 0;
5722 for (i = strlen (templates_directory_uri); uri[i] != '\0'; i++)
5723 {
5724 if (uri[i] == '/')
5725 {
5726 num_levels++;
5727 }
5728 }
5729
5730 if (num_levels > MAX_MENU_LEVELS)
5731 {
5732 return FALSE;
5733 }
5734
5735 return TRUE;
5736 }
5737
5738 static gboolean
filter_templates_callback(NautilusFile * file,gpointer callback_data)5739 filter_templates_callback (NautilusFile *file,
5740 gpointer callback_data)
5741 {
5742 gboolean show_hidden = GPOINTER_TO_INT (callback_data);
5743
5744 if (nautilus_file_is_hidden_file (file))
5745 {
5746 if (!show_hidden)
5747 {
5748 return FALSE;
5749 }
5750
5751 if (nautilus_file_is_directory (file))
5752 {
5753 return FALSE;
5754 }
5755 }
5756
5757 return TRUE;
5758 }
5759
5760 static GList *
filter_templates(GList * files,gboolean show_hidden)5761 filter_templates (GList *files,
5762 gboolean show_hidden)
5763 {
5764 GList *filtered_files;
5765 GList *removed_files;
5766
5767 filtered_files = nautilus_file_list_filter (files,
5768 &removed_files,
5769 filter_templates_callback,
5770 GINT_TO_POINTER (show_hidden));
5771 nautilus_file_list_free (removed_files);
5772
5773 return filtered_files;
5774 }
5775
5776 static GMenuModel *
update_directory_in_templates_menu(NautilusFilesView * view,NautilusDirectory * directory)5777 update_directory_in_templates_menu (NautilusFilesView *view,
5778 NautilusDirectory *directory)
5779 {
5780 NautilusFilesViewPrivate *priv;
5781 GList *file_list, *filtered, *node;
5782 GMenu *menu;
5783 GMenuItem *menu_item;
5784 gboolean any_templates;
5785 NautilusFile *file;
5786 NautilusDirectory *dir;
5787 char *uri;
5788 char *templates_directory_uri;
5789 int num;
5790
5791 g_return_val_if_fail (NAUTILUS_IS_FILES_VIEW (view), NULL);
5792 g_return_val_if_fail (NAUTILUS_IS_DIRECTORY (directory), NULL);
5793
5794 priv = nautilus_files_view_get_instance_private (view);
5795
5796 file_list = nautilus_directory_get_file_list (directory);
5797
5798 /*
5799 * The nautilus_file_list_filter_hidden() function isn't used here, because
5800 * we want to show hidden files, but not directories. This is a compromise
5801 * to allow creating hidden files but to prevent content from .git directory
5802 * for example. See https://gitlab.gnome.org/GNOME/nautilus/issues/1413.
5803 */
5804 filtered = filter_templates (file_list, priv->show_hidden_files);
5805 nautilus_file_list_free (file_list);
5806 templates_directory_uri = nautilus_get_templates_directory_uri ();
5807 menu = g_menu_new ();
5808
5809 filtered = nautilus_file_list_sort_by_display_name (filtered);
5810
5811 num = 0;
5812 any_templates = FALSE;
5813 for (node = filtered; num < TEMPLATE_LIMIT && node != NULL; node = node->next, num++)
5814 {
5815 file = node->data;
5816 if (nautilus_file_is_directory (file))
5817 {
5818 uri = nautilus_file_get_uri (file);
5819 if (directory_belongs_in_templates_menu (templates_directory_uri, uri))
5820 {
5821 g_autoptr (GMenuModel) children_menu = NULL;
5822
5823 dir = nautilus_directory_get_by_uri (uri);
5824 add_directory_to_templates_directory_list (view, dir);
5825
5826 children_menu = update_directory_in_templates_menu (view, dir);
5827
5828 if (children_menu != NULL)
5829 {
5830 g_autofree char *display_name = NULL;
5831 g_autofree char *label = NULL;
5832
5833 display_name = nautilus_file_get_display_name (file);
5834 label = eel_str_double_underscores (display_name);
5835 menu_item = g_menu_item_new_submenu (label, children_menu);
5836 g_menu_append_item (menu, menu_item);
5837 any_templates = TRUE;
5838 g_object_unref (menu_item);
5839 }
5840
5841 nautilus_directory_unref (dir);
5842 }
5843 g_free (uri);
5844 }
5845 else if (nautilus_file_can_read (file))
5846 {
5847 add_template_to_templates_menus (view, file, menu);
5848 any_templates = TRUE;
5849 }
5850 }
5851
5852 nautilus_file_list_free (filtered);
5853 g_free (templates_directory_uri);
5854
5855 if (!any_templates)
5856 {
5857 g_object_unref (menu);
5858 menu = NULL;
5859 }
5860
5861 return G_MENU_MODEL (menu);
5862 }
5863
5864
5865
5866 static void
update_templates_menu(NautilusFilesView * view,GtkBuilder * builder)5867 update_templates_menu (NautilusFilesView *view,
5868 GtkBuilder *builder)
5869 {
5870 NautilusFilesViewPrivate *priv;
5871 g_autolist (NautilusDirectory) sorted_copy = NULL;
5872 g_autoptr (NautilusDirectory) directory = NULL;
5873 g_autoptr (GMenuModel) submenu = NULL;
5874 g_autofree char *templates_directory_uri = NULL;
5875
5876 priv = nautilus_files_view_get_instance_private (view);
5877
5878 if (!nautilus_should_use_templates_directory ())
5879 {
5880 nautilus_view_set_templates_menu (NAUTILUS_VIEW (view), NULL);
5881 return;
5882 }
5883
5884 templates_directory_uri = nautilus_get_templates_directory_uri ();
5885 sorted_copy = nautilus_directory_list_sort_by_uri
5886 (nautilus_directory_list_copy (priv->templates_directory_list));
5887
5888 for (GList *dir_l = sorted_copy; dir_l != NULL; dir_l = dir_l->next)
5889 {
5890 g_autofree char *uri = nautilus_directory_get_uri (dir_l->data);
5891 if (!directory_belongs_in_templates_menu (templates_directory_uri, uri))
5892 {
5893 remove_directory_from_templates_directory_list (view, dir_l->data);
5894 }
5895 }
5896
5897 directory = nautilus_directory_get_by_uri (templates_directory_uri);
5898 submenu = update_directory_in_templates_menu (view, directory);
5899
5900 nautilus_view_set_templates_menu (NAUTILUS_VIEW (view), submenu);
5901 }
5902
5903
5904 static void
action_open_scripts_folder(GSimpleAction * action,GVariant * state,gpointer user_data)5905 action_open_scripts_folder (GSimpleAction *action,
5906 GVariant *state,
5907 gpointer user_data)
5908 {
5909 static GFile *location = NULL;
5910
5911 if (location == NULL)
5912 {
5913 location = g_file_new_for_uri (scripts_directory_uri);
5914 }
5915
5916 nautilus_application_open_location_full (NAUTILUS_APPLICATION (g_application_get_default ()),
5917 location, 0, NULL, NULL, NULL);
5918 }
5919
5920 typedef struct _CopyCallbackData
5921 {
5922 NautilusFilesView *view;
5923 GList *selection;
5924 gboolean is_move;
5925 } CopyCallbackData;
5926
5927 static void
copy_data_free(CopyCallbackData * data)5928 copy_data_free (CopyCallbackData *data)
5929 {
5930 nautilus_file_list_free (data->selection);
5931 g_free (data);
5932 }
5933
5934 static gboolean
uri_is_parent_of_selection(GList * selection,const char * uri)5935 uri_is_parent_of_selection (GList *selection,
5936 const char *uri)
5937 {
5938 gboolean found;
5939 GList *l;
5940 GFile *file;
5941
5942 found = FALSE;
5943
5944 file = g_file_new_for_uri (uri);
5945 for (l = selection; !found && l != NULL; l = l->next)
5946 {
5947 GFile *parent;
5948 parent = nautilus_file_get_parent_location (l->data);
5949 found = g_file_equal (file, parent);
5950 g_object_unref (parent);
5951 }
5952 g_object_unref (file);
5953 return found;
5954 }
5955
5956 static void
on_destination_dialog_folder_changed(GtkFileChooser * chooser,gpointer user_data)5957 on_destination_dialog_folder_changed (GtkFileChooser *chooser,
5958 gpointer user_data)
5959 {
5960 CopyCallbackData *copy_data = user_data;
5961 char *uri;
5962 gboolean found;
5963
5964 uri = gtk_file_chooser_get_current_folder_uri (chooser);
5965 found = uri_is_parent_of_selection (copy_data->selection, uri);
5966 gtk_dialog_set_response_sensitive (GTK_DIALOG (chooser), GTK_RESPONSE_OK, !found);
5967 g_free (uri);
5968 }
5969
5970 static void
on_destination_dialog_response(GtkDialog * dialog,gint response_id,gpointer user_data)5971 on_destination_dialog_response (GtkDialog *dialog,
5972 gint response_id,
5973 gpointer user_data)
5974 {
5975 CopyCallbackData *copy_data = user_data;
5976
5977 if (response_id == GTK_RESPONSE_OK)
5978 {
5979 char *target_uri;
5980 GList *uris, *l;
5981
5982 target_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
5983
5984 uris = NULL;
5985 for (l = copy_data->selection; l != NULL; l = l->next)
5986 {
5987 uris = g_list_prepend (uris,
5988 nautilus_file_get_uri ((NautilusFile *) l->data));
5989 }
5990 uris = g_list_reverse (uris);
5991
5992 nautilus_files_view_move_copy_items (copy_data->view, uris, target_uri,
5993 copy_data->is_move ? GDK_ACTION_MOVE : GDK_ACTION_COPY);
5994
5995 g_list_free_full (uris, g_free);
5996 g_free (target_uri);
5997 }
5998
5999 copy_data_free (copy_data);
6000 gtk_widget_destroy (GTK_WIDGET (dialog));
6001 }
6002
6003 static gboolean
destination_dialog_filter_cb(const GtkFileFilterInfo * filter_info,gpointer user_data)6004 destination_dialog_filter_cb (const GtkFileFilterInfo *filter_info,
6005 gpointer user_data)
6006 {
6007 GList *selection = user_data;
6008 GList *l;
6009
6010 for (l = selection; l != NULL; l = l->next)
6011 {
6012 char *uri;
6013 uri = nautilus_file_get_uri (l->data);
6014 if (strcmp (uri, filter_info->uri) == 0)
6015 {
6016 g_free (uri);
6017 return FALSE;
6018 }
6019 g_free (uri);
6020 }
6021
6022 return TRUE;
6023 }
6024
6025 static GList *
get_selected_folders(GList * selection)6026 get_selected_folders (GList *selection)
6027 {
6028 GList *folders;
6029 GList *l;
6030
6031 folders = NULL;
6032 for (l = selection; l != NULL; l = l->next)
6033 {
6034 if (nautilus_file_is_directory (l->data))
6035 {
6036 folders = g_list_prepend (folders, nautilus_file_ref (l->data));
6037 }
6038 }
6039 return g_list_reverse (folders);
6040 }
6041
6042 static void
copy_or_move_selection(NautilusFilesView * view,gboolean is_move)6043 copy_or_move_selection (NautilusFilesView *view,
6044 gboolean is_move)
6045 {
6046 NautilusFilesViewPrivate *priv;
6047 GtkWidget *dialog;
6048 char *uri;
6049 CopyCallbackData *copy_data;
6050 GList *selection;
6051 const gchar *title;
6052 NautilusDirectory *directory;
6053
6054 priv = nautilus_files_view_get_instance_private (view);
6055
6056 if (is_move)
6057 {
6058 title = _("Select Move Destination");
6059 }
6060 else
6061 {
6062 title = _("Select Copy Destination");
6063 }
6064
6065 selection = nautilus_files_view_get_selection_for_file_transfer (view);
6066
6067 dialog = gtk_file_chooser_dialog_new (title,
6068 GTK_WINDOW (nautilus_files_view_get_window (view)),
6069 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
6070 _("_Cancel"), GTK_RESPONSE_CANCEL,
6071 _("_Select"), GTK_RESPONSE_OK,
6072 NULL);
6073 gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (dialog), FALSE);
6074
6075 gtk_dialog_set_default_response (GTK_DIALOG (dialog),
6076 GTK_RESPONSE_OK);
6077
6078 gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
6079 gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
6080
6081 copy_data = g_new0 (CopyCallbackData, 1);
6082 copy_data->view = view;
6083 copy_data->selection = selection;
6084 copy_data->is_move = is_move;
6085
6086 if (selection != NULL)
6087 {
6088 GtkFileFilter *filter;
6089 GList *folders;
6090
6091 folders = get_selected_folders (selection);
6092
6093 filter = gtk_file_filter_new ();
6094 gtk_file_filter_add_custom (filter,
6095 GTK_FILE_FILTER_URI,
6096 destination_dialog_filter_cb,
6097 folders,
6098 (GDestroyNotify) nautilus_file_list_free);
6099 gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), filter);
6100 }
6101
6102
6103 if (nautilus_view_is_searching (NAUTILUS_VIEW (view)))
6104 {
6105 directory = nautilus_search_directory_get_base_model (NAUTILUS_SEARCH_DIRECTORY (priv->model));
6106 uri = nautilus_directory_get_uri (directory);
6107 }
6108 else
6109 {
6110 uri = nautilus_directory_get_uri (priv->model);
6111 }
6112
6113 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dialog), uri);
6114 g_free (uri);
6115 g_signal_connect (dialog, "current-folder-changed",
6116 G_CALLBACK (on_destination_dialog_folder_changed),
6117 copy_data);
6118 g_signal_connect (dialog, "response",
6119 G_CALLBACK (on_destination_dialog_response),
6120 copy_data);
6121
6122 gtk_widget_show_all (dialog);
6123 }
6124
6125 static void
action_copy(GSimpleAction * action,GVariant * state,gpointer user_data)6126 action_copy (GSimpleAction *action,
6127 GVariant *state,
6128 gpointer user_data)
6129 {
6130 NautilusFilesView *view;
6131 GtkClipboard *clipboard;
6132 GList *selection;
6133
6134 view = NAUTILUS_FILES_VIEW (user_data);
6135
6136 selection = nautilus_files_view_get_selection_for_file_transfer (view);
6137 clipboard = nautilus_clipboard_get (GTK_WIDGET (view));
6138 nautilus_clipboard_prepare_for_files (clipboard, selection, FALSE);
6139
6140 nautilus_file_list_free (selection);
6141 }
6142
6143 static void
action_cut(GSimpleAction * action,GVariant * state,gpointer user_data)6144 action_cut (GSimpleAction *action,
6145 GVariant *state,
6146 gpointer user_data)
6147 {
6148 NautilusFilesView *view;
6149 GList *selection;
6150 GtkClipboard *clipboard;
6151
6152 view = NAUTILUS_FILES_VIEW (user_data);
6153
6154 selection = nautilus_files_view_get_selection_for_file_transfer (view);
6155 clipboard = nautilus_clipboard_get (GTK_WIDGET (view));
6156 nautilus_clipboard_prepare_for_files (clipboard, selection, TRUE);
6157
6158 nautilus_file_list_free (selection);
6159 }
6160
6161 static void
action_create_links_in_place(GSimpleAction * action,GVariant * state,gpointer user_data)6162 action_create_links_in_place (GSimpleAction *action,
6163 GVariant *state,
6164 gpointer user_data)
6165 {
6166 NautilusFilesView *view;
6167 GList *selection;
6168 GList *item_uris;
6169 GList *l;
6170 char *destination_uri;
6171
6172 view = NAUTILUS_FILES_VIEW (user_data);
6173
6174 selection = nautilus_files_view_get_selection_for_file_transfer (view);
6175
6176 item_uris = NULL;
6177 for (l = selection; l != NULL; l = l->next)
6178 {
6179 item_uris = g_list_prepend (item_uris, nautilus_file_get_uri (l->data));
6180 }
6181 item_uris = g_list_reverse (item_uris);
6182
6183 destination_uri = nautilus_files_view_get_backing_uri (view);
6184
6185 nautilus_files_view_move_copy_items (view, item_uris, destination_uri,
6186 GDK_ACTION_LINK);
6187
6188 g_list_free_full (item_uris, g_free);
6189 nautilus_file_list_free (selection);
6190 }
6191
6192 static void
action_copy_to(GSimpleAction * action,GVariant * state,gpointer user_data)6193 action_copy_to (GSimpleAction *action,
6194 GVariant *state,
6195 gpointer user_data)
6196 {
6197 NautilusFilesView *view;
6198
6199 view = NAUTILUS_FILES_VIEW (user_data);
6200 copy_or_move_selection (view, FALSE);
6201 }
6202
6203 static void
action_move_to(GSimpleAction * action,GVariant * state,gpointer user_data)6204 action_move_to (GSimpleAction *action,
6205 GVariant *state,
6206 gpointer user_data)
6207 {
6208 NautilusFilesView *view;
6209
6210 view = NAUTILUS_FILES_VIEW (user_data);
6211 copy_or_move_selection (view, TRUE);
6212 }
6213
6214 typedef struct
6215 {
6216 NautilusFilesView *view;
6217 NautilusFile *target;
6218 } PasteIntoData;
6219
6220 static void
paste_into_clipboard_received_callback(GtkClipboard * clipboard,GtkSelectionData * selection_data,gpointer callback_data)6221 paste_into_clipboard_received_callback (GtkClipboard *clipboard,
6222 GtkSelectionData *selection_data,
6223 gpointer callback_data)
6224 {
6225 NautilusFilesViewPrivate *priv;
6226 PasteIntoData *data;
6227 NautilusFilesView *view;
6228 char *directory_uri;
6229
6230 data = (PasteIntoData *) callback_data;
6231
6232 view = NAUTILUS_FILES_VIEW (data->view);
6233 priv = nautilus_files_view_get_instance_private (view);
6234
6235 if (priv->slot != NULL)
6236 {
6237 directory_uri = nautilus_file_get_activation_uri (data->target);
6238
6239 paste_clipboard_data (view, selection_data, directory_uri);
6240
6241 g_free (directory_uri);
6242 }
6243
6244 g_object_unref (view);
6245 nautilus_file_unref (data->target);
6246 g_free (data);
6247 }
6248
6249 static void
paste_into(NautilusFilesView * view,NautilusFile * target)6250 paste_into (NautilusFilesView *view,
6251 NautilusFile *target)
6252 {
6253 PasteIntoData *data;
6254
6255 g_assert (NAUTILUS_IS_FILES_VIEW (view));
6256 g_assert (NAUTILUS_IS_FILE (target));
6257
6258 data = g_new (PasteIntoData, 1);
6259
6260 data->view = g_object_ref (view);
6261 data->target = nautilus_file_ref (target);
6262
6263 gtk_clipboard_request_contents (nautilus_clipboard_get (GTK_WIDGET (view)),
6264 nautilus_clipboard_get_atom (),
6265 paste_into_clipboard_received_callback,
6266 data);
6267 }
6268
6269 static void
action_paste_files_into(GSimpleAction * action,GVariant * state,gpointer user_data)6270 action_paste_files_into (GSimpleAction *action,
6271 GVariant *state,
6272 gpointer user_data)
6273 {
6274 NautilusFilesView *view;
6275 g_autolist (NautilusFile) selection = NULL;
6276
6277 view = NAUTILUS_FILES_VIEW (user_data);
6278 selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
6279 if (selection != NULL)
6280 {
6281 paste_into (view, NAUTILUS_FILE (selection->data));
6282 }
6283 }
6284
6285 static void
real_action_rename(NautilusFilesView * view)6286 real_action_rename (NautilusFilesView *view)
6287 {
6288 NautilusFile *file;
6289 g_autolist (NautilusFile) selection = NULL;
6290 GtkWidget *dialog;
6291
6292 g_assert (NAUTILUS_IS_FILES_VIEW (view));
6293
6294 selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
6295
6296 if (selection != NULL)
6297 {
6298 /* If there is more than one file selected, invoke a batch renamer */
6299 if (selection->next != NULL)
6300 {
6301 GdkCursor *cursor;
6302 GdkDisplay *display;
6303
6304 display = gtk_widget_get_display (GTK_WIDGET (nautilus_files_view_get_window (view)));
6305 cursor = gdk_cursor_new_from_name (display, "progress");
6306 gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (nautilus_files_view_get_window (view))),
6307 cursor);
6308 g_object_unref (cursor);
6309
6310 dialog = nautilus_batch_rename_dialog_new (selection,
6311 nautilus_files_view_get_model (view),
6312 nautilus_files_view_get_window (view));
6313
6314 gtk_widget_show (GTK_WIDGET (dialog));
6315 }
6316 else
6317 {
6318 file = NAUTILUS_FILE (selection->data);
6319
6320 nautilus_files_view_rename_file_popover_new (view, file);
6321 }
6322 }
6323 }
6324
6325 static void
action_rename(GSimpleAction * action,GVariant * state,gpointer user_data)6326 action_rename (GSimpleAction *action,
6327 GVariant *state,
6328 gpointer user_data)
6329 {
6330 real_action_rename (NAUTILUS_FILES_VIEW (user_data));
6331 }
6332
6333 typedef struct
6334 {
6335 NautilusFilesView *view;
6336 GHashTable *added_locations;
6337 } ExtractData;
6338
6339 static void
extract_done(GList * outputs,gpointer user_data)6340 extract_done (GList *outputs,
6341 gpointer user_data)
6342 {
6343 NautilusFilesViewPrivate *priv;
6344 ExtractData *data;
6345 GList *l;
6346 gboolean all_files_acknowledged;
6347
6348 data = user_data;
6349
6350 if (data->view == NULL)
6351 {
6352 goto out;
6353 }
6354
6355 priv = nautilus_files_view_get_instance_private (data->view);
6356
6357 g_signal_handlers_disconnect_by_func (data->view,
6358 G_CALLBACK (track_newly_added_locations),
6359 data->added_locations);
6360
6361 if (outputs == NULL)
6362 {
6363 goto out;
6364 }
6365
6366 all_files_acknowledged = TRUE;
6367 for (l = outputs; l && all_files_acknowledged; l = l->next)
6368 {
6369 all_files_acknowledged = g_hash_table_contains (data->added_locations,
6370 l->data);
6371 }
6372
6373 if (all_files_acknowledged)
6374 {
6375 GList *selection = NULL;
6376
6377 for (l = outputs; l != NULL; l = l->next)
6378 {
6379 selection = g_list_prepend (selection,
6380 nautilus_file_get (l->data));
6381 }
6382
6383 nautilus_files_view_set_selection (NAUTILUS_VIEW (data->view),
6384 selection);
6385 nautilus_files_view_reveal_selection (data->view);
6386
6387 nautilus_file_list_free (selection);
6388 }
6389 else
6390 {
6391 for (l = outputs; l != NULL; l = l->next)
6392 {
6393 gboolean acknowledged;
6394
6395 acknowledged = g_hash_table_contains (data->added_locations,
6396 l->data);
6397
6398 g_hash_table_insert (priv->pending_reveal,
6399 nautilus_file_get (l->data),
6400 GUINT_TO_POINTER (acknowledged));
6401 }
6402 }
6403 out:
6404 g_hash_table_destroy (data->added_locations);
6405
6406 if (data->view != NULL)
6407 {
6408 g_object_remove_weak_pointer (G_OBJECT (data->view),
6409 (gpointer *) &data->view);
6410 }
6411
6412 g_free (data);
6413 }
6414
6415 static void
extract_files(NautilusFilesView * view,GList * files,GFile * destination_directory)6416 extract_files (NautilusFilesView *view,
6417 GList *files,
6418 GFile *destination_directory)
6419 {
6420 GList *locations = NULL;
6421 GList *l;
6422 gboolean extracting_to_current_directory;
6423
6424 if (files == NULL)
6425 {
6426 return;
6427 }
6428
6429 for (l = files; l != NULL; l = l->next)
6430 {
6431 locations = g_list_prepend (locations,
6432 nautilus_file_get_location (l->data));
6433 }
6434
6435 locations = g_list_reverse (locations);
6436
6437 extracting_to_current_directory = g_file_equal (destination_directory,
6438 nautilus_view_get_location (NAUTILUS_VIEW (view)));
6439
6440 if (extracting_to_current_directory)
6441 {
6442 ExtractData *data;
6443
6444 data = g_new (ExtractData, 1);
6445 data->view = view;
6446 data->added_locations = g_hash_table_new_full (g_file_hash,
6447 (GEqualFunc) g_file_equal,
6448 g_object_unref, NULL);
6449
6450
6451 g_object_add_weak_pointer (G_OBJECT (data->view),
6452 (gpointer *) &data->view);
6453
6454 g_signal_connect_data (view,
6455 "add-files",
6456 G_CALLBACK (track_newly_added_locations),
6457 data->added_locations,
6458 NULL,
6459 G_CONNECT_AFTER);
6460
6461 nautilus_file_operations_extract_files (locations,
6462 destination_directory,
6463 nautilus_files_view_get_containing_window (view),
6464 NULL,
6465 extract_done,
6466 data);
6467 }
6468 else
6469 {
6470 nautilus_file_operations_extract_files (locations,
6471 destination_directory,
6472 nautilus_files_view_get_containing_window (view),
6473 NULL,
6474 NULL,
6475 NULL);
6476 }
6477
6478 g_list_free_full (locations, g_object_unref);
6479 }
6480
6481 typedef struct
6482 {
6483 NautilusFilesView *view;
6484 GList *files;
6485 } ExtractToData;
6486
6487 static void
on_extract_destination_dialog_response(GtkDialog * dialog,gint response_id,gpointer user_data)6488 on_extract_destination_dialog_response (GtkDialog *dialog,
6489 gint response_id,
6490 gpointer user_data)
6491 {
6492 ExtractToData *data;
6493
6494 data = user_data;
6495
6496 if (response_id == GTK_RESPONSE_OK)
6497 {
6498 g_autoptr (GFile) destination_directory = NULL;
6499
6500 destination_directory = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
6501
6502 extract_files (data->view, data->files, destination_directory);
6503 }
6504
6505 gtk_widget_destroy (GTK_WIDGET (dialog));
6506 nautilus_file_list_free (data->files);
6507 g_free (data);
6508 }
6509
6510 static void
extract_files_to_chosen_location(NautilusFilesView * view,GList * files)6511 extract_files_to_chosen_location (NautilusFilesView *view,
6512 GList *files)
6513 {
6514 NautilusFilesViewPrivate *priv;
6515 ExtractToData *data;
6516 GtkWidget *dialog;
6517 g_autofree char *uri = NULL;
6518
6519 priv = nautilus_files_view_get_instance_private (view);
6520
6521 if (files == NULL)
6522 {
6523 return;
6524 }
6525
6526 data = g_new (ExtractToData, 1);
6527
6528 dialog = gtk_file_chooser_dialog_new (_("Select Extract Destination"),
6529 GTK_WINDOW (nautilus_files_view_get_window (view)),
6530 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
6531 _("_Cancel"), GTK_RESPONSE_CANCEL,
6532 _("_Select"), GTK_RESPONSE_OK,
6533 NULL);
6534 gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (dialog), FALSE);
6535
6536 gtk_dialog_set_default_response (GTK_DIALOG (dialog),
6537 GTK_RESPONSE_OK);
6538
6539 gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
6540 gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
6541
6542 /* The file chooser will not be able to display the search directory,
6543 * so we need to get the base directory of the search if we are, in fact,
6544 * in search.
6545 */
6546 if (nautilus_view_is_searching (NAUTILUS_VIEW (view)))
6547 {
6548 NautilusSearchDirectory *search_directory;
6549 NautilusDirectory *directory;
6550
6551 search_directory = NAUTILUS_SEARCH_DIRECTORY (priv->model);
6552 directory = nautilus_search_directory_get_base_model (search_directory);
6553 uri = nautilus_directory_get_uri (directory);
6554 }
6555 else
6556 {
6557 uri = nautilus_directory_get_uri (priv->model);
6558 }
6559
6560 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dialog), uri);
6561
6562 data->view = view;
6563 data->files = nautilus_file_list_copy (files);
6564
6565 g_signal_connect (dialog, "response",
6566 G_CALLBACK (on_extract_destination_dialog_response),
6567 data);
6568
6569 gtk_widget_show_all (dialog);
6570 }
6571
6572 static void
action_extract_here(GSimpleAction * action,GVariant * state,gpointer user_data)6573 action_extract_here (GSimpleAction *action,
6574 GVariant *state,
6575 gpointer user_data)
6576 {
6577 NautilusFilesView *view;
6578 g_autolist (NautilusFile) selection = NULL;
6579 g_autoptr (GFile) location = NULL;
6580 g_autoptr (GFile) parent = NULL;
6581
6582 view = NAUTILUS_FILES_VIEW (user_data);
6583
6584 selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
6585 location = nautilus_file_get_location (NAUTILUS_FILE (g_list_first (selection)->data));
6586 /* Get a parent from a random file. We assume all files has a common parent.
6587 * But don't assume the parent is the view location, since that's not the
6588 * case in list view when expand-folder setting is set
6589 */
6590 parent = g_file_get_parent (location);
6591
6592 extract_files (view, selection, parent);
6593 }
6594
6595 static void
action_extract_to(GSimpleAction * action,GVariant * state,gpointer user_data)6596 action_extract_to (GSimpleAction *action,
6597 GVariant *state,
6598 gpointer user_data)
6599 {
6600 NautilusFilesView *view;
6601 g_autolist (NautilusFile) selection = NULL;
6602
6603 view = NAUTILUS_FILES_VIEW (user_data);
6604
6605 selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
6606
6607 extract_files_to_chosen_location (view, selection);
6608 }
6609
6610 static void
action_compress(GSimpleAction * action,GVariant * state,gpointer user_data)6611 action_compress (GSimpleAction *action,
6612 GVariant *state,
6613 gpointer user_data)
6614 {
6615 NautilusFilesView *view = user_data;
6616
6617 nautilus_files_view_compress_dialog_new (view);
6618 }
6619
6620 static gboolean
can_run_in_terminal(GList * selection)6621 can_run_in_terminal (GList *selection)
6622 {
6623 NautilusFile *file;
6624
6625 if (g_list_length (selection) != 1)
6626 {
6627 return FALSE;
6628 }
6629
6630 file = NAUTILUS_FILE (selection->data);
6631
6632 if (nautilus_file_is_launchable (file) &&
6633 nautilus_file_contains_text (file))
6634 {
6635 g_autofree gchar *activation_uri = NULL;
6636 g_autofree gchar *executable_path = NULL;
6637
6638 activation_uri = nautilus_file_get_activation_uri (file);
6639 executable_path = g_filename_from_uri (activation_uri, NULL, NULL);
6640
6641 if (executable_path != NULL)
6642 {
6643 return TRUE;
6644 }
6645 }
6646
6647 return FALSE;
6648 }
6649
6650 static void
action_run_in_terminal(GSimpleAction * action,GVariant * state,gpointer user_data)6651 action_run_in_terminal (GSimpleAction *action,
6652 GVariant *state,
6653 gpointer user_data)
6654 {
6655 NautilusFilesView *view;
6656 g_autolist (NautilusFile) selection = NULL;
6657 g_autofree char *old_working_dir = NULL;
6658 g_autofree char *uri = NULL;
6659 g_autofree char *executable_path = NULL;
6660 g_autofree char *quoted_path = NULL;
6661 GtkWindow *parent_window;
6662 GdkScreen *screen;
6663
6664 g_assert (NAUTILUS_IS_FILES_VIEW (user_data));
6665
6666 view = NAUTILUS_FILES_VIEW (user_data);
6667
6668 selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
6669
6670 if (!can_run_in_terminal (selection))
6671 {
6672 return;
6673 }
6674
6675 old_working_dir = change_to_view_directory (view);
6676
6677 uri = nautilus_file_get_activation_uri (NAUTILUS_FILE (selection->data));
6678 executable_path = g_filename_from_uri (uri, NULL, NULL);
6679 quoted_path = g_shell_quote (executable_path);
6680
6681 parent_window = nautilus_files_view_get_containing_window (view);
6682 screen = gtk_widget_get_screen (GTK_WIDGET (parent_window));
6683
6684 DEBUG ("Launching in terminal %s", quoted_path);
6685
6686 nautilus_launch_application_from_command (screen, quoted_path, TRUE, NULL);
6687
6688 g_chdir (old_working_dir);
6689 }
6690
6691 #define BG_KEY_PRIMARY_COLOR "primary-color"
6692 #define BG_KEY_SECONDARY_COLOR "secondary-color"
6693 #define BG_KEY_COLOR_TYPE "color-shading-type"
6694 #define BG_KEY_PICTURE_PLACEMENT "picture-options"
6695 #define BG_KEY_PICTURE_URI "picture-uri"
6696
6697 static void
set_uri_as_wallpaper(const char * uri)6698 set_uri_as_wallpaper (const char *uri)
6699 {
6700 GSettings *settings;
6701
6702 settings = gnome_background_preferences;
6703
6704 g_settings_delay (settings);
6705
6706 if (uri == NULL)
6707 {
6708 uri = "";
6709 }
6710
6711 g_settings_set_string (settings, BG_KEY_PICTURE_URI, uri);
6712 g_settings_set_string (settings, BG_KEY_PRIMARY_COLOR, "#000000");
6713 g_settings_set_string (settings, BG_KEY_SECONDARY_COLOR, "#000000");
6714 g_settings_set_enum (settings, BG_KEY_COLOR_TYPE, G_DESKTOP_BACKGROUND_SHADING_SOLID);
6715 g_settings_set_enum (settings, BG_KEY_PICTURE_PLACEMENT, G_DESKTOP_BACKGROUND_STYLE_ZOOM);
6716
6717 /* Apply changes atomically. */
6718 g_settings_apply (settings);
6719 }
6720
6721 static void
wallpaper_copy_done_callback(GHashTable * debuting_files,gboolean success,gpointer data)6722 wallpaper_copy_done_callback (GHashTable *debuting_files,
6723 gboolean success,
6724 gpointer data)
6725 {
6726 GHashTableIter iter;
6727 gpointer key, value;
6728
6729 g_hash_table_iter_init (&iter, debuting_files);
6730 while (g_hash_table_iter_next (&iter, &key, &value))
6731 {
6732 char *uri;
6733 uri = g_file_get_uri (G_FILE (key));
6734 set_uri_as_wallpaper (uri);
6735 g_free (uri);
6736 break;
6737 }
6738 }
6739
6740 static gboolean
can_set_wallpaper(GList * selection)6741 can_set_wallpaper (GList *selection)
6742 {
6743 NautilusFile *file;
6744
6745 if (g_list_length (selection) != 1)
6746 {
6747 return FALSE;
6748 }
6749
6750 file = NAUTILUS_FILE (selection->data);
6751 if (!nautilus_file_is_mime_type (file, "image/*"))
6752 {
6753 return FALSE;
6754 }
6755
6756 /* FIXME: check file size? */
6757
6758 return TRUE;
6759 }
6760
6761 #ifdef HAVE_LIBPORTAL
6762 typedef struct
6763 {
6764 NautilusFile *file;
6765 NautilusFilesView *view;
6766 } WallpaperData;
6767
6768 static void
set_wallpaper_with_portal_cb(GObject * source,GAsyncResult * result,gpointer user_data)6769 set_wallpaper_with_portal_cb (GObject *source,
6770 GAsyncResult *result,
6771 gpointer user_data)
6772 {
6773 XdpPortal *portal = XDP_PORTAL (source);
6774 g_autoptr (GError) error = NULL;
6775 WallpaperData *data = user_data;
6776
6777 if (!xdp_portal_set_wallpaper_finish (portal, result, &error)
6778 && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
6779 {
6780 g_warning ("Failed to set wallpaper via portal: %s", error->message);
6781 set_wallpaper_fallback (data->file, data->view);
6782 }
6783
6784 nautilus_file_unref (data->file);
6785 g_object_unref (data->view);
6786 g_free (data);
6787 }
6788
6789 static void
set_wallpaper_with_portal(NautilusFile * file,gpointer user_data)6790 set_wallpaper_with_portal (NautilusFile *file,
6791 gpointer user_data)
6792 {
6793 g_autoptr (XdpPortal) portal = NULL;
6794 g_autofree gchar *uri = NULL;
6795 XdpParent *parent = NULL;
6796 GtkWidget *toplevel;
6797 WallpaperData *data;
6798
6799 data = g_new0 (WallpaperData, 1);
6800 data->file = nautilus_file_ref (file);
6801 data->view = g_object_ref (user_data);
6802
6803 portal = xdp_portal_new ();
6804 toplevel = gtk_widget_get_ancestor (GTK_WIDGET (user_data), GTK_TYPE_WINDOW);
6805 parent = xdp_parent_new_gtk (GTK_WINDOW (toplevel));
6806 uri = nautilus_file_get_uri (file);
6807
6808 xdp_portal_set_wallpaper (portal,
6809 parent,
6810 uri,
6811 XDP_WALLPAPER_FLAG_BACKGROUND | XDP_WALLPAPER_FLAG_PREVIEW,
6812 NULL,
6813 set_wallpaper_with_portal_cb,
6814 data);
6815 xdp_parent_free (parent);
6816 }
6817 #endif /* HAVE_LIBPORTAL */
6818
6819 static void
set_wallpaper_fallback(NautilusFile * file,gpointer user_data)6820 set_wallpaper_fallback (NautilusFile *file,
6821 gpointer user_data)
6822 {
6823 g_autoptr (GFile) target = NULL;
6824 g_autofree char *file_uri = NULL;
6825 g_autoptr (GFile) file_parent = NULL;
6826
6827 /* Copy the item to Pictures/Wallpaper (internationalized),
6828 * if it's not already there, since it may be remote.
6829 * Then set it as the current wallpaper. */
6830 target = g_file_new_build_filename (g_get_user_special_dir (G_USER_DIRECTORY_PICTURES),
6831 _("Wallpapers"),
6832 NULL);
6833 g_file_make_directory_with_parents (target, NULL, NULL);
6834
6835 file_parent = nautilus_file_get_parent_location (file);
6836 file_uri = nautilus_file_get_uri (file);
6837
6838 if (!g_file_equal (file_parent, target))
6839 {
6840 g_autofree char *target_uri = g_file_get_uri (target);
6841 g_autoptr (GList) uris = g_list_prepend (NULL, file_uri);
6842
6843 nautilus_file_operations_copy_move (uris,
6844 target_uri,
6845 GDK_ACTION_COPY,
6846 GTK_WIDGET (user_data),
6847 NULL,
6848 wallpaper_copy_done_callback,
6849 NULL);
6850 }
6851 else
6852 {
6853 set_uri_as_wallpaper (file_uri);
6854 }
6855 }
6856
6857 static void
action_set_as_wallpaper(GSimpleAction * action,GVariant * state,gpointer user_data)6858 action_set_as_wallpaper (GSimpleAction *action,
6859 GVariant *state,
6860 gpointer user_data)
6861 {
6862 g_autolist (NautilusFile) selection = NULL;
6863
6864 g_assert (NAUTILUS_IS_FILES_VIEW (user_data));
6865
6866 selection = nautilus_view_get_selection (user_data);
6867 if (can_set_wallpaper (selection))
6868 {
6869 NautilusFile *file;
6870
6871 file = NAUTILUS_FILE (selection->data);
6872
6873 #ifdef HAVE_LIBPORTAL
6874 set_wallpaper_with_portal (file, user_data);
6875 #else
6876 set_wallpaper_fallback (file, user_data);
6877 #endif
6878 }
6879 }
6880
6881 static void
file_mount_callback(NautilusFile * file,GFile * result_location,GError * error,gpointer callback_data)6882 file_mount_callback (NautilusFile *file,
6883 GFile *result_location,
6884 GError *error,
6885 gpointer callback_data)
6886 {
6887 NautilusFilesView *view;
6888
6889 view = NAUTILUS_FILES_VIEW (callback_data);
6890
6891 if (error != NULL &&
6892 (error->domain != G_IO_ERROR ||
6893 (error->code != G_IO_ERROR_CANCELLED &&
6894 error->code != G_IO_ERROR_FAILED_HANDLED &&
6895 error->code != G_IO_ERROR_ALREADY_MOUNTED)))
6896 {
6897 char *text;
6898 char *name;
6899 name = nautilus_file_get_display_name (file);
6900 /* Translators: %s is a file name formatted for display */
6901 text = g_strdup_printf (_("Unable to access “%s”"), name);
6902 show_dialog (text,
6903 error->message,
6904 GTK_WINDOW (nautilus_files_view_get_window (view)),
6905 GTK_MESSAGE_ERROR);
6906 g_free (text);
6907 g_free (name);
6908 }
6909 }
6910
6911 static void
file_unmount_callback(NautilusFile * file,GFile * result_location,GError * error,gpointer callback_data)6912 file_unmount_callback (NautilusFile *file,
6913 GFile *result_location,
6914 GError *error,
6915 gpointer callback_data)
6916 {
6917 NautilusFilesView *view;
6918
6919 view = NAUTILUS_FILES_VIEW (callback_data);
6920 g_object_unref (view);
6921
6922 if (error != NULL &&
6923 (error->domain != G_IO_ERROR ||
6924 (error->code != G_IO_ERROR_CANCELLED &&
6925 error->code != G_IO_ERROR_FAILED_HANDLED)))
6926 {
6927 char *text;
6928 char *name;
6929 name = nautilus_file_get_display_name (file);
6930 /* Translators: %s is a file name formatted for display */
6931 text = g_strdup_printf (_("Unable to remove “%s”"), name);
6932 show_dialog (text,
6933 error->message,
6934 GTK_WINDOW (nautilus_files_view_get_window (view)),
6935 GTK_MESSAGE_ERROR);
6936 g_free (text);
6937 g_free (name);
6938 }
6939 }
6940
6941 static void
file_eject_callback(NautilusFile * file,GFile * result_location,GError * error,gpointer callback_data)6942 file_eject_callback (NautilusFile *file,
6943 GFile *result_location,
6944 GError *error,
6945 gpointer callback_data)
6946 {
6947 NautilusFilesView *view;
6948
6949 view = NAUTILUS_FILES_VIEW (callback_data);
6950 g_object_unref (view);
6951
6952 if (error != NULL &&
6953 (error->domain != G_IO_ERROR ||
6954 (error->code != G_IO_ERROR_CANCELLED &&
6955 error->code != G_IO_ERROR_FAILED_HANDLED)))
6956 {
6957 char *text;
6958 char *name;
6959 name = nautilus_file_get_display_name (file);
6960 /* Translators: %s is a file name formatted for display */
6961 text = g_strdup_printf (_("Unable to eject “%s”"), name);
6962 show_dialog (text,
6963 error->message,
6964 GTK_WINDOW (nautilus_files_view_get_window (view)),
6965 GTK_MESSAGE_ERROR);
6966 g_free (text);
6967 g_free (name);
6968 }
6969 }
6970
6971 static void
file_stop_callback(NautilusFile * file,GFile * result_location,GError * error,gpointer callback_data)6972 file_stop_callback (NautilusFile *file,
6973 GFile *result_location,
6974 GError *error,
6975 gpointer callback_data)
6976 {
6977 NautilusFilesView *view;
6978
6979 view = NAUTILUS_FILES_VIEW (callback_data);
6980
6981 if (error != NULL &&
6982 (error->domain != G_IO_ERROR ||
6983 (error->code != G_IO_ERROR_CANCELLED &&
6984 error->code != G_IO_ERROR_FAILED_HANDLED)))
6985 {
6986 show_dialog (_("Unable to stop drive"),
6987 error->message,
6988 GTK_WINDOW (nautilus_files_view_get_window (view)),
6989 GTK_MESSAGE_ERROR);
6990 }
6991 }
6992
6993 static void
action_mount_volume(GSimpleAction * action,GVariant * state,gpointer user_data)6994 action_mount_volume (GSimpleAction *action,
6995 GVariant *state,
6996 gpointer user_data)
6997 {
6998 NautilusFile *file;
6999 GList *selection, *l;
7000 NautilusFilesView *view;
7001 GMountOperation *mount_op;
7002
7003 view = NAUTILUS_FILES_VIEW (user_data);
7004
7005 selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
7006 for (l = selection; l != NULL; l = l->next)
7007 {
7008 file = NAUTILUS_FILE (l->data);
7009
7010 if (nautilus_file_can_mount (file))
7011 {
7012 mount_op = gtk_mount_operation_new (nautilus_files_view_get_containing_window (view));
7013 g_mount_operation_set_password_save (mount_op, G_PASSWORD_SAVE_FOR_SESSION);
7014 nautilus_file_mount (file, mount_op, NULL,
7015 file_mount_callback,
7016 view);
7017 g_object_unref (mount_op);
7018 }
7019 }
7020 nautilus_file_list_free (selection);
7021 }
7022
7023 static void
action_unmount_volume(GSimpleAction * action,GVariant * state,gpointer user_data)7024 action_unmount_volume (GSimpleAction *action,
7025 GVariant *state,
7026 gpointer user_data)
7027 {
7028 NautilusFile *file;
7029 g_autolist (NautilusFile) selection = NULL;
7030 GList *l;
7031 NautilusFilesView *view;
7032
7033 view = NAUTILUS_FILES_VIEW (user_data);
7034
7035 selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
7036
7037 for (l = selection; l != NULL; l = l->next)
7038 {
7039 file = NAUTILUS_FILE (l->data);
7040 if (nautilus_file_can_unmount (file))
7041 {
7042 GMountOperation *mount_op;
7043 mount_op = gtk_mount_operation_new (nautilus_files_view_get_containing_window (view));
7044 nautilus_file_unmount (file, mount_op, NULL,
7045 file_unmount_callback, g_object_ref (view));
7046 g_object_unref (mount_op);
7047 }
7048 }
7049 }
7050
7051 static void
action_eject_volume(GSimpleAction * action,GVariant * state,gpointer user_data)7052 action_eject_volume (GSimpleAction *action,
7053 GVariant *state,
7054 gpointer user_data)
7055 {
7056 NautilusFile *file;
7057 g_autolist (NautilusFile) selection = NULL;
7058 GList *l;
7059 NautilusFilesView *view;
7060
7061 view = NAUTILUS_FILES_VIEW (user_data);
7062
7063 selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
7064 for (l = selection; l != NULL; l = l->next)
7065 {
7066 file = NAUTILUS_FILE (l->data);
7067
7068 if (nautilus_file_can_eject (file))
7069 {
7070 GMountOperation *mount_op;
7071 mount_op = gtk_mount_operation_new (nautilus_files_view_get_containing_window (view));
7072 nautilus_file_eject (file, mount_op, NULL,
7073 file_eject_callback, g_object_ref (view));
7074 g_object_unref (mount_op);
7075 }
7076 }
7077 }
7078
7079 static void
file_start_callback(NautilusFile * file,GFile * result_location,GError * error,gpointer callback_data)7080 file_start_callback (NautilusFile *file,
7081 GFile *result_location,
7082 GError *error,
7083 gpointer callback_data)
7084 {
7085 NautilusFilesView *view;
7086
7087 view = NAUTILUS_FILES_VIEW (callback_data);
7088
7089 if (error != NULL &&
7090 (error->domain != G_IO_ERROR ||
7091 (error->code != G_IO_ERROR_CANCELLED &&
7092 error->code != G_IO_ERROR_FAILED_HANDLED &&
7093 error->code != G_IO_ERROR_ALREADY_MOUNTED)))
7094 {
7095 char *text;
7096 char *name;
7097 name = nautilus_file_get_display_name (file);
7098 /* Translators: %s is a file name formatted for display */
7099 text = g_strdup_printf (_("Unable to start “%s”"), name);
7100 show_dialog (text,
7101 error->message,
7102 GTK_WINDOW (nautilus_files_view_get_window (view)),
7103 GTK_MESSAGE_ERROR);
7104 g_free (text);
7105 g_free (name);
7106 }
7107 }
7108
7109 static void
action_start_volume(GSimpleAction * action,GVariant * state,gpointer user_data)7110 action_start_volume (GSimpleAction *action,
7111 GVariant *state,
7112 gpointer user_data)
7113 {
7114 NautilusFile *file;
7115 g_autolist (NautilusFile) selection = NULL;
7116 GList *l;
7117 NautilusFilesView *view;
7118 GMountOperation *mount_op;
7119
7120 view = NAUTILUS_FILES_VIEW (user_data);
7121
7122 selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
7123 for (l = selection; l != NULL; l = l->next)
7124 {
7125 file = NAUTILUS_FILE (l->data);
7126
7127 if (nautilus_file_can_start (file) || nautilus_file_can_start_degraded (file))
7128 {
7129 mount_op = gtk_mount_operation_new (nautilus_files_view_get_containing_window (view));
7130 nautilus_file_start (file, mount_op, NULL,
7131 file_start_callback, view);
7132 g_object_unref (mount_op);
7133 }
7134 }
7135 }
7136
7137 static void
action_stop_volume(GSimpleAction * action,GVariant * state,gpointer user_data)7138 action_stop_volume (GSimpleAction *action,
7139 GVariant *state,
7140 gpointer user_data)
7141 {
7142 NautilusFile *file;
7143 g_autolist (NautilusFile) selection = NULL;
7144 GList *l;
7145 NautilusFilesView *view;
7146
7147 view = NAUTILUS_FILES_VIEW (user_data);
7148
7149 selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
7150 for (l = selection; l != NULL; l = l->next)
7151 {
7152 file = NAUTILUS_FILE (l->data);
7153
7154 if (nautilus_file_can_stop (file))
7155 {
7156 GMountOperation *mount_op;
7157 mount_op = gtk_mount_operation_new (nautilus_files_view_get_containing_window (view));
7158 nautilus_file_stop (file, mount_op, NULL,
7159 file_stop_callback, view);
7160 g_object_unref (mount_op);
7161 }
7162 }
7163 }
7164
7165 static void
action_detect_media(GSimpleAction * action,GVariant * state,gpointer user_data)7166 action_detect_media (GSimpleAction *action,
7167 GVariant *state,
7168 gpointer user_data)
7169 {
7170 NautilusFile *file;
7171 g_autolist (NautilusFile) selection = NULL;
7172 GList *l;
7173 NautilusView *view;
7174
7175 view = NAUTILUS_VIEW (user_data);
7176
7177 selection = nautilus_view_get_selection (view);
7178 for (l = selection; l != NULL; l = l->next)
7179 {
7180 file = NAUTILUS_FILE (l->data);
7181
7182 if (nautilus_file_can_poll_for_media (file) && !nautilus_file_is_media_check_automatic (file))
7183 {
7184 nautilus_file_poll_for_media (file);
7185 }
7186 }
7187 }
7188
7189 const GActionEntry view_entries[] =
7190 {
7191 /* Toolbar menu */
7192 { "zoom-in", action_zoom_in },
7193 { "zoom-out", action_zoom_out },
7194 { "zoom-standard", action_zoom_standard },
7195 { "show-hidden-files", NULL, NULL, "true", action_show_hidden_files },
7196 /* Background menu */
7197 { "new-folder", action_new_folder },
7198 { "select-all", action_select_all },
7199 { "paste", action_paste_files },
7200 { "paste_accel", action_paste_files_accel },
7201 { "create-link", action_create_links },
7202 { "new-document" },
7203 /* Selection menu */
7204 { "scripts" },
7205 { "new-folder-with-selection", action_new_folder_with_selection },
7206 { "open-scripts-folder", action_open_scripts_folder },
7207 { "open-item-location", action_open_item_location },
7208 { "open-with-default-application", action_open_with_default_application },
7209 { "open-with-other-application", action_open_with_other_application },
7210 { "open-item-new-window", action_open_item_new_window },
7211 { "open-item-new-tab", action_open_item_new_tab },
7212 { "cut", action_cut},
7213 { "copy", action_copy},
7214 { "create-link-in-place", action_create_links_in_place },
7215 { "move-to", action_move_to},
7216 { "copy-to", action_copy_to},
7217 { "move-to-trash", action_move_to_trash},
7218 { "delete-from-trash", action_delete },
7219 { "star", action_star},
7220 { "unstar", action_unstar},
7221 /* We separate the shortcut and the menu item since we want the shortcut
7222 * to always be available, but we don't want the menu item shown if not
7223 * completely necesary. Since the visibility of the menu item is based on
7224 * the action enability, we need to split the actions for the menu and the
7225 * shortcut. */
7226 { "delete-permanently-shortcut", action_delete },
7227 { "delete-permanently-menu-item", action_delete },
7228 /* This is only shown when the setting to show always delete permanently
7229 * is set and when the common use cases for delete permanently which uses
7230 * Delete as a shortcut are not needed. For instance this will be only
7231 * present when the setting is true and when it can trash files */
7232 { "permanent-delete-permanently-menu-item", action_delete },
7233 { "remove-from-recent", action_remove_from_recent },
7234 { "restore-from-trash", action_restore_from_trash},
7235 { "paste-into", action_paste_files_into },
7236 { "rename", action_rename},
7237 { "extract-here", action_extract_here },
7238 { "extract-to", action_extract_to },
7239 { "compress", action_compress },
7240 { "properties", action_properties},
7241 { "current-directory-properties", action_current_dir_properties},
7242 { "run-in-terminal", action_run_in_terminal },
7243 { "set-as-wallpaper", action_set_as_wallpaper },
7244 { "mount-volume", action_mount_volume },
7245 { "unmount-volume", action_unmount_volume },
7246 { "eject-volume", action_eject_volume },
7247 { "start-volume", action_start_volume },
7248 { "stop-volume", action_stop_volume },
7249 { "detect-media", action_detect_media },
7250 /* Only accesible by shorcuts */
7251 { "select-pattern", action_select_pattern },
7252 { "invert-selection", action_invert_selection },
7253 };
7254
7255 static gboolean
can_paste_into_file(NautilusFile * file)7256 can_paste_into_file (NautilusFile *file)
7257 {
7258 if (nautilus_file_is_directory (file) &&
7259 nautilus_file_can_write (file))
7260 {
7261 return TRUE;
7262 }
7263 if (nautilus_file_has_activation_uri (file))
7264 {
7265 GFile *location;
7266 NautilusFile *activation_file;
7267 gboolean res;
7268
7269 location = nautilus_file_get_activation_location (file);
7270 activation_file = nautilus_file_get (location);
7271 g_object_unref (location);
7272
7273 /* The target location might not have data for it read yet,
7274 * and we can't want to do sync I/O, so treat the unknown
7275 * case as can-write */
7276 res = (nautilus_file_get_file_type (activation_file) == G_FILE_TYPE_UNKNOWN) ||
7277 (nautilus_file_get_file_type (activation_file) == G_FILE_TYPE_DIRECTORY &&
7278 nautilus_file_can_write (activation_file));
7279
7280 nautilus_file_unref (activation_file);
7281
7282 return res;
7283 }
7284
7285 return FALSE;
7286 }
7287
7288 static void
on_clipboard_contents_received(GtkClipboard * clipboard,GtkSelectionData * selection_data,gpointer user_data)7289 on_clipboard_contents_received (GtkClipboard *clipboard,
7290 GtkSelectionData *selection_data,
7291 gpointer user_data)
7292 {
7293 NautilusFilesViewPrivate *priv;
7294 NautilusFilesView *view;
7295 gboolean can_link_from_copied_files;
7296 gboolean settings_show_create_link;
7297 gboolean is_read_only;
7298 gboolean selection_contains_recent;
7299 gboolean selection_contains_starred;
7300 GAction *action;
7301
7302 view = NAUTILUS_FILES_VIEW (user_data);
7303 priv = nautilus_files_view_get_instance_private (view);
7304
7305 if (priv->slot == NULL ||
7306 !priv->active)
7307 {
7308 /* We've been destroyed or became inactive since call */
7309 g_object_unref (view);
7310 return;
7311 }
7312
7313 settings_show_create_link = g_settings_get_boolean (nautilus_preferences,
7314 NAUTILUS_PREFERENCES_SHOW_CREATE_LINK);
7315 is_read_only = nautilus_files_view_is_read_only (view);
7316 selection_contains_recent = showing_recent_directory (view);
7317 selection_contains_starred = showing_starred_directory (view);
7318 can_link_from_copied_files = !nautilus_clipboard_is_cut_from_selection_data (selection_data) &&
7319 !selection_contains_recent && !selection_contains_starred &&
7320 !is_read_only && gtk_selection_data_get_length (selection_data) > 0;
7321
7322 action = g_action_map_lookup_action (G_ACTION_MAP (priv->view_action_group),
7323 "create-link");
7324 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7325 can_link_from_copied_files &&
7326 settings_show_create_link);
7327
7328 g_object_unref (view);
7329 }
7330
7331 static void
on_clipboard_targets_received(GtkClipboard * clipboard,GdkAtom * targets,int n_targets,gpointer user_data)7332 on_clipboard_targets_received (GtkClipboard *clipboard,
7333 GdkAtom *targets,
7334 int n_targets,
7335 gpointer user_data)
7336 {
7337 NautilusFilesViewPrivate *priv;
7338 NautilusFilesView *view;
7339 gboolean is_data_copied;
7340 int i;
7341 GAction *action;
7342
7343 view = NAUTILUS_FILES_VIEW (user_data);
7344 priv = nautilus_files_view_get_instance_private (view);
7345 is_data_copied = FALSE;
7346
7347 if (priv->slot == NULL ||
7348 !priv->active)
7349 {
7350 /* We've been destroyed or became inactive since call */
7351 g_object_unref (view);
7352 return;
7353 }
7354
7355 if (targets)
7356 {
7357 for (i = 0; i < n_targets; i++)
7358 {
7359 if (targets[i] == nautilus_clipboard_get_atom ())
7360 {
7361 is_data_copied = TRUE;
7362 }
7363 }
7364 }
7365
7366 action = g_action_map_lookup_action (G_ACTION_MAP (priv->view_action_group),
7367 "paste");
7368 /* Take into account if the action was previously disabled for other reasons,
7369 * like the directory not being writabble */
7370 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7371 is_data_copied && g_action_get_enabled (action));
7372
7373 action = g_action_map_lookup_action (G_ACTION_MAP (priv->view_action_group),
7374 "paste-into");
7375
7376 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7377 is_data_copied && g_action_get_enabled (action));
7378
7379 action = g_action_map_lookup_action (G_ACTION_MAP (priv->view_action_group),
7380 "create-link");
7381
7382 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7383 is_data_copied && g_action_get_enabled (action));
7384
7385 g_object_unref (view);
7386 }
7387
7388 static void
file_should_show_foreach(NautilusFile * file,gboolean * show_mount,gboolean * show_unmount,gboolean * show_eject,gboolean * show_start,gboolean * show_stop,gboolean * show_poll,GDriveStartStopType * start_stop_type)7389 file_should_show_foreach (NautilusFile *file,
7390 gboolean *show_mount,
7391 gboolean *show_unmount,
7392 gboolean *show_eject,
7393 gboolean *show_start,
7394 gboolean *show_stop,
7395 gboolean *show_poll,
7396 GDriveStartStopType *start_stop_type)
7397 {
7398 *show_mount = FALSE;
7399 *show_unmount = FALSE;
7400 *show_eject = FALSE;
7401 *show_start = FALSE;
7402 *show_stop = FALSE;
7403 *show_poll = FALSE;
7404
7405 if (nautilus_file_can_eject (file))
7406 {
7407 *show_eject = TRUE;
7408 }
7409
7410 if (nautilus_file_can_mount (file))
7411 {
7412 *show_mount = TRUE;
7413 }
7414
7415 if (nautilus_file_can_start (file) || nautilus_file_can_start_degraded (file))
7416 {
7417 *show_start = TRUE;
7418 }
7419
7420 if (nautilus_file_can_stop (file))
7421 {
7422 *show_stop = TRUE;
7423 }
7424
7425 /* Dot not show both Unmount and Eject/Safe Removal; too confusing to
7426 * have too many menu entries */
7427 if (nautilus_file_can_unmount (file) && !*show_eject && !*show_stop)
7428 {
7429 *show_unmount = TRUE;
7430 }
7431
7432 if (nautilus_file_can_poll_for_media (file) && !nautilus_file_is_media_check_automatic (file))
7433 {
7434 *show_poll = TRUE;
7435 }
7436
7437 *start_stop_type = nautilus_file_get_start_stop_type (file);
7438 }
7439
7440 static gboolean
can_restore_from_trash(GList * files)7441 can_restore_from_trash (GList *files)
7442 {
7443 NautilusFile *original_file;
7444 NautilusFile *original_dir;
7445 GHashTable *original_dirs_hash;
7446 GList *original_dirs;
7447 gboolean can_restore;
7448
7449 original_file = NULL;
7450 original_dir = NULL;
7451 original_dirs = NULL;
7452 original_dirs_hash = NULL;
7453
7454 if (files != NULL)
7455 {
7456 if (g_list_length (files) == 1)
7457 {
7458 original_file = nautilus_file_get_trash_original_file (files->data);
7459 }
7460 else
7461 {
7462 original_dirs_hash = nautilus_trashed_files_get_original_directories (files, NULL);
7463 if (original_dirs_hash != NULL)
7464 {
7465 original_dirs = g_hash_table_get_keys (original_dirs_hash);
7466 if (g_list_length (original_dirs) == 1)
7467 {
7468 original_dir = nautilus_file_ref (NAUTILUS_FILE (original_dirs->data));
7469 }
7470 }
7471 }
7472 }
7473
7474 can_restore = original_file != NULL || original_dirs != NULL;
7475
7476 nautilus_file_unref (original_file);
7477 nautilus_file_unref (original_dir);
7478 g_list_free (original_dirs);
7479
7480 if (original_dirs_hash != NULL)
7481 {
7482 g_hash_table_destroy (original_dirs_hash);
7483 }
7484 return can_restore;
7485 }
7486
7487 static void
on_clipboard_owner_changed(GtkClipboard * clipboard,GdkEvent * event,gpointer user_data)7488 on_clipboard_owner_changed (GtkClipboard *clipboard,
7489 GdkEvent *event,
7490 gpointer user_data)
7491 {
7492 NautilusFilesView *self = NAUTILUS_FILES_VIEW (user_data);
7493
7494 /* Update paste menu item */
7495 nautilus_files_view_update_context_menus (self);
7496 }
7497
7498 static gboolean
can_delete_all(GList * files)7499 can_delete_all (GList *files)
7500 {
7501 NautilusFile *file;
7502 GList *l;
7503
7504 for (l = files; l != NULL; l = l->next)
7505 {
7506 file = l->data;
7507 if (!nautilus_file_can_delete (file))
7508 {
7509 return FALSE;
7510 }
7511 }
7512 return TRUE;
7513 }
7514
7515 static gboolean
can_trash_all(GList * files)7516 can_trash_all (GList *files)
7517 {
7518 NautilusFile *file;
7519 GList *l;
7520
7521 for (l = files; l != NULL; l = l->next)
7522 {
7523 file = l->data;
7524 if (!nautilus_file_can_trash (file))
7525 {
7526 return FALSE;
7527 }
7528 }
7529 return TRUE;
7530 }
7531
7532 static gboolean
all_in_trash(GList * files)7533 all_in_trash (GList *files)
7534 {
7535 NautilusFile *file;
7536 GList *l;
7537
7538 for (l = files; l != NULL; l = l->next)
7539 {
7540 file = l->data;
7541 if (!nautilus_file_is_in_trash (file))
7542 {
7543 return FALSE;
7544 }
7545 }
7546 return TRUE;
7547 }
7548
7549 static gboolean
can_extract_all(GList * files)7550 can_extract_all (GList *files)
7551 {
7552 NautilusFile *file;
7553 GList *l;
7554
7555 for (l = files; l != NULL; l = l->next)
7556 {
7557 file = l->data;
7558 if (!nautilus_file_is_archive (file))
7559 {
7560 return FALSE;
7561 }
7562 }
7563 return TRUE;
7564 }
7565
7566 static gboolean
nautilus_handles_all_files_to_extract(GList * files)7567 nautilus_handles_all_files_to_extract (GList *files)
7568 {
7569 NautilusFile *file;
7570 GList *l;
7571
7572 for (l = files; l != NULL; l = l->next)
7573 {
7574 file = l->data;
7575 if (!nautilus_mime_file_extracts (file))
7576 {
7577 return FALSE;
7578 }
7579 }
7580 return TRUE;
7581 }
7582
7583 GActionGroup *
nautilus_files_view_get_action_group(NautilusFilesView * view)7584 nautilus_files_view_get_action_group (NautilusFilesView *view)
7585 {
7586 NautilusFilesViewPrivate *priv;
7587
7588 g_assert (NAUTILUS_IS_FILES_VIEW (view));
7589
7590 priv = nautilus_files_view_get_instance_private (view);
7591
7592 return priv->view_action_group;
7593 }
7594
7595 static void
real_update_actions_state(NautilusFilesView * view)7596 real_update_actions_state (NautilusFilesView *view)
7597 {
7598 NautilusFilesViewPrivate *priv;
7599 g_autolist (NautilusFile) selection = NULL;
7600 GList *l;
7601 gint selection_count;
7602 gboolean zoom_level_is_default;
7603 gboolean selection_contains_home_dir;
7604 gboolean selection_contains_recent;
7605 gboolean selection_contains_search;
7606 gboolean selection_contains_starred;
7607 gboolean selection_all_in_trash;
7608 gboolean selection_is_read_only;
7609 gboolean can_create_files;
7610 gboolean can_delete_files;
7611 gboolean can_move_files;
7612 gboolean can_trash_files;
7613 gboolean can_copy_files;
7614 gboolean can_paste_files_into;
7615 gboolean can_extract_files;
7616 gboolean handles_all_files_to_extract;
7617 gboolean can_extract_here;
7618 gboolean item_opens_in_view;
7619 gboolean is_read_only;
7620 GAction *action;
7621 GActionGroup *view_action_group;
7622 gboolean show_mount;
7623 gboolean show_unmount;
7624 gboolean show_eject;
7625 gboolean show_start;
7626 gboolean show_stop;
7627 gboolean show_detect_media;
7628 gboolean settings_show_delete_permanently;
7629 gboolean settings_show_create_link;
7630 GDriveStartStopType start_stop_type;
7631 g_autoptr (GFile) current_location = NULL;
7632 g_autofree gchar *current_uri = NULL;
7633 gboolean can_star_current_directory;
7634 gboolean show_star;
7635 gboolean show_unstar;
7636 gchar *uri;
7637
7638 priv = nautilus_files_view_get_instance_private (view);
7639
7640 view_action_group = priv->view_action_group;
7641
7642 selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
7643 selection_count = g_list_length (selection);
7644 selection_contains_home_dir = home_dir_in_selection (selection);
7645 selection_contains_recent = showing_recent_directory (view);
7646 selection_contains_starred = showing_starred_directory (view);
7647 selection_contains_search = nautilus_view_is_searching (NAUTILUS_VIEW (view));
7648 selection_is_read_only = selection_count == 1 &&
7649 (!nautilus_file_can_write (NAUTILUS_FILE (selection->data)) &&
7650 !nautilus_file_has_activation_uri (NAUTILUS_FILE (selection->data)));
7651 selection_all_in_trash = all_in_trash (selection);
7652 zoom_level_is_default = nautilus_files_view_is_zoom_level_default (view);
7653
7654 is_read_only = nautilus_files_view_is_read_only (view);
7655 can_create_files = nautilus_files_view_supports_creating_files (view);
7656 can_delete_files =
7657 can_delete_all (selection) &&
7658 selection_count != 0 &&
7659 !selection_contains_home_dir;
7660 can_trash_files =
7661 can_trash_all (selection) &&
7662 selection_count != 0 &&
7663 !selection_contains_home_dir;
7664 can_copy_files = selection_count != 0;
7665 can_move_files = can_delete_files && !selection_contains_recent &&
7666 !selection_contains_starred;
7667 can_paste_files_into = (!selection_contains_recent &&
7668 !selection_contains_starred &&
7669 selection_count == 1 &&
7670 can_paste_into_file (NAUTILUS_FILE (selection->data)));
7671 can_extract_files = selection_count != 0 &&
7672 can_extract_all (selection);
7673 can_extract_here = nautilus_files_view_supports_extract_here (view);
7674 handles_all_files_to_extract = nautilus_handles_all_files_to_extract (selection);
7675 settings_show_delete_permanently = g_settings_get_boolean (nautilus_preferences,
7676 NAUTILUS_PREFERENCES_SHOW_DELETE_PERMANENTLY);
7677 settings_show_create_link = g_settings_get_boolean (nautilus_preferences,
7678 NAUTILUS_PREFERENCES_SHOW_CREATE_LINK);
7679 /* Right click actions
7680 * Selection menu actions
7681 */
7682 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7683 "new-folder-with-selection");
7684 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7685 can_create_files && can_delete_files && (selection_count > 1) && !selection_contains_recent
7686 && !selection_contains_starred);
7687
7688 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7689 "rename");
7690 if (selection_count > 1)
7691 {
7692 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7693 nautilus_file_can_rename_files (selection));
7694 }
7695 else
7696 {
7697 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7698 selection_count == 1 &&
7699 nautilus_file_can_rename (selection->data));
7700 }
7701
7702 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7703 "extract-here");
7704 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7705 can_extract_files &&
7706 !handles_all_files_to_extract &&
7707 can_extract_here);
7708
7709 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7710 "extract-to");
7711 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7712 can_extract_files &&
7713 (!handles_all_files_to_extract ||
7714 can_extract_here));
7715
7716 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7717 "compress");
7718 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7719 can_create_files && can_copy_files);
7720
7721 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7722 "open-item-location");
7723
7724 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7725 selection_count == 1 &&
7726 (selection_contains_recent || selection_contains_search ||
7727 selection_contains_starred));
7728
7729 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7730 "new-folder");
7731 g_simple_action_set_enabled (G_SIMPLE_ACTION (action), can_create_files);
7732
7733 item_opens_in_view = selection_count != 0;
7734
7735 for (l = selection; l != NULL; l = l->next)
7736 {
7737 NautilusFile *file;
7738
7739 file = NAUTILUS_FILE (selection->data);
7740
7741 if (!nautilus_file_opens_in_view (file))
7742 {
7743 item_opens_in_view = FALSE;
7744 }
7745
7746 if (!item_opens_in_view)
7747 {
7748 break;
7749 }
7750 }
7751
7752 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7753 "open-with-default-application");
7754 g_simple_action_set_enabled (G_SIMPLE_ACTION (action), selection_count != 0);
7755
7756 /* Allow to select a different application to open the item */
7757 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7758 "open-with-other-application");
7759 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7760 selection_count > 0);
7761
7762 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7763 "open-item-new-tab");
7764 g_simple_action_set_enabled (G_SIMPLE_ACTION (action), item_opens_in_view);
7765 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7766 "open-item-new-window");
7767 g_simple_action_set_enabled (G_SIMPLE_ACTION (action), item_opens_in_view);
7768 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7769 "run-in-terminal");
7770 g_simple_action_set_enabled (G_SIMPLE_ACTION (action), can_run_in_terminal (selection));
7771 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7772 "set-as-wallpaper");
7773 g_simple_action_set_enabled (G_SIMPLE_ACTION (action), can_set_wallpaper (selection));
7774 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7775 "restore-from-trash");
7776 g_simple_action_set_enabled (G_SIMPLE_ACTION (action), can_restore_from_trash (selection));
7777
7778 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7779 "move-to-trash");
7780 g_simple_action_set_enabled (G_SIMPLE_ACTION (action), can_trash_files);
7781
7782 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7783 "delete-from-trash");
7784 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7785 can_delete_files && selection_all_in_trash);
7786
7787 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7788 "delete-permanently-shortcut");
7789 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7790 can_delete_files);
7791
7792 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7793 "delete-permanently-menu-item");
7794 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7795 can_delete_files && !can_trash_files &&
7796 !selection_all_in_trash && !selection_contains_recent &&
7797 !selection_contains_starred);
7798
7799 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7800 "permanent-delete-permanently-menu-item");
7801 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7802 can_delete_files && can_trash_files &&
7803 settings_show_delete_permanently &&
7804 !selection_all_in_trash && !selection_contains_recent &&
7805 !selection_contains_starred);
7806
7807 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7808 "remove-from-recent");
7809 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7810 selection_contains_recent && selection_count > 0);
7811
7812 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7813 "cut");
7814 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7815 can_move_files && !selection_contains_recent &&
7816 !selection_contains_starred);
7817 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7818 "copy");
7819 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7820 can_copy_files);
7821 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7822 "create-link-in-place");
7823 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7824 can_copy_files &&
7825 can_create_files &&
7826 settings_show_create_link);
7827 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7828 "copy-to");
7829 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7830 can_copy_files);
7831 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7832 "move-to");
7833 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7834 can_move_files && !selection_contains_recent &&
7835 !selection_contains_starred);
7836
7837 /* Drive menu */
7838 show_mount = (selection != NULL);
7839 show_unmount = (selection != NULL);
7840 show_eject = (selection != NULL);
7841 show_start = (selection != NULL && selection_count == 1);
7842 show_stop = (selection != NULL && selection_count == 1);
7843 show_detect_media = (selection != NULL && selection_count == 1);
7844 for (l = selection; l != NULL && (show_mount || show_unmount
7845 || show_eject
7846 || show_start || show_stop
7847 || show_detect_media);
7848 l = l->next)
7849 {
7850 NautilusFile *file;
7851 gboolean show_mount_one;
7852 gboolean show_unmount_one;
7853 gboolean show_eject_one;
7854 gboolean show_start_one;
7855 gboolean show_stop_one;
7856 gboolean show_detect_media_one;
7857
7858 file = NAUTILUS_FILE (l->data);
7859 file_should_show_foreach (file,
7860 &show_mount_one,
7861 &show_unmount_one,
7862 &show_eject_one,
7863 &show_start_one,
7864 &show_stop_one,
7865 &show_detect_media_one,
7866 &start_stop_type);
7867
7868 show_mount &= show_mount_one;
7869 show_unmount &= show_unmount_one;
7870 show_eject &= show_eject_one;
7871 show_start &= show_start_one;
7872 show_stop &= show_stop_one;
7873 show_detect_media &= show_detect_media_one;
7874 }
7875
7876 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7877 "mount-volume");
7878 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7879 show_mount);
7880 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7881 "unmount-volume");
7882 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7883 show_unmount);
7884 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7885 "eject-volume");
7886 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7887 show_eject);
7888 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7889 "start-volume");
7890 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7891 show_start);
7892 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7893 "stop-volume");
7894 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7895 show_stop);
7896 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7897 "detect-media");
7898 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7899 show_detect_media);
7900
7901 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7902 "scripts");
7903 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7904 priv->scripts_menu != NULL);
7905
7906 /* Background menu actions */
7907 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7908 "new-folder");
7909 g_simple_action_set_enabled (G_SIMPLE_ACTION (action), can_create_files);
7910 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7911 "paste");
7912 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7913 !is_read_only && !selection_contains_recent &&
7914 !selection_contains_starred);
7915
7916 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7917 "paste-into");
7918 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7919 !selection_is_read_only && !selection_contains_recent &&
7920 can_paste_files_into && !selection_contains_starred);
7921
7922 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7923 "properties");
7924 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7925 TRUE);
7926 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7927 "current-directory-properties");
7928 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7929 !selection_contains_search);
7930 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7931 "new-document");
7932 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7933 can_create_files &&
7934 !selection_contains_recent &&
7935 !selection_contains_starred &&
7936 priv->templates_menu != NULL);
7937
7938 /* Actions that are related to the clipboard need request, request the data
7939 * and update them once we have the data */
7940 g_object_ref (view); /* Need to keep the object alive until we get the reply */
7941 gtk_clipboard_request_targets (nautilus_clipboard_get (GTK_WIDGET (view)),
7942 on_clipboard_targets_received,
7943 view);
7944
7945 g_object_ref (view); /* Need to keep the object alive until we get the reply */
7946 gtk_clipboard_request_contents (nautilus_clipboard_get (GTK_WIDGET (view)),
7947 nautilus_clipboard_get_atom (),
7948 on_clipboard_contents_received,
7949 view);
7950
7951 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7952 "select-all");
7953 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7954 !nautilus_files_view_is_empty (view) &&
7955 !priv->loading);
7956
7957 /* Toolbar menu actions */
7958 g_action_group_change_action_state (view_action_group,
7959 "show-hidden-files",
7960 g_variant_new_boolean (priv->show_hidden_files));
7961
7962 /* Zoom */
7963 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7964 "zoom-in");
7965 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7966 nautilus_files_view_can_zoom_in (view));
7967 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7968 "zoom-out");
7969 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7970 nautilus_files_view_can_zoom_out (view));
7971 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7972 "zoom-standard");
7973 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7974 nautilus_files_view_supports_zooming (view) && !zoom_level_is_default);
7975 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
7976 "zoom-to-level");
7977 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
7978 !nautilus_files_view_is_empty (view));
7979
7980 current_location = nautilus_file_get_location (nautilus_files_view_get_directory_as_file (view));
7981 current_uri = g_file_get_uri (current_location);
7982 can_star_current_directory = nautilus_tag_manager_can_star_contents (priv->tag_manager, current_location);
7983
7984 show_star = (selection != NULL) &&
7985 (can_star_current_directory || selection_contains_starred);
7986 show_unstar = (selection != NULL) &&
7987 (can_star_current_directory || selection_contains_starred);
7988 for (l = selection; l != NULL; l = l->next)
7989 {
7990 NautilusFile *file;
7991
7992 file = NAUTILUS_FILE (l->data);
7993 uri = nautilus_file_get_uri (file);
7994
7995 if (!show_star && !show_unstar)
7996 {
7997 break;
7998 }
7999
8000 if (nautilus_tag_manager_file_is_starred (priv->tag_manager, uri))
8001 {
8002 show_star = FALSE;
8003 }
8004 else
8005 {
8006 show_unstar = FALSE;
8007 }
8008
8009 g_free (uri);
8010 }
8011
8012 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
8013 "star");
8014 g_simple_action_set_enabled (G_SIMPLE_ACTION (action), show_star);
8015
8016 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
8017 "unstar");
8018 g_simple_action_set_enabled (G_SIMPLE_ACTION (action), show_unstar);
8019 }
8020
8021 /* Convenience function to be called when updating menus,
8022 * so children can subclass it and it will be called when
8023 * they chain up to the parent in update_context_menus
8024 * or update_toolbar_menus
8025 */
8026 void
nautilus_files_view_update_actions_state(NautilusFilesView * view)8027 nautilus_files_view_update_actions_state (NautilusFilesView *view)
8028 {
8029 g_assert (NAUTILUS_IS_FILES_VIEW (view));
8030
8031 NAUTILUS_FILES_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->update_actions_state (view);
8032 }
8033
8034 static void
update_selection_menu(NautilusFilesView * view,GtkBuilder * builder)8035 update_selection_menu (NautilusFilesView *view,
8036 GtkBuilder *builder)
8037 {
8038 NautilusFilesViewPrivate *priv = nautilus_files_view_get_instance_private (view);
8039 g_autolist (NautilusFile) selection = NULL;
8040 GList *l;
8041 gint selection_count;
8042 gboolean show_app;
8043 gboolean show_run;
8044 gboolean show_extract;
8045 gboolean item_opens_in_view;
8046 gchar *item_label;
8047 GAppInfo *app;
8048 GIcon *app_icon;
8049 GMenuItem *menu_item;
8050 GObject *object;
8051 gboolean show_mount;
8052 gboolean show_unmount;
8053 gboolean show_eject;
8054 gboolean show_start;
8055 gboolean show_stop;
8056 gboolean show_detect_media;
8057 GDriveStartStopType start_stop_type;
8058
8059 selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
8060 selection_count = g_list_length (selection);
8061
8062 show_mount = (selection != NULL);
8063 show_unmount = (selection != NULL);
8064 show_eject = (selection != NULL);
8065 show_start = (selection != NULL && selection_count == 1);
8066 show_stop = (selection != NULL && selection_count == 1);
8067 show_detect_media = (selection != NULL && selection_count == 1);
8068 start_stop_type = G_DRIVE_START_STOP_TYPE_UNKNOWN;
8069 item_label = g_strdup_printf (ngettext ("New Folder with Selection (%'d Item)",
8070 "New Folder with Selection (%'d Items)",
8071 selection_count),
8072 selection_count);
8073 menu_item = g_menu_item_new (item_label, "view.new-folder-with-selection");
8074 g_menu_item_set_attribute (menu_item, "hidden-when", "s", "action-disabled");
8075 object = gtk_builder_get_object (builder, "new-folder-with-selection-section");
8076 g_menu_append_item (G_MENU (object), menu_item);
8077 g_object_unref (menu_item);
8078 g_free (item_label);
8079
8080 /* Open With <App> menu item */
8081 show_extract = show_app = show_run = item_opens_in_view = selection_count != 0;
8082 for (l = selection; l != NULL; l = l->next)
8083 {
8084 NautilusFile *file;
8085
8086 file = NAUTILUS_FILE (l->data);
8087
8088 if (!nautilus_mime_file_extracts (file))
8089 {
8090 show_extract = FALSE;
8091 }
8092
8093 if (!nautilus_mime_file_opens_in_external_app (file))
8094 {
8095 show_app = FALSE;
8096 }
8097
8098 if (!nautilus_mime_file_launches (file))
8099 {
8100 show_run = FALSE;
8101 }
8102
8103 if (!nautilus_file_opens_in_view (file))
8104 {
8105 item_opens_in_view = FALSE;
8106 }
8107
8108 if (!show_extract && !show_app && !show_run && !item_opens_in_view)
8109 {
8110 break;
8111 }
8112 }
8113
8114 item_label = NULL;
8115 app = NULL;
8116 app_icon = NULL;
8117 if (show_app)
8118 {
8119 app = nautilus_mime_get_default_application_for_files (selection);
8120 }
8121
8122 if (app != NULL)
8123 {
8124 char *escaped_app;
8125
8126 escaped_app = eel_str_double_underscores (g_app_info_get_name (app));
8127 item_label = g_strdup_printf (_("Open With %s"), escaped_app);
8128
8129 app_icon = g_app_info_get_icon (app);
8130 if (app_icon != NULL)
8131 {
8132 g_object_ref (app_icon);
8133 }
8134 g_free (escaped_app);
8135 g_object_unref (app);
8136 }
8137 else if (show_run)
8138 {
8139 item_label = g_strdup (_("Run"));
8140 }
8141 else if (show_extract)
8142 {
8143 item_label = nautilus_files_view_supports_extract_here (view) ?
8144 g_strdup (_("Extract Here")) :
8145 g_strdup (_("Extract to…"));
8146 }
8147 else
8148 {
8149 item_label = g_strdup (_("Open"));
8150 }
8151
8152 menu_item = g_menu_item_new (item_label, "view.open-with-default-application");
8153 if (app_icon != NULL)
8154 {
8155 g_menu_item_set_icon (menu_item, app_icon);
8156 }
8157
8158 object = gtk_builder_get_object (builder, "open-with-application-section");
8159 g_menu_prepend_item (G_MENU (object), menu_item);
8160
8161 g_free (item_label);
8162 g_object_unref (menu_item);
8163
8164 /* Drives */
8165 for (l = selection; l != NULL && (show_mount || show_unmount
8166 || show_eject
8167 || show_start || show_stop
8168 || show_detect_media);
8169 l = l->next)
8170 {
8171 NautilusFile *file;
8172 gboolean show_mount_one;
8173 gboolean show_unmount_one;
8174 gboolean show_eject_one;
8175 gboolean show_start_one;
8176 gboolean show_stop_one;
8177 gboolean show_detect_media_one;
8178
8179 file = NAUTILUS_FILE (l->data);
8180 file_should_show_foreach (file,
8181 &show_mount_one,
8182 &show_unmount_one,
8183 &show_eject_one,
8184 &show_start_one,
8185 &show_stop_one,
8186 &show_detect_media_one,
8187 &start_stop_type);
8188
8189 show_mount &= show_mount_one;
8190 show_unmount &= show_unmount_one;
8191 show_eject &= show_eject_one;
8192 show_start &= show_start_one;
8193 show_stop &= show_stop_one;
8194 show_detect_media &= show_detect_media_one;
8195 }
8196
8197 if (show_start)
8198 {
8199 switch (start_stop_type)
8200 {
8201 default:
8202 case G_DRIVE_START_STOP_TYPE_UNKNOWN:
8203 case G_DRIVE_START_STOP_TYPE_SHUTDOWN:
8204 {
8205 item_label = _("_Start");
8206 }
8207 break;
8208
8209 case G_DRIVE_START_STOP_TYPE_NETWORK:
8210 {
8211 item_label = _("_Connect");
8212 }
8213 break;
8214
8215 case G_DRIVE_START_STOP_TYPE_MULTIDISK:
8216 {
8217 item_label = _("_Start Multi-disk Drive");
8218 }
8219 break;
8220
8221 case G_DRIVE_START_STOP_TYPE_PASSWORD:
8222 {
8223 item_label = _("U_nlock Drive");
8224 }
8225 break;
8226 }
8227
8228 menu_item = g_menu_item_new (item_label, "view.start-volume");
8229 object = gtk_builder_get_object (builder, "drive-section");
8230 g_menu_append_item (G_MENU (object), menu_item);
8231 g_object_unref (menu_item);
8232 }
8233
8234 if (show_stop)
8235 {
8236 switch (start_stop_type)
8237 {
8238 default:
8239 case G_DRIVE_START_STOP_TYPE_UNKNOWN:
8240 {
8241 item_label = _("Stop Drive");
8242 }
8243 break;
8244
8245 case G_DRIVE_START_STOP_TYPE_SHUTDOWN:
8246 {
8247 item_label = _("_Safely Remove Drive");
8248 }
8249 break;
8250
8251 case G_DRIVE_START_STOP_TYPE_NETWORK:
8252 {
8253 item_label = _("_Disconnect");
8254 }
8255 break;
8256
8257 case G_DRIVE_START_STOP_TYPE_MULTIDISK:
8258 {
8259 item_label = _("_Stop Multi-disk Drive");
8260 }
8261 break;
8262
8263 case G_DRIVE_START_STOP_TYPE_PASSWORD:
8264 {
8265 item_label = _("_Lock Drive");
8266 }
8267 break;
8268 }
8269
8270 menu_item = g_menu_item_new (item_label, "view.stop-volume");
8271 object = gtk_builder_get_object (builder, "drive-section");
8272 g_menu_append_item (G_MENU (object), menu_item);
8273 g_object_unref (menu_item);
8274 }
8275
8276 if (!priv->scripts_menu_updated)
8277 {
8278 update_scripts_menu (view, builder);
8279 priv->scripts_menu_updated = TRUE;
8280 }
8281 object = gtk_builder_get_object (builder, "scripts-submenu-section");
8282 nautilus_gmenu_set_from_model (G_MENU (object), priv->scripts_menu);
8283 }
8284
8285 static void
update_background_menu(NautilusFilesView * view,GtkBuilder * builder)8286 update_background_menu (NautilusFilesView *view,
8287 GtkBuilder *builder)
8288 {
8289 NautilusFilesViewPrivate *priv = nautilus_files_view_get_instance_private (view);
8290 GObject *object;
8291
8292 if (nautilus_files_view_supports_creating_files (view) &&
8293 !showing_recent_directory (view) &&
8294 !showing_starred_directory (view))
8295 {
8296 if (!priv->templates_menu_updated)
8297 {
8298 update_templates_menu (view, builder);
8299 priv->templates_menu_updated = TRUE;
8300 }
8301
8302 object = gtk_builder_get_object (builder, "templates-submenu");
8303 nautilus_gmenu_set_from_model (G_MENU (object), priv->templates_menu);
8304 }
8305 }
8306
8307 static void
real_update_context_menus(NautilusFilesView * view)8308 real_update_context_menus (NautilusFilesView *view)
8309 {
8310 NautilusFilesViewPrivate *priv;
8311 g_autoptr (GtkBuilder) builder = NULL;
8312 GObject *object;
8313
8314 priv = nautilus_files_view_get_instance_private (view);
8315 builder = gtk_builder_new_from_resource ("/org/gnome/nautilus/ui/nautilus-files-view-context-menus.ui");
8316
8317 g_clear_object (&priv->background_menu_model);
8318 g_clear_object (&priv->selection_menu_model);
8319
8320 object = gtk_builder_get_object (builder, "background-menu");
8321 priv->background_menu_model = g_object_ref (G_MENU (object));
8322
8323 object = gtk_builder_get_object (builder, "selection-menu");
8324 priv->selection_menu_model = g_object_ref (G_MENU (object));
8325
8326 update_selection_menu (view, builder);
8327 update_background_menu (view, builder);
8328 update_extensions_menus (view, builder);
8329
8330 nautilus_files_view_update_actions_state (view);
8331 }
8332
8333 /* Convenience function to reset the context menus owned by the view and update
8334 * them with the current state.
8335 * Children can subclass it and add items on the menu after chaining up to the
8336 * parent, so menus are already reseted.
8337 * It will also update the actions state, which will also update children
8338 * actions state if the children subclass nautilus_files_view_update_actions_state
8339 */
8340 void
nautilus_files_view_update_context_menus(NautilusFilesView * view)8341 nautilus_files_view_update_context_menus (NautilusFilesView *view)
8342 {
8343 g_assert (NAUTILUS_IS_FILES_VIEW (view));
8344
8345 NAUTILUS_FILES_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->update_context_menus (view);
8346 }
8347
8348 static void
nautilus_files_view_reset_view_menu(NautilusFilesView * view)8349 nautilus_files_view_reset_view_menu (NautilusFilesView *view)
8350 {
8351 NautilusFilesViewPrivate *priv;
8352 GActionGroup *view_action_group;
8353 gboolean sort_available;
8354 g_autofree gchar *zoom_level_percent = NULL;
8355 NautilusFile *file;
8356
8357 view_action_group = nautilus_files_view_get_action_group (view);
8358 priv = nautilus_files_view_get_instance_private (view);
8359 file = nautilus_files_view_get_directory_as_file (NAUTILUS_FILES_VIEW (view));
8360
8361 gtk_widget_set_visible (priv->visible_columns,
8362 g_action_group_has_action (view_action_group, "visible-columns"));
8363
8364 sort_available = g_action_group_get_action_enabled (view_action_group, "sort");
8365 gtk_widget_set_visible (priv->sort_menu, sort_available);
8366 gtk_widget_set_visible (priv->sort_trash_time,
8367 nautilus_file_is_in_trash (file));
8368
8369 /* We want to make insensitive available actions but that are not current
8370 * available due to the directory
8371 */
8372 gtk_widget_set_sensitive (priv->sort_menu,
8373 !nautilus_files_view_is_empty (view));
8374 gtk_widget_set_sensitive (priv->zoom_controls_box,
8375 !nautilus_files_view_is_empty (view));
8376
8377 zoom_level_percent = g_strdup_printf ("%.0f%%", nautilus_files_view_get_zoom_level_percentage (view) * 100.0);
8378 gtk_label_set_label (GTK_LABEL (priv->zoom_level_label), zoom_level_percent);
8379 }
8380
8381 /* Convenience function to reset the menus owned by the view but managed on
8382 * the toolbar, and update them with the current state.
8383 * It will also update the actions state, which will also update children
8384 * actions state if the children subclass nautilus_files_view_update_actions_state
8385 */
8386 void
nautilus_files_view_update_toolbar_menus(NautilusFilesView * view)8387 nautilus_files_view_update_toolbar_menus (NautilusFilesView *view)
8388 {
8389 NautilusWindow *window;
8390 NautilusFilesViewPrivate *priv;
8391
8392 g_assert (NAUTILUS_IS_FILES_VIEW (view));
8393
8394 priv = nautilus_files_view_get_instance_private (view);
8395
8396 /* Don't update after destroy (#349551),
8397 * or if we are not active.
8398 */
8399 if (priv->slot == NULL ||
8400 !priv->active)
8401 {
8402 return;
8403 }
8404 window = nautilus_files_view_get_window (view);
8405 nautilus_window_reset_menus (window);
8406
8407 nautilus_files_view_update_actions_state (view);
8408 nautilus_files_view_reset_view_menu (view);
8409 }
8410
8411 static GdkRectangle *
nautilus_files_view_reveal_for_selection_context_menu(NautilusFilesView * view)8412 nautilus_files_view_reveal_for_selection_context_menu (NautilusFilesView *view)
8413 {
8414 return NAUTILUS_FILES_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->reveal_for_selection_context_menu (view);
8415 }
8416
8417 /**
8418 * nautilus_files_view_pop_up_selection_context_menu
8419 *
8420 * Pop up a context menu appropriate to the selected items.
8421 * @view: NautilusFilesView of interest.
8422 * @event: The event that triggered this context menu.
8423 *
8424 **/
8425 void
nautilus_files_view_pop_up_selection_context_menu(NautilusFilesView * view,const GdkEvent * event)8426 nautilus_files_view_pop_up_selection_context_menu (NautilusFilesView *view,
8427 const GdkEvent *event)
8428 {
8429 NautilusFilesViewPrivate *priv;
8430
8431 g_assert (NAUTILUS_IS_FILES_VIEW (view));
8432
8433 priv = nautilus_files_view_get_instance_private (view);
8434
8435 /* Make the context menu items not flash as they update to proper disabled,
8436 * etc. states by forcing menus to update now.
8437 */
8438 update_context_menus_if_pending (view);
8439
8440 if (NULL == priv->selection_menu)
8441 {
8442 priv->selection_menu = gtk_menu_new ();
8443
8444 gtk_menu_attach_to_widget (GTK_MENU (priv->selection_menu),
8445 GTK_WIDGET (view),
8446 NULL);
8447 }
8448
8449 gtk_menu_shell_bind_model (GTK_MENU_SHELL (priv->selection_menu),
8450 G_MENU_MODEL (priv->selection_menu_model),
8451 NULL,
8452 TRUE);
8453
8454 if (event != NULL)
8455 {
8456 gtk_menu_popup_at_pointer (GTK_MENU (priv->selection_menu), event);
8457 }
8458 else
8459 {
8460 /* If triggered from the keyboard, popup at selection, not pointer */
8461 g_autofree GdkRectangle *rectangle = NULL;
8462
8463 rectangle = nautilus_files_view_reveal_for_selection_context_menu (view);
8464 g_return_if_fail (rectangle != NULL);
8465
8466 gtk_menu_popup_at_rect (GTK_MENU (priv->selection_menu),
8467 gtk_widget_get_window (GTK_WIDGET (view)),
8468 rectangle,
8469 GDK_GRAVITY_SOUTH_WEST,
8470 GDK_GRAVITY_NORTH_WEST,
8471 NULL);
8472 }
8473 }
8474
8475 /**
8476 * nautilus_files_view_pop_up_background_context_menu
8477 *
8478 * Pop up a context menu appropriate to the location in view.
8479 * @view: NautilusFilesView of interest.
8480 *
8481 **/
8482 void
nautilus_files_view_pop_up_background_context_menu(NautilusFilesView * view,const GdkEvent * event)8483 nautilus_files_view_pop_up_background_context_menu (NautilusFilesView *view,
8484 const GdkEvent *event)
8485 {
8486 NautilusFilesViewPrivate *priv;
8487
8488 g_assert (NAUTILUS_IS_FILES_VIEW (view));
8489
8490 priv = nautilus_files_view_get_instance_private (view);
8491
8492 /* Make the context menu items not flash as they update to proper disabled,
8493 * etc. states by forcing menus to update now.
8494 */
8495 update_context_menus_if_pending (view);
8496
8497 if (NULL == priv->background_menu)
8498 {
8499 priv->background_menu = gtk_menu_new ();
8500
8501 gtk_menu_attach_to_widget (GTK_MENU (priv->background_menu),
8502 GTK_WIDGET (view),
8503 NULL);
8504 }
8505 gtk_menu_shell_bind_model (GTK_MENU_SHELL (priv->background_menu),
8506 G_MENU_MODEL (priv->background_menu_model),
8507 NULL,
8508 TRUE);
8509 if (event != NULL)
8510 {
8511 gtk_menu_popup_at_pointer (GTK_MENU (priv->background_menu), event);
8512 }
8513 else
8514 {
8515 /* It was triggered from the keyboard, so pop up from the center of view.
8516 */
8517 gtk_menu_popup_at_widget (GTK_MENU (priv->background_menu),
8518 GTK_WIDGET (view),
8519 GDK_GRAVITY_CENTER,
8520 GDK_GRAVITY_CENTER,
8521 NULL);
8522 }
8523 }
8524
8525 static gboolean
popup_menu_callback(NautilusFilesView * view)8526 popup_menu_callback (NautilusFilesView *view)
8527 {
8528 g_autolist (NautilusFile) selection = NULL;
8529
8530 selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
8531
8532 if (selection != NULL)
8533 {
8534 nautilus_files_view_pop_up_selection_context_menu (view, NULL);
8535 }
8536 else
8537 {
8538 nautilus_files_view_pop_up_background_context_menu (view, NULL);
8539 }
8540
8541 return TRUE;
8542 }
8543
8544 static void
schedule_update_context_menus(NautilusFilesView * view)8545 schedule_update_context_menus (NautilusFilesView *view)
8546 {
8547 NautilusFilesViewPrivate *priv;
8548
8549 g_assert (NAUTILUS_IS_FILES_VIEW (view));
8550
8551 priv = nautilus_files_view_get_instance_private (view);
8552
8553 /* Don't schedule updates after destroy (#349551),
8554 * or if we are not active.
8555 */
8556 if (priv->slot == NULL ||
8557 !priv->active)
8558 {
8559 return;
8560 }
8561
8562 /* Schedule a menu update with the current update interval */
8563 if (priv->update_context_menus_timeout_id == 0)
8564 {
8565 priv->update_context_menus_timeout_id
8566 = g_timeout_add (priv->update_interval, update_context_menus_timeout_callback, view);
8567 }
8568 }
8569
8570 static void
remove_update_status_idle_callback(NautilusFilesView * view)8571 remove_update_status_idle_callback (NautilusFilesView *view)
8572 {
8573 NautilusFilesViewPrivate *priv;
8574
8575 priv = nautilus_files_view_get_instance_private (view);
8576
8577 if (priv->update_status_idle_id != 0)
8578 {
8579 g_source_remove (priv->update_status_idle_id);
8580 priv->update_status_idle_id = 0;
8581 }
8582 }
8583
8584 static gboolean
update_status_idle_callback(gpointer data)8585 update_status_idle_callback (gpointer data)
8586 {
8587 NautilusFilesViewPrivate *priv;
8588 NautilusFilesView *view;
8589
8590 view = NAUTILUS_FILES_VIEW (data);
8591 priv = nautilus_files_view_get_instance_private (view);
8592 nautilus_files_view_display_selection_info (view);
8593 priv->update_status_idle_id = 0;
8594 return FALSE;
8595 }
8596
8597 static void
schedule_update_status(NautilusFilesView * view)8598 schedule_update_status (NautilusFilesView *view)
8599 {
8600 NautilusFilesViewPrivate *priv;
8601
8602 g_assert (NAUTILUS_IS_FILES_VIEW (view));
8603
8604 priv = nautilus_files_view_get_instance_private (view);
8605
8606 /* Make sure we haven't already destroyed it */
8607 if (priv->slot == NULL)
8608 {
8609 return;
8610 }
8611
8612 if (priv->loading)
8613 {
8614 /* Don't update status bar while loading the dir */
8615 return;
8616 }
8617
8618 if (priv->update_status_idle_id == 0)
8619 {
8620 priv->update_status_idle_id =
8621 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE - 20,
8622 update_status_idle_callback, view, NULL);
8623 }
8624 }
8625
8626 /**
8627 * nautilus_files_view_notify_selection_changed:
8628 *
8629 * Notify this view that the selection has changed. This is normally
8630 * called only by subclasses.
8631 * @view: NautilusFilesView whose selection has changed.
8632 *
8633 **/
8634 void
nautilus_files_view_notify_selection_changed(NautilusFilesView * view)8635 nautilus_files_view_notify_selection_changed (NautilusFilesView *view)
8636 {
8637 NautilusFilesViewPrivate *priv;
8638 GtkWindow *window;
8639 g_autolist (NautilusFile) selection = NULL;
8640
8641 g_return_if_fail (NAUTILUS_IS_FILES_VIEW (view));
8642
8643 priv = nautilus_files_view_get_instance_private (view);
8644
8645 selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
8646 window = nautilus_files_view_get_containing_window (view);
8647 DEBUG_FILES (selection, "Selection changed in window %p", window);
8648
8649 priv->selection_was_removed = FALSE;
8650
8651 /* Schedule a display of the new selection. */
8652 if (priv->display_selection_idle_id == 0)
8653 {
8654 priv->display_selection_idle_id
8655 = g_idle_add (display_selection_info_idle_callback,
8656 view);
8657 }
8658
8659 if (priv->batching_selection_level != 0)
8660 {
8661 priv->selection_changed_while_batched = TRUE;
8662 }
8663 else
8664 {
8665 /* Here is the work we do only when we're not
8666 * batching selection changes. In other words, it's the slower
8667 * stuff that we don't want to slow down selection techniques
8668 * such as rubberband-selecting in icon view.
8669 */
8670
8671 /* Schedule an update of menu item states to match selection */
8672 schedule_update_context_menus (view);
8673 }
8674 }
8675
8676 static void
file_changed_callback(NautilusFile * file,gpointer callback_data)8677 file_changed_callback (NautilusFile *file,
8678 gpointer callback_data)
8679 {
8680 NautilusFilesView *view = NAUTILUS_FILES_VIEW (callback_data);
8681
8682 schedule_changes (view);
8683
8684 schedule_update_context_menus (view);
8685 schedule_update_status (view);
8686 }
8687
8688 /**
8689 * load_directory:
8690 *
8691 * Switch the displayed location to a new uri. If the uri is not valid,
8692 * the location will not be switched; user feedback will be provided instead.
8693 * @view: NautilusFilesView whose location will be changed.
8694 * @uri: A string representing the uri to switch to.
8695 *
8696 **/
8697 static void
load_directory(NautilusFilesView * view,NautilusDirectory * directory)8698 load_directory (NautilusFilesView *view,
8699 NautilusDirectory *directory)
8700 {
8701 NautilusFileAttributes attributes;
8702 NautilusFilesViewPrivate *priv;
8703
8704 g_assert (NAUTILUS_IS_FILES_VIEW (view));
8705 g_assert (NAUTILUS_IS_DIRECTORY (directory));
8706
8707 priv = nautilus_files_view_get_instance_private (view);
8708
8709 nautilus_profile_start (NULL);
8710
8711 nautilus_files_view_stop_loading (view);
8712 g_signal_emit (view, signals[CLEAR], 0);
8713
8714 priv->loading = TRUE;
8715
8716 setup_loading_floating_bar (view);
8717
8718 /* HACK: Fix for https://gitlab.gnome.org/GNOME/nautilus/-/issues/1452 */
8719 {
8720 GtkScrolledWindow *content = GTK_SCROLLED_WINDOW (priv->scrolled_window);
8721
8722 /* If we load a new location while the view is still scrolling due to
8723 * kinetic deceleration, we get a sudden jump to the same scrolling
8724 * position as the previous location, as well as residual scrolling
8725 * movement in the new location.
8726 *
8727 * This is both undesirable and unexpected from a user POV, so we want
8728 * to abort deceleration when switching locations.
8729 *
8730 * However, gtk_scrolled_window_cancel_deceleration() is private. So,
8731 * we make use of an undocumented behavior of ::set_kinetic_scrolling(),
8732 * which calls ::cancel_deceleration() when set to FALSE.
8733 */
8734 gtk_scrolled_window_set_kinetic_scrolling (content, FALSE);
8735 gtk_scrolled_window_set_kinetic_scrolling (content, TRUE);
8736 }
8737
8738 /* Update menus when directory is empty, before going to new
8739 * location, so they won't have any false lingering knowledge
8740 * of old selection.
8741 */
8742 schedule_update_context_menus (view);
8743
8744 while (priv->subdirectory_list != NULL)
8745 {
8746 nautilus_files_view_remove_subdirectory (view,
8747 priv->subdirectory_list->data);
8748 }
8749
8750 /* Avoid freeing it and won't be able to ref it */
8751 if (priv->model != directory)
8752 {
8753 nautilus_directory_unref (priv->model);
8754 priv->model = nautilus_directory_ref (directory);
8755 }
8756
8757 nautilus_file_unref (priv->directory_as_file);
8758 priv->directory_as_file = nautilus_directory_get_corresponding_file (directory);
8759
8760 g_clear_object (&priv->location);
8761 priv->location = nautilus_directory_get_location (directory);
8762
8763 g_object_notify (G_OBJECT (view), "location");
8764 g_object_notify (G_OBJECT (view), "loading");
8765 g_object_notify (G_OBJECT (view), "searching");
8766
8767 /* FIXME bugzilla.gnome.org 45062: In theory, we also need to monitor metadata here (as
8768 * well as doing a call when ready), in case external forces
8769 * change the directory's file metadata.
8770 */
8771 attributes =
8772 NAUTILUS_FILE_ATTRIBUTE_INFO |
8773 NAUTILUS_FILE_ATTRIBUTE_MOUNT |
8774 NAUTILUS_FILE_ATTRIBUTE_FILESYSTEM_INFO;
8775 priv->metadata_for_directory_as_file_pending = TRUE;
8776 priv->metadata_for_files_in_directory_pending = TRUE;
8777 nautilus_file_call_when_ready
8778 (priv->directory_as_file,
8779 attributes,
8780 metadata_for_directory_as_file_ready_callback, view);
8781 nautilus_directory_call_when_ready
8782 (priv->model,
8783 attributes,
8784 FALSE,
8785 metadata_for_files_in_directory_ready_callback, view);
8786
8787 /* If capabilities change, then we need to update the menus
8788 * because of New Folder, and relative emblems.
8789 */
8790 attributes =
8791 NAUTILUS_FILE_ATTRIBUTE_INFO |
8792 NAUTILUS_FILE_ATTRIBUTE_FILESYSTEM_INFO;
8793 nautilus_file_monitor_add (priv->directory_as_file,
8794 &priv->directory_as_file,
8795 attributes);
8796
8797 priv->file_changed_handler_id = g_signal_connect
8798 (priv->directory_as_file, "changed",
8799 G_CALLBACK (file_changed_callback), view);
8800
8801 nautilus_profile_end (NULL);
8802 }
8803
8804 static void
finish_loading(NautilusFilesView * view)8805 finish_loading (NautilusFilesView *view)
8806 {
8807 NautilusFileAttributes attributes;
8808 NautilusFilesViewPrivate *priv;
8809
8810 priv = nautilus_files_view_get_instance_private (view);
8811
8812 nautilus_profile_start (NULL);
8813
8814 /* Tell interested parties that we've begun loading this directory now.
8815 * Subclasses use this to know that the new metadata is now available.
8816 */
8817 nautilus_profile_start ("BEGIN_LOADING");
8818 g_signal_emit (view, signals[BEGIN_LOADING], 0);
8819 nautilus_profile_end ("BEGIN_LOADING");
8820
8821 nautilus_files_view_check_empty_states (view);
8822
8823 if (nautilus_directory_are_all_files_seen (priv->model))
8824 {
8825 /* Unschedule a pending update and schedule a new one with the minimal
8826 * update interval. This gives the view a short chance at gathering the
8827 * (cached) deep counts.
8828 */
8829 unschedule_display_of_pending_files (view);
8830 schedule_timeout_display_of_pending_files (view, UPDATE_INTERVAL_MIN);
8831 }
8832
8833 /* Start loading. */
8834
8835 /* Connect handlers to learn about loading progress. */
8836 priv->done_loading_handler_id = g_signal_connect (priv->model, "done-loading",
8837 G_CALLBACK (done_loading_callback), view);
8838 priv->load_error_handler_id = g_signal_connect (priv->model, "load-error",
8839 G_CALLBACK (load_error_callback), view);
8840
8841 /* Monitor the things needed to get the right icon. Also
8842 * monitor a directory's item count because the "size"
8843 * attribute is based on that, and the file's metadata
8844 * and possible custom name.
8845 */
8846 attributes =
8847 NAUTILUS_FILE_ATTRIBUTES_FOR_ICON |
8848 NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT |
8849 NAUTILUS_FILE_ATTRIBUTE_INFO |
8850 NAUTILUS_FILE_ATTRIBUTE_MOUNT |
8851 NAUTILUS_FILE_ATTRIBUTE_EXTENSION_INFO;
8852
8853 priv->files_added_handler_id = g_signal_connect
8854 (priv->model, "files-added",
8855 G_CALLBACK (files_added_callback), view);
8856 priv->files_changed_handler_id = g_signal_connect
8857 (priv->model, "files-changed",
8858 G_CALLBACK (files_changed_callback), view);
8859
8860 nautilus_directory_file_monitor_add (priv->model,
8861 &priv->model,
8862 priv->show_hidden_files,
8863 attributes,
8864 files_added_callback, view);
8865
8866 nautilus_profile_end (NULL);
8867 }
8868
8869 static void
finish_loading_if_all_metadata_loaded(NautilusFilesView * view)8870 finish_loading_if_all_metadata_loaded (NautilusFilesView *view)
8871 {
8872 NautilusFilesViewPrivate *priv;
8873
8874 priv = nautilus_files_view_get_instance_private (view);
8875
8876 if (!priv->metadata_for_directory_as_file_pending &&
8877 !priv->metadata_for_files_in_directory_pending)
8878 {
8879 finish_loading (view);
8880 }
8881 }
8882
8883 static void
metadata_for_directory_as_file_ready_callback(NautilusFile * file,gpointer callback_data)8884 metadata_for_directory_as_file_ready_callback (NautilusFile *file,
8885 gpointer callback_data)
8886 {
8887 NautilusFilesView *view;
8888 NautilusFilesViewPrivate *priv;
8889
8890 view = callback_data;
8891
8892 g_assert (NAUTILUS_IS_FILES_VIEW (view));
8893 priv = nautilus_files_view_get_instance_private (view);
8894 g_assert (priv->directory_as_file == file);
8895 g_assert (priv->metadata_for_directory_as_file_pending);
8896
8897 nautilus_profile_start (NULL);
8898
8899 priv->metadata_for_directory_as_file_pending = FALSE;
8900
8901 finish_loading_if_all_metadata_loaded (view);
8902 nautilus_profile_end (NULL);
8903 }
8904
8905 static void
metadata_for_files_in_directory_ready_callback(NautilusDirectory * directory,GList * files,gpointer callback_data)8906 metadata_for_files_in_directory_ready_callback (NautilusDirectory *directory,
8907 GList *files,
8908 gpointer callback_data)
8909 {
8910 NautilusFilesView *view;
8911 NautilusFilesViewPrivate *priv;
8912
8913 view = callback_data;
8914
8915 g_assert (NAUTILUS_IS_FILES_VIEW (view));
8916 priv = nautilus_files_view_get_instance_private (view);
8917 g_assert (priv->model == directory);
8918 g_assert (priv->metadata_for_files_in_directory_pending);
8919
8920 nautilus_profile_start (NULL);
8921
8922 priv->metadata_for_files_in_directory_pending = FALSE;
8923
8924 finish_loading_if_all_metadata_loaded (view);
8925 nautilus_profile_end (NULL);
8926 }
8927
8928 static void
disconnect_model_handlers(NautilusFilesView * view)8929 disconnect_model_handlers (NautilusFilesView *view)
8930 {
8931 NautilusFilesViewPrivate *priv;
8932
8933 priv = nautilus_files_view_get_instance_private (view);
8934
8935 if (priv->model == NULL)
8936 {
8937 return;
8938 }
8939 g_clear_signal_handler (&priv->files_added_handler_id, priv->model);
8940 g_clear_signal_handler (&priv->files_changed_handler_id, priv->model);
8941 g_clear_signal_handler (&priv->done_loading_handler_id, priv->model);
8942 g_clear_signal_handler (&priv->load_error_handler_id, priv->model);
8943 g_clear_signal_handler (&priv->file_changed_handler_id, priv->directory_as_file);
8944 nautilus_file_cancel_call_when_ready (priv->directory_as_file,
8945 metadata_for_directory_as_file_ready_callback,
8946 view);
8947 nautilus_directory_cancel_callback (priv->model,
8948 metadata_for_files_in_directory_ready_callback,
8949 view);
8950 nautilus_directory_file_monitor_remove (priv->model,
8951 &priv->model);
8952 nautilus_file_monitor_remove (priv->directory_as_file,
8953 &priv->directory_as_file);
8954 }
8955
8956 static void
nautilus_files_view_select_file(NautilusFilesView * view,NautilusFile * file)8957 nautilus_files_view_select_file (NautilusFilesView *view,
8958 NautilusFile *file)
8959 {
8960 GList file_list;
8961
8962 file_list.data = file;
8963 file_list.next = NULL;
8964 file_list.prev = NULL;
8965 nautilus_files_view_call_set_selection (view, &file_list);
8966 }
8967
8968 /**
8969 * nautilus_files_view_stop_loading:
8970 *
8971 * Stop the current ongoing process, such as switching to a new uri.
8972 * @view: NautilusFilesView in question.
8973 *
8974 **/
8975 void
nautilus_files_view_stop_loading(NautilusFilesView * view)8976 nautilus_files_view_stop_loading (NautilusFilesView *view)
8977 {
8978 NautilusFilesViewPrivate *priv;
8979
8980 g_return_if_fail (NAUTILUS_IS_FILES_VIEW (view));
8981
8982 priv = nautilus_files_view_get_instance_private (view);
8983
8984 unschedule_display_of_pending_files (view);
8985 reset_update_interval (view);
8986
8987 /* Free extra undisplayed files */
8988 g_list_free_full (priv->new_added_files, file_and_directory_free);
8989 priv->new_added_files = NULL;
8990
8991 g_list_free_full (priv->new_changed_files, file_and_directory_free);
8992 priv->new_changed_files = NULL;
8993
8994 g_hash_table_remove_all (priv->non_ready_files);
8995
8996 g_list_free_full (priv->old_added_files, file_and_directory_free);
8997 priv->old_added_files = NULL;
8998
8999 g_list_free_full (priv->old_changed_files, file_and_directory_free);
9000 priv->old_changed_files = NULL;
9001
9002 g_list_free_full (priv->pending_selection, g_object_unref);
9003 priv->pending_selection = NULL;
9004
9005 done_loading (view, FALSE);
9006
9007 disconnect_model_handlers (view);
9008 }
9009
9010 gboolean
nautilus_files_view_is_editable(NautilusFilesView * view)9011 nautilus_files_view_is_editable (NautilusFilesView *view)
9012 {
9013 NautilusDirectory *directory;
9014
9015 directory = nautilus_files_view_get_model (view);
9016
9017 if (directory != NULL)
9018 {
9019 return nautilus_directory_is_editable (directory);
9020 }
9021
9022 return TRUE;
9023 }
9024
9025 static gboolean
nautilus_files_view_is_read_only(NautilusFilesView * view)9026 nautilus_files_view_is_read_only (NautilusFilesView *view)
9027 {
9028 NautilusFile *file;
9029
9030 if (!nautilus_files_view_is_editable (view))
9031 {
9032 return TRUE;
9033 }
9034
9035 file = nautilus_files_view_get_directory_as_file (view);
9036 if (file != NULL)
9037 {
9038 return !nautilus_file_can_write (file);
9039 }
9040 return FALSE;
9041 }
9042
9043 /**
9044 * nautilus_files_view_should_show_file
9045 *
9046 * Returns whether or not this file should be displayed based on
9047 * current filtering options.
9048 */
9049 gboolean
nautilus_files_view_should_show_file(NautilusFilesView * view,NautilusFile * file)9050 nautilus_files_view_should_show_file (NautilusFilesView *view,
9051 NautilusFile *file)
9052 {
9053 NautilusFilesViewPrivate *priv;
9054
9055 priv = nautilus_files_view_get_instance_private (view);
9056
9057 return nautilus_file_should_show (file,
9058 priv->show_hidden_files);
9059 }
9060
9061 void
nautilus_files_view_ignore_hidden_file_preferences(NautilusFilesView * view)9062 nautilus_files_view_ignore_hidden_file_preferences (NautilusFilesView *view)
9063 {
9064 NautilusFilesViewPrivate *priv;
9065
9066 priv = nautilus_files_view_get_instance_private (view);
9067
9068 g_return_if_fail (priv->model == NULL);
9069
9070 if (priv->ignore_hidden_file_preferences)
9071 {
9072 return;
9073 }
9074
9075 priv->show_hidden_files = FALSE;
9076 priv->ignore_hidden_file_preferences = TRUE;
9077 }
9078
9079 char *
nautilus_files_view_get_uri(NautilusFilesView * view)9080 nautilus_files_view_get_uri (NautilusFilesView *view)
9081 {
9082 NautilusFilesViewPrivate *priv;
9083
9084 g_return_val_if_fail (NAUTILUS_IS_FILES_VIEW (view), NULL);
9085
9086 priv = nautilus_files_view_get_instance_private (view);
9087
9088 if (priv->model == NULL)
9089 {
9090 return NULL;
9091 }
9092 return nautilus_directory_get_uri (priv->model);
9093 }
9094
9095 void
nautilus_files_view_move_copy_items(NautilusFilesView * view,const GList * item_uris,const char * target_uri,int copy_action)9096 nautilus_files_view_move_copy_items (NautilusFilesView *view,
9097 const GList *item_uris,
9098 const char *target_uri,
9099 int copy_action)
9100 {
9101 NautilusFile *target_file;
9102
9103 target_file = nautilus_file_get_existing_by_uri (target_uri);
9104 if (copy_action == GDK_ACTION_COPY &&
9105 nautilus_is_file_roller_installed () &&
9106 target_file != NULL &&
9107 nautilus_file_is_archive (target_file))
9108 {
9109 char *command, *quoted_uri, *tmp;
9110 const GList *l;
9111 GdkScreen *screen;
9112
9113 /* Handle dropping onto a file-roller archiver file, instead of starting a move/copy */
9114
9115 nautilus_file_unref (target_file);
9116
9117 quoted_uri = g_shell_quote (target_uri);
9118 command = g_strconcat ("file-roller -a ", quoted_uri, NULL);
9119 g_free (quoted_uri);
9120
9121 for (l = item_uris; l != NULL; l = l->next)
9122 {
9123 quoted_uri = g_shell_quote ((char *) l->data);
9124
9125 tmp = g_strconcat (command, " ", quoted_uri, NULL);
9126 g_free (command);
9127 command = tmp;
9128
9129 g_free (quoted_uri);
9130 }
9131
9132 screen = gtk_widget_get_screen (GTK_WIDGET (view));
9133 if (screen == NULL)
9134 {
9135 screen = gdk_screen_get_default ();
9136 }
9137
9138 nautilus_launch_application_from_command (screen, command, FALSE, NULL);
9139 g_free (command);
9140
9141 return;
9142 }
9143 nautilus_file_unref (target_file);
9144
9145 nautilus_file_operations_copy_move
9146 (item_uris,
9147 target_uri, copy_action, GTK_WIDGET (view),
9148 NULL,
9149 copy_move_done_callback, pre_copy_move (view));
9150 }
9151
9152 static void
nautilus_files_view_trash_state_changed_callback(NautilusTrashMonitor * trash_monitor,gboolean state,gpointer callback_data)9153 nautilus_files_view_trash_state_changed_callback (NautilusTrashMonitor *trash_monitor,
9154 gboolean state,
9155 gpointer callback_data)
9156 {
9157 NautilusFilesView *view;
9158
9159 view = (NautilusFilesView *) callback_data;
9160 g_assert (NAUTILUS_IS_FILES_VIEW (view));
9161
9162 schedule_update_context_menus (view);
9163 }
9164
9165 void
nautilus_files_view_start_batching_selection_changes(NautilusFilesView * view)9166 nautilus_files_view_start_batching_selection_changes (NautilusFilesView *view)
9167 {
9168 NautilusFilesViewPrivate *priv;
9169
9170 g_return_if_fail (NAUTILUS_IS_FILES_VIEW (view));
9171 priv = nautilus_files_view_get_instance_private (view);
9172
9173 ++priv->batching_selection_level;
9174 priv->selection_changed_while_batched = FALSE;
9175 }
9176
9177 void
nautilus_files_view_stop_batching_selection_changes(NautilusFilesView * view)9178 nautilus_files_view_stop_batching_selection_changes (NautilusFilesView *view)
9179 {
9180 NautilusFilesViewPrivate *priv;
9181
9182 g_return_if_fail (NAUTILUS_IS_FILES_VIEW (view));
9183 priv = nautilus_files_view_get_instance_private (view);
9184 g_return_if_fail (priv->batching_selection_level > 0);
9185
9186 if (--priv->batching_selection_level == 0)
9187 {
9188 if (priv->selection_changed_while_batched)
9189 {
9190 nautilus_files_view_notify_selection_changed (view);
9191 }
9192 }
9193 }
9194
9195 static void
nautilus_files_view_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)9196 nautilus_files_view_get_property (GObject *object,
9197 guint prop_id,
9198 GValue *value,
9199 GParamSpec *pspec)
9200 {
9201 NautilusFilesView *view = NAUTILUS_FILES_VIEW (object);
9202 NautilusFilesViewPrivate *priv = nautilus_files_view_get_instance_private (view);
9203
9204 switch (prop_id)
9205 {
9206 case PROP_LOADING:
9207 {
9208 g_value_set_boolean (value, nautilus_view_is_loading (NAUTILUS_VIEW (view)));
9209 }
9210 break;
9211
9212 case PROP_SEARCHING:
9213 {
9214 g_value_set_boolean (value, nautilus_view_is_searching (NAUTILUS_VIEW (view)));
9215 }
9216 break;
9217
9218 case PROP_LOCATION:
9219 {
9220 g_value_set_object (value, nautilus_view_get_location (NAUTILUS_VIEW (view)));
9221 }
9222 break;
9223
9224 case PROP_SELECTION:
9225 {
9226 g_value_set_pointer (value, nautilus_view_get_selection (NAUTILUS_VIEW (view)));
9227 }
9228 break;
9229
9230 case PROP_SEARCH_QUERY:
9231 {
9232 g_value_set_object (value, priv->search_query);
9233 }
9234 break;
9235
9236 case PROP_EXTENSIONS_BACKGROUND_MENU:
9237 {
9238 g_value_set_object (value,
9239 real_get_extensions_background_menu (NAUTILUS_VIEW (view)));
9240 }
9241 break;
9242
9243 case PROP_TEMPLATES_MENU:
9244 {
9245 g_value_set_object (value,
9246 real_get_templates_menu (NAUTILUS_VIEW (view)));
9247 }
9248 break;
9249
9250 default:
9251 {
9252 g_assert_not_reached ();
9253 }
9254 break;
9255 }
9256 }
9257
9258 static void
nautilus_files_view_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)9259 nautilus_files_view_set_property (GObject *object,
9260 guint prop_id,
9261 const GValue *value,
9262 GParamSpec *pspec)
9263 {
9264 NautilusFilesView *directory_view;
9265 NautilusFilesViewPrivate *priv;
9266 NautilusWindowSlot *slot;
9267
9268 directory_view = NAUTILUS_FILES_VIEW (object);
9269 priv = nautilus_files_view_get_instance_private (directory_view);
9270
9271 switch (prop_id)
9272 {
9273 case PROP_WINDOW_SLOT:
9274 {
9275 g_assert (priv->slot == NULL);
9276
9277 slot = NAUTILUS_WINDOW_SLOT (g_value_get_object (value));
9278 priv->slot = slot;
9279
9280 g_signal_connect_object (priv->slot,
9281 "notify::active", G_CALLBACK (slot_active_changed),
9282 directory_view, 0);
9283 }
9284 break;
9285
9286 case PROP_SUPPORTS_ZOOMING:
9287 {
9288 priv->supports_zooming = g_value_get_boolean (value);
9289 }
9290 break;
9291
9292 case PROP_LOCATION:
9293 {
9294 nautilus_view_set_location (NAUTILUS_VIEW (directory_view), g_value_get_object (value));
9295 }
9296 break;
9297
9298 case PROP_SEARCH_QUERY:
9299 {
9300 nautilus_view_set_search_query (NAUTILUS_VIEW (directory_view), g_value_get_object (value));
9301 }
9302 break;
9303
9304 case PROP_SELECTION:
9305 {
9306 nautilus_view_set_selection (NAUTILUS_VIEW (directory_view), g_value_get_pointer (value));
9307 }
9308 break;
9309
9310 case PROP_EXTENSIONS_BACKGROUND_MENU:
9311 {
9312 real_set_extensions_background_menu (NAUTILUS_VIEW (directory_view),
9313 g_value_get_object (value));
9314 }
9315 break;
9316
9317 case PROP_TEMPLATES_MENU:
9318 {
9319 real_set_templates_menu (NAUTILUS_VIEW (directory_view),
9320 g_value_get_object (value));
9321 }
9322 break;
9323
9324 default:
9325 {
9326 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
9327 }
9328 break;
9329 }
9330 }
9331
9332 /* handle Ctrl+Scroll, which will cause a zoom-in/out */
9333 static gboolean
on_event(GtkWidget * widget,GdkEvent * event,gpointer user_data)9334 on_event (GtkWidget *widget,
9335 GdkEvent *event,
9336 gpointer user_data)
9337 {
9338 NautilusFilesView *directory_view;
9339 static gdouble total_delta_y = 0;
9340 GdkModifierType state;
9341 GdkScrollDirection direction;
9342 gdouble delta_x, delta_y;
9343
9344 directory_view = NAUTILUS_FILES_VIEW (widget);
9345
9346 if (gdk_event_get_event_type (event) != GDK_SCROLL)
9347 {
9348 return GDK_EVENT_PROPAGATE;
9349 }
9350
9351 if (!gdk_event_get_state (event, &state))
9352 {
9353 return GDK_EVENT_PROPAGATE;
9354 }
9355
9356 if (!(state & GDK_CONTROL_MASK))
9357 {
9358 return GDK_EVENT_PROPAGATE;
9359 }
9360
9361 if (gdk_event_get_scroll_direction (event, &direction))
9362 {
9363 if (direction == GDK_SCROLL_UP)
9364 {
9365 /* Zoom In */
9366 nautilus_files_view_bump_zoom_level (directory_view, 1);
9367 return GDK_EVENT_STOP;
9368 }
9369 else if (direction == GDK_SCROLL_DOWN)
9370 {
9371 /* Zoom Out */
9372 nautilus_files_view_bump_zoom_level (directory_view, -1);
9373 return GDK_EVENT_STOP;
9374 }
9375 }
9376
9377 if (gdk_event_get_scroll_deltas (event, &delta_x, &delta_y))
9378 {
9379 /* try to emulate a normal scrolling event by summing deltas */
9380 total_delta_y += delta_y;
9381
9382 if (total_delta_y >= 1)
9383 {
9384 total_delta_y = 0;
9385 /* emulate scroll down */
9386 nautilus_files_view_bump_zoom_level (directory_view, -1);
9387 return GDK_EVENT_STOP;
9388 }
9389 else if (total_delta_y <= -1)
9390 {
9391 total_delta_y = 0;
9392 /* emulate scroll up */
9393 nautilus_files_view_bump_zoom_level (directory_view, 1);
9394 return GDK_EVENT_STOP;
9395 }
9396 else
9397 {
9398 /* eat event */
9399 return GDK_EVENT_STOP;
9400 }
9401 }
9402
9403 return GDK_EVENT_PROPAGATE;
9404 }
9405
9406 static void
action_reload_enabled_changed(GActionGroup * action_group,gchar * action_name,gboolean enabled,NautilusFilesView * view)9407 action_reload_enabled_changed (GActionGroup *action_group,
9408 gchar *action_name,
9409 gboolean enabled,
9410 NautilusFilesView *view)
9411 {
9412 NautilusFilesViewPrivate *priv;
9413
9414 priv = nautilus_files_view_get_instance_private (view);
9415
9416 gtk_widget_set_visible (priv->reload, enabled);
9417 }
9418
9419 static void
action_stop_enabled_changed(GActionGroup * action_group,gchar * action_name,gboolean enabled,NautilusFilesView * view)9420 action_stop_enabled_changed (GActionGroup *action_group,
9421 gchar *action_name,
9422 gboolean enabled,
9423 NautilusFilesView *view)
9424 {
9425 NautilusFilesViewPrivate *priv;
9426
9427 priv = nautilus_files_view_get_instance_private (view);
9428
9429 gtk_widget_set_visible (priv->stop, enabled);
9430 }
9431
9432 static void
nautilus_files_view_parent_set(GtkWidget * widget,GtkWidget * old_parent)9433 nautilus_files_view_parent_set (GtkWidget *widget,
9434 GtkWidget *old_parent)
9435 {
9436 NautilusWindow *window;
9437 NautilusFilesView *view;
9438 NautilusFilesViewPrivate *priv;
9439 GtkWidget *parent;
9440
9441 view = NAUTILUS_FILES_VIEW (widget);
9442 priv = nautilus_files_view_get_instance_private (view);
9443
9444 parent = gtk_widget_get_parent (widget);
9445 window = nautilus_files_view_get_window (view);
9446 g_assert (parent == NULL || old_parent == NULL);
9447
9448 if (GTK_WIDGET_CLASS (nautilus_files_view_parent_class)->parent_set != NULL)
9449 {
9450 GTK_WIDGET_CLASS (nautilus_files_view_parent_class)->parent_set (widget, old_parent);
9451 }
9452
9453 if (priv->stop_signal_handler > 0)
9454 {
9455 g_signal_handler_disconnect (window, priv->stop_signal_handler);
9456 priv->stop_signal_handler = 0;
9457 }
9458
9459 if (priv->reload_signal_handler > 0)
9460 {
9461 g_signal_handler_disconnect (window, priv->reload_signal_handler);
9462 priv->reload_signal_handler = 0;
9463 }
9464
9465 if (parent != NULL)
9466 {
9467 g_assert (old_parent == NULL);
9468
9469 if (priv->slot == nautilus_window_get_active_slot (window))
9470 {
9471 priv->active = TRUE;
9472 gtk_widget_insert_action_group (GTK_WIDGET (nautilus_files_view_get_window (view)),
9473 "view",
9474 G_ACTION_GROUP (priv->view_action_group));
9475 }
9476
9477 priv->stop_signal_handler =
9478 g_signal_connect (window,
9479 "action-enabled-changed::stop",
9480 G_CALLBACK (action_stop_enabled_changed),
9481 view);
9482 priv->reload_signal_handler =
9483 g_signal_connect (window,
9484 "action-enabled-changed::reload",
9485 G_CALLBACK (action_reload_enabled_changed),
9486 view);
9487 }
9488 else
9489 {
9490 remove_update_context_menus_timeout_callback (view);
9491 /* Only remove the action group if it matchs the current view
9492 * action group. If not, we can remove an action group set by
9493 * a different view i.e. if the slot_active function is called
9494 * before this one
9495 */
9496 if (gtk_widget_get_action_group (GTK_WIDGET (window), "view") ==
9497 priv->view_action_group)
9498 {
9499 gtk_widget_insert_action_group (GTK_WIDGET (nautilus_files_view_get_window (view)),
9500 "view",
9501 NULL);
9502 }
9503 }
9504 }
9505
9506 static gboolean
nautilus_files_view_event(GtkWidget * widget,GdkEvent * event)9507 nautilus_files_view_event (GtkWidget *widget,
9508 GdkEvent *event)
9509 {
9510 NautilusFilesView *view;
9511 NautilusFilesViewPrivate *priv;
9512 guint keyval;
9513
9514 if (gdk_event_get_event_type (event) != GDK_KEY_PRESS)
9515 {
9516 return GDK_EVENT_PROPAGATE;
9517 }
9518
9519 view = NAUTILUS_FILES_VIEW (widget);
9520 priv = nautilus_files_view_get_instance_private (view);
9521
9522 if (G_UNLIKELY (!gdk_event_get_keyval (event, &keyval)))
9523 {
9524 g_return_val_if_reached (GDK_EVENT_PROPAGATE);
9525 }
9526
9527 for (gint i = 0; i < G_N_ELEMENTS (extra_view_keybindings); i++)
9528 {
9529 if (extra_view_keybindings[i].keyval == keyval)
9530 {
9531 GAction *action;
9532
9533 action = g_action_map_lookup_action (G_ACTION_MAP (priv->view_action_group),
9534 extra_view_keybindings[i].action);
9535
9536 if (g_action_get_enabled (action))
9537 {
9538 g_action_activate (action, NULL);
9539 return GDK_EVENT_STOP;
9540 }
9541
9542 break;
9543 }
9544 }
9545
9546 return GDK_EVENT_PROPAGATE;
9547 }
9548
9549 static NautilusQuery *
nautilus_files_view_get_search_query(NautilusView * view)9550 nautilus_files_view_get_search_query (NautilusView *view)
9551 {
9552 NautilusFilesViewPrivate *priv;
9553
9554 priv = nautilus_files_view_get_instance_private (NAUTILUS_FILES_VIEW (view));
9555
9556 return priv->search_query;
9557 }
9558
9559 static void
set_search_query_internal(NautilusFilesView * files_view,NautilusQuery * query,NautilusDirectory * base_model)9560 set_search_query_internal (NautilusFilesView *files_view,
9561 NautilusQuery *query,
9562 NautilusDirectory *base_model)
9563 {
9564 GFile *location;
9565 NautilusFilesViewPrivate *priv;
9566
9567 location = NULL;
9568 priv = nautilus_files_view_get_instance_private (files_view);
9569
9570 g_set_object (&priv->search_query, query);
9571 g_object_notify (G_OBJECT (files_view), "search-query");
9572
9573 if (!nautilus_query_is_empty (query))
9574 {
9575 if (nautilus_view_is_searching (NAUTILUS_VIEW (files_view)))
9576 {
9577 /*
9578 * Reuse the search directory and reload it.
9579 */
9580 nautilus_search_directory_set_query (NAUTILUS_SEARCH_DIRECTORY (priv->model), query);
9581 /* It's important to use load_directory instead of set_location,
9582 * since the location is already correct, however we need
9583 * to reload the directory with the new query set. But
9584 * set_location has a check for wheter the location is a
9585 * search directory, so setting the location to a search
9586 * directory when is already serching will enter a loop.
9587 */
9588 load_directory (files_view, priv->model);
9589 }
9590 else
9591 {
9592 NautilusDirectory *directory;
9593 gchar *uri;
9594
9595 uri = nautilus_search_directory_generate_new_uri ();
9596 location = g_file_new_for_uri (uri);
9597
9598 directory = nautilus_directory_get (location);
9599 g_assert (NAUTILUS_IS_SEARCH_DIRECTORY (directory));
9600 nautilus_search_directory_set_base_model (NAUTILUS_SEARCH_DIRECTORY (directory), base_model);
9601 nautilus_search_directory_set_query (NAUTILUS_SEARCH_DIRECTORY (directory), query);
9602
9603 load_directory (files_view, directory);
9604
9605 g_object_notify (G_OBJECT (files_view), "searching");
9606
9607 nautilus_directory_unref (directory);
9608 g_free (uri);
9609 }
9610 }
9611 else
9612 {
9613 if (nautilus_view_is_searching (NAUTILUS_VIEW (files_view)))
9614 {
9615 location = nautilus_directory_get_location (base_model);
9616
9617 nautilus_view_set_location (NAUTILUS_VIEW (files_view), location);
9618 }
9619 }
9620 g_clear_object (&location);
9621 }
9622
9623 static void
nautilus_files_view_set_search_query(NautilusView * view,NautilusQuery * query)9624 nautilus_files_view_set_search_query (NautilusView *view,
9625 NautilusQuery *query)
9626 {
9627 NautilusDirectory *base_model;
9628 NautilusFilesView *files_view;
9629 NautilusFilesViewPrivate *priv;
9630
9631 files_view = NAUTILUS_FILES_VIEW (view);
9632 priv = nautilus_files_view_get_instance_private (files_view);
9633
9634 if (nautilus_view_is_searching (view))
9635 {
9636 base_model = nautilus_search_directory_get_base_model (NAUTILUS_SEARCH_DIRECTORY (priv->model));
9637 }
9638 else
9639 {
9640 base_model = priv->model;
9641 }
9642
9643 set_search_query_internal (NAUTILUS_FILES_VIEW (view), query, base_model);
9644 }
9645
9646 static GFile *
nautilus_files_view_get_location(NautilusView * view)9647 nautilus_files_view_get_location (NautilusView *view)
9648 {
9649 NautilusFilesViewPrivate *priv;
9650 NautilusFilesView *files_view;
9651
9652 files_view = NAUTILUS_FILES_VIEW (view);
9653 priv = nautilus_files_view_get_instance_private (files_view);
9654
9655 return priv->location;
9656 }
9657
9658 static gboolean
nautilus_files_view_is_loading(NautilusView * view)9659 nautilus_files_view_is_loading (NautilusView *view)
9660 {
9661 NautilusFilesViewPrivate *priv;
9662 NautilusFilesView *files_view;
9663
9664 files_view = NAUTILUS_FILES_VIEW (view);
9665 priv = nautilus_files_view_get_instance_private (files_view);
9666
9667 return priv->loading;
9668 }
9669
9670 static void
nautilus_files_view_iface_init(NautilusViewInterface * iface)9671 nautilus_files_view_iface_init (NautilusViewInterface *iface)
9672 {
9673 iface->get_location = nautilus_files_view_get_location;
9674 iface->set_location = nautilus_files_view_set_location;
9675 iface->get_selection = nautilus_files_view_get_selection;
9676 iface->set_selection = nautilus_files_view_set_selection;
9677 iface->get_search_query = nautilus_files_view_get_search_query;
9678 iface->set_search_query = nautilus_files_view_set_search_query;
9679 iface->get_toolbar_menu_sections = nautilus_files_view_get_toolbar_menu_sections;
9680 iface->is_searching = nautilus_files_view_is_searching;
9681 iface->is_loading = nautilus_files_view_is_loading;
9682 iface->get_view_id = nautilus_files_view_get_view_id;
9683 iface->get_templates_menu = nautilus_files_view_get_templates_menu;
9684 iface->set_templates_menu = nautilus_files_view_set_templates_menu;
9685 iface->get_extensions_background_menu = nautilus_files_view_get_extensions_background_menu;
9686 iface->set_extensions_background_menu = nautilus_files_view_set_extensions_background_menu;
9687 }
9688
9689 static void
nautilus_files_view_class_init(NautilusFilesViewClass * klass)9690 nautilus_files_view_class_init (NautilusFilesViewClass *klass)
9691 {
9692 GObjectClass *oclass;
9693 GtkWidgetClass *widget_class;
9694
9695 widget_class = GTK_WIDGET_CLASS (klass);
9696 oclass = G_OBJECT_CLASS (klass);
9697
9698 oclass->finalize = nautilus_files_view_finalize;
9699 oclass->get_property = nautilus_files_view_get_property;
9700 oclass->set_property = nautilus_files_view_set_property;
9701
9702 widget_class->destroy = nautilus_files_view_destroy;
9703 widget_class->event = nautilus_files_view_event;
9704 widget_class->parent_set = nautilus_files_view_parent_set;
9705 widget_class->grab_focus = nautilus_files_view_grab_focus;
9706
9707
9708 signals[ADD_FILES] =
9709 g_signal_new ("add-files",
9710 G_TYPE_FROM_CLASS (klass),
9711 G_SIGNAL_RUN_LAST,
9712 G_STRUCT_OFFSET (NautilusFilesViewClass, add_files),
9713 NULL, NULL,
9714 g_cclosure_marshal_generic,
9715 G_TYPE_NONE, 1, G_TYPE_POINTER);
9716 signals[BEGIN_FILE_CHANGES] =
9717 g_signal_new ("begin-file-changes",
9718 G_TYPE_FROM_CLASS (klass),
9719 G_SIGNAL_RUN_LAST,
9720 G_STRUCT_OFFSET (NautilusFilesViewClass, begin_file_changes),
9721 NULL, NULL,
9722 g_cclosure_marshal_VOID__VOID,
9723 G_TYPE_NONE, 0);
9724 signals[BEGIN_LOADING] =
9725 g_signal_new ("begin-loading",
9726 G_TYPE_FROM_CLASS (klass),
9727 G_SIGNAL_RUN_LAST,
9728 G_STRUCT_OFFSET (NautilusFilesViewClass, begin_loading),
9729 NULL, NULL,
9730 g_cclosure_marshal_VOID__VOID,
9731 G_TYPE_NONE, 0);
9732 signals[CLEAR] =
9733 g_signal_new ("clear",
9734 G_TYPE_FROM_CLASS (klass),
9735 G_SIGNAL_RUN_LAST,
9736 G_STRUCT_OFFSET (NautilusFilesViewClass, clear),
9737 NULL, NULL,
9738 g_cclosure_marshal_VOID__VOID,
9739 G_TYPE_NONE, 0);
9740 signals[END_FILE_CHANGES] =
9741 g_signal_new ("end-file-changes",
9742 G_TYPE_FROM_CLASS (klass),
9743 G_SIGNAL_RUN_LAST,
9744 G_STRUCT_OFFSET (NautilusFilesViewClass, end_file_changes),
9745 NULL, NULL,
9746 g_cclosure_marshal_VOID__VOID,
9747 G_TYPE_NONE, 0);
9748 signals[END_LOADING] =
9749 g_signal_new ("end-loading",
9750 G_TYPE_FROM_CLASS (klass),
9751 G_SIGNAL_RUN_LAST,
9752 G_STRUCT_OFFSET (NautilusFilesViewClass, end_loading),
9753 NULL, NULL,
9754 g_cclosure_marshal_VOID__BOOLEAN,
9755 G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
9756 signals[FILE_CHANGED] =
9757 g_signal_new ("file-changed",
9758 G_TYPE_FROM_CLASS (klass),
9759 G_SIGNAL_RUN_LAST,
9760 G_STRUCT_OFFSET (NautilusFilesViewClass, file_changed),
9761 NULL, NULL,
9762 g_cclosure_marshal_generic,
9763 G_TYPE_NONE, 2, NAUTILUS_TYPE_FILE, NAUTILUS_TYPE_DIRECTORY);
9764 signals[REMOVE_FILE] =
9765 g_signal_new ("remove-file",
9766 G_TYPE_FROM_CLASS (klass),
9767 G_SIGNAL_RUN_LAST,
9768 G_STRUCT_OFFSET (NautilusFilesViewClass, remove_file),
9769 NULL, NULL,
9770 g_cclosure_marshal_generic,
9771 G_TYPE_NONE, 2, NAUTILUS_TYPE_FILE, NAUTILUS_TYPE_DIRECTORY);
9772 signals[SELECTION_CHANGED] =
9773 g_signal_new ("selection-changed",
9774 G_TYPE_FROM_CLASS (klass),
9775 G_SIGNAL_RUN_LAST,
9776 0,
9777 NULL, NULL,
9778 g_cclosure_marshal_VOID__VOID,
9779 G_TYPE_NONE, 0);
9780
9781 klass->get_backing_uri = real_get_backing_uri;
9782 klass->get_window = nautilus_files_view_get_window;
9783 klass->update_context_menus = real_update_context_menus;
9784 klass->update_actions_state = real_update_actions_state;
9785 klass->check_empty_states = real_check_empty_states;
9786
9787 g_object_class_install_property (
9788 oclass,
9789 PROP_WINDOW_SLOT,
9790 g_param_spec_object ("window-slot",
9791 "Window Slot",
9792 "The parent window slot reference",
9793 NAUTILUS_TYPE_WINDOW_SLOT,
9794 G_PARAM_WRITABLE |
9795 G_PARAM_CONSTRUCT_ONLY));
9796 g_object_class_install_property (
9797 oclass,
9798 PROP_SUPPORTS_ZOOMING,
9799 g_param_spec_boolean ("supports-zooming",
9800 "Supports zooming",
9801 "Whether the view supports zooming",
9802 TRUE,
9803 G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
9804 G_PARAM_STATIC_STRINGS));
9805
9806 g_object_class_override_property (oclass, PROP_LOADING, "loading");
9807 g_object_class_override_property (oclass, PROP_SEARCHING, "searching");
9808 g_object_class_override_property (oclass, PROP_LOCATION, "location");
9809 g_object_class_override_property (oclass, PROP_SELECTION, "selection");
9810 g_object_class_override_property (oclass, PROP_SEARCH_QUERY, "search-query");
9811 g_object_class_override_property (oclass, PROP_EXTENSIONS_BACKGROUND_MENU, "extensions-background-menu");
9812 g_object_class_override_property (oclass, PROP_TEMPLATES_MENU, "templates-menu");
9813 }
9814
9815 static void
nautilus_files_view_init(NautilusFilesView * view)9816 nautilus_files_view_init (NautilusFilesView *view)
9817 {
9818 NautilusFilesViewPrivate *priv;
9819 GtkBuilder *builder;
9820 AtkObject *atk_object;
9821 NautilusDirectory *scripts_directory;
9822 NautilusDirectory *templates_directory;
9823 gchar *templates_uri;
9824 GtkClipboard *clipboard;
9825 GApplication *app;
9826 const gchar *open_accels[] =
9827 {
9828 "Return",
9829 "KP_Enter",
9830 "<control>o",
9831 "<alt>Down",
9832 NULL
9833 };
9834 const gchar *open_properties[] =
9835 {
9836 "<control>i",
9837 "<alt>Return",
9838 NULL
9839 };
9840 const gchar *zoom_in_accels[] =
9841 {
9842 "<control>equal",
9843 "<control>plus",
9844 "<control>KP_Add",
9845 "ZoomIn",
9846 NULL
9847 };
9848 const gchar *zoom_out_accels[] =
9849 {
9850 "<control>minus",
9851 "<control>KP_Subtract",
9852 "ZoomOut",
9853 NULL
9854 };
9855 const gchar *zoom_standard_accels[] =
9856 {
9857 "<control>0",
9858 "<control>KP_0",
9859 NULL
9860 };
9861 const gchar *move_to_trash_accels[] =
9862 {
9863 "Delete",
9864 "KP_Delete",
9865 NULL
9866 };
9867 const gchar *delete_permanently_accels[] =
9868 {
9869 "<shift>Delete",
9870 "<shift>KP_Delete",
9871 NULL
9872 };
9873
9874 nautilus_profile_start (NULL);
9875
9876 priv = nautilus_files_view_get_instance_private (view);
9877
9878 /* Toolbar menu */
9879 builder = gtk_builder_new_from_resource ("/org/gnome/nautilus/ui/nautilus-toolbar-view-menu.ui");
9880 priv->toolbar_menu_sections = g_new0 (NautilusToolbarMenuSections, 1);
9881 priv->toolbar_menu_sections->supports_undo_redo = TRUE;
9882 priv->toolbar_menu_sections->zoom_section = GTK_WIDGET (g_object_ref_sink (gtk_builder_get_object (builder, "zoom_section")));
9883 priv->toolbar_menu_sections->extended_section = GTK_WIDGET (g_object_ref_sink (gtk_builder_get_object (builder, "extended_section")));
9884 priv->zoom_controls_box = GTK_WIDGET (gtk_builder_get_object (builder, "zoom_controls_box"));
9885 priv->zoom_level_label = GTK_WIDGET (gtk_builder_get_object (builder, "zoom_level_label"));
9886
9887 priv->sort_menu = GTK_WIDGET (gtk_builder_get_object (builder, "sort_menu"));
9888 priv->sort_trash_time = GTK_WIDGET (gtk_builder_get_object (builder, "sort_trash_time"));
9889 priv->visible_columns = GTK_WIDGET (gtk_builder_get_object (builder, "visible_columns"));
9890 priv->reload = GTK_WIDGET (gtk_builder_get_object (builder, "reload"));
9891 priv->stop = GTK_WIDGET (gtk_builder_get_object (builder, "stop"));
9892
9893 g_signal_connect (view,
9894 "end-file-changes",
9895 G_CALLBACK (on_end_file_changes),
9896 view);
9897 g_signal_connect (view,
9898 "notify::selection",
9899 G_CALLBACK (nautilus_files_view_preview_update),
9900 view);
9901
9902 g_object_unref (builder);
9903
9904 /* Main widgets */
9905 gtk_orientable_set_orientation (GTK_ORIENTABLE (view), GTK_ORIENTATION_VERTICAL);
9906 priv->overlay = gtk_overlay_new ();
9907 gtk_widget_set_vexpand (priv->overlay, TRUE);
9908 gtk_widget_set_hexpand (priv->overlay, TRUE);
9909 gtk_container_add (GTK_CONTAINER (view), priv->overlay);
9910 gtk_widget_show (priv->overlay);
9911
9912 /* NautilusFloatingBar listen to its parent's 'event' signal
9913 * and GtkOverlay doesn't have it enabled by default, so we have to add them
9914 * here.
9915 */
9916 gtk_widget_add_events (GTK_WIDGET (priv->overlay),
9917 GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
9918
9919 /* Scrolled Window */
9920 priv->scrolled_window = gtk_scrolled_window_new (NULL, NULL);
9921 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scrolled_window),
9922 GTK_POLICY_AUTOMATIC,
9923 GTK_POLICY_AUTOMATIC);
9924 gtk_widget_show (priv->scrolled_window);
9925
9926 g_signal_connect_swapped (priv->scrolled_window,
9927 "event",
9928 G_CALLBACK (on_event),
9929 view);
9930 g_signal_connect_swapped (priv->scrolled_window,
9931 "popup-menu",
9932 G_CALLBACK (popup_menu_callback),
9933 view);
9934
9935 gtk_container_add (GTK_CONTAINER (priv->overlay), priv->scrolled_window);
9936
9937 /* Empty states */
9938 builder = gtk_builder_new_from_resource ("/org/gnome/nautilus/ui/nautilus-no-search-results.ui");
9939 priv->no_search_results_widget = GTK_WIDGET (gtk_builder_get_object (builder, "no_search_results"));
9940 gtk_overlay_add_overlay (GTK_OVERLAY (priv->overlay), priv->no_search_results_widget);
9941 gtk_overlay_set_overlay_pass_through (GTK_OVERLAY (priv->overlay),
9942 priv->no_search_results_widget,
9943 TRUE);
9944 g_object_unref (builder);
9945
9946 builder = gtk_builder_new_from_resource ("/org/gnome/nautilus/ui/nautilus-folder-is-empty.ui");
9947 priv->folder_is_empty_widget = GTK_WIDGET (gtk_builder_get_object (builder, "folder_is_empty"));
9948 gtk_overlay_add_overlay (GTK_OVERLAY (priv->overlay), priv->folder_is_empty_widget);
9949 gtk_overlay_set_overlay_pass_through (GTK_OVERLAY (priv->overlay),
9950 priv->folder_is_empty_widget,
9951 TRUE);
9952 g_object_unref (builder);
9953
9954 builder = gtk_builder_new_from_resource ("/org/gnome/nautilus/ui/nautilus-starred-is-empty.ui");
9955 priv->starred_is_empty_widget = GTK_WIDGET (gtk_builder_get_object (builder, "starred_is_empty"));
9956 gtk_overlay_add_overlay (GTK_OVERLAY (priv->overlay), priv->starred_is_empty_widget);
9957 gtk_overlay_set_overlay_pass_through (GTK_OVERLAY (priv->overlay),
9958 priv->starred_is_empty_widget,
9959 TRUE);
9960 g_object_unref (builder);
9961
9962 builder = gtk_builder_new_from_resource ("/org/gnome/nautilus/ui/nautilus-trash-is-empty.ui");
9963 priv->trash_is_empty_widget = GTK_WIDGET (gtk_builder_get_object (builder, "trash_is_empty"));
9964 gtk_overlay_add_overlay (GTK_OVERLAY (priv->overlay), priv->trash_is_empty_widget);
9965 gtk_overlay_set_overlay_pass_through (GTK_OVERLAY (priv->overlay),
9966 priv->trash_is_empty_widget,
9967 TRUE);
9968 g_object_unref (builder);
9969
9970 /* Floating bar */
9971 priv->floating_bar = nautilus_floating_bar_new (NULL, NULL, FALSE);
9972 gtk_widget_set_halign (priv->floating_bar, GTK_ALIGN_END);
9973 gtk_widget_set_valign (priv->floating_bar, GTK_ALIGN_END);
9974 gtk_overlay_add_overlay (GTK_OVERLAY (priv->overlay), priv->floating_bar);
9975
9976 g_signal_connect (priv->floating_bar,
9977 "action",
9978 G_CALLBACK (floating_bar_action_cb),
9979 view);
9980
9981 priv->non_ready_files =
9982 g_hash_table_new_full (file_and_directory_hash,
9983 file_and_directory_equal,
9984 file_and_directory_free,
9985 NULL);
9986
9987 priv->pending_reveal = g_hash_table_new (NULL, NULL);
9988
9989 gtk_style_context_set_junction_sides (gtk_widget_get_style_context (GTK_WIDGET (view)),
9990 GTK_JUNCTION_TOP | GTK_JUNCTION_LEFT);
9991
9992 if (set_up_scripts_directory_global ())
9993 {
9994 scripts_directory = nautilus_directory_get_by_uri (scripts_directory_uri);
9995 add_directory_to_scripts_directory_list (view, scripts_directory);
9996 nautilus_directory_unref (scripts_directory);
9997 }
9998 else
9999 {
10000 g_warning ("Ignoring scripts directory, it may be a broken link\n");
10001 }
10002
10003 if (nautilus_should_use_templates_directory ())
10004 {
10005 templates_uri = nautilus_get_templates_directory_uri ();
10006 templates_directory = nautilus_directory_get_by_uri (templates_uri);
10007 g_free (templates_uri);
10008 add_directory_to_templates_directory_list (view, templates_directory);
10009 nautilus_directory_unref (templates_directory);
10010 }
10011 update_templates_directory (view);
10012
10013 priv->sort_directories_first =
10014 g_settings_get_boolean (gtk_filechooser_preferences, NAUTILUS_PREFERENCES_SORT_DIRECTORIES_FIRST);
10015 priv->show_hidden_files =
10016 g_settings_get_boolean (gtk_filechooser_preferences, NAUTILUS_PREFERENCES_SHOW_HIDDEN_FILES);
10017
10018 g_signal_connect_object (nautilus_trash_monitor_get (), "trash-state-changed",
10019 G_CALLBACK (nautilus_files_view_trash_state_changed_callback), view, 0);
10020
10021 /* React to clipboard changes */
10022 clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
10023 g_signal_connect (clipboard, "owner-change",
10024 G_CALLBACK (on_clipboard_owner_changed), view);
10025
10026 /* Register to menu provider extension signal managing menu updates */
10027 g_signal_connect_object (nautilus_signaller_get_current (), "popup-menu-changed",
10028 G_CALLBACK (schedule_update_context_menus), view, G_CONNECT_SWAPPED);
10029
10030 gtk_widget_show (GTK_WIDGET (view));
10031
10032 g_signal_connect_swapped (nautilus_preferences,
10033 "changed::" NAUTILUS_PREFERENCES_CLICK_POLICY,
10034 G_CALLBACK (click_policy_changed_callback),
10035 view);
10036 g_signal_connect_swapped (gtk_filechooser_preferences,
10037 "changed::" NAUTILUS_PREFERENCES_SORT_DIRECTORIES_FIRST,
10038 G_CALLBACK (sort_directories_first_changed_callback), view);
10039 g_signal_connect_swapped (gtk_filechooser_preferences,
10040 "changed::" NAUTILUS_PREFERENCES_SHOW_HIDDEN_FILES,
10041 G_CALLBACK (show_hidden_files_changed_callback), view);
10042 g_signal_connect_swapped (gnome_lockdown_preferences,
10043 "changed::" NAUTILUS_PREFERENCES_LOCKDOWN_COMMAND_LINE,
10044 G_CALLBACK (schedule_update_context_menus), view);
10045
10046 priv->in_destruction = FALSE;
10047
10048 /* Accessibility */
10049 atk_object = gtk_widget_get_accessible (GTK_WIDGET (view));
10050 atk_object_set_name (atk_object, _("Content View"));
10051 atk_object_set_description (atk_object, _("View of the current folder"));
10052
10053 priv->view_action_group = G_ACTION_GROUP (g_simple_action_group_new ());
10054 g_action_map_add_action_entries (G_ACTION_MAP (priv->view_action_group),
10055 view_entries,
10056 G_N_ELEMENTS (view_entries),
10057 view);
10058 gtk_widget_insert_action_group (GTK_WIDGET (view),
10059 "view",
10060 G_ACTION_GROUP (priv->view_action_group));
10061 app = g_application_get_default ();
10062
10063 /* Toolbar menu */
10064 nautilus_application_set_accelerators (app, "view.zoom-in", zoom_in_accels);
10065 nautilus_application_set_accelerators (app, "view.zoom-out", zoom_out_accels);
10066 nautilus_application_set_accelerator (app, "view.show-hidden-files", "<control>h");
10067 /* Background menu */
10068 nautilus_application_set_accelerator (app, "view.select-all", "<control>a");
10069 nautilus_application_set_accelerator (app, "view.paste_accel", "<control>v");
10070 nautilus_application_set_accelerator (app, "view.create-link", "<control>m");
10071 /* Selection menu */
10072 nautilus_application_set_accelerators (app, "view.open-with-default-application", open_accels);
10073 nautilus_application_set_accelerator (app, "view.open-item-new-tab", "<control>Return");
10074 nautilus_application_set_accelerator (app, "view.open-item-new-window", "<Shift>Return");
10075 nautilus_application_set_accelerators (app, "view.move-to-trash", move_to_trash_accels);
10076 nautilus_application_set_accelerators (app, "view.delete-from-trash", move_to_trash_accels);
10077 nautilus_application_set_accelerators (app, "view.delete-permanently-shortcut", delete_permanently_accels);
10078 /* When trash is not available, allow the "Delete" keys to delete permanently, that is, when
10079 * the menu item is available, since we never make both the trash and delete-permanently-menu-item
10080 * actions active */
10081 nautilus_application_set_accelerators (app, "view.delete-permanently-menu-item", move_to_trash_accels);
10082 nautilus_application_set_accelerators (app, "view.permanent-delete-permanently-menu-item", delete_permanently_accels);
10083 nautilus_application_set_accelerators (app, "view.properties", open_properties);
10084 nautilus_application_set_accelerator (app, "view.open-item-location", "<control><alt>o");
10085 nautilus_application_set_accelerator (app, "view.rename", "F2");
10086 nautilus_application_set_accelerator (app, "view.cut", "<control>x");
10087 nautilus_application_set_accelerator (app, "view.copy", "<control>c");
10088 nautilus_application_set_accelerator (app, "view.create-link-in-place", "<control><shift>m");
10089 nautilus_application_set_accelerator (app, "view.new-folder", "<control><shift>n");
10090 /* Only accesible by shorcuts */
10091 nautilus_application_set_accelerator (app, "view.select-pattern", "<control>s");
10092 nautilus_application_set_accelerators (app, "view.zoom-standard", zoom_standard_accels);
10093 nautilus_application_set_accelerator (app, "view.invert-selection", "<shift><control>i");
10094
10095 priv->starred_cancellable = g_cancellable_new ();
10096 priv->tag_manager = nautilus_tag_manager_get ();
10097
10098 priv->rename_file_controller = nautilus_rename_file_popover_controller_new ();
10099
10100 nautilus_profile_end (NULL);
10101 }
10102
10103 NautilusFilesView *
nautilus_files_view_new(guint id,NautilusWindowSlot * slot)10104 nautilus_files_view_new (guint id,
10105 NautilusWindowSlot *slot)
10106 {
10107 NautilusFilesView *view = NULL;
10108 gboolean use_experimental_views;
10109
10110 use_experimental_views = g_settings_get_boolean (nautilus_preferences,
10111 NAUTILUS_PREFERENCES_USE_EXPERIMENTAL_VIEWS);
10112 switch (id)
10113 {
10114 case NAUTILUS_VIEW_GRID_ID:
10115 {
10116 if (use_experimental_views)
10117 {
10118 view = NAUTILUS_FILES_VIEW (nautilus_view_icon_controller_new (slot));
10119 }
10120 else
10121 {
10122 view = nautilus_canvas_view_new (slot);
10123 }
10124 }
10125 break;
10126
10127 case NAUTILUS_VIEW_LIST_ID:
10128 {
10129 view = nautilus_list_view_new (slot);
10130 }
10131 break;
10132 }
10133
10134 if (view == NULL)
10135 {
10136 g_critical ("Unknown view type ID: %d", id);
10137 }
10138 else if (g_object_is_floating (view))
10139 {
10140 g_object_ref_sink (view);
10141 }
10142
10143 return view;
10144 }
10145