1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2
3 /* fm-directory-view.c
4 *
5 * Copyright (C) 1999, 2000 Free Software Foundation
6 * Copyright (C) 2000, 2001 Eazel, Inc.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public
19 * License along with this program; if not, write to the
20 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 *
23 * Authors: Ettore Perazzoli,
24 * John Sullivan <sullivan@eazel.com>,
25 * Darin Adler <darin@bentspoon.com>,
26 * Pavel Cisler <pavel@eazel.com>,
27 * David Emory Watson <dwatson@cs.ucr.edu>
28 */
29
30 #include <config.h>
31 #include <math.h>
32
33 #include <gdk/gdkkeysyms.h>
34 #include <gdk/gdkx.h>
35 #include <gtk/gtk.h>
36 #include <glib/gi18n.h>
37 #include <glib/gstdio.h>
38 #include <gio/gio.h>
39
40 #define MATE_DESKTOP_USE_UNSTABLE_API
41 #include <libmate-desktop/mate-desktop-utils.h>
42
43 #include <eel/eel-background.h>
44 #include <eel/eel-glib-extensions.h>
45 #include <eel/eel-mate-extensions.h>
46 #include <eel/eel-gtk-extensions.h>
47 #include <eel/eel-gtk-macros.h>
48 #include <eel/eel-stock-dialogs.h>
49 #include <eel/eel-string.h>
50 #include <eel/eel-vfs-extensions.h>
51
52 #include <libcaja-private/caja-recent.h>
53 #include <libcaja-extension/caja-menu-provider.h>
54 #include <libcaja-private/caja-clipboard.h>
55 #include <libcaja-private/caja-clipboard-monitor.h>
56 #include <libcaja-private/caja-debug-log.h>
57 #include <libcaja-private/caja-desktop-icon-file.h>
58 #include <libcaja-private/caja-desktop-directory.h>
59 #include <libcaja-private/caja-extensions.h>
60 #include <libcaja-private/caja-search-directory.h>
61 #include <libcaja-private/caja-directory-background.h>
62 #include <libcaja-private/caja-directory.h>
63 #include <libcaja-private/caja-dnd.h>
64 #include <libcaja-private/caja-file-attributes.h>
65 #include <libcaja-private/caja-file-changes-queue.h>
66 #include <libcaja-private/caja-file-dnd.h>
67 #include <libcaja-private/caja-file-operations.h>
68 #include <libcaja-private/caja-file-utilities.h>
69 #include <libcaja-private/caja-file-private.h> /* for caja_file_get_existing_by_uri */
70 #include <libcaja-private/caja-global-preferences.h>
71 #include <libcaja-private/caja-link.h>
72 #include <libcaja-private/caja-metadata.h>
73 #include <libcaja-private/caja-mime-actions.h>
74 #include <libcaja-private/caja-module.h>
75 #include <libcaja-private/caja-program-choosing.h>
76 #include <libcaja-private/caja-trash-monitor.h>
77 #include <libcaja-private/caja-ui-utilities.h>
78 #include <libcaja-private/caja-signaller.h>
79 #include <libcaja-private/caja-autorun.h>
80 #include <libcaja-private/caja-icon-names.h>
81 #include <libcaja-private/caja-undostack-manager.h>
82
83 #include "fm-directory-view.h"
84 #include "fm-list-view.h"
85 #include "fm-desktop-icon-view.h"
86 #include "fm-actions.h"
87 #include "fm-error-reporting.h"
88 #include "fm-marshal.h"
89 #include "fm-properties-window.h"
90 #include "libcaja-private/caja-open-with-dialog.h"
91
92 /* Minimum starting update inverval */
93 #define UPDATE_INTERVAL_MIN 100
94 /* Maximum update interval */
95 #define UPDATE_INTERVAL_MAX 2000
96 /* Amount of miliseconds the update interval is increased */
97 #define UPDATE_INTERVAL_INC 250
98 /* Interval at which the update interval is increased */
99 #define UPDATE_INTERVAL_TIMEOUT_INTERVAL 250
100 /* Milliseconds that have to pass without a change to reset the update interval */
101 #define UPDATE_INTERVAL_RESET 1000
102
103 #define SILENT_WINDOW_OPEN_LIMIT 5
104
105 #define DUPLICATE_HORIZONTAL_ICON_OFFSET 70
106 #define DUPLICATE_VERTICAL_ICON_OFFSET 30
107
108 #define MAX_QUEUED_UPDATES 500
109
110 #define FM_DIRECTORY_VIEW_MENU_PATH_APPLICATIONS_SUBMENU_PLACEHOLDER "/MenuBar/File/Open Placeholder/Open With/Applications Placeholder"
111 #define FM_DIRECTORY_VIEW_MENU_PATH_APPLICATIONS_PLACEHOLDER "/MenuBar/File/Open Placeholder/Applications Placeholder"
112 #define FM_DIRECTORY_VIEW_MENU_PATH_SCRIPTS_PLACEHOLDER "/MenuBar/File/Open Placeholder/Scripts/Scripts Placeholder"
113 #define FM_DIRECTORY_VIEW_MENU_PATH_EXTENSION_ACTIONS_PLACEHOLDER "/MenuBar/Edit/Extension Actions"
114 #define FM_DIRECTORY_VIEW_MENU_PATH_NEW_DOCUMENTS_PLACEHOLDER "/MenuBar/File/New Items Placeholder/New Documents/New Documents Placeholder"
115 #define FM_DIRECTORY_VIEW_MENU_PATH_OPEN "/MenuBar/File/Open Placeholder/Open"
116
117 #define FM_DIRECTORY_VIEW_POPUP_PATH_SELECTION "/selection"
118 #define FM_DIRECTORY_VIEW_POPUP_PATH_APPLICATIONS_SUBMENU_PLACEHOLDER "/selection/Open Placeholder/Open With/Applications Placeholder"
119 #define FM_DIRECTORY_VIEW_POPUP_PATH_APPLICATIONS_PLACEHOLDER "/selection/Open Placeholder/Applications Placeholder"
120 #define FM_DIRECTORY_VIEW_POPUP_PATH_SCRIPTS_PLACEHOLDER "/selection/Open Placeholder/Scripts/Scripts Placeholder"
121 #define FM_DIRECTORY_VIEW_POPUP_PATH_EXTENSION_ACTIONS "/selection/Extension Actions"
122 #define FM_DIRECTORY_VIEW_POPUP_PATH_OPEN "/selection/Open Placeholder/Open"
123
124 #define FM_DIRECTORY_VIEW_POPUP_PATH_BACKGROUND "/background"
125 #define FM_DIRECTORY_VIEW_POPUP_PATH_BACKGROUND_SCRIPTS_PLACEHOLDER "/background/Before Zoom Items/New Object Items/Scripts/Scripts Placeholder"
126 #define FM_DIRECTORY_VIEW_POPUP_PATH_BACKGROUND_NEW_DOCUMENTS_PLACEHOLDER "/background/Before Zoom Items/New Object Items/New Documents/New Documents Placeholder"
127
128 #define FM_DIRECTORY_VIEW_POPUP_PATH_LOCATION "/location"
129
130 #define MAX_MENU_LEVELS 5
131 #define TEMPLATE_LIMIT 30
132
133 enum {
134 ADD_FILE,
135 BEGIN_FILE_CHANGES,
136 BEGIN_LOADING,
137 CLEAR,
138 END_FILE_CHANGES,
139 FLUSH_ADDED_FILES,
140 END_LOADING,
141 FILE_CHANGED,
142 LOAD_ERROR,
143 MOVE_COPY_ITEMS,
144 REMOVE_FILE,
145 TRASH,
146 DELETE,
147 LAST_SIGNAL
148 };
149
150 enum
151 {
152 PROP_0,
153 PROP_WINDOW_SLOT
154 };
155
156
157 static guint signals[LAST_SIGNAL] = { 0 };
158
159 static GdkAtom copied_files_atom;
160
161 static char *scripts_directory_uri;
162 static int scripts_directory_uri_length;
163
164 struct FMDirectoryViewDetails
165 {
166 CajaWindowInfo *window;
167 CajaWindowSlotInfo *slot;
168 CajaDirectory *model;
169 CajaFile *directory_as_file;
170 CajaFile *location_popup_directory_as_file;
171 GdkEventButton *location_popup_event;
172 GtkActionGroup *dir_action_group;
173 guint dir_merge_id;
174
175 GList *scripts_directory_list;
176 GtkActionGroup *scripts_action_group;
177 guint scripts_merge_id;
178
179 GList *templates_directory_list;
180 GtkActionGroup *templates_action_group;
181 guint templates_merge_id;
182
183 GtkActionGroup *extensions_menu_action_group;
184 guint extensions_menu_merge_id;
185
186 guint display_selection_idle_id;
187 guint update_menus_timeout_id;
188 guint update_status_idle_id;
189 guint reveal_selection_idle_id;
190
191 guint display_pending_source_id;
192 guint changes_timeout_id;
193
194 guint update_interval;
195 guint64 last_queued;
196
197 guint files_added_handler_id;
198 guint files_changed_handler_id;
199 guint load_error_handler_id;
200 guint done_loading_handler_id;
201 guint file_changed_handler_id;
202
203 guint delayed_rename_file_id;
204
205 GList *new_added_files;
206 GList *new_changed_files;
207
208 GHashTable *non_ready_files;
209
210 GList *old_added_files;
211 GList *old_changed_files;
212
213 GList *pending_locations_selected;
214
215 /* whether we are in the active slot */
216 gboolean active;
217
218 /* loading indicates whether this view has begun loading a directory.
219 * This flag should need not be set inside subclasses. FMDirectoryView automatically
220 * sets 'loading' to TRUE before it begins loading a directory's contents and to FALSE
221 * after it finishes loading the directory and its view.
222 */
223 gboolean loading;
224 gboolean menu_states_untrustworthy;
225 gboolean scripts_invalid;
226 gboolean templates_invalid;
227 gboolean reported_load_error;
228
229 /* flag to indicate that no file updates should be dispatched to subclasses.
230 * This is a workaround for bug #87701 that prevents the list view from
231 * losing focus when the underlying GtkTreeView is updated.
232 */
233 gboolean updates_frozen;
234 guint updates_queued;
235 gboolean needs_reload;
236
237 gboolean sort_directories_first;
238
239 gboolean show_foreign_files;
240 gboolean show_hidden_files;
241 gboolean ignore_hidden_file_preferences;
242
243 gboolean show_backup_files;
244
245 gboolean batching_selection_level;
246 gboolean selection_changed_while_batched;
247
248 gboolean selection_was_removed;
249
250 gboolean metadata_for_directory_as_file_pending;
251 gboolean metadata_for_files_in_directory_pending;
252
253 gboolean selection_change_is_due_to_shell;
254 gboolean send_selection_change_to_shell;
255
256 GtkActionGroup *open_with_action_group;
257 guint open_with_merge_id;
258
259 GList *subdirectory_list;
260
261 gboolean allow_moves;
262
263 GdkPoint context_menu_position;
264
265 gboolean undo_active;
266 gboolean redo_active;
267 gchar* undo_action_description;
268 gchar* undo_action_label;
269 gchar* redo_action_description;
270 gchar* redo_action_label;
271 };
272
273 typedef struct {
274 CajaFile *file;
275 CajaDirectory *directory;
276 } FileAndDirectory;
277
278 /* forward declarations */
279
280 static gboolean display_selection_info_idle_callback (gpointer data);
281 static void fm_directory_view_class_init (FMDirectoryViewClass *klass);
282 static void fm_directory_view_init (FMDirectoryView *view);
283 static void fm_directory_view_duplicate_selection (FMDirectoryView *view,
284 GList *files,
285 GArray *item_locations);
286 static void fm_directory_view_create_links_for_files (FMDirectoryView *view,
287 GList *files,
288 GArray *item_locations);
289 static void trash_or_delete_files (GtkWindow *parent_window,
290 const GList *files,
291 gboolean delete_if_all_already_in_trash,
292 FMDirectoryView *view);
293 static void load_directory (FMDirectoryView *view,
294 CajaDirectory *directory);
295 static void fm_directory_view_merge_menus (FMDirectoryView *view);
296 static void fm_directory_view_unmerge_menus (FMDirectoryView *view);
297 static void fm_directory_view_init_show_hidden_files (FMDirectoryView *view);
298 static void fm_directory_view_init_show_backup_files (FMDirectoryView *view);
299 static void fm_directory_view_load_location (CajaView *caja_view,
300 const char *location);
301 static void fm_directory_view_stop_loading (CajaView *caja_view);
302 static void fm_directory_view_drop_proxy_received_uris (FMDirectoryView *view,
303 const GList *source_uri_list,
304 const char *target_uri,
305 GdkDragAction action);
306 static void fm_directory_view_drop_proxy_received_netscape_url (FMDirectoryView *view,
307 const char *netscape_url,
308 const char *target_uri,
309 GdkDragAction action);
310 static void clipboard_changed_callback (CajaClipboardMonitor *monitor,
311 FMDirectoryView *view);
312 static void open_one_in_new_window (gpointer data,
313 gpointer callback_data);
314 static void open_one_in_folder_window (gpointer data,
315 gpointer callback_data);
316 static void schedule_update_menus (FMDirectoryView *view);
317 static void schedule_update_menus_callback (gpointer callback_data);
318 static void remove_update_menus_timeout_callback (FMDirectoryView *view);
319 static void schedule_update_status (FMDirectoryView *view);
320 static void remove_update_status_idle_callback (FMDirectoryView *view);
321 static void reset_update_interval (FMDirectoryView *view);
322 static void schedule_idle_display_of_pending_files (FMDirectoryView *view);
323 static void unschedule_display_of_pending_files (FMDirectoryView *view);
324 static void disconnect_model_handlers (FMDirectoryView *view);
325 static void metadata_for_directory_as_file_ready_callback (CajaFile *file,
326 gpointer callback_data);
327 static void metadata_for_files_in_directory_ready_callback (CajaDirectory *directory,
328 GList *files,
329 gpointer callback_data);
330 static void fm_directory_view_trash_state_changed_callback (CajaTrashMonitor *trash,
331 gboolean state,
332 gpointer callback_data);
333 static void fm_directory_view_select_file (FMDirectoryView *view,
334 CajaFile *file);
335
336 static GdkDragAction ask_link_action (FMDirectoryView *view);
337 static void update_templates_directory (FMDirectoryView *view);
338 static void user_dirs_changed (FMDirectoryView *view);
339 static void fm_directory_view_set_is_active (FMDirectoryView *view,
340 gboolean is_active);
341
342 static gboolean file_list_all_are_folders (GList *file_list);
343
344 static void action_open_scripts_folder_callback (GtkAction *action,
345 gpointer callback_data);
346 static void action_cut_files_callback (GtkAction *action,
347 gpointer callback_data);
348 static void action_copy_files_callback (GtkAction *action,
349 gpointer callback_data);
350 static void action_paste_files_callback (GtkAction *action,
351 gpointer callback_data);
352 static void action_copy_to_next_pane_callback (GtkAction *action,
353 gpointer callback_data);
354 static void action_move_to_next_pane_callback (GtkAction *action,
355 gpointer callback_data);
356 static void action_rename_callback (GtkAction *action,
357 gpointer callback_data);
358 static void action_rename_select_all_callback (GtkAction *action,
359 gpointer callback_data);
360 static void action_paste_files_into_callback (GtkAction *action,
361 gpointer callback_data);
362 static void action_connect_to_server_link_callback (GtkAction *action,
363 gpointer data);
364 static void action_mount_volume_callback (GtkAction *action,
365 gpointer data);
366 static void action_unmount_volume_callback (GtkAction *action,
367 gpointer data);
368 static void action_format_volume_callback (GtkAction *action,
369 gpointer data);
370 static void action_start_volume_callback (GtkAction *action,
371 gpointer data);
372 static void action_stop_volume_callback (GtkAction *action,
373 gpointer data);
374 static void action_detect_media_callback (GtkAction *action,
375 gpointer data);
376
377 /* location popup-related actions */
378
379 static void action_location_open_alternate_callback (GtkAction *action,
380 gpointer callback_data);
381 static void action_location_open_folder_window_callback (GtkAction *action,
382 gpointer callback_data);
383
384 static void action_location_cut_callback (GtkAction *action,
385 gpointer callback_data);
386 static void action_location_copy_callback (GtkAction *action,
387 gpointer callback_data);
388 static void action_location_trash_callback (GtkAction *action,
389 gpointer callback_data);
390 static void action_location_delete_callback (GtkAction *action,
391 gpointer callback_data);
392 static void action_location_properties_callback (GtkAction *action,
393 gpointer callback_data);
394
395 static void unschedule_pop_up_location_context_menu (FMDirectoryView *view);
396
397 static inline void fm_directory_view_widget_to_file_operation_position (FMDirectoryView *view,
398 GdkPoint *position);
399 static void fm_directory_view_widget_to_file_operation_position_xy (FMDirectoryView *view,
400 int *x, int *y);
401
402 /* undo-related actions */
403
404 static void undo_redo_menu_update_callback (CajaUndoStackManager* manager, gpointer arg1, gpointer data);
405
406 static void undo_update_menu (FMDirectoryView *view);
407
408 static void finish_undoredo_callback (gpointer data);
409
410 static void real_action_undo (FMDirectoryView *view);
411
412 static void real_action_redo (FMDirectoryView *view);
413
414 static void action_undo_callback (GtkAction *action, gpointer callback_data);
415
416 static void action_redo_callback (GtkAction *action, gpointer callback_data);
417
418 EEL_CLASS_BOILERPLATE (FMDirectoryView, fm_directory_view, GTK_TYPE_SCROLLED_WINDOW)
419
420 EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (fm_directory_view, add_file)
421 EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (fm_directory_view, bump_zoom_level)
422 EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (fm_directory_view, can_zoom_in)
423 EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (fm_directory_view, can_zoom_out)
424 EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (fm_directory_view, clear)
425 EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (fm_directory_view, file_changed)
426 EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (fm_directory_view, get_background_widget)
427 EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (fm_directory_view, get_selection)
428 EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (fm_directory_view, get_selection_for_file_transfer)
429 EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (fm_directory_view, get_item_count)
430 EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (fm_directory_view, is_empty)
431 EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (fm_directory_view, reset_to_defaults)
432 EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (fm_directory_view, restore_default_zoom_level)
433 EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (fm_directory_view, select_all)
434 EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (fm_directory_view, set_selection)
435 EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (fm_directory_view, zoom_to_level)
436 EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (fm_directory_view, get_zoom_level)
437 EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (fm_directory_view, invert_selection)
438
439 typedef struct {
440 GAppInfo *application;
441 GList *files;
442 FMDirectoryView *directory_view;
443 } ApplicationLaunchParameters;
444
445 typedef struct {
446 CajaFile *file;
447 FMDirectoryView *directory_view;
448 } ScriptLaunchParameters;
449
450 typedef struct {
451 CajaFile *file;
452 FMDirectoryView *directory_view;
453 } CreateTemplateParameters;
454
455 static ApplicationLaunchParameters *
application_launch_parameters_new(GAppInfo * application,GList * files,FMDirectoryView * directory_view)456 application_launch_parameters_new (GAppInfo *application,
457 GList *files,
458 FMDirectoryView *directory_view)
459 {
460 ApplicationLaunchParameters *result;
461
462 result = g_new0 (ApplicationLaunchParameters, 1);
463 result->application = g_object_ref (application);
464 result->files = caja_file_list_copy (files);
465
466 if (directory_view != NULL) {
467 g_object_ref (directory_view);
468 result->directory_view = directory_view;
469 }
470
471 return result;
472 }
473
474 static void
application_launch_parameters_free(ApplicationLaunchParameters * parameters)475 application_launch_parameters_free (ApplicationLaunchParameters *parameters)
476 {
477 g_object_unref (parameters->application);
478 caja_file_list_free (parameters->files);
479
480 if (parameters->directory_view != NULL) {
481 g_object_unref (parameters->directory_view);
482 }
483
484 g_free (parameters);
485 }
486
487 static GList *
file_and_directory_list_to_files(GList * fad_list)488 file_and_directory_list_to_files (GList *fad_list)
489 {
490 GList *res, *l;
491 FileAndDirectory *fad = NULL;
492
493 res = NULL;
494 for (l = fad_list; l != NULL; l = l->next) {
495 fad = l->data;
496 res = g_list_prepend (res, caja_file_ref (fad->file));
497 }
498 return g_list_reverse (res);
499 }
500
501
502 static GList *
file_and_directory_list_from_files(CajaDirectory * directory,GList * files)503 file_and_directory_list_from_files (CajaDirectory *directory, GList *files)
504 {
505 GList *res, *l;
506 FileAndDirectory *fad = NULL;
507
508 res = NULL;
509 for (l = files; l != NULL; l = l->next) {
510 fad = g_new0 (FileAndDirectory, 1);
511 fad->directory = caja_directory_ref (directory);
512 fad->file = caja_file_ref (l->data);
513 res = g_list_prepend (res, fad);
514 }
515 return g_list_reverse (res);
516 }
517
518 static void
file_and_directory_free(FileAndDirectory * fad)519 file_and_directory_free (FileAndDirectory *fad)
520 {
521 caja_directory_unref (fad->directory);
522 caja_file_unref (fad->file);
523 g_free (fad);
524 }
525
526
527 static void
file_and_directory_list_free(GList * list)528 file_and_directory_list_free (GList *list)
529 {
530 GList *l;
531
532 for (l = list; l != NULL; l = l->next) {
533 file_and_directory_free (l->data);
534 }
535
536 g_list_free (list);
537 }
538
539 static gboolean
file_and_directory_equal(gconstpointer v1,gconstpointer v2)540 file_and_directory_equal (gconstpointer v1,
541 gconstpointer v2)
542 {
543 const FileAndDirectory *fad1, *fad2;
544 fad1 = v1;
545 fad2 = v2;
546
547 return (fad1->file == fad2->file &&
548 fad1->directory == fad2->directory);
549 }
550
551 static guint
file_and_directory_hash(gconstpointer v)552 file_and_directory_hash (gconstpointer v)
553 {
554 const FileAndDirectory *fad;
555
556 fad = v;
557 return GPOINTER_TO_UINT (fad->file) ^ GPOINTER_TO_UINT (fad->directory);
558 }
559
560
561
562
563 static ScriptLaunchParameters *
script_launch_parameters_new(CajaFile * file,FMDirectoryView * directory_view)564 script_launch_parameters_new (CajaFile *file,
565 FMDirectoryView *directory_view)
566 {
567 ScriptLaunchParameters *result;
568
569 result = g_new0 (ScriptLaunchParameters, 1);
570 g_object_ref (directory_view);
571 result->directory_view = directory_view;
572 caja_file_ref (file);
573 result->file = file;
574
575 return result;
576 }
577
578 static void
script_launch_parameters_free(ScriptLaunchParameters * parameters)579 script_launch_parameters_free (ScriptLaunchParameters *parameters)
580 {
581 g_object_unref (parameters->directory_view);
582 caja_file_unref (parameters->file);
583 g_free (parameters);
584 }
585
586 static CreateTemplateParameters *
create_template_parameters_new(CajaFile * file,FMDirectoryView * directory_view)587 create_template_parameters_new (CajaFile *file,
588 FMDirectoryView *directory_view)
589 {
590 CreateTemplateParameters *result;
591
592 result = g_new0 (CreateTemplateParameters, 1);
593 g_object_ref (directory_view);
594 result->directory_view = directory_view;
595 caja_file_ref (file);
596 result->file = file;
597
598 return result;
599 }
600
601 static void
create_templates_parameters_free(CreateTemplateParameters * parameters)602 create_templates_parameters_free (CreateTemplateParameters *parameters)
603 {
604 g_object_unref (parameters->directory_view);
605 caja_file_unref (parameters->file);
606 g_free (parameters);
607 }
608
609 CajaWindowInfo *
fm_directory_view_get_caja_window(FMDirectoryView * view)610 fm_directory_view_get_caja_window (FMDirectoryView *view)
611 {
612 g_assert (view->details->window != NULL);
613
614 return view->details->window;
615 }
616
617 CajaWindowSlotInfo *
fm_directory_view_get_caja_window_slot(FMDirectoryView * view)618 fm_directory_view_get_caja_window_slot (FMDirectoryView *view)
619 {
620 g_assert (view->details->slot != NULL);
621
622 return view->details->slot;
623 }
624
625 /* Returns the GtkWindow that this directory view occupies, or NULL
626 * if at the moment this directory view is not in a GtkWindow or the
627 * GtkWindow cannot be determined. Primarily used for parenting dialogs.
628 */
629 GtkWindow *
fm_directory_view_get_containing_window(FMDirectoryView * view)630 fm_directory_view_get_containing_window (FMDirectoryView *view)
631 {
632 GtkWidget *window;
633
634 g_assert (FM_IS_DIRECTORY_VIEW (view));
635
636 window = gtk_widget_get_ancestor (GTK_WIDGET (view), GTK_TYPE_WINDOW);
637 if (window == NULL) {
638 return NULL;
639 }
640
641 return GTK_WINDOW (window);
642 }
643
644 static gboolean
fm_directory_view_confirm_multiple(GtkWindow * parent_window,int count,gboolean tabs)645 fm_directory_view_confirm_multiple (GtkWindow *parent_window,
646 int count,
647 gboolean tabs)
648 {
649 GtkDialog *dialog;
650 char *prompt;
651 char *detail;
652 int response;
653
654 if (count <= SILENT_WINDOW_OPEN_LIMIT) {
655 return TRUE;
656 }
657
658 prompt = _("Are you sure you want to open all files?");
659 if (tabs) {
660 detail = g_strdup_printf (ngettext("This will open %'d separate tab.",
661 "This will open %'d separate tabs.", count), count);
662 } else {
663 detail = g_strdup_printf (ngettext("This will open %'d separate window.",
664 "This will open %'d separate windows.", count), count);
665 }
666 dialog = eel_show_yes_no_dialog (prompt, detail,
667 "gtk-ok", "process-stop",
668 parent_window);
669 g_free (detail);
670
671 response = gtk_dialog_run (dialog);
672 gtk_widget_destroy (GTK_WIDGET (dialog));
673
674 return response == GTK_RESPONSE_YES;
675 }
676
677 static gboolean
selection_contains_one_item_in_menu_callback(FMDirectoryView * view,GList * selection)678 selection_contains_one_item_in_menu_callback (FMDirectoryView *view, GList *selection)
679 {
680 if (eel_g_list_exactly_one_item (selection)) {
681 return TRUE;
682 }
683
684 /* If we've requested a menu update that hasn't yet occurred, then
685 * the mismatch here doesn't surprise us, and we won't complain.
686 * Otherwise, we will complain.
687 */
688 if (!view->details->menu_states_untrustworthy) {
689 g_warning ("Expected one selected item, found %'d. No action will be performed.",
690 g_list_length (selection));
691 }
692
693 return FALSE;
694 }
695
696 static gboolean
selection_not_empty_in_menu_callback(FMDirectoryView * view,GList * selection)697 selection_not_empty_in_menu_callback (FMDirectoryView *view, GList *selection)
698 {
699 if (selection != NULL) {
700 return TRUE;
701 }
702
703 /* If we've requested a menu update that hasn't yet occurred, then
704 * the mismatch here doesn't surprise us, and we won't complain.
705 * Otherwise, we will complain.
706 */
707 if (!view->details->menu_states_untrustworthy) {
708 g_warning ("Empty selection found when selection was expected. No action will be performed.");
709 }
710
711 return FALSE;
712 }
713
714 static char *
get_view_directory(FMDirectoryView * view)715 get_view_directory (FMDirectoryView *view)
716 {
717 char *uri, *path;
718 GFile *f;
719
720 uri = caja_directory_get_uri (view->details->model);
721 if (eel_uri_is_desktop (uri)) {
722 g_free (uri);
723 uri = caja_get_desktop_directory_uri ();
724
725 }
726 f = g_file_new_for_uri (uri);
727 path = g_file_get_path (f);
728 g_object_unref (f);
729 g_free (uri);
730
731 return path;
732 }
733
734 void
fm_directory_view_activate_files(FMDirectoryView * view,GList * files,CajaWindowOpenMode mode,CajaWindowOpenFlags flags,gboolean confirm_multiple)735 fm_directory_view_activate_files (FMDirectoryView *view,
736 GList *files,
737 CajaWindowOpenMode mode,
738 CajaWindowOpenFlags flags,
739 gboolean confirm_multiple)
740 {
741 char *path;
742
743 path = get_view_directory (view);
744 caja_mime_activate_files (fm_directory_view_get_containing_window (view),
745 view->details->slot,
746 files,
747 path,
748 mode,
749 flags,
750 confirm_multiple);
751
752 g_free (path);
753 }
754
755 void
fm_directory_view_activate_file(FMDirectoryView * view,CajaFile * file,CajaWindowOpenMode mode,CajaWindowOpenFlags flags)756 fm_directory_view_activate_file (FMDirectoryView *view,
757 CajaFile *file,
758 CajaWindowOpenMode mode,
759 CajaWindowOpenFlags flags)
760 {
761 char *path;
762
763 path = get_view_directory (view);
764 caja_mime_activate_file (fm_directory_view_get_containing_window (view),
765 view->details->slot,
766 file,
767 path,
768 mode,
769 flags);
770
771 g_free (path);
772 }
773
774 static void
action_open_callback(GtkAction * action,gpointer callback_data)775 action_open_callback (GtkAction *action,
776 gpointer callback_data)
777 {
778 GList *selection;
779 FMDirectoryView *view;
780
781 view = FM_DIRECTORY_VIEW (callback_data);
782
783 selection = fm_directory_view_get_selection (view);
784 fm_directory_view_activate_files (view,
785 selection,
786 CAJA_WINDOW_OPEN_ACCORDING_TO_MODE,
787 0,
788 TRUE);
789 caja_file_list_free (selection);
790 }
791
792 static void
action_open_close_parent_callback(GtkAction * action,gpointer callback_data)793 action_open_close_parent_callback (GtkAction *action,
794 gpointer callback_data)
795 {
796 GList *selection;
797 FMDirectoryView *view;
798
799 view = FM_DIRECTORY_VIEW (callback_data);
800
801 selection = fm_directory_view_get_selection (view);
802 fm_directory_view_activate_files (view,
803 selection,
804 CAJA_WINDOW_OPEN_ACCORDING_TO_MODE,
805 CAJA_WINDOW_OPEN_FLAG_CLOSE_BEHIND,
806 TRUE);
807 caja_file_list_free (selection);
808 }
809
810
811 static void
action_open_alternate_callback(GtkAction * action,gpointer callback_data)812 action_open_alternate_callback (GtkAction *action,
813 gpointer callback_data)
814 {
815 FMDirectoryView *view;
816 GList *selection;
817 GtkWindow *window;
818
819 view = FM_DIRECTORY_VIEW (callback_data);
820 selection = fm_directory_view_get_selection (view);
821
822 window = fm_directory_view_get_containing_window (view);
823
824 if (fm_directory_view_confirm_multiple (window, g_list_length (selection), FALSE)) {
825 g_list_foreach (selection, open_one_in_new_window, view);
826 }
827
828 caja_file_list_free (selection);
829 }
830
831 static void
action_open_new_tab_callback(GtkAction * action,gpointer callback_data)832 action_open_new_tab_callback (GtkAction *action,
833 gpointer callback_data)
834 {
835 FMDirectoryView *view;
836 GList *selection;
837 GtkWindow *window;
838
839 view = FM_DIRECTORY_VIEW (callback_data);
840 selection = fm_directory_view_get_selection (view);
841
842 window = fm_directory_view_get_containing_window (view);
843
844 if (fm_directory_view_confirm_multiple (window, g_list_length (selection), TRUE)) {
845 fm_directory_view_activate_files (view,
846 selection,
847 CAJA_WINDOW_OPEN_ACCORDING_TO_MODE,
848 CAJA_WINDOW_OPEN_FLAG_NEW_TAB,
849 FALSE);
850 }
851
852 caja_file_list_free (selection);
853 }
854
855 static void
action_open_folder_window_callback(GtkAction * action,gpointer callback_data)856 action_open_folder_window_callback (GtkAction *action,
857 gpointer callback_data)
858 {
859 FMDirectoryView *view;
860 GList *selection;
861 GtkWindow *window;
862
863 view = FM_DIRECTORY_VIEW (callback_data);
864 selection = fm_directory_view_get_selection (view);
865
866 window = fm_directory_view_get_containing_window (view);
867
868 if (fm_directory_view_confirm_multiple (window, g_list_length (selection), FALSE)) {
869 g_list_foreach (selection, open_one_in_folder_window, view);
870 }
871
872 caja_file_list_free (selection);
873 }
874
875 static void
open_location(FMDirectoryView * directory_view,const char * new_uri,CajaWindowOpenMode mode,CajaWindowOpenFlags flags)876 open_location (FMDirectoryView *directory_view,
877 const char *new_uri,
878 CajaWindowOpenMode mode,
879 CajaWindowOpenFlags flags)
880 {
881 GtkWindow *window;
882 GFile *location;
883
884 g_assert (FM_IS_DIRECTORY_VIEW (directory_view));
885 g_assert (new_uri != NULL);
886
887 window = fm_directory_view_get_containing_window (directory_view);
888 caja_debug_log (FALSE, CAJA_DEBUG_LOG_DOMAIN_USER,
889 "directory view open_location window=%p: %s", window, new_uri);
890 location = g_file_new_for_uri (new_uri);
891 caja_window_slot_info_open_location (directory_view->details->slot,
892 location, mode, flags, NULL);
893 g_object_unref (location);
894 }
895
896 static void
application_selected_cb(CajaOpenWithDialog * dialog,GAppInfo * app,gpointer user_data)897 application_selected_cb (CajaOpenWithDialog *dialog,
898 GAppInfo *app,
899 gpointer user_data)
900 {
901 GtkWindow *parent_window;
902 CajaFile *file;
903 GList files;
904
905 parent_window = GTK_WINDOW (user_data);
906
907 file = g_object_get_data (G_OBJECT (dialog), "directory-view:file");
908
909 files.next = NULL;
910 files.prev = NULL;
911 files.data = file;
912 caja_launch_application (app, &files, parent_window);
913 }
914
915 static void
choose_program(FMDirectoryView * view,CajaFile * file)916 choose_program (FMDirectoryView *view,
917 CajaFile *file)
918 {
919 GtkWidget *dialog;
920 char *uri;
921 char *mime_type;
922
923 g_assert (FM_IS_DIRECTORY_VIEW (view));
924 g_assert (CAJA_IS_FILE (file));
925
926 caja_file_ref (file);
927 uri = caja_file_get_uri (file);
928 mime_type = caja_file_get_mime_type (file);
929
930 dialog = caja_open_with_dialog_new (uri, mime_type, NULL);
931 g_object_set_data_full (G_OBJECT (dialog),
932 "directory-view:file",
933 g_object_ref (file),
934 (GDestroyNotify)g_object_unref);
935
936 gtk_window_set_screen (GTK_WINDOW (dialog),
937 gtk_widget_get_screen (GTK_WIDGET (view)));
938 gtk_widget_show (dialog);
939
940 g_signal_connect_object (dialog,
941 "application_selected",
942 G_CALLBACK (application_selected_cb),
943 fm_directory_view_get_containing_window (view),
944 0);
945
946 g_free (uri);
947 g_free (mime_type);
948 caja_file_unref (file);
949 }
950
951 static void
open_with_other_program(FMDirectoryView * view)952 open_with_other_program (FMDirectoryView *view)
953 {
954 GList *selection;
955
956 g_assert (FM_IS_DIRECTORY_VIEW (view));
957
958 selection = fm_directory_view_get_selection (view);
959
960 if (selection_contains_one_item_in_menu_callback (view, selection)) {
961 choose_program (view, CAJA_FILE (selection->data));
962 }
963
964 caja_file_list_free (selection);
965 }
966
967 static void
action_other_application_callback(GtkAction * action,gpointer callback_data)968 action_other_application_callback (GtkAction *action,
969 gpointer callback_data)
970 {
971 g_assert (FM_IS_DIRECTORY_VIEW (callback_data));
972
973 open_with_other_program (FM_DIRECTORY_VIEW (callback_data));
974 }
975
976 static void
trash_or_delete_selected_files(FMDirectoryView * view)977 trash_or_delete_selected_files (FMDirectoryView *view)
978 {
979 /* This might be rapidly called multiple times for the same selection
980 * when using keybindings. So we remember if the current selection
981 * was already removed (but the view doesn't know about it yet).
982 */
983 if (!view->details->selection_was_removed) {
984 GList *selection;
985
986 selection = fm_directory_view_get_selection_for_file_transfer (view);
987 trash_or_delete_files (fm_directory_view_get_containing_window (view),
988 selection, TRUE,
989 view);
990 caja_file_list_free (selection);
991 view->details->selection_was_removed = TRUE;
992 }
993 }
994
995 static gboolean
real_trash(FMDirectoryView * view)996 real_trash (FMDirectoryView *view)
997 {
998 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
999 GtkAction *action;
1000
1001 action = gtk_action_group_get_action (view->details->dir_action_group,
1002 FM_ACTION_TRASH);
1003 if (gtk_action_get_sensitive (action) &&
1004 gtk_action_get_visible (action)) {
1005 trash_or_delete_selected_files (view);
1006 return TRUE;
1007 }
1008 G_GNUC_END_IGNORE_DEPRECATIONS;
1009 return FALSE;
1010 }
1011
1012 static void
action_trash_callback(GtkAction * action,gpointer callback_data)1013 action_trash_callback (GtkAction *action,
1014 gpointer callback_data)
1015 {
1016 trash_or_delete_selected_files (FM_DIRECTORY_VIEW (callback_data));
1017 }
1018
1019 static void
delete_selected_files(FMDirectoryView * view)1020 delete_selected_files (FMDirectoryView *view)
1021 {
1022 GList *selection;
1023 GList *node;
1024 GList *locations;
1025
1026 selection = fm_directory_view_get_selection_for_file_transfer (view);
1027 if (selection == NULL) {
1028 return;
1029 }
1030
1031 locations = NULL;
1032 for (node = selection; node != NULL; node = node->next) {
1033 locations = g_list_prepend (locations,
1034 caja_file_get_location ((CajaFile *) node->data));
1035 }
1036 locations = g_list_reverse (locations);
1037
1038 caja_file_operations_delete (locations, fm_directory_view_get_containing_window (view), NULL, NULL);
1039
1040 g_list_free_full (locations, g_object_unref);
1041 caja_file_list_free (selection);
1042 }
1043
1044 static void
action_delete_callback(GtkAction * action,gpointer callback_data)1045 action_delete_callback (GtkAction *action,
1046 gpointer callback_data)
1047 {
1048 delete_selected_files (FM_DIRECTORY_VIEW (callback_data));
1049 }
1050
1051 static void
action_restore_from_trash_callback(GtkAction * action,gpointer callback_data)1052 action_restore_from_trash_callback (GtkAction *action,
1053 gpointer callback_data)
1054 {
1055 FMDirectoryView *view;
1056 GList *selection;
1057
1058 view = FM_DIRECTORY_VIEW (callback_data);
1059
1060 selection = fm_directory_view_get_selection_for_file_transfer (view);
1061 caja_restore_files_from_trash (selection,
1062 fm_directory_view_get_containing_window (view));
1063
1064 caja_file_list_free (selection);
1065
1066 }
1067
1068 static gboolean
real_delete(FMDirectoryView * view)1069 real_delete (FMDirectoryView *view)
1070 {
1071 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1072 GtkAction *action;
1073
1074 action = gtk_action_group_get_action (view->details->dir_action_group,
1075 FM_ACTION_TRASH);
1076 if (gtk_action_get_sensitive (action) &&
1077 gtk_action_get_visible (action)) {
1078 delete_selected_files (view);
1079 return TRUE;
1080 }
1081 G_GNUC_END_IGNORE_DEPRECATIONS;
1082 return FALSE;
1083 }
1084
1085 static void
action_duplicate_callback(GtkAction * action,gpointer callback_data)1086 action_duplicate_callback (GtkAction *action,
1087 gpointer callback_data)
1088 {
1089 FMDirectoryView *view;
1090 GList *selection;
1091
1092 view = FM_DIRECTORY_VIEW (callback_data);
1093 selection = fm_directory_view_get_selection_for_file_transfer (view);
1094 if (selection_not_empty_in_menu_callback (view, selection)) {
1095 GArray *selected_item_locations;
1096
1097 /* FIXME bugzilla.gnome.org 45061:
1098 * should change things here so that we use a get_icon_locations (view, selection).
1099 * Not a problem in this case but in other places the selection may change by
1100 * the time we go and retrieve the icon positions, relying on the selection
1101 * staying intact to ensure the right sequence and count of positions is fragile.
1102 */
1103 selected_item_locations = fm_directory_view_get_selected_icon_locations (view);
1104 fm_directory_view_duplicate_selection (view, selection, selected_item_locations);
1105 g_array_free (selected_item_locations, TRUE);
1106 }
1107
1108 caja_file_list_free (selection);
1109 }
1110
1111 static void
action_create_link_callback(GtkAction * action,gpointer callback_data)1112 action_create_link_callback (GtkAction *action,
1113 gpointer callback_data)
1114 {
1115 FMDirectoryView *view;
1116 GList *selection;
1117
1118 g_assert (FM_IS_DIRECTORY_VIEW (callback_data));
1119
1120 view = FM_DIRECTORY_VIEW (callback_data);
1121 selection = fm_directory_view_get_selection (view);
1122 if (selection_not_empty_in_menu_callback (view, selection)) {
1123 GArray *selected_item_locations;
1124
1125 selected_item_locations = fm_directory_view_get_selected_icon_locations (view);
1126 fm_directory_view_create_links_for_files (view, selection, selected_item_locations);
1127 g_array_free (selected_item_locations, TRUE);
1128 }
1129
1130 caja_file_list_free (selection);
1131 }
1132
1133 static void
action_select_all_callback(GtkAction * action,gpointer callback_data)1134 action_select_all_callback (GtkAction *action,
1135 gpointer callback_data)
1136 {
1137 g_assert (FM_IS_DIRECTORY_VIEW (callback_data));
1138
1139 fm_directory_view_select_all (callback_data);
1140 }
1141
1142 static void
action_invert_selection_callback(GtkAction * action,gpointer callback_data)1143 action_invert_selection_callback (GtkAction *action,
1144 gpointer callback_data)
1145 {
1146 g_assert (FM_IS_DIRECTORY_VIEW (callback_data));
1147
1148 fm_directory_view_invert_selection (callback_data);
1149 }
1150
1151
1152 static void
pattern_select_response_cb(GtkWidget * dialog,int response,gpointer user_data)1153 pattern_select_response_cb (GtkWidget *dialog, int response, gpointer user_data)
1154 {
1155 FMDirectoryView *view;
1156 CajaDirectory *directory;
1157 GtkWidget *entry;
1158 GList *selection;
1159 GError *error;
1160
1161 view = FM_DIRECTORY_VIEW (user_data);
1162
1163 switch (response) {
1164 case GTK_RESPONSE_OK :
1165 entry = g_object_get_data (G_OBJECT (dialog), "entry");
1166 directory = fm_directory_view_get_model (view);
1167 selection = caja_directory_match_pattern (directory,
1168 gtk_entry_get_text (GTK_ENTRY (entry)));
1169
1170 if (selection) {
1171 fm_directory_view_set_selection (view, selection);
1172 caja_file_list_free (selection);
1173
1174 fm_directory_view_reveal_selection(view);
1175 }
1176 /* fall through */
1177 case GTK_RESPONSE_NONE :
1178 case GTK_RESPONSE_DELETE_EVENT :
1179 case GTK_RESPONSE_CANCEL :
1180 gtk_widget_destroy (GTK_WIDGET (dialog));
1181 break;
1182 case GTK_RESPONSE_HELP :
1183 error = NULL;
1184 gtk_show_uri_on_window (GTK_WINDOW (dialog),
1185 "help:mate-user-guide/caja-select-pattern",
1186 gtk_get_current_event_time (), &error);
1187 if (error) {
1188 eel_show_error_dialog (_("There was an error displaying help."), error->message,
1189 GTK_WINDOW (dialog));
1190 g_error_free (error);
1191 }
1192 break;
1193 default :
1194 g_assert_not_reached ();
1195 }
1196 }
1197
1198 static void
select_pattern(FMDirectoryView * view)1199 select_pattern (FMDirectoryView *view)
1200 {
1201 GtkWidget *dialog;
1202 GtkWidget *label;
1203 GtkWidget *example;
1204 GtkWidget *grid;
1205 GtkWidget *entry;
1206 char *example_pattern;
1207
1208 dialog = gtk_dialog_new ();
1209 gtk_window_set_title (GTK_WINDOW (dialog), _("Select Items Matching"));
1210 gtk_window_set_transient_for (GTK_WINDOW (dialog), fm_directory_view_get_containing_window (view));
1211 gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
1212
1213 eel_dialog_add_button (GTK_DIALOG (dialog),
1214 _("_Help"),
1215 "help-browser",
1216 GTK_RESPONSE_HELP);
1217
1218 eel_dialog_add_button (GTK_DIALOG (dialog),
1219 _("_Cancel"),
1220 "process-stop",
1221 GTK_RESPONSE_CANCEL);
1222
1223 eel_dialog_add_button (GTK_DIALOG (dialog),
1224 _("_OK"),
1225 "gtk-ok",
1226 GTK_RESPONSE_OK);
1227
1228 gtk_dialog_set_default_response (GTK_DIALOG (dialog),
1229 GTK_RESPONSE_OK);
1230 gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
1231 gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 2);
1232
1233 label = gtk_label_new_with_mnemonic (_("_Pattern:"));
1234
1235 gtk_widget_set_halign (label, GTK_ALIGN_START);
1236
1237 example = gtk_label_new (NULL);
1238 gtk_widget_set_halign (example, GTK_ALIGN_START);
1239 example_pattern = g_strdup_printf ("<b>%s</b><i>%s</i>",
1240 _("Examples: "),
1241 "*.png, file\?\?.txt, pict*.\?\?\?");
1242 gtk_label_set_markup (GTK_LABEL (example), example_pattern);
1243 g_free (example_pattern);
1244 gtk_widget_set_halign (example, GTK_ALIGN_START);
1245
1246 entry = gtk_entry_new ();
1247 gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
1248 gtk_widget_set_hexpand (entry, TRUE);
1249
1250 grid = gtk_grid_new ();
1251 g_object_set (grid,
1252 "orientation", GTK_ORIENTATION_VERTICAL,
1253 "border-width", 6,
1254 "row-spacing", 6,
1255 "column-spacing", 12,
1256 NULL);
1257
1258 gtk_container_add (GTK_CONTAINER (grid), label);
1259 gtk_grid_attach_next_to (GTK_GRID (grid), entry, label,
1260 GTK_POS_RIGHT, 1, 1);
1261 gtk_grid_attach_next_to (GTK_GRID (grid), example, entry,
1262 GTK_POS_BOTTOM, 1, 1);
1263
1264 gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
1265 gtk_widget_show_all (grid);
1266 gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), grid);
1267
1268 g_object_set_data (G_OBJECT (dialog), "entry", entry);
1269 g_signal_connect (dialog, "response",
1270 G_CALLBACK (pattern_select_response_cb),
1271 view);
1272 gtk_widget_show_all (dialog);
1273 }
1274
1275 static void
action_select_pattern_callback(GtkAction * action,gpointer callback_data)1276 action_select_pattern_callback (GtkAction *action,
1277 gpointer callback_data)
1278 {
1279 g_assert (FM_IS_DIRECTORY_VIEW (callback_data));
1280
1281 select_pattern(callback_data);
1282 }
1283
1284 static void
action_reset_to_defaults_callback(GtkAction * action,gpointer callback_data)1285 action_reset_to_defaults_callback (GtkAction *action,
1286 gpointer callback_data)
1287 {
1288 g_assert (FM_IS_DIRECTORY_VIEW (callback_data));
1289
1290 fm_directory_view_reset_to_defaults (callback_data);
1291 }
1292
1293
1294 static void
hidden_files_mode_changed(CajaWindow * window,gpointer callback_data)1295 hidden_files_mode_changed (CajaWindow *window,
1296 gpointer callback_data)
1297 {
1298 FMDirectoryView *directory_view;
1299
1300 directory_view = FM_DIRECTORY_VIEW (callback_data);
1301
1302 fm_directory_view_init_show_hidden_files (directory_view);
1303 }
1304
1305 static void
backup_files_mode_changed(CajaWindow * window,gpointer callback_data)1306 backup_files_mode_changed (CajaWindow *window,
1307 gpointer callback_data)
1308 {
1309 FMDirectoryView *directory_view;
1310
1311 directory_view = FM_DIRECTORY_VIEW (callback_data);
1312
1313 fm_directory_view_init_show_backup_files (directory_view);
1314 }
1315
1316 static void
action_save_search_callback(GtkAction * action,gpointer callback_data)1317 action_save_search_callback (GtkAction *action,
1318 gpointer callback_data)
1319 {
1320 FMDirectoryView *directory_view;
1321
1322 directory_view = FM_DIRECTORY_VIEW (callback_data);
1323
1324 if (directory_view->details->model &&
1325 CAJA_IS_SEARCH_DIRECTORY (directory_view->details->model)) {
1326 CajaSearchDirectory *search;
1327
1328 search = CAJA_SEARCH_DIRECTORY (directory_view->details->model);
1329 caja_search_directory_save_search (search);
1330
1331 /* Save search is disabled */
1332 schedule_update_menus (directory_view);
1333 }
1334 }
1335
1336 static void
query_name_entry_changed_cb(GtkWidget * entry,GtkWidget * button)1337 query_name_entry_changed_cb (GtkWidget *entry, GtkWidget *button)
1338 {
1339 const char *text;
1340 gboolean sensitive;
1341
1342 text = gtk_entry_get_text (GTK_ENTRY (entry));
1343
1344 sensitive = (text != NULL) && (*text != 0);
1345
1346 gtk_widget_set_sensitive (button, sensitive);
1347 }
1348
1349
1350 static void
action_save_search_as_callback(GtkAction * action,gpointer callback_data)1351 action_save_search_as_callback (GtkAction *action,
1352 gpointer callback_data)
1353 {
1354 FMDirectoryView *directory_view;
1355
1356 directory_view = FM_DIRECTORY_VIEW (callback_data);
1357
1358 if (directory_view->details->model &&
1359 CAJA_IS_SEARCH_DIRECTORY (directory_view->details->model)) {
1360 CajaSearchDirectory *search;
1361 GtkWidget *dialog, *grid, *label, *entry, *chooser, *save_button;
1362
1363 search = CAJA_SEARCH_DIRECTORY (directory_view->details->model);
1364
1365 dialog = gtk_dialog_new ();
1366 gtk_window_set_title (GTK_WINDOW (dialog), _("Save Search as"));
1367 gtk_window_set_transient_for (GTK_WINDOW (dialog), fm_directory_view_get_containing_window (directory_view));
1368
1369 eel_dialog_add_button (GTK_DIALOG (dialog),
1370 _("_Cancel"),
1371 "process-stop",
1372 GTK_RESPONSE_CANCEL);
1373
1374 save_button = eel_dialog_add_button (GTK_DIALOG (dialog), _("_Save"),
1375 "document-save", GTK_RESPONSE_OK);
1376
1377 gtk_dialog_set_default_response (GTK_DIALOG (dialog),
1378 GTK_RESPONSE_OK);
1379 gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
1380 gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 2);
1381 gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
1382
1383 grid = gtk_grid_new ();
1384 g_object_set (grid,
1385 "orientation", GTK_ORIENTATION_VERTICAL,
1386 "border-width", 5,
1387 "row-spacing", 6,
1388 "column-spacing", 12,
1389 NULL);
1390 gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), grid, TRUE, TRUE, 0);
1391 gtk_widget_show (grid);
1392
1393 label = gtk_label_new_with_mnemonic (_("Search _name:"));
1394 gtk_label_set_xalign (GTK_LABEL (label), 0.0);
1395 gtk_container_add (GTK_CONTAINER (grid), label);
1396 gtk_widget_show (label);
1397 entry = gtk_entry_new ();
1398 gtk_widget_set_hexpand (entry, TRUE);
1399 gtk_grid_attach_next_to (GTK_GRID (grid), entry, label,
1400 GTK_POS_RIGHT, 1, 1);
1401 gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
1402 gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
1403
1404 gtk_widget_set_sensitive (save_button, FALSE);
1405 g_signal_connect (entry, "changed",
1406 G_CALLBACK (query_name_entry_changed_cb), save_button);
1407
1408 gtk_widget_show (entry);
1409 label = gtk_label_new_with_mnemonic (_("_Folder:"));
1410 gtk_label_set_xalign (GTK_LABEL (label), 0.0);
1411 gtk_container_add (GTK_CONTAINER (grid), label);
1412 gtk_widget_show (label);
1413
1414 chooser = gtk_file_chooser_button_new (_("Select Folder to Save Search In"),
1415 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
1416 gtk_widget_set_hexpand (chooser, TRUE);
1417 gtk_grid_attach_next_to (GTK_GRID (grid), chooser, label,
1418 GTK_POS_RIGHT, 1, 1);
1419 gtk_label_set_mnemonic_widget (GTK_LABEL (label), chooser);
1420 gtk_widget_show (chooser);
1421
1422 gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (chooser), TRUE);
1423
1424 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (chooser),
1425 g_get_home_dir ());
1426
1427 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
1428 const char *entry_text;
1429 char *filename, *filename_utf8, *dirname, *path, *uri;
1430 GFile *location;
1431
1432 entry_text = gtk_entry_get_text (GTK_ENTRY (entry));
1433 if (g_str_has_suffix (entry_text, CAJA_SAVED_SEARCH_EXTENSION)) {
1434 filename_utf8 = g_strdup (entry_text);
1435 } else {
1436 filename_utf8 = g_strconcat (entry_text, CAJA_SAVED_SEARCH_EXTENSION, NULL);
1437 }
1438
1439 filename = g_filename_from_utf8 (filename_utf8, -1, NULL, NULL, NULL);
1440 g_free (filename_utf8);
1441
1442 dirname = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser));
1443
1444 path = g_build_filename (dirname, filename, NULL);
1445 g_free (filename);
1446 g_free (dirname);
1447
1448 uri = g_filename_to_uri (path, NULL, NULL);
1449 g_free (path);
1450
1451 caja_search_directory_save_to_file (search, uri);
1452 location = g_file_new_for_uri (uri);
1453 caja_file_changes_queue_file_added (location);
1454 g_object_unref (location);
1455 caja_file_changes_consume_changes (TRUE);
1456 g_free (uri);
1457 }
1458
1459 gtk_widget_destroy (dialog);
1460 }
1461 }
1462
1463
1464 static void
action_empty_trash_callback(GtkAction * action,gpointer callback_data)1465 action_empty_trash_callback (GtkAction *action,
1466 gpointer callback_data)
1467 {
1468 g_assert (FM_IS_DIRECTORY_VIEW (callback_data));
1469
1470 caja_file_operations_empty_trash (GTK_WIDGET (callback_data));
1471 }
1472
1473 static void
action_new_folder_callback(GtkAction * action,gpointer callback_data)1474 action_new_folder_callback (GtkAction *action,
1475 gpointer callback_data)
1476 {
1477 g_assert (FM_IS_DIRECTORY_VIEW (callback_data));
1478
1479 fm_directory_view_new_folder (FM_DIRECTORY_VIEW (callback_data));
1480 }
1481
1482 static void
action_new_empty_file_callback(GtkAction * action,gpointer callback_data)1483 action_new_empty_file_callback (GtkAction *action,
1484 gpointer callback_data)
1485 {
1486 g_assert (FM_IS_DIRECTORY_VIEW (callback_data));
1487
1488 fm_directory_view_new_file (FM_DIRECTORY_VIEW (callback_data), NULL, NULL);
1489 }
1490
1491 static void
action_new_launcher_callback(GtkAction * action,gpointer callback_data)1492 action_new_launcher_callback (GtkAction *action,
1493 gpointer callback_data)
1494 {
1495 char *parent_uri;
1496 FMDirectoryView *view;
1497 GtkWindow *window;
1498
1499 g_assert (FM_IS_DIRECTORY_VIEW (callback_data));
1500
1501 view = FM_DIRECTORY_VIEW (callback_data);
1502
1503 parent_uri = fm_directory_view_get_backing_uri (view);
1504
1505 window = fm_directory_view_get_containing_window (view);
1506 caja_debug_log (FALSE, CAJA_DEBUG_LOG_DOMAIN_USER,
1507 "directory view create new launcher in window=%p: %s", window, parent_uri);
1508 caja_launch_application_from_command (gtk_widget_get_screen (GTK_WIDGET (view)),
1509 "mate-desktop-item-edit",
1510 "mate-desktop-item-edit",
1511 FALSE,
1512 "--create-new", parent_uri, NULL);
1513
1514 g_free (parent_uri);
1515 }
1516
1517 static void
action_properties_callback(GtkAction * action,gpointer callback_data)1518 action_properties_callback (GtkAction *action,
1519 gpointer callback_data)
1520 {
1521 FMDirectoryView *view;
1522 GList *selection;
1523
1524 g_assert (FM_IS_DIRECTORY_VIEW (callback_data));
1525
1526 view = FM_DIRECTORY_VIEW (callback_data);
1527 selection = fm_directory_view_get_selection (view);
1528 if (g_list_length (selection) == 0) {
1529 if (view->details->directory_as_file != NULL) {
1530 GList *files;
1531
1532 files = g_list_append (NULL, caja_file_ref (view->details->directory_as_file));
1533
1534 fm_properties_window_present (files, GTK_WIDGET (view));
1535
1536 caja_file_list_free (files);
1537 }
1538 } else {
1539 fm_properties_window_present (selection, GTK_WIDGET (view));
1540 }
1541 caja_file_list_free (selection);
1542 }
1543
1544 static void
action_location_properties_callback(GtkAction * action,gpointer callback_data)1545 action_location_properties_callback (GtkAction *action,
1546 gpointer callback_data)
1547 {
1548 FMDirectoryView *view;
1549 GList *files;
1550
1551 g_assert (FM_IS_DIRECTORY_VIEW (callback_data));
1552
1553 view = FM_DIRECTORY_VIEW (callback_data);
1554 g_assert (CAJA_IS_FILE (view->details->location_popup_directory_as_file));
1555
1556 files = g_list_append (NULL, caja_file_ref (view->details->location_popup_directory_as_file));
1557
1558 fm_properties_window_present (files, GTK_WIDGET (view));
1559
1560 caja_file_list_free (files);
1561 }
1562
1563 static gboolean
all_files_in_trash(GList * files)1564 all_files_in_trash (GList *files)
1565 {
1566 GList *node;
1567
1568 /* Result is ambiguous if called on NULL, so disallow. */
1569 g_return_val_if_fail (files != NULL, FALSE);
1570
1571 for (node = files; node != NULL; node = node->next) {
1572 if (!caja_file_is_in_trash (CAJA_FILE (node->data))) {
1573 return FALSE;
1574 }
1575 }
1576
1577 return TRUE;
1578 }
1579
1580 static gboolean
all_selected_items_in_trash(FMDirectoryView * view)1581 all_selected_items_in_trash (FMDirectoryView *view)
1582 {
1583 GList *selection;
1584 gboolean result;
1585
1586 /* If the contents share a parent directory, we need only
1587 * check that parent directory. Otherwise we have to inspect
1588 * each selected item.
1589 */
1590 selection = fm_directory_view_get_selection (view);
1591 result = (selection == NULL) ? FALSE : all_files_in_trash (selection);
1592 caja_file_list_free (selection);
1593
1594 return result;
1595 }
1596
1597 static gboolean
we_are_in_vfolder_desktop_dir(FMDirectoryView * view)1598 we_are_in_vfolder_desktop_dir (FMDirectoryView *view)
1599 {
1600 CajaFile *file;
1601 char *mime_type;
1602
1603 g_return_val_if_fail (FM_IS_DIRECTORY_VIEW (view), FALSE);
1604
1605 if (view->details->model == NULL) {
1606 return FALSE;
1607 }
1608
1609 file = caja_directory_get_corresponding_file (view->details->model);
1610 mime_type = caja_file_get_mime_type (file);
1611 caja_file_unref (file);
1612
1613 if (mime_type != NULL
1614 && strcmp (mime_type, "x-directory/vfolder-desktop") == 0) {
1615 g_free (mime_type);
1616 return TRUE;
1617 } else {
1618 g_free (mime_type);
1619 return FALSE;
1620 }
1621 }
1622
1623 /* Preferences changed callbacks */
1624 static void
text_attribute_names_changed_callback(gpointer callback_data)1625 text_attribute_names_changed_callback (gpointer callback_data)
1626 {
1627 FMDirectoryView *view;
1628
1629 view = FM_DIRECTORY_VIEW (callback_data);
1630
1631 EEL_CALL_METHOD
1632 (FM_DIRECTORY_VIEW_CLASS, view,
1633 text_attribute_names_changed, (view));
1634 }
1635
1636 static void
image_display_policy_changed_callback(gpointer callback_data)1637 image_display_policy_changed_callback (gpointer callback_data)
1638 {
1639 FMDirectoryView *view;
1640
1641 view = FM_DIRECTORY_VIEW (callback_data);
1642
1643 EEL_CALL_METHOD
1644 (FM_DIRECTORY_VIEW_CLASS, view,
1645 image_display_policy_changed, (view));
1646 }
1647
1648 static void
click_policy_changed_callback(gpointer callback_data)1649 click_policy_changed_callback (gpointer callback_data)
1650 {
1651 FMDirectoryView *view;
1652
1653 view = FM_DIRECTORY_VIEW (callback_data);
1654
1655 EEL_CALL_METHOD
1656 (FM_DIRECTORY_VIEW_CLASS, view,
1657 click_policy_changed, (view));
1658 }
1659
1660 gboolean
fm_directory_view_should_sort_directories_first(FMDirectoryView * view)1661 fm_directory_view_should_sort_directories_first (FMDirectoryView *view)
1662 {
1663 return view->details->sort_directories_first;
1664 }
1665
1666 static void
sort_directories_first_changed_callback(gpointer callback_data)1667 sort_directories_first_changed_callback (gpointer callback_data)
1668 {
1669 FMDirectoryView *view;
1670 gboolean preference_value;
1671
1672 view = FM_DIRECTORY_VIEW (callback_data);
1673
1674 preference_value =
1675 g_settings_get_boolean (caja_preferences, CAJA_PREFERENCES_SORT_DIRECTORIES_FIRST);
1676
1677 if (preference_value != view->details->sort_directories_first) {
1678 view->details->sort_directories_first = preference_value;
1679 EEL_CALL_METHOD
1680 (FM_DIRECTORY_VIEW_CLASS, view,
1681 sort_directories_first_changed, (view));
1682 }
1683 }
1684
set_up_scripts_directory_global(void)1685 static void set_up_scripts_directory_global(void)
1686 {
1687 if (scripts_directory_uri != NULL)
1688 {
1689 return;
1690 }
1691
1692 char* scripts_directory_path;
1693 scripts_directory_path = g_build_filename (g_get_user_config_dir (), "caja", "scripts", NULL);
1694
1695 if (g_mkdir_with_parents(scripts_directory_path, 0755) == 0)
1696 {
1697 scripts_directory_uri = g_filename_to_uri(scripts_directory_path, NULL, NULL);
1698 scripts_directory_uri_length = strlen(scripts_directory_uri);
1699
1700 /* Support for GNOME Nautilus scripts
1701 */
1702 char* nautilus_scripts_path = g_build_filename(g_get_home_dir(), ".gnome2", "nautilus-scripts", NULL);
1703
1704 if (g_file_test(nautilus_scripts_path, G_FILE_TEST_IS_DIR) == TRUE)
1705 {
1706 char* nautilus_syslink = g_build_filename(g_get_user_config_dir(), "caja", "scripts", "nautilus", NULL);
1707 /* If link already exists, or also any other kind of file/dir with same name, ignore it */
1708 if (g_file_test(nautilus_syslink, G_FILE_TEST_IS_SYMLINK) == FALSE &&
1709 g_file_test(nautilus_syslink, G_FILE_TEST_EXISTS) == FALSE &&
1710 g_file_test(nautilus_syslink, G_FILE_TEST_IS_DIR) == FALSE)
1711 {
1712 /* Check if we need to create a link */
1713 GDir* dir = g_dir_open(nautilus_scripts_path, 0, NULL);
1714
1715 if (dir)
1716 {
1717 /* If directory contains files, we can create the link */
1718 int count = 0;
1719
1720 while (g_dir_read_name(dir) != NULL)
1721 {
1722 count++;
1723 }
1724
1725 if (count > 0)
1726 {
1727 /* Create link to nautilus folder */
1728 int res = symlink (nautilus_scripts_path, nautilus_syslink);
1729 if (res != 0)
1730 g_warning ("Can't create symlink to nautilus scripts folder");
1731 }
1732
1733 g_dir_close(dir);
1734 }
1735 }
1736
1737 g_free(nautilus_syslink);
1738 }
1739
1740 g_free(nautilus_scripts_path);
1741 }
1742
1743 g_free(scripts_directory_path);
1744 }
1745
1746 static void
scripts_added_or_changed_callback(CajaDirectory * directory,GList * files,gpointer callback_data)1747 scripts_added_or_changed_callback (CajaDirectory *directory,
1748 GList *files,
1749 gpointer callback_data)
1750 {
1751 FMDirectoryView *view;
1752
1753 view = FM_DIRECTORY_VIEW (callback_data);
1754
1755 view->details->scripts_invalid = TRUE;
1756 if (view->details->active) {
1757 schedule_update_menus (view);
1758 }
1759 }
1760
1761 static void
templates_added_or_changed_callback(CajaDirectory * directory,GList * files,gpointer callback_data)1762 templates_added_or_changed_callback (CajaDirectory *directory,
1763 GList *files,
1764 gpointer callback_data)
1765 {
1766 FMDirectoryView *view;
1767
1768 view = FM_DIRECTORY_VIEW (callback_data);
1769
1770 view->details->templates_invalid = TRUE;
1771 if (view->details->active) {
1772 schedule_update_menus (view);
1773 }
1774 }
1775
1776 static void
add_directory_to_directory_list(FMDirectoryView * view,CajaDirectory * directory,GList ** directory_list,GCallback changed_callback)1777 add_directory_to_directory_list (FMDirectoryView *view,
1778 CajaDirectory *directory,
1779 GList **directory_list,
1780 GCallback changed_callback)
1781 {
1782 CajaFileAttributes attributes;
1783
1784 if (g_list_find (*directory_list, directory) == NULL) {
1785 caja_directory_ref (directory);
1786
1787 attributes =
1788 CAJA_FILE_ATTRIBUTES_FOR_ICON |
1789 CAJA_FILE_ATTRIBUTE_INFO |
1790 CAJA_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT;
1791
1792 caja_directory_file_monitor_add (directory, directory_list,
1793 FALSE, attributes,
1794 (CajaDirectoryCallback)changed_callback, view);
1795
1796 g_signal_connect_object (directory, "files_added",
1797 G_CALLBACK (changed_callback), view, 0);
1798 g_signal_connect_object (directory, "files_changed",
1799 G_CALLBACK (changed_callback), view, 0);
1800
1801 *directory_list = g_list_append (*directory_list, directory);
1802 }
1803 }
1804
1805 static void
remove_directory_from_directory_list(FMDirectoryView * view,CajaDirectory * directory,GList ** directory_list,GCallback changed_callback)1806 remove_directory_from_directory_list (FMDirectoryView *view,
1807 CajaDirectory *directory,
1808 GList **directory_list,
1809 GCallback changed_callback)
1810 {
1811 *directory_list = g_list_remove (*directory_list, directory);
1812
1813 g_signal_handlers_disconnect_by_func (directory,
1814 G_CALLBACK (changed_callback),
1815 view);
1816
1817 caja_directory_file_monitor_remove (directory, directory_list);
1818
1819 caja_directory_unref (directory);
1820 }
1821
1822
1823 static void
add_directory_to_scripts_directory_list(FMDirectoryView * view,CajaDirectory * directory)1824 add_directory_to_scripts_directory_list (FMDirectoryView *view,
1825 CajaDirectory *directory)
1826 {
1827 add_directory_to_directory_list (view, directory,
1828 &view->details->scripts_directory_list,
1829 G_CALLBACK (scripts_added_or_changed_callback));
1830 }
1831
1832 static void
remove_directory_from_scripts_directory_list(FMDirectoryView * view,CajaDirectory * directory)1833 remove_directory_from_scripts_directory_list (FMDirectoryView *view,
1834 CajaDirectory *directory)
1835 {
1836 remove_directory_from_directory_list (view, directory,
1837 &view->details->scripts_directory_list,
1838 G_CALLBACK (scripts_added_or_changed_callback));
1839 }
1840
1841 static void
add_directory_to_templates_directory_list(FMDirectoryView * view,CajaDirectory * directory)1842 add_directory_to_templates_directory_list (FMDirectoryView *view,
1843 CajaDirectory *directory)
1844 {
1845 add_directory_to_directory_list (view, directory,
1846 &view->details->templates_directory_list,
1847 G_CALLBACK (templates_added_or_changed_callback));
1848 }
1849
1850 static void
remove_directory_from_templates_directory_list(FMDirectoryView * view,CajaDirectory * directory)1851 remove_directory_from_templates_directory_list (FMDirectoryView *view,
1852 CajaDirectory *directory)
1853 {
1854 remove_directory_from_directory_list (view, directory,
1855 &view->details->templates_directory_list,
1856 G_CALLBACK (templates_added_or_changed_callback));
1857 }
1858
1859 static void
slot_active(CajaWindowSlot * slot,FMDirectoryView * view)1860 slot_active (CajaWindowSlot *slot,
1861 FMDirectoryView *view)
1862 {
1863 g_assert (!view->details->active);
1864 view->details->active = TRUE;
1865
1866 fm_directory_view_merge_menus (view);
1867 schedule_update_menus (view);
1868 }
1869
1870 static void
slot_inactive(CajaWindowSlot * slot,FMDirectoryView * view)1871 slot_inactive (CajaWindowSlot *slot,
1872 FMDirectoryView *view)
1873 {
1874 g_assert (view->details->active ||
1875 gtk_widget_get_parent (GTK_WIDGET (view)) == NULL);
1876 view->details->active = FALSE;
1877
1878 fm_directory_view_unmerge_menus (view);
1879 remove_update_menus_timeout_callback (view);
1880 }
1881
1882 static void
fm_directory_view_grab_focus(CajaView * view)1883 fm_directory_view_grab_focus (CajaView *view)
1884 {
1885 /* focus the child of the scrolled window if it exists */
1886 GtkWidget *child;
1887 child = gtk_bin_get_child (GTK_BIN (view));
1888 if (child) {
1889 gtk_widget_grab_focus (GTK_WIDGET (child));
1890 }
1891 }
1892
1893 static void
view_iface_update_menus(CajaView * view)1894 view_iface_update_menus (CajaView *view)
1895 {
1896 fm_directory_view_update_menus (FM_DIRECTORY_VIEW (view));
1897 }
1898
1899 static GtkWidget *
fm_directory_view_get_widget(CajaView * view)1900 fm_directory_view_get_widget (CajaView *view)
1901 {
1902 return GTK_WIDGET (view);
1903 }
1904
1905 static int
fm_directory_view_get_selection_count(CajaView * view)1906 fm_directory_view_get_selection_count (CajaView *view)
1907 {
1908 /* FIXME: This could be faster if we special cased it in subclasses */
1909 GList *files;
1910 int len;
1911
1912 files = fm_directory_view_get_selection (FM_DIRECTORY_VIEW (view));
1913 len = g_list_length (files);
1914 caja_file_list_free (files);
1915
1916 return len;
1917 }
1918
1919 static GList *
fm_directory_view_get_selection_locations(CajaView * view)1920 fm_directory_view_get_selection_locations (CajaView *view)
1921 {
1922 GList *files;
1923 GList *locations;
1924 GList *l;
1925 GFile *location = NULL;
1926
1927 files = fm_directory_view_get_selection (FM_DIRECTORY_VIEW (view));
1928 locations = NULL;
1929 for (l = files; l != NULL; l = l->next) {
1930 location = caja_file_get_location (CAJA_FILE (l->data));
1931 locations = g_list_prepend (locations, location);
1932 }
1933 caja_file_list_free (files);
1934
1935 return g_list_reverse (locations);
1936 }
1937
1938 static GList *
file_list_from_location_list(const GList * uri_list)1939 file_list_from_location_list (const GList *uri_list)
1940 {
1941 GList *file_list;
1942 const GList *node;
1943
1944 file_list = NULL;
1945 for (node = uri_list; node != NULL; node = node->next) {
1946 file_list = g_list_prepend
1947 (file_list,
1948 caja_file_get (node->data));
1949 }
1950 return g_list_reverse (file_list);
1951 }
1952
1953 static void
fm_directory_view_set_selection_locations(CajaView * caja_view,GList * selection_locations)1954 fm_directory_view_set_selection_locations (CajaView *caja_view,
1955 GList *selection_locations)
1956 {
1957 FMDirectoryView *view;
1958
1959 view = FM_DIRECTORY_VIEW (caja_view);
1960
1961 if (!view->details->loading) {
1962 GList *selection;
1963
1964 /* If we aren't still loading, set the selection right now,
1965 * and reveal the new selection.
1966 */
1967 selection = file_list_from_location_list (selection_locations);
1968 view->details->selection_change_is_due_to_shell = TRUE;
1969 fm_directory_view_set_selection (view, selection);
1970 view->details->selection_change_is_due_to_shell = FALSE;
1971 fm_directory_view_reveal_selection (view);
1972 caja_file_list_free (selection);
1973 } else {
1974 /* If we are still loading, set the list of pending URIs instead.
1975 * done_loading() will eventually select the pending URIs and reveal them.
1976 */
1977 g_list_free_full (view->details->pending_locations_selected, g_object_unref);
1978 view->details->pending_locations_selected =
1979 g_list_copy_deep (selection_locations, (GCopyFunc) g_object_ref, NULL);
1980 }
1981 }
1982
1983
1984 void
fm_directory_view_init_view_iface(CajaViewIface * iface)1985 fm_directory_view_init_view_iface (CajaViewIface *iface)
1986 {
1987 iface->grab_focus = fm_directory_view_grab_focus;
1988 iface->update_menus = view_iface_update_menus;
1989
1990 iface->get_widget = fm_directory_view_get_widget;
1991 iface->load_location = fm_directory_view_load_location;
1992 iface->stop_loading = fm_directory_view_stop_loading;
1993
1994 iface->get_selection_count = fm_directory_view_get_selection_count;
1995 iface->get_selection = fm_directory_view_get_selection_locations;
1996 iface->set_selection = fm_directory_view_set_selection_locations;
1997 iface->set_is_active = (gpointer)fm_directory_view_set_is_active;
1998
1999 iface->supports_zooming = (gpointer)fm_directory_view_supports_zooming;
2000 iface->bump_zoom_level = (gpointer)fm_directory_view_bump_zoom_level;
2001 iface->zoom_to_level = (gpointer)fm_directory_view_zoom_to_level;
2002 iface->restore_default_zoom_level = (gpointer)fm_directory_view_restore_default_zoom_level;
2003 iface->can_zoom_in = (gpointer)fm_directory_view_can_zoom_in;
2004 iface->can_zoom_out = (gpointer)fm_directory_view_can_zoom_out;
2005 iface->get_zoom_level = (gpointer)fm_directory_view_get_zoom_level;
2006
2007 iface->pop_up_location_context_menu = (gpointer)fm_directory_view_pop_up_location_context_menu;
2008 iface->drop_proxy_received_uris = (gpointer)fm_directory_view_drop_proxy_received_uris;
2009 iface->drop_proxy_received_netscape_url = (gpointer)fm_directory_view_drop_proxy_received_netscape_url;
2010 }
2011
2012 static void
fm_directory_view_init(FMDirectoryView * view)2013 fm_directory_view_init (FMDirectoryView *view)
2014 {
2015 CajaDirectory *scripts_directory;
2016
2017 view->details = g_new0 (FMDirectoryViewDetails, 1);
2018
2019 /* Default to true; desktop-icon-view sets to false */
2020 view->details->show_foreign_files = TRUE;
2021
2022 view->details->non_ready_files =
2023 g_hash_table_new_full (file_and_directory_hash,
2024 file_and_directory_equal,
2025 (GDestroyNotify)file_and_directory_free,
2026 NULL);
2027
2028 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (view),
2029 GTK_POLICY_AUTOMATIC,
2030 GTK_POLICY_AUTOMATIC);
2031 gtk_scrolled_window_set_hadjustment (GTK_SCROLLED_WINDOW (view), NULL);
2032 gtk_scrolled_window_set_vadjustment (GTK_SCROLLED_WINDOW (view), NULL);
2033 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (view), GTK_SHADOW_ETCHED_IN);
2034 gtk_scrolled_window_set_overlay_scrolling (GTK_SCROLLED_WINDOW (view), FALSE);
2035
2036 set_up_scripts_directory_global ();
2037 scripts_directory = caja_directory_get_by_uri (scripts_directory_uri);
2038 add_directory_to_scripts_directory_list (view, scripts_directory);
2039 caja_directory_unref (scripts_directory);
2040
2041 if (caja_should_use_templates_directory ()) {
2042 CajaDirectory *templates_directory;
2043 char *templates_uri;
2044
2045 templates_uri = caja_get_templates_directory_uri ();
2046 templates_directory = caja_directory_get_by_uri (templates_uri);
2047 g_free (templates_uri);
2048 add_directory_to_templates_directory_list (view, templates_directory);
2049 caja_directory_unref (templates_directory);
2050 }
2051 update_templates_directory (view);
2052 g_signal_connect_object (caja_signaller_get_current (),
2053 "user_dirs_changed",
2054 G_CALLBACK (user_dirs_changed),
2055 view, G_CONNECT_SWAPPED);
2056
2057 view->details->sort_directories_first =
2058 g_settings_get_boolean (caja_preferences, CAJA_PREFERENCES_SORT_DIRECTORIES_FIRST);
2059
2060 g_signal_connect_object (caja_trash_monitor_get (), "trash_state_changed",
2061 G_CALLBACK (fm_directory_view_trash_state_changed_callback), view, 0);
2062
2063 /* React to clipboard changes */
2064 g_signal_connect_object (caja_clipboard_monitor_get (), "clipboard_changed",
2065 G_CALLBACK (clipboard_changed_callback), view, 0);
2066
2067 /* Register to menu provider extension signal managing menu updates */
2068 g_signal_connect_object (caja_signaller_get_current (), "popup_menu_changed",
2069 G_CALLBACK (fm_directory_view_update_menus), view, G_CONNECT_SWAPPED);
2070
2071 gtk_widget_show (GTK_WIDGET (view));
2072
2073 g_signal_connect_swapped (caja_preferences,
2074 "changed::" CAJA_PREFERENCES_ENABLE_DELETE,
2075 G_CALLBACK (schedule_update_menus_callback), view);
2076 g_signal_connect_swapped (caja_icon_view_preferences,
2077 "changed::" CAJA_PREFERENCES_ICON_VIEW_CAPTIONS,
2078 G_CALLBACK(text_attribute_names_changed_callback),
2079 view);
2080 g_signal_connect_swapped (caja_preferences,
2081 "changed::" CAJA_PREFERENCES_SHOW_IMAGE_FILE_THUMBNAILS,
2082 G_CALLBACK (image_display_policy_changed_callback),
2083 view);
2084 g_signal_connect_swapped (caja_preferences,
2085 "changed::" CAJA_PREFERENCES_CLICK_POLICY,
2086 G_CALLBACK(click_policy_changed_callback),
2087 view);
2088 g_signal_connect_swapped (caja_preferences,
2089 "changed::" CAJA_PREFERENCES_SORT_DIRECTORIES_FIRST,
2090 G_CALLBACK(sort_directories_first_changed_callback),
2091 view);
2092 g_signal_connect_swapped (mate_lockdown_preferences,
2093 "changed::" CAJA_PREFERENCES_LOCKDOWN_COMMAND_LINE,
2094 G_CALLBACK (schedule_update_menus), view);
2095
2096 /* Update undo actions stuff and connect signals from the undostack manager */
2097 view->details->undo_active = FALSE;
2098 view->details->redo_active = FALSE;
2099 view->details->undo_action_description = NULL;
2100 view->details->undo_action_label = NULL;
2101 view->details->redo_action_description = NULL;
2102 view->details->redo_action_label = NULL;
2103
2104 CajaUndoStackManager* manager = caja_undostack_manager_instance ();
2105
2106 g_signal_connect_object (G_OBJECT(manager), "request-menu-update",
2107 G_CALLBACK(undo_redo_menu_update_callback), view, 0);
2108
2109 caja_undostack_manager_request_menu_update (caja_undostack_manager_instance());
2110 }
2111
2112 static void
real_unmerge_menus(FMDirectoryView * view)2113 real_unmerge_menus (FMDirectoryView *view)
2114 {
2115 GtkUIManager *ui_manager;
2116
2117 if (view->details->window == NULL) {
2118 return;
2119 }
2120
2121 ui_manager = caja_window_info_get_ui_manager (view->details->window);
2122
2123 caja_ui_unmerge_ui (ui_manager,
2124 &view->details->dir_merge_id,
2125 &view->details->dir_action_group);
2126 caja_ui_unmerge_ui (ui_manager,
2127 &view->details->extensions_menu_merge_id,
2128 &view->details->extensions_menu_action_group);
2129 caja_ui_unmerge_ui (ui_manager,
2130 &view->details->open_with_merge_id,
2131 &view->details->open_with_action_group);
2132 caja_ui_unmerge_ui (ui_manager,
2133 &view->details->scripts_merge_id,
2134 &view->details->scripts_action_group);
2135 caja_ui_unmerge_ui (ui_manager,
2136 &view->details->templates_merge_id,
2137 &view->details->templates_action_group);
2138 }
2139
2140 static void
fm_directory_view_destroy(GtkWidget * object)2141 fm_directory_view_destroy (GtkWidget *object)
2142 {
2143 FMDirectoryView *view;
2144 GList *node, *next;
2145
2146 view = FM_DIRECTORY_VIEW (object);
2147
2148 disconnect_model_handlers (view);
2149
2150 fm_directory_view_unmerge_menus (view);
2151
2152 /* We don't own the window, so no unref */
2153 view->details->slot = NULL;
2154 view->details->window = NULL;
2155
2156 fm_directory_view_stop (view);
2157 fm_directory_view_clear (view);
2158
2159 for (node = view->details->scripts_directory_list; node != NULL; node = next) {
2160 next = node->next;
2161 remove_directory_from_scripts_directory_list (view, node->data);
2162 }
2163
2164 for (node = view->details->templates_directory_list; node != NULL; node = next) {
2165 next = node->next;
2166 remove_directory_from_templates_directory_list (view, node->data);
2167 }
2168
2169 while (view->details->subdirectory_list != NULL) {
2170 fm_directory_view_remove_subdirectory (view,
2171 view->details->subdirectory_list->data);
2172 }
2173
2174 remove_update_menus_timeout_callback (view);
2175 remove_update_status_idle_callback (view);
2176
2177 if (view->details->display_selection_idle_id != 0) {
2178 g_source_remove (view->details->display_selection_idle_id);
2179 view->details->display_selection_idle_id = 0;
2180 }
2181
2182 if (view->details->reveal_selection_idle_id != 0) {
2183 g_source_remove (view->details->reveal_selection_idle_id);
2184 view->details->reveal_selection_idle_id = 0;
2185 }
2186
2187 if (view->details->delayed_rename_file_id != 0) {
2188 g_source_remove (view->details->delayed_rename_file_id);
2189 view->details->delayed_rename_file_id = 0;
2190 }
2191
2192 if (view->details->model) {
2193 caja_directory_unref (view->details->model);
2194 view->details->model = NULL;
2195 }
2196
2197 if (view->details->directory_as_file) {
2198 caja_file_unref (view->details->directory_as_file);
2199 view->details->directory_as_file = NULL;
2200 }
2201
2202 EEL_CALL_PARENT (GTK_WIDGET_CLASS, destroy, (object));
2203 }
2204
2205 static void
fm_directory_view_finalize(GObject * object)2206 fm_directory_view_finalize (GObject *object)
2207 {
2208 FMDirectoryView *view;
2209
2210 view = FM_DIRECTORY_VIEW (object);
2211
2212 g_signal_handlers_disconnect_by_func (caja_preferences,
2213 schedule_update_menus_callback, view);
2214 g_signal_handlers_disconnect_by_func (caja_icon_view_preferences,
2215 text_attribute_names_changed_callback, view);
2216 g_signal_handlers_disconnect_by_func (caja_preferences,
2217 image_display_policy_changed_callback, view);
2218 g_signal_handlers_disconnect_by_func (caja_preferences,
2219 click_policy_changed_callback, view);
2220 g_signal_handlers_disconnect_by_func (caja_preferences,
2221 sort_directories_first_changed_callback, view);
2222 g_signal_handlers_disconnect_by_func (mate_lockdown_preferences,
2223 schedule_update_menus, view);
2224
2225 unschedule_pop_up_location_context_menu (view);
2226 if (view->details->location_popup_event != NULL) {
2227 gdk_event_free ((GdkEvent *) view->details->location_popup_event);
2228 }
2229
2230 g_hash_table_destroy (view->details->non_ready_files);
2231
2232 g_free (view->details);
2233
2234 EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
2235 }
2236
2237 /**
2238 * fm_directory_view_display_selection_info:
2239 *
2240 * Display information about the current selection, and notify the view frame of the changed selection.
2241 * @view: FMDirectoryView for which to display selection info.
2242 *
2243 **/
2244 void
fm_directory_view_display_selection_info(FMDirectoryView * view)2245 fm_directory_view_display_selection_info (FMDirectoryView *view)
2246 {
2247 GList *selection;
2248 goffset non_folder_size;
2249 gboolean non_folder_size_known;
2250 guint non_folder_count, folder_count, folder_item_count;
2251 gboolean folder_item_count_known;
2252 guint file_item_count;
2253 GList *p;
2254 char *first_item_name;
2255 char *non_folder_str;
2256 char *folder_count_str;
2257 char *folder_item_count_str;
2258 char *status_string;
2259 char *free_space_str;
2260 char *obj_selected_free_space_str;
2261 CajaFile *file = NULL;
2262
2263 g_return_if_fail (FM_IS_DIRECTORY_VIEW (view));
2264
2265 selection = fm_directory_view_get_selection (view);
2266
2267 folder_item_count_known = TRUE;
2268 folder_count = 0;
2269 folder_item_count = 0;
2270 non_folder_count = 0;
2271 non_folder_size_known = FALSE;
2272 non_folder_size = 0;
2273 first_item_name = NULL;
2274 folder_count_str = NULL;
2275 non_folder_str = NULL;
2276 folder_item_count_str = NULL;
2277 free_space_str = NULL;
2278 obj_selected_free_space_str = NULL;
2279
2280 for (p = selection; p != NULL; p = p->next) {
2281 file = p->data;
2282 if (caja_file_is_directory (file)) {
2283 folder_count++;
2284 if (caja_file_get_directory_item_count (file, &file_item_count, NULL)) {
2285 folder_item_count += file_item_count;
2286 } else {
2287 folder_item_count_known = FALSE;
2288 }
2289 } else {
2290 non_folder_count++;
2291 if (!caja_file_can_get_size (file)) {
2292 non_folder_size_known = TRUE;
2293 non_folder_size += caja_file_get_size (file);
2294 }
2295 }
2296
2297 if (first_item_name == NULL) {
2298 first_item_name = caja_file_get_display_name (file);
2299 }
2300 }
2301
2302 caja_file_list_free (selection);
2303
2304 /* Break out cases for localization's sake. But note that there are still pieces
2305 * being assembled in a particular order, which may be a problem for some localizers.
2306 */
2307
2308 if (folder_count != 0) {
2309 if (folder_count == 1 && non_folder_count == 0) {
2310 folder_count_str = g_strdup_printf (_("\"%s\" selected"), first_item_name);
2311 } else {
2312 folder_count_str = g_strdup_printf (ngettext("%'d folder selected",
2313 "%'d folders selected",
2314 folder_count),
2315 folder_count);
2316 }
2317
2318 if (folder_count == 1) {
2319 if (!folder_item_count_known) {
2320 folder_item_count_str = g_strdup ("");
2321 } else {
2322 folder_item_count_str = g_strdup_printf (ngettext(" (containing %'d item)",
2323 " (containing %'d items)",
2324 folder_item_count),
2325 folder_item_count);
2326 }
2327 }
2328 else {
2329 if (!folder_item_count_known) {
2330 folder_item_count_str = g_strdup ("");
2331 } else {
2332 /* Translators: this is preceded with a string of form 'N folders' (N more than 1) */
2333 folder_item_count_str = g_strdup_printf (ngettext(" (containing a total of %'d item)",
2334 " (containing a total of %'d items)",
2335 folder_item_count),
2336 folder_item_count);
2337 }
2338
2339 }
2340 }
2341
2342 if (non_folder_count != 0) {
2343 char *items_string;
2344
2345 if (folder_count == 0) {
2346 if (non_folder_count == 1) {
2347 items_string = g_strdup_printf (_("\"%s\" selected"),
2348 first_item_name);
2349 } else {
2350 items_string = g_strdup_printf (ngettext("%'d item selected",
2351 "%'d items selected",
2352 non_folder_count),
2353 non_folder_count);
2354 }
2355 } else {
2356 /* Folders selected also, use "other" terminology */
2357 items_string = g_strdup_printf (ngettext("%'d other item selected",
2358 "%'d other items selected",
2359 non_folder_count),
2360 non_folder_count);
2361 }
2362
2363 if (non_folder_size_known) {
2364 char *size_string;
2365
2366 if (g_settings_get_boolean (caja_preferences, CAJA_PREFERENCES_USE_IEC_UNITS))
2367 size_string = g_format_size_full (non_folder_size, G_FORMAT_SIZE_IEC_UNITS);
2368 else
2369 size_string = g_format_size(non_folder_size);
2370
2371 /* Translators: This is marked for translation in case a localiser
2372 * needs to use something other than parentheses. The
2373 * first message gives the number of items selected;
2374 * the message in parentheses the size of those items.
2375 */
2376 non_folder_str = g_strdup_printf (_("%s (%s)"),
2377 items_string,
2378 size_string);
2379
2380 g_free (size_string);
2381 g_free (items_string);
2382 } else {
2383 non_folder_str = items_string;
2384 }
2385 }
2386
2387 free_space_str = caja_file_get_volume_free_space (view->details->directory_as_file);
2388 if (free_space_str != NULL) {
2389 obj_selected_free_space_str = g_strdup_printf (_("Free space: %s"), free_space_str);
2390 }
2391 if (folder_count == 0 && non_folder_count == 0) {
2392 char *item_count_str;
2393 guint item_count;
2394
2395 item_count = fm_directory_view_get_item_count (view);
2396
2397 item_count_str = g_strdup_printf (ngettext ("%'u item", "%'u items", item_count), item_count);
2398
2399 if (free_space_str != NULL) {
2400 status_string = g_strdup_printf (_("%s, Free space: %s"), item_count_str, free_space_str);
2401 g_free (item_count_str);
2402 } else {
2403 status_string = item_count_str;
2404 }
2405
2406 } else if (folder_count == 0) {
2407 if (free_space_str == NULL) {
2408 status_string = g_strdup (non_folder_str);
2409 } else {
2410 /* Marking this for translation, since you
2411 * might want to change "," to something else.
2412 * After the comma the amount of free space will
2413 * be shown.
2414 */
2415 status_string = g_strdup_printf (_("%s, %s"),
2416 non_folder_str,
2417 obj_selected_free_space_str);
2418 }
2419 } else if (non_folder_count == 0) {
2420 if (free_space_str == NULL) {
2421 /* No use marking this for translation, since you
2422 * can't reorder the strings, which is the main thing
2423 * you'd want to do.
2424 */
2425 status_string = g_strdup_printf ("%s%s",
2426 folder_count_str,
2427 folder_item_count_str);
2428 } else {
2429 /* Marking this for translation, since you
2430 * might want to change "," to something else.
2431 * After the comma the amount of free space will
2432 * be shown.
2433 */
2434 status_string = g_strdup_printf (_("%s%s, %s"),
2435 folder_count_str,
2436 folder_item_count_str,
2437 obj_selected_free_space_str);
2438 }
2439 } else {
2440 if (obj_selected_free_space_str == NULL) {
2441 /* This is marked for translation in case a localizer
2442 * needs to change ", " to something else. The comma
2443 * is between the message about the number of folders
2444 * and the number of items in those folders and the
2445 * message about the number of other items and the
2446 * total size of those items.
2447 */
2448 status_string = g_strdup_printf (_("%s%s, %s"),
2449 folder_count_str,
2450 folder_item_count_str,
2451 non_folder_str);
2452 } else {
2453 /* This is marked for translation in case a localizer
2454 * needs to change ", " to something else. The first comma
2455 * is between the message about the number of folders
2456 * and the number of items in those folders and the
2457 * message about the number of other items and the
2458 * total size of those items. After the second comma
2459 * the free space is written.
2460 */
2461 status_string = g_strdup_printf (_("%s%s, %s, %s"),
2462 folder_count_str,
2463 folder_item_count_str,
2464 non_folder_str,
2465 obj_selected_free_space_str);
2466 }
2467 }
2468
2469 g_free (free_space_str);
2470 g_free (obj_selected_free_space_str);
2471 g_free (first_item_name);
2472 g_free (folder_count_str);
2473 g_free (folder_item_count_str);
2474 g_free (non_folder_str);
2475
2476 caja_window_slot_info_set_status (view->details->slot,
2477 status_string);
2478 g_free (status_string);
2479 }
2480
2481 void
fm_directory_view_send_selection_change(FMDirectoryView * view)2482 fm_directory_view_send_selection_change (FMDirectoryView *view)
2483 {
2484 caja_window_info_report_selection_changed (view->details->window);
2485
2486 view->details->send_selection_change_to_shell = FALSE;
2487 }
2488
2489 gboolean
fm_directory_view_get_allow_moves(FMDirectoryView * view)2490 fm_directory_view_get_allow_moves (FMDirectoryView *view)
2491 {
2492 return view->details->allow_moves;
2493 }
2494
2495 static void
fm_directory_view_load_location(CajaView * caja_view,const char * location)2496 fm_directory_view_load_location (CajaView *caja_view,
2497 const char *location)
2498 {
2499 CajaDirectory *directory;
2500 FMDirectoryView *directory_view;
2501
2502 directory_view = FM_DIRECTORY_VIEW (caja_view);
2503
2504 if (eel_uri_is_search (location)) {
2505 directory_view->details->allow_moves = FALSE;
2506 } else {
2507 directory_view->details->allow_moves = TRUE;
2508 }
2509
2510 directory = caja_directory_get_by_uri (location);
2511 load_directory (directory_view, directory);
2512 caja_directory_unref (directory);
2513 }
2514
2515 static void
fm_directory_view_stop_loading(CajaView * caja_view)2516 fm_directory_view_stop_loading (CajaView *caja_view)
2517 {
2518 fm_directory_view_stop (FM_DIRECTORY_VIEW (caja_view));
2519 }
2520
2521 static gboolean
reveal_selection_idle_callback(gpointer data)2522 reveal_selection_idle_callback (gpointer data)
2523 {
2524 FMDirectoryView *view;
2525
2526 view = FM_DIRECTORY_VIEW (data);
2527
2528 view->details->reveal_selection_idle_id = 0;
2529 fm_directory_view_reveal_selection (view);
2530
2531 return FALSE;
2532 }
2533
2534 static void
done_loading(FMDirectoryView * view,gboolean all_files_seen)2535 done_loading (FMDirectoryView *view,
2536 gboolean all_files_seen)
2537 {
2538 if (!view->details->loading) {
2539 return;
2540 }
2541
2542 /* This can be called during destruction, in which case there
2543 * is no CajaWindowInfo any more.
2544 */
2545 if (view->details->window != NULL) {
2546 GList *locations_selected;
2547
2548 if (all_files_seen) {
2549 caja_window_info_report_load_complete (view->details->window, CAJA_VIEW (view));
2550 }
2551
2552 schedule_update_menus (view);
2553 schedule_update_status (view);
2554 reset_update_interval (view);
2555
2556 locations_selected = view->details->pending_locations_selected;
2557
2558 if (locations_selected != NULL && all_files_seen) {
2559 GList *selection;
2560
2561 view->details->pending_locations_selected = NULL;
2562
2563 selection = file_list_from_location_list (locations_selected);
2564
2565 view->details->selection_change_is_due_to_shell = TRUE;
2566 fm_directory_view_set_selection (view, selection);
2567 view->details->selection_change_is_due_to_shell = FALSE;
2568 caja_file_list_free (selection);
2569
2570 if (FM_IS_LIST_VIEW (view)) {
2571 /* HACK: We should be able to directly call reveal_selection here,
2572 * but at this point the GtkTreeView hasn't allocated the new nodes
2573 * yet, and it has a bug in the scroll calculation dealing with this
2574 * special case. It would always make the selection the top row, even
2575 * if no scrolling would be neccessary to reveal it. So we let it
2576 * allocate before revealing.
2577 */
2578 if (view->details->reveal_selection_idle_id != 0) {
2579 g_source_remove (view->details->reveal_selection_idle_id);
2580 }
2581 view->details->reveal_selection_idle_id =
2582 g_idle_add (reveal_selection_idle_callback, view);
2583 } else {
2584 fm_directory_view_reveal_selection (view);
2585 }
2586 }
2587 g_list_free_full (locations_selected, g_object_unref);
2588 fm_directory_view_display_selection_info (view);
2589 }
2590
2591 fm_directory_view_end_loading (view, all_files_seen);
2592
2593 view->details->loading = FALSE;
2594 }
2595
2596
2597 typedef struct {
2598 GHashTable *debuting_files;
2599 GList *added_files;
2600 } DebutingFilesData;
2601
2602 static void
debuting_files_data_free(DebutingFilesData * data)2603 debuting_files_data_free (DebutingFilesData *data)
2604 {
2605 g_hash_table_unref (data->debuting_files);
2606 caja_file_list_free (data->added_files);
2607 g_free (data);
2608 }
2609
2610 /* This signal handler watch for the arrival of the icons created
2611 * as the result of a file operation. Once the last one is detected
2612 * it selects and reveals them all.
2613 */
2614 static void
debuting_files_add_file_callback(FMDirectoryView * view,CajaFile * new_file,CajaDirectory * directory,DebutingFilesData * data)2615 debuting_files_add_file_callback (FMDirectoryView *view,
2616 CajaFile *new_file,
2617 CajaDirectory *directory,
2618 DebutingFilesData *data)
2619 {
2620 GFile *location;
2621
2622 location = caja_file_get_location (new_file);
2623
2624 if (g_hash_table_remove (data->debuting_files, location)) {
2625 caja_file_ref (new_file);
2626 data->added_files = g_list_prepend (data->added_files, new_file);
2627
2628 if (g_hash_table_size (data->debuting_files) == 0) {
2629 fm_directory_view_set_selection (view, data->added_files);
2630 fm_directory_view_reveal_selection (view);
2631 g_signal_handlers_disconnect_by_func (view,
2632 G_CALLBACK (debuting_files_add_file_callback),
2633 data);
2634 }
2635 }
2636
2637 g_object_unref (location);
2638 }
2639
2640 typedef struct {
2641 GList *added_files;
2642 FMDirectoryView *directory_view;
2643 } CopyMoveDoneData;
2644
2645 static void
copy_move_done_data_free(CopyMoveDoneData * data)2646 copy_move_done_data_free (CopyMoveDoneData *data)
2647 {
2648 g_assert (data != NULL);
2649
2650 eel_remove_weak_pointer (&data->directory_view);
2651 caja_file_list_free (data->added_files);
2652 g_free (data);
2653 }
2654
2655 static void
pre_copy_move_add_file_callback(FMDirectoryView * view,CajaFile * new_file,CajaDirectory * directory,CopyMoveDoneData * data)2656 pre_copy_move_add_file_callback (FMDirectoryView *view,
2657 CajaFile *new_file,
2658 CajaDirectory *directory,
2659 CopyMoveDoneData *data)
2660 {
2661 caja_file_ref (new_file);
2662 data->added_files = g_list_prepend (data->added_files, new_file);
2663 }
2664
2665 /* This needs to be called prior to caja_file_operations_copy_move.
2666 * It hooks up a signal handler to catch any icons that get added before
2667 * the copy_done_callback is invoked. The return value should be passed
2668 * as the data for uri_copy_move_done_callback.
2669 */
2670 static CopyMoveDoneData *
pre_copy_move(FMDirectoryView * directory_view)2671 pre_copy_move (FMDirectoryView *directory_view)
2672 {
2673 CopyMoveDoneData *copy_move_done_data;
2674
2675 copy_move_done_data = g_new0 (CopyMoveDoneData, 1);
2676 copy_move_done_data->directory_view = directory_view;
2677
2678 eel_add_weak_pointer (©_move_done_data->directory_view);
2679
2680 /* We need to run after the default handler adds the folder we want to
2681 * operate on. The ADD_FILE signal is registered as G_SIGNAL_RUN_LAST, so we
2682 * must use connect_after.
2683 */
2684 g_signal_connect (directory_view, "add_file",
2685 G_CALLBACK (pre_copy_move_add_file_callback), copy_move_done_data);
2686
2687 return copy_move_done_data;
2688 }
2689
2690 /* This function is used to pull out any debuting uris that were added
2691 * and (as a side effect) remove them from the debuting uri hash table.
2692 */
2693 static gboolean
copy_move_done_partition_func(gpointer data,gpointer callback_data)2694 copy_move_done_partition_func (gpointer data, gpointer callback_data)
2695 {
2696 GFile *location;
2697 gboolean result;
2698
2699 location = caja_file_get_location (CAJA_FILE (data));
2700 result = g_hash_table_remove ((GHashTable *) callback_data, location);
2701 g_object_unref (location);
2702
2703 return result;
2704 }
2705
2706 static gboolean
remove_not_really_moved_files(gpointer key,gpointer value,gpointer callback_data)2707 remove_not_really_moved_files (gpointer key,
2708 gpointer value,
2709 gpointer callback_data)
2710 {
2711 GList **added_files;
2712 GFile *loc;
2713
2714 loc = key;
2715
2716 if (GPOINTER_TO_INT (value)) {
2717 return FALSE;
2718 }
2719
2720 added_files = callback_data;
2721 *added_files = g_list_prepend (*added_files,
2722 caja_file_get (loc));
2723 return TRUE;
2724 }
2725
2726
2727 /* When this function is invoked, the file operation is over, but all
2728 * the icons may not have been added to the directory view yet, so
2729 * we can't select them yet.
2730 *
2731 * We're passed a hash table of the uri's to look out for, we hook
2732 * up a signal handler to await their arrival.
2733 */
2734 static void
copy_move_done_callback(GHashTable * debuting_files,gpointer data)2735 copy_move_done_callback (GHashTable *debuting_files, gpointer data)
2736 {
2737 FMDirectoryView *directory_view;
2738 CopyMoveDoneData *copy_move_done_data;
2739 DebutingFilesData *debuting_files_data;
2740
2741 copy_move_done_data = (CopyMoveDoneData *) data;
2742 directory_view = copy_move_done_data->directory_view;
2743
2744 if (directory_view != NULL) {
2745 g_assert (FM_IS_DIRECTORY_VIEW (directory_view));
2746
2747 debuting_files_data = g_new (DebutingFilesData, 1);
2748 debuting_files_data->debuting_files = g_hash_table_ref (debuting_files);
2749 debuting_files_data->added_files = eel_g_list_partition
2750 (copy_move_done_data->added_files,
2751 copy_move_done_partition_func,
2752 debuting_files,
2753 ©_move_done_data->added_files);
2754
2755 /* We're passed the same data used by pre_copy_move_add_file_callback, so disconnecting
2756 * it will free data. We've already siphoned off the added_files we need, and stashed the
2757 * directory_view pointer.
2758 */
2759 g_signal_handlers_disconnect_by_func (directory_view,
2760 G_CALLBACK (pre_copy_move_add_file_callback),
2761 data);
2762
2763 /* Any items in the debuting_files hash table that have
2764 * "FALSE" as their value aren't really being copied
2765 * or moved, so we can't wait for an add_file signal
2766 * to come in for those.
2767 */
2768 g_hash_table_foreach_remove (debuting_files,
2769 remove_not_really_moved_files,
2770 &debuting_files_data->added_files);
2771
2772 if (g_hash_table_size (debuting_files) == 0) {
2773 /* on the off-chance that all the icons have already been added */
2774 if (debuting_files_data->added_files != NULL) {
2775 fm_directory_view_set_selection (directory_view,
2776 debuting_files_data->added_files);
2777 fm_directory_view_reveal_selection (directory_view);
2778 }
2779 debuting_files_data_free (debuting_files_data);
2780 } else {
2781 /* We need to run after the default handler adds the folder we want to
2782 * operate on. The ADD_FILE signal is registered as G_SIGNAL_RUN_LAST, so we
2783 * must use connect_after.
2784 */
2785 g_signal_connect_data (directory_view,
2786 "add_file",
2787 G_CALLBACK (debuting_files_add_file_callback),
2788 debuting_files_data,
2789 (GClosureNotify) debuting_files_data_free,
2790 G_CONNECT_AFTER);
2791 }
2792
2793 /* Schedule menu update for undo items */
2794 schedule_update_menus (directory_view);
2795
2796 }
2797
2798 copy_move_done_data_free (copy_move_done_data);
2799 }
2800
2801 static gboolean
real_file_still_belongs(FMDirectoryView * view,CajaFile * file,CajaDirectory * directory)2802 real_file_still_belongs (FMDirectoryView *view, CajaFile *file, CajaDirectory *directory)
2803 {
2804 if (view->details->model != directory &&
2805 g_list_find (view->details->subdirectory_list, directory) == NULL) {
2806 return FALSE;
2807 }
2808
2809 return caja_directory_contains_file (directory, file);
2810 }
2811
2812 static gboolean
still_should_show_file(FMDirectoryView * view,CajaFile * file,CajaDirectory * directory)2813 still_should_show_file (FMDirectoryView *view, CajaFile *file, CajaDirectory *directory)
2814 {
2815 return fm_directory_view_should_show_file (view, file)
2816 && EEL_INVOKE_METHOD (FM_DIRECTORY_VIEW_CLASS, view, file_still_belongs, (view, file, directory));
2817 }
2818
2819 static gboolean
ready_to_load(CajaFile * file)2820 ready_to_load (CajaFile *file)
2821 {
2822 return caja_file_check_if_ready (file,
2823 CAJA_FILE_ATTRIBUTES_FOR_ICON);
2824 }
2825
2826 static int
compare_files_cover(gconstpointer a,gconstpointer b,gpointer callback_data)2827 compare_files_cover (gconstpointer a, gconstpointer b, gpointer callback_data)
2828 {
2829 const FileAndDirectory *fad1, *fad2;
2830 FMDirectoryView *view;
2831
2832 view = callback_data;
2833 fad1 = a; fad2 = b;
2834
2835 if (fad1->directory < fad2->directory) {
2836 return -1;
2837 } else if (fad1->directory > fad2->directory) {
2838 return 1;
2839 } else {
2840 return EEL_INVOKE_METHOD (FM_DIRECTORY_VIEW_CLASS, view, compare_files,
2841 (view, fad1->file, fad2->file));
2842 }
2843 }
2844 static void
sort_files(FMDirectoryView * view,GList ** list)2845 sort_files (FMDirectoryView *view, GList **list)
2846 {
2847 *list = g_list_sort_with_data (*list, compare_files_cover, view);
2848
2849 }
2850
2851 /* Go through all the new added and changed files.
2852 * Put any that are not ready to load in the non_ready_files hash table.
2853 * Add all the rest to the old_added_files and old_changed_files lists.
2854 * Sort the old_*_files lists if anything was added to them.
2855 */
2856 static void
process_new_files(FMDirectoryView * view)2857 process_new_files (FMDirectoryView *view)
2858 {
2859 GList *new_added_files, *new_changed_files, *old_added_files, *old_changed_files;
2860 GHashTable *non_ready_files;
2861 GList *node, *next;
2862 FileAndDirectory *pending;
2863 gboolean in_non_ready;
2864
2865 new_added_files = view->details->new_added_files;
2866 view->details->new_added_files = NULL;
2867 new_changed_files = view->details->new_changed_files;
2868 view->details->new_changed_files = NULL;
2869
2870 non_ready_files = view->details->non_ready_files;
2871
2872 old_added_files = view->details->old_added_files;
2873 old_changed_files = view->details->old_changed_files;
2874
2875 /* Newly added files go into the old_added_files list if they're
2876 * ready, and into the hash table if they're not.
2877 */
2878 for (node = new_added_files; node != NULL; node = next) {
2879 next = node->next;
2880 pending = (FileAndDirectory *)node->data;
2881 in_non_ready = g_hash_table_lookup (non_ready_files, pending) != NULL;
2882 if (fm_directory_view_should_show_file (view, pending->file)) {
2883 if (ready_to_load (pending->file)) {
2884 if (in_non_ready) {
2885 g_hash_table_remove (non_ready_files, pending);
2886 }
2887 new_added_files = g_list_delete_link (new_added_files, node);
2888 old_added_files = g_list_prepend (old_added_files, pending);
2889 } else {
2890 if (!in_non_ready) {
2891 new_added_files = g_list_delete_link (new_added_files, node);
2892 g_hash_table_insert (non_ready_files, pending, pending);
2893 }
2894 }
2895 }
2896 }
2897 file_and_directory_list_free (new_added_files);
2898
2899 /* Newly changed files go into the old_added_files list if they're ready
2900 * and were seen non-ready in the past, into the old_changed_files list
2901 * if they are read and were not seen non-ready in the past, and into
2902 * the hash table if they're not ready.
2903 */
2904 for (node = new_changed_files; node != NULL; node = next) {
2905 next = node->next;
2906 pending = (FileAndDirectory *)node->data;
2907 if (!still_should_show_file (view, pending->file, pending->directory) || ready_to_load (pending->file)) {
2908 if (g_hash_table_lookup (non_ready_files, pending) != NULL) {
2909 g_hash_table_remove (non_ready_files, pending);
2910 if (still_should_show_file (view, pending->file, pending->directory)) {
2911 new_changed_files = g_list_delete_link (new_changed_files, node);
2912 old_added_files = g_list_prepend (old_added_files, pending);
2913 }
2914 } else if (fm_directory_view_should_show_file (view, pending->file)) {
2915 new_changed_files = g_list_delete_link (new_changed_files, node);
2916 old_changed_files = g_list_prepend (old_changed_files, pending);
2917 }
2918 }
2919 }
2920 file_and_directory_list_free (new_changed_files);
2921
2922 /* If any files were added to old_added_files, then resort it. */
2923 if (old_added_files != view->details->old_added_files) {
2924 view->details->old_added_files = old_added_files;
2925 sort_files (view, &view->details->old_added_files);
2926 }
2927
2928 /* Resort old_changed_files too, since file attributes
2929 * relevant to sorting could have changed.
2930 */
2931 if (old_changed_files != view->details->old_changed_files) {
2932 view->details->old_changed_files = old_changed_files;
2933 sort_files (view, &view->details->old_changed_files);
2934 }
2935
2936 }
2937
2938 static void
process_old_files(FMDirectoryView * view)2939 process_old_files (FMDirectoryView *view)
2940 {
2941 GList *files_added, *files_changed, *node;
2942 GList *selection, *files;
2943 gboolean send_selection_change;
2944
2945 files_added = view->details->old_added_files;
2946 files_changed = view->details->old_changed_files;
2947
2948 send_selection_change = FALSE;
2949
2950 if (files_added != NULL || files_changed != NULL) {
2951 FileAndDirectory *pending = NULL;
2952
2953 g_signal_emit (view, signals[BEGIN_FILE_CHANGES], 0);
2954
2955 for (node = files_added; node != NULL; node = node->next) {
2956 pending = node->data;
2957 g_signal_emit (view,
2958 signals[ADD_FILE], 0, pending->file, pending->directory);
2959 }
2960
2961 for (node = files_changed; node != NULL; node = node->next) {
2962 pending = node->data;
2963 g_signal_emit (view,
2964 signals[still_should_show_file (view, pending->file, pending->directory)
2965 ? FILE_CHANGED : REMOVE_FILE], 0,
2966 pending->file, pending->directory);
2967 }
2968
2969 g_signal_emit (view, signals[END_FILE_CHANGES], 0);
2970
2971 if (files_changed != NULL) {
2972 selection = fm_directory_view_get_selection (view);
2973 files = file_and_directory_list_to_files (files_changed);
2974 send_selection_change = eel_g_lists_sort_and_check_for_intersection
2975 (&files, &selection);
2976 caja_file_list_free (files);
2977 caja_file_list_free (selection);
2978 }
2979
2980 file_and_directory_list_free (view->details->old_added_files);
2981 view->details->old_added_files = NULL;
2982
2983 file_and_directory_list_free (view->details->old_changed_files);
2984 view->details->old_changed_files = NULL;
2985 }
2986
2987 if (send_selection_change) {
2988 /* Send a selection change since some file names could
2989 * have changed.
2990 */
2991 fm_directory_view_send_selection_change (view);
2992 }
2993 }
2994
2995 static void
display_pending_files(FMDirectoryView * view)2996 display_pending_files (FMDirectoryView *view)
2997 {
2998
2999 /* Don't dispatch any updates while the view is frozen. */
3000 if (view->details->updates_frozen) {
3001 return;
3002 }
3003
3004 process_new_files (view);
3005 process_old_files (view);
3006
3007 if (view->details->model != NULL
3008 && caja_directory_are_all_files_seen (view->details->model)
3009 && g_hash_table_size (view->details->non_ready_files) == 0) {
3010 done_loading (view, TRUE);
3011 }
3012 }
3013
3014 void
fm_directory_view_freeze_updates(FMDirectoryView * view)3015 fm_directory_view_freeze_updates (FMDirectoryView *view)
3016 {
3017 view->details->updates_frozen = TRUE;
3018 view->details->updates_queued = 0;
3019 view->details->needs_reload = FALSE;
3020 }
3021
3022 void
fm_directory_view_unfreeze_updates(FMDirectoryView * view)3023 fm_directory_view_unfreeze_updates (FMDirectoryView *view)
3024 {
3025 view->details->updates_frozen = FALSE;
3026
3027 if (view->details->needs_reload) {
3028 view->details->needs_reload = FALSE;
3029 if (view->details->model != NULL) {
3030 load_directory (view, view->details->model);
3031 }
3032 } else {
3033 schedule_idle_display_of_pending_files (view);
3034 }
3035 }
3036
3037 static gboolean
display_selection_info_idle_callback(gpointer data)3038 display_selection_info_idle_callback (gpointer data)
3039 {
3040 FMDirectoryView *view;
3041
3042 view = FM_DIRECTORY_VIEW (data);
3043
3044 g_object_ref (G_OBJECT (view));
3045
3046 view->details->display_selection_idle_id = 0;
3047 fm_directory_view_display_selection_info (view);
3048 if (view->details->send_selection_change_to_shell) {
3049 fm_directory_view_send_selection_change (view);
3050 }
3051
3052 g_object_unref (G_OBJECT (view));
3053
3054 return FALSE;
3055 }
3056
3057 static void
remove_update_menus_timeout_callback(FMDirectoryView * view)3058 remove_update_menus_timeout_callback (FMDirectoryView *view)
3059 {
3060 if (view->details->update_menus_timeout_id != 0) {
3061 g_source_remove (view->details->update_menus_timeout_id);
3062 view->details->update_menus_timeout_id = 0;
3063 }
3064 }
3065
3066 static void
update_menus_if_pending(FMDirectoryView * view)3067 update_menus_if_pending (FMDirectoryView *view)
3068 {
3069 if (!view->details->menu_states_untrustworthy) {
3070 return;
3071 }
3072
3073 remove_update_menus_timeout_callback (view);
3074 fm_directory_view_update_menus (view);
3075 }
3076
3077 static gboolean
update_menus_timeout_callback(gpointer data)3078 update_menus_timeout_callback (gpointer data)
3079 {
3080 FMDirectoryView *view;
3081
3082 view = FM_DIRECTORY_VIEW (data);
3083
3084 g_object_ref (G_OBJECT (view));
3085
3086 view->details->update_menus_timeout_id = 0;
3087 fm_directory_view_update_menus (view);
3088
3089 g_object_unref (G_OBJECT (view));
3090
3091 return FALSE;
3092 }
3093
3094 static gboolean
display_pending_callback(gpointer data)3095 display_pending_callback (gpointer data)
3096 {
3097 FMDirectoryView *view;
3098
3099 view = FM_DIRECTORY_VIEW (data);
3100
3101 g_object_ref (G_OBJECT (view));
3102
3103 view->details->display_pending_source_id = 0;
3104
3105 display_pending_files (view);
3106
3107 g_object_unref (G_OBJECT (view));
3108
3109 return FALSE;
3110 }
3111
3112 static void
schedule_idle_display_of_pending_files(FMDirectoryView * view)3113 schedule_idle_display_of_pending_files (FMDirectoryView *view)
3114 {
3115 /* Get rid of a pending source as it might be a timeout */
3116 unschedule_display_of_pending_files (view);
3117
3118 /* We want higher priority than the idle that handles the relayout
3119 to avoid a resort on each add. But we still want to allow repaints
3120 and other hight prio events while we have pending files to show. */
3121 view->details->display_pending_source_id =
3122 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE - 20,
3123 display_pending_callback, view, NULL);
3124 }
3125
3126 static void
schedule_timeout_display_of_pending_files(FMDirectoryView * view,guint interval)3127 schedule_timeout_display_of_pending_files (FMDirectoryView *view, guint interval)
3128 {
3129 /* No need to schedule an update if there's already one pending. */
3130 if (view->details->display_pending_source_id != 0) {
3131 return;
3132 }
3133
3134 view->details->display_pending_source_id =
3135 g_timeout_add (interval, display_pending_callback, view);
3136 }
3137
3138 static void
unschedule_display_of_pending_files(FMDirectoryView * view)3139 unschedule_display_of_pending_files (FMDirectoryView *view)
3140 {
3141 /* Get rid of source if it's active. */
3142 if (view->details->display_pending_source_id != 0) {
3143 g_source_remove (view->details->display_pending_source_id);
3144 view->details->display_pending_source_id = 0;
3145 }
3146 }
3147
3148 static void
queue_pending_files(FMDirectoryView * view,CajaDirectory * directory,GList * files,GList ** pending_list)3149 queue_pending_files (FMDirectoryView *view,
3150 CajaDirectory *directory,
3151 GList *files,
3152 GList **pending_list)
3153 {
3154 if (files == NULL) {
3155 return;
3156 }
3157
3158 /* Don't queue any more updates if we need to reload anyway */
3159 if (view->details->needs_reload) {
3160 return;
3161 }
3162
3163 if (view->details->updates_frozen) {
3164 view->details->updates_queued += g_list_length (files);
3165 /* Mark the directory for reload when there are too much queued
3166 * changes to prevent the pending list from growing infinitely.
3167 */
3168 if (view->details->updates_queued > MAX_QUEUED_UPDATES) {
3169 view->details->needs_reload = TRUE;
3170 return;
3171 }
3172 }
3173
3174
3175
3176 *pending_list = g_list_concat (file_and_directory_list_from_files (directory, files),
3177 *pending_list);
3178
3179 if (! view->details->loading || caja_directory_are_all_files_seen (directory)) {
3180 schedule_timeout_display_of_pending_files (view, view->details->update_interval);
3181 }
3182 }
3183
3184 static void
remove_changes_timeout_callback(FMDirectoryView * view)3185 remove_changes_timeout_callback (FMDirectoryView *view)
3186 {
3187 if (view->details->changes_timeout_id != 0) {
3188 g_source_remove (view->details->changes_timeout_id);
3189 view->details->changes_timeout_id = 0;
3190 }
3191 }
3192
3193 static void
reset_update_interval(FMDirectoryView * view)3194 reset_update_interval (FMDirectoryView *view)
3195 {
3196 view->details->update_interval = UPDATE_INTERVAL_MIN;
3197 remove_changes_timeout_callback (view);
3198 /* Reschedule a pending timeout to idle */
3199 if (view->details->display_pending_source_id != 0) {
3200 schedule_idle_display_of_pending_files (view);
3201 }
3202 }
3203
3204 static gboolean
changes_timeout_callback(gpointer data)3205 changes_timeout_callback (gpointer data)
3206 {
3207 gint64 now;
3208 gint64 time_delta;
3209 gboolean ret;
3210 FMDirectoryView *view;
3211
3212 view = FM_DIRECTORY_VIEW (data);
3213
3214 g_object_ref (G_OBJECT (view));
3215
3216 now = g_get_monotonic_time();
3217 time_delta = now - view->details->last_queued;
3218
3219 if (time_delta < UPDATE_INTERVAL_RESET*1000) {
3220 if (view->details->update_interval < UPDATE_INTERVAL_MAX &&
3221 view->details->loading) {
3222 /* Increase */
3223 view->details->update_interval += UPDATE_INTERVAL_INC;
3224 }
3225 ret = TRUE;
3226 } else {
3227 /* Reset */
3228 reset_update_interval (view);
3229 ret = FALSE;
3230 }
3231
3232 g_object_unref (G_OBJECT (view));
3233
3234 return ret;
3235 }
3236
3237 static void
schedule_changes(FMDirectoryView * view)3238 schedule_changes (FMDirectoryView *view)
3239 {
3240 /* Remember when the change was queued */
3241 view->details->last_queued = g_get_monotonic_time();
3242
3243 /* No need to schedule if there are already changes pending or during loading */
3244 if (view->details->changes_timeout_id != 0 ||
3245 view->details->loading) {
3246 return;
3247 }
3248
3249 view->details->changes_timeout_id =
3250 g_timeout_add (UPDATE_INTERVAL_TIMEOUT_INTERVAL, changes_timeout_callback, view);
3251 }
3252
3253 static void
action_undo_callback(GtkAction * action,gpointer callback_data)3254 action_undo_callback (GtkAction *action,
3255 gpointer callback_data)
3256 {
3257 real_action_undo (FM_DIRECTORY_VIEW (callback_data));
3258 }
3259
3260 static void
action_redo_callback(GtkAction * action,gpointer callback_data)3261 action_redo_callback (GtkAction *action,
3262 gpointer callback_data)
3263 {
3264 real_action_redo (FM_DIRECTORY_VIEW (callback_data));
3265 }
3266
3267 static void
files_added_callback(CajaDirectory * directory,GList * files,gpointer callback_data)3268 files_added_callback (CajaDirectory *directory,
3269 GList *files,
3270 gpointer callback_data)
3271 {
3272 FMDirectoryView *view;
3273 GtkWindow *window;
3274 char *uri;
3275
3276 view = FM_DIRECTORY_VIEW (callback_data);
3277
3278 window = fm_directory_view_get_containing_window (view);
3279 uri = fm_directory_view_get_uri (view);
3280 caja_debug_log_with_file_list (FALSE, CAJA_DEBUG_LOG_DOMAIN_ASYNC, files,
3281 "files added in window %p: %s",
3282 window,
3283 uri ? uri : "(no directory)");
3284 g_free (uri);
3285
3286 schedule_changes (view);
3287
3288 queue_pending_files (view, directory, files, &view->details->new_added_files);
3289
3290 /* The number of items could have changed */
3291 schedule_update_status (view);
3292 }
3293
3294 static void
files_changed_callback(CajaDirectory * directory,GList * files,gpointer callback_data)3295 files_changed_callback (CajaDirectory *directory,
3296 GList *files,
3297 gpointer callback_data)
3298 {
3299 FMDirectoryView *view;
3300 GtkWindow *window;
3301 char *uri;
3302
3303 view = FM_DIRECTORY_VIEW (callback_data);
3304
3305 window = fm_directory_view_get_containing_window (view);
3306 uri = fm_directory_view_get_uri (view);
3307 caja_debug_log_with_file_list (FALSE, CAJA_DEBUG_LOG_DOMAIN_ASYNC, files,
3308 "files changed in window %p: %s",
3309 window,
3310 uri ? uri : "(no directory)");
3311 g_free (uri);
3312
3313 schedule_changes (view);
3314
3315 queue_pending_files (view, directory, files, &view->details->new_changed_files);
3316
3317 /* The free space or the number of items could have changed */
3318 schedule_update_status (view);
3319
3320 /* A change in MIME type could affect the Open with menu, for
3321 * one thing, so we need to update menus when files change.
3322 */
3323 schedule_update_menus (view);
3324 }
3325
3326 static void
done_loading_callback(CajaDirectory * directory,gpointer callback_data)3327 done_loading_callback (CajaDirectory *directory,
3328 gpointer callback_data)
3329 {
3330 FMDirectoryView *view;
3331
3332 view = FM_DIRECTORY_VIEW (callback_data);
3333
3334 process_new_files (view);
3335 if (g_hash_table_size (view->details->non_ready_files) == 0) {
3336 /* Unschedule a pending update and schedule a new one with the minimal
3337 * update interval. This gives the view a short chance at gathering the
3338 * (cached) deep counts.
3339 */
3340 unschedule_display_of_pending_files (view);
3341 schedule_timeout_display_of_pending_files (view, UPDATE_INTERVAL_MIN);
3342 }
3343 }
3344
3345 static void
load_error_callback(CajaDirectory * directory,GError * error,gpointer callback_data)3346 load_error_callback (CajaDirectory *directory,
3347 GError *error,
3348 gpointer callback_data)
3349 {
3350 FMDirectoryView *view;
3351
3352 view = FM_DIRECTORY_VIEW (callback_data);
3353
3354 /* FIXME: By doing a stop, we discard some pending files. Is
3355 * that OK?
3356 */
3357 fm_directory_view_stop (view);
3358
3359 /* Emit a signal to tell subclasses that a load error has
3360 * occurred, so they can handle it in the UI.
3361 */
3362 g_signal_emit (view,
3363 signals[LOAD_ERROR], 0, error);
3364 }
3365
3366 static void
real_load_error(FMDirectoryView * view,GError * error)3367 real_load_error (FMDirectoryView *view, GError *error)
3368 {
3369 /* Report only one error per failed directory load (from the UI
3370 * point of view, not from the CajaDirectory point of view).
3371 * Otherwise you can get multiple identical errors caused by
3372 * unrelated code that just happens to try to iterate this
3373 * directory.
3374 */
3375 if (!view->details->reported_load_error) {
3376 fm_report_error_loading_directory
3377 (fm_directory_view_get_directory_as_file (view),
3378 error,
3379 fm_directory_view_get_containing_window (view));
3380 }
3381 view->details->reported_load_error = TRUE;
3382 }
3383
3384 void
fm_directory_view_add_subdirectory(FMDirectoryView * view,CajaDirectory * directory)3385 fm_directory_view_add_subdirectory (FMDirectoryView *view,
3386 CajaDirectory*directory)
3387 {
3388 CajaFileAttributes attributes;
3389
3390 g_assert (!g_list_find (view->details->subdirectory_list, directory));
3391
3392 caja_directory_ref (directory);
3393
3394 attributes =
3395 CAJA_FILE_ATTRIBUTES_FOR_ICON |
3396 CAJA_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT |
3397 CAJA_FILE_ATTRIBUTE_INFO |
3398 CAJA_FILE_ATTRIBUTE_LINK_INFO |
3399 CAJA_FILE_ATTRIBUTE_MOUNT |
3400 CAJA_FILE_ATTRIBUTE_EXTENSION_INFO;
3401
3402 caja_directory_file_monitor_add (directory,
3403 &view->details->model,
3404 view->details->show_hidden_files,
3405 attributes,
3406 files_added_callback, view);
3407
3408 g_signal_connect
3409 (directory, "files_added",
3410 G_CALLBACK (files_added_callback), view);
3411 g_signal_connect
3412 (directory, "files_changed",
3413 G_CALLBACK (files_changed_callback), view);
3414
3415 view->details->subdirectory_list = g_list_prepend (
3416 view->details->subdirectory_list, directory);
3417 }
3418
3419 void
fm_directory_view_remove_subdirectory(FMDirectoryView * view,CajaDirectory * directory)3420 fm_directory_view_remove_subdirectory (FMDirectoryView *view,
3421 CajaDirectory*directory)
3422 {
3423 g_assert (g_list_find (view->details->subdirectory_list, directory));
3424
3425 view->details->subdirectory_list = g_list_remove (
3426 view->details->subdirectory_list, directory);
3427
3428 g_signal_handlers_disconnect_by_func (directory,
3429 G_CALLBACK (files_added_callback),
3430 view);
3431 g_signal_handlers_disconnect_by_func (directory,
3432 G_CALLBACK (files_changed_callback),
3433 view);
3434
3435 caja_directory_file_monitor_remove (directory, &view->details->model);
3436
3437 caja_directory_unref (directory);
3438 }
3439
3440 /**
3441 * fm_directory_view_clear:
3442 *
3443 * Emit the signal to clear the contents of the view. Subclasses must
3444 * override the signal handler for this signal. This is normally called
3445 * only by FMDirectoryView.
3446 * @view: FMDirectoryView to empty.
3447 *
3448 **/
3449 void
fm_directory_view_clear(FMDirectoryView * view)3450 fm_directory_view_clear (FMDirectoryView *view)
3451 {
3452 g_return_if_fail (FM_IS_DIRECTORY_VIEW (view));
3453
3454 g_signal_emit (view, signals[CLEAR], 0);
3455 }
3456
3457 /**
3458 * fm_directory_view_begin_loading:
3459 *
3460 * Emit the signal to prepare for loading the contents of a new location.
3461 * Subclasses might want to override the signal handler for this signal.
3462 * This is normally called only by FMDirectoryView.
3463 * @view: FMDirectoryView that is switching to view a new location.
3464 *
3465 **/
3466 void
fm_directory_view_begin_loading(FMDirectoryView * view)3467 fm_directory_view_begin_loading (FMDirectoryView *view)
3468 {
3469 g_return_if_fail (FM_IS_DIRECTORY_VIEW (view));
3470
3471 g_signal_emit (view, signals[BEGIN_LOADING], 0);
3472 }
3473
3474 /**
3475 * fm_directory_view_end_loading:
3476 *
3477 * Emit the signal after loading the contents of a new location.
3478 * Subclasses might want to override the signal handler for this signal.
3479 * This is normally called only by FMDirectoryView.
3480 * @view: FMDirectoryView that is switching to view a new location.
3481 *
3482 **/
3483 void
fm_directory_view_end_loading(FMDirectoryView * view,gboolean all_files_seen)3484 fm_directory_view_end_loading (FMDirectoryView *view,
3485 gboolean all_files_seen)
3486 {
3487 g_return_if_fail (FM_IS_DIRECTORY_VIEW (view));
3488
3489 g_signal_emit (view, signals[END_LOADING], 0, all_files_seen);
3490 }
3491
3492 /**
3493 * fm_directory_view_get_loading:
3494 * @view: an #FMDirectoryView.
3495 *
3496 * Return value: #gboolean inicating whether @view is currently loaded.
3497 *
3498 **/
3499 gboolean
fm_directory_view_get_loading(FMDirectoryView * view)3500 fm_directory_view_get_loading (FMDirectoryView *view)
3501 {
3502 g_return_val_if_fail (FM_IS_DIRECTORY_VIEW (view), FALSE);
3503
3504 return view->details->loading;
3505 }
3506
3507 /**
3508 * fm_directory_view_bump_zoom_level:
3509 *
3510 * bump the current zoom level by invoking the relevant subclass through the slot
3511 *
3512 **/
3513 void
fm_directory_view_bump_zoom_level(FMDirectoryView * view,int zoom_increment)3514 fm_directory_view_bump_zoom_level (FMDirectoryView *view, int zoom_increment)
3515 {
3516 g_return_if_fail (FM_IS_DIRECTORY_VIEW (view));
3517
3518 if (!fm_directory_view_supports_zooming (view)) {
3519 return;
3520 }
3521
3522 EEL_CALL_METHOD
3523 (FM_DIRECTORY_VIEW_CLASS, view,
3524 bump_zoom_level, (view, zoom_increment));
3525 }
3526
3527 /**
3528 * fm_directory_view_zoom_to_level:
3529 *
3530 * Set the current zoom level by invoking the relevant subclass through the slot
3531 *
3532 **/
3533 void
fm_directory_view_zoom_to_level(FMDirectoryView * view,CajaZoomLevel zoom_level)3534 fm_directory_view_zoom_to_level (FMDirectoryView *view,
3535 CajaZoomLevel zoom_level)
3536 {
3537 g_return_if_fail (FM_IS_DIRECTORY_VIEW (view));
3538
3539 if (!fm_directory_view_supports_zooming (view)) {
3540 return;
3541 }
3542
3543 EEL_CALL_METHOD
3544 (FM_DIRECTORY_VIEW_CLASS, view,
3545 zoom_to_level, (view, zoom_level));
3546 }
3547
3548
3549 CajaZoomLevel
fm_directory_view_get_zoom_level(FMDirectoryView * view)3550 fm_directory_view_get_zoom_level (FMDirectoryView *view)
3551 {
3552 g_return_val_if_fail (FM_IS_DIRECTORY_VIEW (view), CAJA_ZOOM_LEVEL_STANDARD);
3553
3554 if (!fm_directory_view_supports_zooming (view)) {
3555 return CAJA_ZOOM_LEVEL_STANDARD;
3556 }
3557
3558 return EEL_CALL_METHOD_WITH_RETURN_VALUE
3559 (FM_DIRECTORY_VIEW_CLASS, view,
3560 get_zoom_level, (view));
3561 }
3562
3563 /**
3564 * fm_directory_view_restore_default_zoom_level:
3565 *
3566 * restore to the default zoom level by invoking the relevant subclass through the slot
3567 *
3568 **/
3569 void
fm_directory_view_restore_default_zoom_level(FMDirectoryView * view)3570 fm_directory_view_restore_default_zoom_level (FMDirectoryView *view)
3571 {
3572 g_return_if_fail (FM_IS_DIRECTORY_VIEW (view));
3573
3574 if (!fm_directory_view_supports_zooming (view)) {
3575 return;
3576 }
3577
3578 EEL_CALL_METHOD
3579 (FM_DIRECTORY_VIEW_CLASS, view,
3580 restore_default_zoom_level, (view));
3581 }
3582
3583 /**
3584 * fm_directory_view_can_zoom_in:
3585 *
3586 * Determine whether the view can be zoomed any closer.
3587 * @view: The zoomable FMDirectoryView.
3588 *
3589 * Return value: TRUE if @view can be zoomed any closer, FALSE otherwise.
3590 *
3591 **/
3592 gboolean
fm_directory_view_can_zoom_in(FMDirectoryView * view)3593 fm_directory_view_can_zoom_in (FMDirectoryView *view)
3594 {
3595 g_return_val_if_fail (FM_IS_DIRECTORY_VIEW (view), FALSE);
3596
3597 if (!fm_directory_view_supports_zooming (view)) {
3598 return FALSE;
3599 }
3600
3601 return EEL_CALL_METHOD_WITH_RETURN_VALUE
3602 (FM_DIRECTORY_VIEW_CLASS, view,
3603 can_zoom_in, (view));
3604 }
3605
3606 /**
3607 * fm_directory_view_can_rename_file
3608 *
3609 * Determine whether a file can be renamed.
3610 * @file: A CajaFile
3611 *
3612 * Return value: TRUE if @file can be renamed, FALSE otherwise.
3613 *
3614 **/
3615 static gboolean
fm_directory_view_can_rename_file(FMDirectoryView * view,CajaFile * file)3616 fm_directory_view_can_rename_file (FMDirectoryView *view, CajaFile *file)
3617 {
3618 return EEL_CALL_METHOD_WITH_RETURN_VALUE
3619 (FM_DIRECTORY_VIEW_CLASS, view,
3620 can_rename_file, (view, file));
3621 }
3622
3623 /**
3624 * fm_directory_view_can_zoom_out:
3625 *
3626 * Determine whether the view can be zoomed any further away.
3627 * @view: The zoomable FMDirectoryView.
3628 *
3629 * Return value: TRUE if @view can be zoomed any further away, FALSE otherwise.
3630 *
3631 **/
3632 gboolean
fm_directory_view_can_zoom_out(FMDirectoryView * view)3633 fm_directory_view_can_zoom_out (FMDirectoryView *view)
3634 {
3635 g_return_val_if_fail (FM_IS_DIRECTORY_VIEW (view), FALSE);
3636
3637 if (!fm_directory_view_supports_zooming (view)) {
3638 return FALSE;
3639 }
3640
3641 return EEL_CALL_METHOD_WITH_RETURN_VALUE
3642 (FM_DIRECTORY_VIEW_CLASS, view,
3643 can_zoom_out, (view));
3644 }
3645
3646 GtkWidget *
fm_directory_view_get_background_widget(FMDirectoryView * view)3647 fm_directory_view_get_background_widget (FMDirectoryView *view)
3648 {
3649 g_return_val_if_fail (FM_IS_DIRECTORY_VIEW (view), NULL);
3650
3651 return EEL_CALL_METHOD_WITH_RETURN_VALUE
3652 (FM_DIRECTORY_VIEW_CLASS, view,
3653 get_background_widget, (view));
3654 }
3655
3656 EelBackground *
fm_directory_view_get_background(FMDirectoryView * view)3657 fm_directory_view_get_background (FMDirectoryView *view)
3658 {
3659 return eel_get_widget_background (fm_directory_view_get_background_widget (view));
3660 }
3661
3662 static void
real_set_is_active(FMDirectoryView * view,gboolean is_active)3663 real_set_is_active (FMDirectoryView *view,
3664 gboolean is_active)
3665 {
3666 EelBackground *bg;
3667
3668 bg = fm_directory_view_get_background (view);
3669 eel_background_set_active (bg, is_active);
3670 }
3671
3672 static void
fm_directory_view_set_is_active(FMDirectoryView * view,gboolean is_active)3673 fm_directory_view_set_is_active (FMDirectoryView *view,
3674 gboolean is_active)
3675 {
3676 g_return_if_fail (FM_IS_DIRECTORY_VIEW (view));
3677
3678 EEL_CALL_METHOD (FM_DIRECTORY_VIEW_CLASS, view,
3679 set_is_active, (view, is_active));
3680 }
3681
3682 /**
3683 * fm_directory_view_get_selection:
3684 *
3685 * Get a list of CajaFile pointers that represents the
3686 * currently-selected items in this view. Subclasses must override
3687 * the signal handler for the 'get_selection' signal. Callers are
3688 * responsible for g_free-ing the list (but not its data).
3689 * @view: FMDirectoryView whose selected items are of interest.
3690 *
3691 * Return value: GList of CajaFile pointers representing the selection.
3692 *
3693 **/
3694 GList *
fm_directory_view_get_selection(FMDirectoryView * view)3695 fm_directory_view_get_selection (FMDirectoryView *view)
3696 {
3697 g_return_val_if_fail (FM_IS_DIRECTORY_VIEW (view), NULL);
3698
3699 return EEL_CALL_METHOD_WITH_RETURN_VALUE
3700 (FM_DIRECTORY_VIEW_CLASS, view,
3701 get_selection, (view));
3702 }
3703
3704 void
fm_directory_view_invert_selection(FMDirectoryView * view)3705 fm_directory_view_invert_selection (FMDirectoryView *view)
3706 {
3707 g_return_if_fail (FM_IS_DIRECTORY_VIEW (view));
3708
3709 EEL_CALL_METHOD
3710 (FM_DIRECTORY_VIEW_CLASS, view,
3711 invert_selection, (view));
3712 }
3713
3714 GList *
fm_directory_view_get_selection_for_file_transfer(FMDirectoryView * view)3715 fm_directory_view_get_selection_for_file_transfer (FMDirectoryView *view)
3716 {
3717 g_return_val_if_fail (FM_IS_DIRECTORY_VIEW (view), NULL);
3718
3719 return EEL_CALL_METHOD_WITH_RETURN_VALUE
3720 (FM_DIRECTORY_VIEW_CLASS, view,
3721 get_selection_for_file_transfer, (view));
3722 }
3723
3724 guint
fm_directory_view_get_item_count(FMDirectoryView * view)3725 fm_directory_view_get_item_count (FMDirectoryView *view)
3726 {
3727 g_return_val_if_fail (FM_IS_DIRECTORY_VIEW (view), 0);
3728
3729 return EEL_CALL_METHOD_WITH_RETURN_VALUE
3730 (FM_DIRECTORY_VIEW_CLASS, view,
3731 get_item_count, (view));
3732 }
3733
3734 GtkUIManager *
fm_directory_view_get_ui_manager(FMDirectoryView * view)3735 fm_directory_view_get_ui_manager (FMDirectoryView *view)
3736 {
3737 if (view->details->window == NULL) {
3738 return NULL;
3739 }
3740 return caja_window_info_get_ui_manager (view->details->window);
3741 }
3742
3743 /**
3744 * fm_directory_view_get_model:
3745 *
3746 * Get the model for this FMDirectoryView.
3747 * @view: FMDirectoryView of interest.
3748 *
3749 * Return value: CajaDirectory for this view.
3750 *
3751 **/
3752 CajaDirectory *
fm_directory_view_get_model(FMDirectoryView * view)3753 fm_directory_view_get_model (FMDirectoryView *view)
3754 {
3755 g_return_val_if_fail (FM_IS_DIRECTORY_VIEW (view), NULL);
3756
3757 return view->details->model;
3758 }
3759
3760 GdkAtom
fm_directory_view_get_copied_files_atom(FMDirectoryView * view)3761 fm_directory_view_get_copied_files_atom (FMDirectoryView *view)
3762 {
3763 g_return_val_if_fail (FM_IS_DIRECTORY_VIEW (view), GDK_NONE);
3764
3765 return copied_files_atom;
3766 }
3767
3768 static void
prepend_uri_one(gpointer data,gpointer callback_data)3769 prepend_uri_one (gpointer data, gpointer callback_data)
3770 {
3771 CajaFile *file;
3772 GList **result;
3773
3774 g_assert (CAJA_IS_FILE (data));
3775 g_assert (callback_data != NULL);
3776
3777 result = (GList **) callback_data;
3778 file = (CajaFile *) data;
3779 *result = g_list_prepend (*result, caja_file_get_uri (file));
3780 }
3781
3782 static void
offset_drop_points(GArray * relative_item_points,int x_offset,int y_offset)3783 offset_drop_points (GArray *relative_item_points,
3784 int x_offset, int y_offset)
3785 {
3786 guint index;
3787
3788 if (relative_item_points == NULL) {
3789 return;
3790 }
3791
3792 for (index = 0; index < relative_item_points->len; index++) {
3793 g_array_index (relative_item_points, GdkPoint, index).x += x_offset;
3794 g_array_index (relative_item_points, GdkPoint, index).y += y_offset;
3795 }
3796 }
3797
3798 static void
fm_directory_view_create_links_for_files(FMDirectoryView * view,GList * files,GArray * relative_item_points)3799 fm_directory_view_create_links_for_files (FMDirectoryView *view, GList *files,
3800 GArray *relative_item_points)
3801 {
3802 GList *uris;
3803 char *dir_uri;
3804 CopyMoveDoneData *copy_move_done_data;
3805 g_assert (relative_item_points->len == 0
3806 || g_list_length (files) == relative_item_points->len);
3807
3808 g_assert (FM_IS_DIRECTORY_VIEW (view));
3809 g_assert (files != NULL);
3810
3811 /* create a list of URIs */
3812 uris = NULL;
3813 g_list_foreach (files, prepend_uri_one, &uris);
3814 uris = g_list_reverse (uris);
3815
3816 g_assert (g_list_length (uris) == g_list_length (files));
3817
3818 /* offset the drop locations a bit so that we don't pile
3819 * up the icons on top of each other
3820 */
3821 offset_drop_points (relative_item_points,
3822 DUPLICATE_HORIZONTAL_ICON_OFFSET,
3823 DUPLICATE_VERTICAL_ICON_OFFSET);
3824
3825 copy_move_done_data = pre_copy_move (view);
3826 dir_uri = fm_directory_view_get_backing_uri (view);
3827 caja_file_operations_copy_move (uris, relative_item_points, dir_uri, GDK_ACTION_LINK,
3828 GTK_WIDGET (view), copy_move_done_callback, copy_move_done_data);
3829 g_free (dir_uri);
3830 g_list_free_full (uris, g_free);
3831 }
3832
3833 static void
fm_directory_view_duplicate_selection(FMDirectoryView * view,GList * files,GArray * relative_item_points)3834 fm_directory_view_duplicate_selection (FMDirectoryView *view, GList *files,
3835 GArray *relative_item_points)
3836 {
3837 GList *uris;
3838 CopyMoveDoneData *copy_move_done_data;
3839
3840 g_assert (FM_IS_DIRECTORY_VIEW (view));
3841 g_assert (files != NULL);
3842 g_assert (g_list_length (files) == relative_item_points->len
3843 || relative_item_points->len == 0);
3844
3845 /* create a list of URIs */
3846 uris = NULL;
3847 g_list_foreach (files, prepend_uri_one, &uris);
3848 uris = g_list_reverse (uris);
3849
3850 g_assert (g_list_length (uris) == g_list_length (files));
3851
3852 /* offset the drop locations a bit so that we don't pile
3853 * up the icons on top of each other
3854 */
3855 offset_drop_points (relative_item_points,
3856 DUPLICATE_HORIZONTAL_ICON_OFFSET,
3857 DUPLICATE_VERTICAL_ICON_OFFSET);
3858
3859 copy_move_done_data = pre_copy_move (view);
3860 caja_file_operations_copy_move (uris, relative_item_points, NULL, GDK_ACTION_COPY,
3861 GTK_WIDGET (view), copy_move_done_callback, copy_move_done_data);
3862 g_list_free_full (uris, g_free);
3863 }
3864
3865 /* special_link_in_selection
3866 *
3867 * Return TRUE if one of our special links is in the selection.
3868 * Special links include the following:
3869 * CAJA_DESKTOP_LINK_TRASH, CAJA_DESKTOP_LINK_HOME, CAJA_DESKTOP_LINK_MOUNT
3870 */
3871
3872 static gboolean
special_link_in_selection(FMDirectoryView * view)3873 special_link_in_selection (FMDirectoryView *view)
3874 {
3875 gboolean saw_link;
3876 GList *selection, *node;
3877 CajaFile *file = NULL;
3878
3879 g_return_val_if_fail (FM_IS_DIRECTORY_VIEW (view), FALSE);
3880
3881 saw_link = FALSE;
3882
3883 selection = fm_directory_view_get_selection (FM_DIRECTORY_VIEW (view));
3884
3885 for (node = selection; node != NULL; node = node->next) {
3886 file = CAJA_FILE (node->data);
3887
3888 saw_link = CAJA_IS_DESKTOP_ICON_FILE (file);
3889
3890 if (saw_link) {
3891 break;
3892 }
3893 }
3894
3895 caja_file_list_free (selection);
3896
3897 return saw_link;
3898 }
3899
3900 /* desktop_or_home_dir_in_selection
3901 *
3902 * Return TRUE if either the desktop or the home directory is in the selection.
3903 */
3904
3905 static gboolean
desktop_or_home_dir_in_selection(FMDirectoryView * view)3906 desktop_or_home_dir_in_selection (FMDirectoryView *view)
3907 {
3908 gboolean saw_desktop_or_home_dir;
3909 GList *selection, *node;
3910 CajaFile *file = NULL;
3911
3912 g_return_val_if_fail (FM_IS_DIRECTORY_VIEW (view), FALSE);
3913
3914 saw_desktop_or_home_dir = FALSE;
3915
3916 selection = fm_directory_view_get_selection (FM_DIRECTORY_VIEW (view));
3917
3918 for (node = selection; node != NULL; node = node->next) {
3919 file = CAJA_FILE (node->data);
3920
3921 saw_desktop_or_home_dir =
3922 caja_file_is_home (file)
3923 || caja_file_is_desktop_directory (file);
3924
3925 if (saw_desktop_or_home_dir) {
3926 break;
3927 }
3928 }
3929
3930 caja_file_list_free (selection);
3931
3932 return saw_desktop_or_home_dir;
3933 }
3934
3935 static void
trash_or_delete_done_cb(GHashTable * debuting_uris,gboolean user_cancel,FMDirectoryView * view)3936 trash_or_delete_done_cb (GHashTable *debuting_uris,
3937 gboolean user_cancel,
3938 FMDirectoryView *view)
3939 {
3940 if (user_cancel) {
3941 view->details->selection_was_removed = FALSE;
3942 }
3943 }
3944
3945 static void
trash_or_delete_files(GtkWindow * parent_window,const GList * files,gboolean delete_if_all_already_in_trash,FMDirectoryView * view)3946 trash_or_delete_files (GtkWindow *parent_window,
3947 const GList *files,
3948 gboolean delete_if_all_already_in_trash,
3949 FMDirectoryView *view)
3950 {
3951 GList *locations;
3952 const GList *node;
3953
3954 locations = NULL;
3955 for (node = files; node != NULL; node = node->next) {
3956 locations = g_list_prepend (locations,
3957 caja_file_get_location ((CajaFile *) node->data));
3958 }
3959
3960 locations = g_list_reverse (locations);
3961
3962 caja_file_operations_trash_or_delete (locations,
3963 parent_window,
3964 (CajaDeleteCallback) trash_or_delete_done_cb,
3965 view);
3966 g_list_free_full (locations, g_object_unref);
3967 }
3968
3969 static gboolean
can_rename_file(FMDirectoryView * view,CajaFile * file)3970 can_rename_file (FMDirectoryView *view, CajaFile *file)
3971 {
3972 return caja_file_can_rename (file);
3973 }
3974
3975 static void
start_renaming_file(FMDirectoryView * view,CajaFile * file,gboolean select_all)3976 start_renaming_file (FMDirectoryView *view,
3977 CajaFile *file,
3978 gboolean select_all)
3979 {
3980 if (file != NULL) {
3981 fm_directory_view_select_file (view, file);
3982 }
3983 }
3984
3985 typedef struct {
3986 FMDirectoryView *view;
3987 CajaFile *new_file;
3988 } RenameData;
3989
3990 static gboolean
delayed_rename_file_hack_callback(RenameData * data)3991 delayed_rename_file_hack_callback (RenameData *data)
3992 {
3993 FMDirectoryView *view;
3994 CajaFile *new_file;
3995
3996 view = data->view;
3997 new_file = data->new_file;
3998
3999 if (view->details->window != NULL &&
4000 view->details->active) {
4001 EEL_CALL_METHOD (FM_DIRECTORY_VIEW_CLASS, view, start_renaming_file, (view, new_file, FALSE));
4002 fm_directory_view_reveal_selection (view);
4003 }
4004
4005 return FALSE;
4006 }
4007
4008 static void
delayed_rename_file_hack_removed(RenameData * data)4009 delayed_rename_file_hack_removed (RenameData *data)
4010 {
4011 g_object_unref (data->view);
4012 caja_file_unref (data->new_file);
4013 g_free (data);
4014 }
4015
4016
4017 static void
rename_file(FMDirectoryView * view,CajaFile * new_file)4018 rename_file (FMDirectoryView *view, CajaFile *new_file)
4019 {
4020 /* HACK!!!!
4021 This is a work around bug in listview. After the rename is
4022 enabled we will get file changes due to info about the new
4023 file being read, which will cause the model to change. When
4024 the model changes GtkTreeView clears the editing. This hack just
4025 delays editing for some time to try to avoid this problem.
4026 A major problem is that the selection of the row causes us
4027 to load the slow mimetype for the file, which leads to a
4028 file_changed. So, before we delay we select the row.
4029 */
4030 if (FM_IS_LIST_VIEW (view)) {
4031 RenameData *data;
4032
4033 fm_directory_view_select_file (view, new_file);
4034
4035 data = g_new (RenameData, 1);
4036 data->view = g_object_ref (view);
4037 data->new_file = caja_file_ref (new_file);
4038 if (view->details->delayed_rename_file_id != 0) {
4039 g_source_remove (view->details->delayed_rename_file_id);
4040 }
4041 view->details->delayed_rename_file_id =
4042 g_timeout_add_full (G_PRIORITY_DEFAULT,
4043 100, (GSourceFunc)delayed_rename_file_hack_callback,
4044 data, (GDestroyNotify) delayed_rename_file_hack_removed);
4045
4046 return;
4047 }
4048
4049 /* no need to select because start_renaming_file selects
4050 * fm_directory_view_select_file (view, new_file);
4051 */
4052 EEL_CALL_METHOD (FM_DIRECTORY_VIEW_CLASS, view, start_renaming_file, (view, new_file, FALSE));
4053 fm_directory_view_reveal_selection (view);
4054 }
4055
4056 static void
reveal_newly_added_folder(FMDirectoryView * view,CajaFile * new_file,CajaDirectory * directory,GFile * target_location)4057 reveal_newly_added_folder (FMDirectoryView *view, CajaFile *new_file,
4058 CajaDirectory *directory, GFile *target_location)
4059 {
4060 GFile *location;
4061
4062 location = caja_file_get_location (new_file);
4063 if (g_file_equal (location, target_location)) {
4064 g_signal_handlers_disconnect_by_func (view,
4065 G_CALLBACK (reveal_newly_added_folder),
4066 (void *) target_location);
4067 rename_file (view, new_file);
4068 }
4069 g_object_unref (location);
4070 }
4071
4072 typedef struct {
4073 FMDirectoryView *directory_view;
4074 GHashTable *added_locations;
4075 } NewFolderData;
4076
4077
4078 static void
track_newly_added_locations(FMDirectoryView * view,CajaFile * new_file,CajaDirectory * directory,gpointer user_data)4079 track_newly_added_locations (FMDirectoryView *view, CajaFile *new_file,
4080 CajaDirectory *directory, gpointer user_data)
4081 {
4082 NewFolderData *data;
4083
4084 data = user_data;
4085
4086 g_hash_table_insert (data->added_locations, caja_file_get_location (new_file), NULL);
4087 }
4088
4089 static void
new_folder_done(GFile * new_folder,gpointer user_data)4090 new_folder_done (GFile *new_folder, gpointer user_data)
4091 {
4092 FMDirectoryView *directory_view;
4093 CajaFile *file;
4094 char screen_string[32];
4095 GdkScreen *screen;
4096 NewFolderData *data;
4097
4098 data = (NewFolderData *)user_data;
4099
4100 directory_view = data->directory_view;
4101
4102 if (directory_view == NULL) {
4103 goto fail;
4104 }
4105
4106 g_signal_handlers_disconnect_by_func (directory_view,
4107 G_CALLBACK (track_newly_added_locations),
4108 (void *) data);
4109
4110 if (new_folder == NULL) {
4111 goto fail;
4112 }
4113
4114 screen = gtk_widget_get_screen (GTK_WIDGET (directory_view));
4115 g_snprintf (screen_string, sizeof (screen_string), "%d", gdk_x11_screen_get_screen_number (screen));
4116
4117
4118 file = caja_file_get (new_folder);
4119 caja_file_set_metadata
4120 (file, CAJA_METADATA_KEY_SCREEN,
4121 NULL,
4122 screen_string);
4123
4124 if (g_hash_table_lookup_extended (data->added_locations, new_folder, NULL, NULL)) {
4125 /* The file was already added */
4126 rename_file (directory_view, file);
4127 } else {
4128 /* We need to run after the default handler adds the folder we want to
4129 * operate on. The ADD_FILE signal is registered as G_SIGNAL_RUN_LAST, so we
4130 * must use connect_after.
4131 */
4132 g_signal_connect_data (directory_view,
4133 "add_file",
4134 G_CALLBACK (reveal_newly_added_folder),
4135 g_object_ref (new_folder),
4136 (GClosureNotify)g_object_unref,
4137 G_CONNECT_AFTER);
4138 }
4139 caja_file_unref (file);
4140
4141 fail:
4142 g_hash_table_destroy (data->added_locations);
4143 eel_remove_weak_pointer (&data->directory_view);
4144 g_free (data);
4145 }
4146
4147
4148 static NewFolderData *
new_folder_data_new(FMDirectoryView * directory_view)4149 new_folder_data_new (FMDirectoryView *directory_view)
4150 {
4151 NewFolderData *data;
4152
4153 data = g_new (NewFolderData, 1);
4154 data->directory_view = directory_view;
4155 data->added_locations = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal,
4156 g_object_unref, NULL);
4157 eel_add_weak_pointer (&data->directory_view);
4158
4159 return data;
4160 }
4161
4162 static GdkPoint *
context_menu_to_file_operation_position(FMDirectoryView * directory_view)4163 context_menu_to_file_operation_position (FMDirectoryView *directory_view)
4164 {
4165 g_return_val_if_fail (FM_IS_DIRECTORY_VIEW (directory_view), NULL);
4166
4167 if (fm_directory_view_using_manual_layout (directory_view)
4168 && directory_view->details->context_menu_position.x >= 0
4169 && directory_view->details->context_menu_position.y >= 0) {
4170 EEL_CALL_METHOD (FM_DIRECTORY_VIEW_CLASS, directory_view,
4171 widget_to_file_operation_position,
4172 (directory_view, &directory_view->details->context_menu_position));
4173 return &directory_view->details->context_menu_position;
4174 } else {
4175 return NULL;
4176 }
4177 }
4178
4179 static void
update_context_menu_position_from_event(FMDirectoryView * view,GdkEventButton * event)4180 update_context_menu_position_from_event (FMDirectoryView *view,
4181 GdkEventButton *event)
4182 {
4183 g_return_if_fail (FM_IS_DIRECTORY_VIEW (view));
4184
4185 if (event != NULL) {
4186 view->details->context_menu_position.x = event->x;
4187 view->details->context_menu_position.y = event->y;
4188 } else {
4189 view->details->context_menu_position.x = -1;
4190 view->details->context_menu_position.y = -1;
4191 }
4192 }
4193
4194 void
fm_directory_view_new_folder(FMDirectoryView * directory_view)4195 fm_directory_view_new_folder (FMDirectoryView *directory_view)
4196 {
4197 char *parent_uri;
4198 NewFolderData *data;
4199 GdkPoint *pos;
4200
4201 data = new_folder_data_new (directory_view);
4202
4203 g_signal_connect_data (directory_view,
4204 "add_file",
4205 G_CALLBACK (track_newly_added_locations),
4206 data,
4207 (GClosureNotify)NULL,
4208 G_CONNECT_AFTER);
4209
4210 pos = context_menu_to_file_operation_position (directory_view);
4211
4212 parent_uri = fm_directory_view_get_backing_uri (directory_view);
4213 caja_file_operations_new_folder (GTK_WIDGET (directory_view),
4214 pos, parent_uri,
4215 new_folder_done, data);
4216
4217 g_free (parent_uri);
4218 }
4219
4220 static NewFolderData *
setup_new_folder_data(FMDirectoryView * directory_view)4221 setup_new_folder_data (FMDirectoryView *directory_view)
4222 {
4223 NewFolderData *data;
4224
4225 data = new_folder_data_new (directory_view);
4226
4227 g_signal_connect_data (directory_view,
4228 "add_file",
4229 G_CALLBACK (track_newly_added_locations),
4230 data,
4231 (GClosureNotify)NULL,
4232 G_CONNECT_AFTER);
4233
4234 return data;
4235 }
4236
4237 static void
fm_directory_view_new_file_with_initial_contents(FMDirectoryView * directory_view,const char * parent_uri,const char * filename,const char * initial_contents,int length,GdkPoint * pos)4238 fm_directory_view_new_file_with_initial_contents (FMDirectoryView *directory_view,
4239 const char *parent_uri,
4240 const char *filename,
4241 const char *initial_contents,
4242 int length,
4243 GdkPoint *pos)
4244 {
4245 NewFolderData *data;
4246
4247 g_assert (parent_uri != NULL);
4248
4249 data = setup_new_folder_data (directory_view);
4250
4251 if (pos == NULL) {
4252 pos = context_menu_to_file_operation_position (directory_view);
4253 }
4254
4255 caja_file_operations_new_file (GTK_WIDGET (directory_view),
4256 pos, parent_uri, filename,
4257 initial_contents, length,
4258 new_folder_done, data);
4259 }
4260
4261 void
fm_directory_view_new_file(FMDirectoryView * directory_view,const char * parent_uri,CajaFile * source)4262 fm_directory_view_new_file (FMDirectoryView *directory_view,
4263 const char *parent_uri,
4264 CajaFile *source)
4265 {
4266 GdkPoint *pos;
4267 NewFolderData *data;
4268 char *source_uri;
4269 char *container_uri;
4270
4271 container_uri = NULL;
4272 if (parent_uri == NULL) {
4273 container_uri = fm_directory_view_get_backing_uri (directory_view);
4274 g_assert (container_uri != NULL);
4275 }
4276
4277 if (source == NULL) {
4278 fm_directory_view_new_file_with_initial_contents (directory_view,
4279 parent_uri != NULL ? parent_uri : container_uri,
4280 NULL,
4281 NULL,
4282 0,
4283 NULL);
4284 g_free (container_uri);
4285 return;
4286 }
4287
4288 g_return_if_fail (caja_file_is_local (source));
4289
4290 pos = context_menu_to_file_operation_position (directory_view);
4291
4292 data = setup_new_folder_data (directory_view);
4293
4294 source_uri = caja_file_get_uri (source);
4295
4296 caja_file_operations_new_file_from_template (GTK_WIDGET (directory_view),
4297 pos,
4298 parent_uri != NULL ? parent_uri : container_uri,
4299 NULL,
4300 source_uri,
4301 new_folder_done, data);
4302
4303 g_free (source_uri);
4304 g_free (container_uri);
4305 }
4306
4307 /* handle the open command */
4308
4309 static void
open_one_in_new_window(gpointer data,gpointer callback_data)4310 open_one_in_new_window (gpointer data, gpointer callback_data)
4311 {
4312 g_assert (CAJA_IS_FILE (data));
4313 g_assert (FM_IS_DIRECTORY_VIEW (callback_data));
4314
4315 fm_directory_view_activate_file (FM_DIRECTORY_VIEW (callback_data),
4316 CAJA_FILE (data),
4317 CAJA_WINDOW_OPEN_IN_NAVIGATION,
4318 0);
4319 }
4320
4321 static void
open_one_in_folder_window(gpointer data,gpointer callback_data)4322 open_one_in_folder_window (gpointer data, gpointer callback_data)
4323 {
4324 g_assert (CAJA_IS_FILE (data));
4325 g_assert (FM_IS_DIRECTORY_VIEW (callback_data));
4326
4327 fm_directory_view_activate_file (FM_DIRECTORY_VIEW (callback_data),
4328 CAJA_FILE (data),
4329 CAJA_WINDOW_OPEN_IN_SPATIAL,
4330 0);
4331 }
4332
4333 CajaFile *
fm_directory_view_get_directory_as_file(FMDirectoryView * view)4334 fm_directory_view_get_directory_as_file (FMDirectoryView *view)
4335 {
4336 g_assert (FM_IS_DIRECTORY_VIEW (view));
4337
4338 return view->details->directory_as_file;
4339 }
4340
4341 static void
open_with_launch_application_callback(GtkAction * action,gpointer callback_data)4342 open_with_launch_application_callback (GtkAction *action,
4343 gpointer callback_data)
4344 {
4345 ApplicationLaunchParameters *launch_parameters;
4346
4347 launch_parameters = (ApplicationLaunchParameters *) callback_data;
4348 caja_launch_application
4349 (launch_parameters->application,
4350 launch_parameters->files,
4351 fm_directory_view_get_containing_window (launch_parameters->directory_view));
4352 }
4353
4354 static void
open_parent_folder_callback(GtkAction * action,gpointer callback_data)4355 open_parent_folder_callback (GtkAction *action,
4356 gpointer callback_data)
4357 {
4358 gchar *uri;
4359
4360 uri = (gchar *) callback_data;
4361 g_app_info_launch_default_for_uri (uri, NULL, NULL);
4362 }
4363
4364 static char *
escape_action_name(const char * action_name,const char * prefix)4365 escape_action_name (const char *action_name,
4366 const char *prefix)
4367 {
4368 GString *s;
4369
4370 if (action_name == NULL) {
4371 return NULL;
4372 }
4373
4374 s = g_string_new (prefix);
4375
4376 while (*action_name != 0) {
4377 switch (*action_name) {
4378 case '\\':
4379 g_string_append (s, "\\\\");
4380 break;
4381 case '/':
4382 g_string_append (s, "\\s");
4383 break;
4384 case '&':
4385 g_string_append (s, "\\a");
4386 break;
4387 case '"':
4388 g_string_append (s, "\\q");
4389 break;
4390 default:
4391 g_string_append_c (s, *action_name);
4392 }
4393
4394 action_name ++;
4395 }
4396 return g_string_free (s, FALSE);
4397 }
4398
4399 static char *
escape_action_path(const char * action_path)4400 escape_action_path (const char *action_path)
4401 {
4402 GString *s;
4403
4404 if (action_path == NULL) {
4405 return NULL;
4406 }
4407
4408 s = g_string_sized_new (strlen (action_path) + 2);
4409
4410 while (*action_path != 0) {
4411 switch (*action_path) {
4412 case '\\':
4413 g_string_append (s, "\\\\");
4414 break;
4415 case '&':
4416 g_string_append (s, "\\a");
4417 break;
4418 case '"':
4419 g_string_append (s, "\\q");
4420 break;
4421 default:
4422 g_string_append_c (s, *action_path);
4423 }
4424
4425 action_path ++;
4426 }
4427 return g_string_free (s, FALSE);
4428 }
4429
4430
4431 static void
add_submenu(GtkUIManager * ui_manager,GtkActionGroup * action_group,guint merge_id,const char * parent_path,const char * uri,const char * label,cairo_surface_t * surface,gboolean add_action)4432 add_submenu (GtkUIManager *ui_manager,
4433 GtkActionGroup *action_group,
4434 guint merge_id,
4435 const char *parent_path,
4436 const char *uri,
4437 const char *label,
4438 cairo_surface_t *surface,
4439 gboolean add_action)
4440 {
4441 if (parent_path != NULL) {
4442 char *escaped_label;
4443 char *action_name;
4444 char *submenu_name;
4445 char *escaped_submenu_name;
4446
4447 action_name = escape_action_name (uri, "submenu_");
4448 submenu_name = g_path_get_basename (uri);
4449 escaped_submenu_name = escape_action_path (submenu_name);
4450 escaped_label = eel_str_double_underscores (label);
4451
4452 if (add_action) {
4453 GtkAction *action;
4454
4455 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
4456 action = gtk_action_new (action_name,
4457 escaped_label,
4458 NULL,
4459 NULL);
4460 G_GNUC_END_IGNORE_DEPRECATIONS;
4461 if (surface != NULL) {
4462 g_object_set_data_full (G_OBJECT (action), "menu-icon",
4463 cairo_surface_reference (surface),
4464 (GDestroyNotify)cairo_surface_destroy);
4465 }
4466
4467 g_object_set (action, "hide-if-empty", FALSE, NULL);
4468
4469 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
4470 gtk_action_group_add_action (action_group,
4471 action);
4472 G_GNUC_END_IGNORE_DEPRECATIONS;
4473 g_object_unref (action);
4474 }
4475
4476 gtk_ui_manager_add_ui (ui_manager,
4477 merge_id,
4478 parent_path,
4479 escaped_submenu_name,
4480 action_name,
4481 GTK_UI_MANAGER_MENU,
4482 FALSE);
4483 g_free (action_name);
4484 g_free (escaped_label);
4485 g_free (submenu_name);
4486 g_free (escaped_submenu_name);
4487 }
4488 }
4489
4490 static void
add_application_to_open_with_menu(FMDirectoryView * view,GAppInfo * application,GList * files,int index,const char * menu_placeholder,const char * popup_placeholder,const gboolean submenu)4491 add_application_to_open_with_menu (FMDirectoryView *view,
4492 GAppInfo *application,
4493 GList *files,
4494 int index,
4495 const char *menu_placeholder,
4496 const char *popup_placeholder,
4497 const gboolean submenu)
4498 {
4499 ApplicationLaunchParameters *launch_parameters;
4500 char *tip;
4501 char *label;
4502 char *action_name;
4503 char *escaped_app;
4504 char *path;
4505 GtkAction *action;
4506 GIcon *app_icon;
4507 GtkWidget *menuitem;
4508
4509 launch_parameters = application_launch_parameters_new
4510 (application, files, view);
4511 escaped_app = eel_str_double_underscores (g_app_info_get_display_name (application));
4512 if (submenu)
4513 label = g_strdup_printf ("%s", escaped_app);
4514 else
4515 label = g_strdup_printf (_("Open With %s"), escaped_app);
4516
4517 tip = g_strdup_printf (ngettext ("Use \"%s\" to open the selected item",
4518 "Use \"%s\" to open the selected items",
4519 g_list_length (files)),
4520 escaped_app);
4521 g_free (escaped_app);
4522
4523 action_name = g_strdup_printf ("open_with_%d", index);
4524
4525 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
4526 action = gtk_action_new (action_name,
4527 label,
4528 tip,
4529 NULL);
4530 G_GNUC_END_IGNORE_DEPRECATIONS;
4531
4532 app_icon = g_app_info_get_icon (application);
4533 if (app_icon != NULL) {
4534 g_object_ref (app_icon);
4535 } else {
4536 app_icon = g_themed_icon_new ("application-x-executable");
4537 }
4538
4539 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
4540 gtk_action_set_gicon (action, app_icon);
4541 G_GNUC_END_IGNORE_DEPRECATIONS;
4542 g_object_unref (app_icon);
4543
4544 g_signal_connect_data (action, "activate",
4545 G_CALLBACK (open_with_launch_application_callback),
4546 launch_parameters,
4547 (GClosureNotify)application_launch_parameters_free, 0);
4548
4549 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
4550 gtk_action_group_add_action (view->details->open_with_action_group,
4551 action);
4552 G_GNUC_END_IGNORE_DEPRECATIONS;
4553 g_object_unref (action);
4554
4555 gtk_ui_manager_add_ui (caja_window_info_get_ui_manager (view->details->window),
4556 view->details->open_with_merge_id,
4557 menu_placeholder,
4558 action_name,
4559 action_name,
4560 GTK_UI_MANAGER_MENUITEM,
4561 FALSE);
4562
4563 path = g_strdup_printf ("%s/%s", menu_placeholder, action_name);
4564 menuitem = gtk_ui_manager_get_widget (
4565 caja_window_info_get_ui_manager (view->details->window),
4566 path);
4567 gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (menuitem), TRUE);
4568 g_free (path);
4569
4570 gtk_ui_manager_add_ui (caja_window_info_get_ui_manager (view->details->window),
4571 view->details->open_with_merge_id,
4572 popup_placeholder,
4573 action_name,
4574 action_name,
4575 GTK_UI_MANAGER_MENUITEM,
4576 FALSE);
4577
4578 path = g_strdup_printf ("%s/%s", popup_placeholder, action_name);
4579 menuitem = gtk_ui_manager_get_widget (
4580 caja_window_info_get_ui_manager (view->details->window),
4581 path);
4582 gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (menuitem), TRUE);
4583
4584 g_free (path);
4585 g_free (action_name);
4586 g_free (label);
4587 g_free (tip);
4588 }
4589
4590 static void
add_parent_folder_to_open_menu(FMDirectoryView * view,GList * files,const char * menu_placeholder,const char * popup_placeholder)4591 add_parent_folder_to_open_menu (FMDirectoryView *view,
4592 GList *files,
4593 const char *menu_placeholder,
4594 const char *popup_placeholder)
4595 {
4596 CajaFile *file;
4597 gchar *uri;
4598 char *tip;
4599 char *label;
4600 char *action_name;
4601 char *path;
4602 GtkAction *action;
4603 GtkWidget *menuitem;
4604
4605 file = g_list_first(files)->data;
4606
4607 if (caja_file_is_directory (file))
4608 return;
4609
4610 uri = caja_file_get_parent_uri (file);
4611
4612 label = g_strdup (_("Open parent location"));
4613 tip = g_strdup (_("Open parent location for the selected item"));
4614 action_name = g_strdup ("open_location");
4615
4616 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
4617 action = gtk_action_new (action_name,
4618 label,
4619 tip,
4620 NULL);
4621
4622 gtk_action_set_icon_name (action, "folder");
4623 G_GNUC_END_IGNORE_DEPRECATIONS;
4624
4625 g_signal_connect_data (action, "activate",
4626 G_CALLBACK (open_parent_folder_callback),
4627 uri, (GClosureNotify)g_free, 0);
4628
4629 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
4630 gtk_action_group_add_action (view->details->open_with_action_group,
4631 action);
4632 G_GNUC_END_IGNORE_DEPRECATIONS;
4633 g_object_unref (action);
4634
4635 gtk_ui_manager_add_ui (caja_window_info_get_ui_manager (view->details->window),
4636 view->details->open_with_merge_id,
4637 menu_placeholder,
4638 action_name,
4639 action_name,
4640 GTK_UI_MANAGER_MENUITEM,
4641 FALSE);
4642
4643 path = g_strdup_printf ("%s/%s", menu_placeholder, action_name);
4644 menuitem = gtk_ui_manager_get_widget (
4645 caja_window_info_get_ui_manager (view->details->window),
4646 path);
4647 gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (menuitem), TRUE);
4648 g_free (path);
4649
4650 gtk_ui_manager_add_ui (caja_window_info_get_ui_manager (view->details->window),
4651 view->details->open_with_merge_id,
4652 popup_placeholder,
4653 action_name,
4654 action_name,
4655 GTK_UI_MANAGER_MENUITEM,
4656 FALSE);
4657
4658 path = g_strdup_printf ("%s/%s", popup_placeholder, action_name);
4659 menuitem = gtk_ui_manager_get_widget (
4660 caja_window_info_get_ui_manager (view->details->window),
4661 path);
4662 gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (menuitem), TRUE);
4663
4664 g_free (path);
4665 g_free (action_name);
4666 g_free (label);
4667 g_free (tip);
4668 }
4669
4670 static void
get_x_content_async_callback(char ** content,gpointer user_data)4671 get_x_content_async_callback (char **content,
4672 gpointer user_data)
4673 {
4674 FMDirectoryView *view;
4675
4676 view = FM_DIRECTORY_VIEW (user_data);
4677
4678 if (view->details->window != NULL) {
4679 schedule_update_menus (view);
4680 }
4681 g_object_unref (view);
4682 }
4683
4684 static void
add_x_content_apps(FMDirectoryView * view,CajaFile * file,GList ** applications)4685 add_x_content_apps (FMDirectoryView *view, CajaFile *file, GList **applications)
4686 {
4687 GMount *mount;
4688 char **x_content_types;
4689
4690 g_return_if_fail (applications != NULL);
4691
4692 mount = caja_file_get_mount (file);
4693
4694 if (mount == NULL) {
4695 return;
4696 }
4697
4698 x_content_types = caja_autorun_get_cached_x_content_types_for_mount (mount);
4699 if (x_content_types != NULL) {
4700 unsigned int n;
4701
4702 for (n = 0; x_content_types[n] != NULL; n++) {
4703 char *x_content_type = x_content_types[n];
4704 GList *app_info_for_x_content_type;
4705
4706 app_info_for_x_content_type = g_app_info_get_all_for_type (x_content_type);
4707 *applications = g_list_concat (*applications, app_info_for_x_content_type);
4708 }
4709 g_strfreev (x_content_types);
4710 } else {
4711 caja_autorun_get_x_content_types_for_mount_async (mount,
4712 get_x_content_async_callback,
4713 NULL,
4714 g_object_ref (view));
4715
4716 }
4717
4718 g_object_unref (mount);
4719 }
4720
4721 static void
reset_open_with_menu(FMDirectoryView * view,GList * selection)4722 reset_open_with_menu (FMDirectoryView *view, GList *selection)
4723 {
4724 GList *applications, *node;
4725 gboolean submenu_visible, filter_default;
4726 int num_applications;
4727 int index;
4728 gboolean other_applications_visible;
4729 gboolean open_with_chooser_visible;
4730 GtkUIManager *ui_manager;
4731 GtkAction *action;
4732 GAppInfo *default_app;
4733
4734 /* Clear any previous inserted items in the applications and viewers placeholders */
4735
4736 ui_manager = caja_window_info_get_ui_manager (view->details->window);
4737 caja_ui_unmerge_ui (ui_manager,
4738 &view->details->open_with_merge_id,
4739 &view->details->open_with_action_group);
4740
4741 caja_ui_prepare_merge_ui (ui_manager,
4742 "OpenWithGroup",
4743 &view->details->open_with_merge_id,
4744 &view->details->open_with_action_group);
4745
4746 num_applications = 0;
4747
4748 other_applications_visible = (selection != NULL);
4749 filter_default = (selection != NULL);
4750
4751 default_app = NULL;
4752 if (filter_default) {
4753 default_app = caja_mime_get_default_application_for_files (selection);
4754 }
4755
4756 applications = NULL;
4757 if (other_applications_visible) {
4758 applications = caja_mime_get_applications_for_files (selection);
4759 }
4760
4761 if (g_list_length (selection) == 1) {
4762 add_x_content_apps (view, CAJA_FILE (selection->data), &applications);
4763 }
4764
4765
4766 num_applications = g_list_length (applications);
4767
4768 if (file_list_all_are_folders (selection)) {
4769 submenu_visible = (num_applications > 2);
4770 } else {
4771 submenu_visible = (num_applications > 3);
4772 }
4773
4774 for (node = applications, index = 0; node != NULL; node = node->next, index++) {
4775 GAppInfo *application;
4776 char *menu_path;
4777 char *popup_path;
4778
4779 application = node->data;
4780
4781 if (default_app != NULL && g_app_info_equal (default_app, application)) {
4782 continue;
4783 }
4784
4785 if (submenu_visible) {
4786 menu_path = FM_DIRECTORY_VIEW_MENU_PATH_APPLICATIONS_SUBMENU_PLACEHOLDER;
4787 popup_path = FM_DIRECTORY_VIEW_POPUP_PATH_APPLICATIONS_SUBMENU_PLACEHOLDER;
4788 } else {
4789 menu_path = FM_DIRECTORY_VIEW_MENU_PATH_APPLICATIONS_PLACEHOLDER;
4790 popup_path = FM_DIRECTORY_VIEW_POPUP_PATH_APPLICATIONS_PLACEHOLDER;
4791 }
4792
4793 gtk_ui_manager_add_ui (caja_window_info_get_ui_manager (view->details->window),
4794 view->details->open_with_merge_id,
4795 menu_path,
4796 "separator",
4797 NULL,
4798 GTK_UI_MANAGER_SEPARATOR,
4799 FALSE);
4800
4801 add_application_to_open_with_menu (view,
4802 node->data,
4803 selection,
4804 index,
4805 menu_path, popup_path, submenu_visible);
4806
4807 }
4808 g_list_free_full (applications, g_object_unref);
4809 if (default_app != NULL) {
4810 g_object_unref (default_app);
4811 }
4812
4813 /* Show open parent folder action if we are in search mode */
4814 if (eel_uri_is_search (fm_directory_view_get_uri (view)) && g_list_length (selection) == 1)
4815 add_parent_folder_to_open_menu (view,
4816 selection,
4817 FM_DIRECTORY_VIEW_MENU_PATH_OPEN,
4818 FM_DIRECTORY_VIEW_POPUP_PATH_OPEN);
4819
4820 open_with_chooser_visible = other_applications_visible &&
4821 g_list_length (selection) == 1;
4822
4823 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
4824 if (submenu_visible) {
4825 action = gtk_action_group_get_action (view->details->dir_action_group,
4826 FM_ACTION_OTHER_APPLICATION1);
4827 gtk_action_set_visible (action, open_with_chooser_visible);
4828 action = gtk_action_group_get_action (view->details->dir_action_group,
4829 FM_ACTION_OTHER_APPLICATION2);
4830 gtk_action_set_visible (action, FALSE);
4831 } else {
4832 action = gtk_action_group_get_action (view->details->dir_action_group,
4833 FM_ACTION_OTHER_APPLICATION1);
4834 gtk_action_set_visible (action, FALSE);
4835 action = gtk_action_group_get_action (view->details->dir_action_group,
4836 FM_ACTION_OTHER_APPLICATION2);
4837 gtk_action_set_visible (action, open_with_chooser_visible);
4838 }
4839 G_GNUC_END_IGNORE_DEPRECATIONS;
4840 }
4841
4842 static GList *
get_all_extension_menu_items(GtkWidget * window,GList * selection)4843 get_all_extension_menu_items (GtkWidget *window,
4844 GList *selection)
4845 {
4846 GList *items;
4847 GList *providers;
4848 GList *l;
4849
4850 providers = caja_extensions_get_for_type (CAJA_TYPE_MENU_PROVIDER);
4851 items = NULL;
4852
4853 for (l = providers; l != NULL; l = l->next) {
4854 CajaMenuProvider *provider;
4855 GList *file_items;
4856
4857 provider = CAJA_MENU_PROVIDER (l->data);
4858 file_items = caja_menu_provider_get_file_items (provider,
4859 window,
4860 selection);
4861 items = g_list_concat (items, file_items);
4862 }
4863
4864 caja_module_extension_list_free (providers);
4865
4866 return items;
4867 }
4868
4869 typedef struct
4870 {
4871 CajaMenuItem *item;
4872 FMDirectoryView *view;
4873 GList *selection;
4874 GtkAction *action;
4875 } ExtensionActionCallbackData;
4876
4877
4878 static void
extension_action_callback_data_free(ExtensionActionCallbackData * data)4879 extension_action_callback_data_free (ExtensionActionCallbackData *data)
4880 {
4881 g_object_unref (data->item);
4882 caja_file_list_free (data->selection);
4883
4884 g_free (data);
4885 }
4886
4887 static gboolean
search_in_menu_items(GList * items,const char * item_name)4888 search_in_menu_items (GList* items, const char *item_name)
4889 {
4890 GList* list;
4891
4892 for (list = items; list != NULL; list = list->next) {
4893 CajaMenu* menu;
4894 char *name;
4895
4896 g_object_get (list->data, "name", &name, NULL);
4897 if (strcmp (name, item_name) == 0) {
4898 g_free (name);
4899 return TRUE;
4900 }
4901 g_free (name);
4902
4903 menu = NULL;
4904 g_object_get (list->data, "menu", &menu, NULL);
4905 if (menu != NULL) {
4906 gboolean ret;
4907 GList* submenus;
4908
4909 submenus = caja_menu_get_items (menu);
4910 ret = search_in_menu_items (submenus, item_name);
4911 caja_menu_item_list_free (submenus);
4912 g_object_unref (menu);
4913 if (ret) {
4914 return TRUE;
4915 }
4916 }
4917 }
4918 return FALSE;
4919 }
4920
4921 static void
extension_action_callback(GtkAction * action,gpointer callback_data)4922 extension_action_callback (GtkAction *action,
4923 gpointer callback_data)
4924 {
4925 ExtensionActionCallbackData *data;
4926 char *item_name;
4927 gboolean is_valid;
4928 GList *l;
4929 GList *items;
4930
4931 data = callback_data;
4932
4933 /* Make sure the selected menu item is valid for the final sniffed
4934 * mime type */
4935 g_object_get (data->item, "name", &item_name, NULL);
4936 items = get_all_extension_menu_items (gtk_widget_get_toplevel (GTK_WIDGET (data->view)),
4937 data->selection);
4938
4939 is_valid = search_in_menu_items (items, item_name);
4940
4941 for (l = items; l != NULL; l = l->next) {
4942 g_object_unref (l->data);
4943 }
4944 g_list_free (items);
4945
4946 g_free (item_name);
4947
4948 if (is_valid) {
4949 caja_menu_item_activate (data->item);
4950 }
4951 }
4952
4953 static cairo_surface_t *
get_menu_icon(const char * icon_name,GtkWidget * widget)4954 get_menu_icon (const char *icon_name,
4955 GtkWidget *widget)
4956 {
4957 CajaIconInfo *info;
4958 cairo_surface_t *surface;
4959 int size, scale;
4960
4961 size = caja_get_icon_size_for_stock_size (GTK_ICON_SIZE_MENU);
4962 scale = gtk_widget_get_scale_factor (widget);
4963
4964 if (g_path_is_absolute (icon_name)) {
4965 info = caja_icon_info_lookup_from_path (icon_name, size, scale);
4966 } else {
4967 info = caja_icon_info_lookup_from_name (icon_name, size, scale);
4968 }
4969 surface = caja_icon_info_get_surface_nodefault_at_size (info, size);
4970 g_object_unref (info);
4971
4972 return surface;
4973 }
4974
4975 static cairo_surface_t *
get_menu_icon_for_file(CajaFile * file,GtkWidget * widget)4976 get_menu_icon_for_file (CajaFile *file,
4977 GtkWidget *widget)
4978 {
4979 CajaIconInfo *info;
4980 cairo_surface_t *surface;
4981 int size, scale;
4982
4983 size = caja_get_icon_size_for_stock_size (GTK_ICON_SIZE_MENU);
4984 scale = gtk_widget_get_scale_factor (widget);
4985
4986 info = caja_file_get_icon (file, size, scale, 0);
4987 surface = caja_icon_info_get_surface_nodefault_at_size (info, size);
4988 g_object_unref (info);
4989
4990 return surface;
4991 }
4992
4993 static GtkAction *
add_extension_action_for_files(FMDirectoryView * view,CajaMenuItem * item,GList * files)4994 add_extension_action_for_files (FMDirectoryView *view,
4995 CajaMenuItem *item,
4996 GList *files)
4997 {
4998 char *name, *label, *tip, *icon;
4999 gboolean sensitive, priority;
5000 GtkAction *action;
5001 ExtensionActionCallbackData *data;
5002
5003 g_object_get (G_OBJECT (item),
5004 "name", &name, "label", &label,
5005 "tip", &tip, "icon", &icon,
5006 "sensitive", &sensitive,
5007 "priority", &priority,
5008 NULL);
5009
5010 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
5011 action = gtk_action_new (name,
5012 label,
5013 tip,
5014 icon);
5015 G_GNUC_END_IGNORE_DEPRECATIONS;
5016
5017 if (icon != NULL) {
5018 cairo_surface_t *surface;
5019
5020 surface = get_menu_icon (icon, GTK_WIDGET (view));
5021
5022 if (surface != NULL) {
5023 g_object_set_data_full (G_OBJECT (action), "menu-icon",
5024 surface,
5025 (GDestroyNotify)cairo_surface_destroy);
5026 }
5027 }
5028
5029 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
5030 gtk_action_set_sensitive (action, sensitive);
5031 G_GNUC_END_IGNORE_DEPRECATIONS;
5032 g_object_set (action, "is-important", priority, NULL);
5033
5034 data = g_new0 (ExtensionActionCallbackData, 1);
5035 data->item = g_object_ref (item);
5036 data->view = view;
5037 data->selection = caja_file_list_copy (files);
5038 data->action = action;
5039
5040 g_signal_connect_data (action, "activate",
5041 G_CALLBACK (extension_action_callback),
5042 data,
5043 (GClosureNotify)extension_action_callback_data_free, 0);
5044
5045 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
5046 gtk_action_group_add_action (view->details->extensions_menu_action_group,
5047 GTK_ACTION (action));
5048 G_GNUC_END_IGNORE_DEPRECATIONS;
5049 g_object_unref (action);
5050
5051 g_free (name);
5052 g_free (label);
5053 g_free (tip);
5054 g_free (icon);
5055
5056 return action;
5057 }
5058
5059 static void
add_extension_menu_items(FMDirectoryView * view,GList * files,GList * menu_items,const char * subdirectory)5060 add_extension_menu_items (FMDirectoryView *view,
5061 GList *files,
5062 GList *menu_items,
5063 const char *subdirectory)
5064 {
5065 GtkUIManager *ui_manager;
5066 GList *l;
5067
5068 ui_manager = caja_window_info_get_ui_manager (view->details->window);
5069
5070 for (l = menu_items; l; l = l->next) {
5071 CajaMenuItem *item;
5072 CajaMenu *menu;
5073 GtkAction *action;
5074 const gchar *action_name;
5075 char *path;
5076
5077 item = CAJA_MENU_ITEM (l->data);
5078
5079 g_object_get (item, "menu", &menu, NULL);
5080
5081 action = add_extension_action_for_files (view, item, files);
5082
5083 path = g_build_path ("/", FM_DIRECTORY_VIEW_POPUP_PATH_EXTENSION_ACTIONS, subdirectory, NULL);
5084 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
5085 action_name = gtk_action_get_name (action);
5086 G_GNUC_END_IGNORE_DEPRECATIONS;
5087
5088 gtk_ui_manager_add_ui (ui_manager,
5089 view->details->extensions_menu_merge_id,
5090 path,
5091 action_name,
5092 action_name,
5093 (menu != NULL) ? GTK_UI_MANAGER_MENU : GTK_UI_MANAGER_MENUITEM,
5094 FALSE);
5095 g_free (path);
5096
5097 path = g_build_path ("/", FM_DIRECTORY_VIEW_MENU_PATH_EXTENSION_ACTIONS_PLACEHOLDER, subdirectory, NULL);
5098 gtk_ui_manager_add_ui (ui_manager,
5099 view->details->extensions_menu_merge_id,
5100 path,
5101 action_name,
5102 action_name,
5103 (menu != NULL) ? GTK_UI_MANAGER_MENU : GTK_UI_MANAGER_MENUITEM,
5104 FALSE);
5105 g_free (path);
5106
5107 /* recursively fill the menu */
5108 if (menu != NULL) {
5109 char *subdir;
5110 GList *children;
5111
5112 children = caja_menu_get_items (menu);
5113
5114 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
5115 subdir = g_build_path ("/", subdirectory, gtk_action_get_name (action), NULL);
5116 G_GNUC_END_IGNORE_DEPRECATIONS;
5117 add_extension_menu_items (view,
5118 files,
5119 children,
5120 subdir);
5121
5122 caja_menu_item_list_free (children);
5123 g_free (subdir);
5124 }
5125 }
5126 }
5127
5128 static void
reset_extension_actions_menu(FMDirectoryView * view,GList * selection)5129 reset_extension_actions_menu (FMDirectoryView *view, GList *selection)
5130 {
5131 GList *items;
5132 GtkUIManager *ui_manager;
5133
5134 /* Clear any previous inserted items in the extension actions placeholder */
5135 ui_manager = caja_window_info_get_ui_manager (view->details->window);
5136
5137 caja_ui_unmerge_ui (ui_manager,
5138 &view->details->extensions_menu_merge_id,
5139 &view->details->extensions_menu_action_group);
5140
5141 caja_ui_prepare_merge_ui (ui_manager,
5142 "DirExtensionsMenuGroup",
5143 &view->details->extensions_menu_merge_id,
5144 &view->details->extensions_menu_action_group);
5145
5146 items = get_all_extension_menu_items (gtk_widget_get_toplevel (GTK_WIDGET (view)),
5147 selection);
5148 if (items != NULL) {
5149 add_extension_menu_items (view, selection, items, "");
5150
5151 g_list_free_full (items, g_object_unref);
5152 }
5153 }
5154
5155 static char *
change_to_view_directory(FMDirectoryView * view)5156 change_to_view_directory (FMDirectoryView *view)
5157 {
5158 char *path;
5159 char *old_path;
5160
5161 old_path = g_get_current_dir ();
5162
5163 path = get_view_directory (view);
5164
5165 /* FIXME: What to do about non-local directories? */
5166 if (path != NULL) {
5167 g_chdir (path);
5168 }
5169
5170 g_free (path);
5171
5172 return old_path;
5173 }
5174
5175 static char **
get_file_names_as_parameter_array(GList * selection,CajaDirectory * model)5176 get_file_names_as_parameter_array (GList *selection,
5177 CajaDirectory *model)
5178 {
5179 char **parameters;
5180 GList *node;
5181 GFile *model_location;
5182 int i;
5183 CajaFile *file = NULL;
5184 GFile *file_location = NULL;
5185
5186 if (model == NULL) {
5187 return NULL;
5188 }
5189
5190 parameters = g_new (char *, g_list_length (selection) + 1);
5191
5192 model_location = caja_directory_get_location (model);
5193
5194 for (node = selection, i = 0; node != NULL; node = node->next, i++) {
5195 file = CAJA_FILE (node->data);
5196
5197 if (!caja_file_is_local (file)) {
5198 parameters[i] = NULL;
5199 g_strfreev (parameters);
5200 return NULL;
5201 }
5202
5203 file_location = caja_file_get_location (CAJA_FILE (node->data));
5204 parameters[i] = g_file_get_relative_path (model_location, file_location);
5205 if (parameters[i] == NULL) {
5206 parameters[i] = g_file_get_path (file_location);
5207 }
5208 g_object_unref (file_location);
5209 }
5210
5211 g_object_unref (model_location);
5212
5213 parameters[i] = NULL;
5214 return parameters;
5215 }
5216
5217 static char *
get_file_paths_or_uris_as_newline_delimited_string(GList * selection,gboolean get_paths)5218 get_file_paths_or_uris_as_newline_delimited_string (GList *selection, gboolean get_paths)
5219 {
5220 char *path;
5221 char *result;
5222 CajaDesktopLink *link;
5223 GString *expanding_string;
5224 GList *node;
5225 GFile *location;
5226
5227 expanding_string = g_string_new ("");
5228 for (node = selection; node != NULL; node = node->next) {
5229 char *uri;
5230
5231 uri = NULL;
5232
5233 if (CAJA_IS_DESKTOP_ICON_FILE (node->data)) {
5234 link = caja_desktop_icon_file_get_link (CAJA_DESKTOP_ICON_FILE (node->data));
5235 if (link != NULL) {
5236 location = caja_desktop_link_get_activation_location (link);
5237 uri = g_file_get_uri (location);
5238 g_object_unref (location);
5239 g_object_unref (G_OBJECT (link));
5240 }
5241 } else {
5242 uri = caja_file_get_uri (CAJA_FILE (node->data));
5243 }
5244 if (uri == NULL) {
5245 continue;
5246 }
5247
5248 if (get_paths) {
5249 path = g_filename_from_uri (uri, NULL, NULL);
5250 if (path != NULL) {
5251 g_string_append (expanding_string, path);
5252 g_free (path);
5253 g_string_append (expanding_string, "\n");
5254 }
5255 } else {
5256 g_string_append (expanding_string, uri);
5257 g_string_append (expanding_string, "\n");
5258 }
5259 g_free (uri);
5260 }
5261
5262 result = expanding_string->str;
5263 g_string_free (expanding_string, FALSE);
5264
5265 return result;
5266 }
5267
5268 static char *
get_file_paths_as_newline_delimited_string(GList * selection)5269 get_file_paths_as_newline_delimited_string (GList *selection)
5270 {
5271 return get_file_paths_or_uris_as_newline_delimited_string (selection, TRUE);
5272 }
5273
5274 static char *
get_file_uris_as_newline_delimited_string(GList * selection)5275 get_file_uris_as_newline_delimited_string (GList *selection)
5276 {
5277 return get_file_paths_or_uris_as_newline_delimited_string (selection, FALSE);
5278 }
5279
5280 /* returns newly allocated strings for setting the environment variables */
5281 static void
get_strings_for_environment_variables(FMDirectoryView * view,GList * selected_files,char ** file_paths,char ** uris,char ** uri)5282 get_strings_for_environment_variables (FMDirectoryView *view, GList *selected_files,
5283 char **file_paths, char **uris, char **uri)
5284 {
5285 char *directory_uri;
5286
5287 /* We need to check that the directory uri starts with "file:" since
5288 * caja_directory_is_local returns FALSE for nfs.
5289 */
5290 directory_uri = caja_directory_get_uri (view->details->model);
5291 if (eel_str_has_prefix (directory_uri, "file:") ||
5292 eel_uri_is_desktop (directory_uri) ||
5293 eel_uri_is_trash (directory_uri)) {
5294 *file_paths = get_file_paths_as_newline_delimited_string (selected_files);
5295 } else {
5296 *file_paths = g_strdup ("");
5297 }
5298 g_free (directory_uri);
5299
5300 *uris = get_file_uris_as_newline_delimited_string (selected_files);
5301
5302 *uri = caja_directory_get_uri (view->details->model);
5303 if (eel_uri_is_desktop (*uri)) {
5304 g_free (*uri);
5305 *uri = caja_get_desktop_directory_uri ();
5306 }
5307 }
5308
5309 static FMDirectoryView *
get_directory_view_of_extra_pane(FMDirectoryView * view)5310 get_directory_view_of_extra_pane (FMDirectoryView *view)
5311 {
5312 CajaWindowSlotInfo *slot;
5313
5314 slot = caja_window_info_get_extra_slot (fm_directory_view_get_caja_window (view));
5315 if (slot != NULL) {
5316 CajaView *next_view;
5317
5318 next_view = caja_window_slot_info_get_current_view (slot);
5319
5320 if (FM_IS_DIRECTORY_VIEW (next_view)) {
5321 return FM_DIRECTORY_VIEW (next_view);
5322 }
5323 }
5324 return NULL;
5325 }
5326
5327 /*
5328 * Set up some environment variables that scripts can use
5329 * to take advantage of the current Caja state.
5330 */
set_script_environment_variables(FMDirectoryView * view,GList * selected_files)5331 static void set_script_environment_variables(FMDirectoryView* view, GList* selected_files)
5332 {
5333 char* file_paths;
5334 char* uris;
5335 char* uri;
5336 char* geometry_string;
5337 FMDirectoryView* next_view;
5338
5339 get_strings_for_environment_variables(view, selected_files, &file_paths, &uris, &uri);
5340
5341 g_setenv("CAJA_SCRIPT_SELECTED_FILE_PATHS", file_paths, TRUE);
5342 g_setenv("NAUTILUS_SCRIPT_SELECTED_FILE_PATHS", file_paths, TRUE); // compatibilidad GNOME
5343
5344 g_free(file_paths);
5345
5346 g_setenv("CAJA_SCRIPT_SELECTED_URIS", uris, TRUE);
5347 g_setenv("NAUTILUS_SCRIPT_SELECTED_URIS", uris, TRUE); // compatibilidad GNOME
5348
5349 g_free(uris);
5350
5351 g_setenv("CAJA_SCRIPT_CURRENT_URI", uri, TRUE);
5352 g_setenv("NAUTILUS_SCRIPT_CURRENT_URI", uri, TRUE); // compatibilidad GNOME
5353
5354
5355 g_free(uri);
5356
5357 geometry_string = eel_gtk_window_get_geometry_string(GTK_WINDOW (fm_directory_view_get_containing_window (view)));
5358
5359 g_setenv("CAJA_SCRIPT_WINDOW_GEOMETRY", geometry_string, TRUE);
5360 g_setenv("NAUTILUS_SCRIPT_WINDOW_GEOMETRY", geometry_string, TRUE); // compatibilidad GNOME
5361
5362 g_free(geometry_string);
5363
5364 /* next pane */
5365 next_view = get_directory_view_of_extra_pane(view);
5366
5367 if (next_view)
5368 {
5369 GList* next_pane_selected_files = fm_directory_view_get_selection (next_view);
5370
5371 get_strings_for_environment_variables(next_view, next_pane_selected_files, &file_paths, &uris, &uri);
5372
5373 caja_file_list_free(next_pane_selected_files);
5374 }
5375 else
5376 {
5377 file_paths = g_strdup("");
5378 uris = g_strdup("");
5379 uri = g_strdup("");
5380 }
5381
5382 g_setenv("CAJA_SCRIPT_NEXT_PANE_SELECTED_FILE_PATHS", file_paths, TRUE);
5383 g_setenv("NAUTILUS_SCRIPT_NEXT_PANE_SELECTED_FILE_PATHS", file_paths, TRUE); // compatibilidad GNOME
5384 g_free(file_paths);
5385
5386 g_setenv("CAJA_SCRIPT_NEXT_PANE_SELECTED_URIS", uris, TRUE);
5387 g_setenv("NAUTILUS_SCRIPT_NEXT_PANE_SELECTED_URIS", uris, TRUE); // compatibilidad GNOME
5388 g_free(uris);
5389
5390 g_setenv("CAJA_SCRIPT_NEXT_PANE_CURRENT_URI", uri, TRUE);
5391 g_setenv("NAUTILUS_SCRIPT_NEXT_PANE_CURRENT_URI", uri, TRUE); // compatibilidad GNOME
5392 g_free(uri);
5393 }
5394
5395 /* Unset all the special script environment variables. */
unset_script_environment_variables(void)5396 static void unset_script_environment_variables(void)
5397 {
5398 g_unsetenv("CAJA_SCRIPT_SELECTED_FILE_PATHS");
5399 g_unsetenv("NAUTILUS_SCRIPT_SELECTED_FILE_PATHS");
5400
5401 g_unsetenv("CAJA_SCRIPT_SELECTED_URIS");
5402 g_unsetenv("NAUTILUS_SCRIPT_SELECTED_URIS");
5403
5404 g_unsetenv("CAJA_SCRIPT_CURRENT_URI");
5405 g_unsetenv("NAUTILUS_SCRIPT_CURRENT_URI");
5406
5407 g_unsetenv("CAJA_SCRIPT_WINDOW_GEOMETRY");
5408 g_unsetenv("NAUTILUS_SCRIPT_WINDOW_GEOMETRY");
5409
5410 g_unsetenv("CAJA_SCRIPT_NEXT_PANE_SELECTED_FILE_PATHS");
5411 g_unsetenv("NAUTILUS_SCRIPT_NEXT_PANE_SELECTED_FILE_PATHS");
5412
5413 g_unsetenv("CAJA_SCRIPT_NEXT_PANE_SELECTED_URIS");
5414 g_unsetenv("NAUTILUS_SCRIPT_NEXT_PANE_SELECTED_URIS");
5415
5416 g_unsetenv("CAJA_SCRIPT_NEXT_PANE_CURRENT_URI");
5417 g_unsetenv("NAUTILUS_SCRIPT_NEXT_PANE_CURRENT_URI");
5418 }
5419
5420 static void
run_script_callback(GtkAction * action,gpointer callback_data)5421 run_script_callback (GtkAction *action, gpointer callback_data)
5422 {
5423 ScriptLaunchParameters *launch_parameters;
5424 GdkScreen *screen;
5425 GList *selected_files;
5426 char *file_uri;
5427 char *local_file_path;
5428 char *quoted_path;
5429 char *old_working_dir;
5430 char **parameters, *name;
5431 GtkWindow *window;
5432
5433 launch_parameters = (ScriptLaunchParameters *) callback_data;
5434
5435 file_uri = caja_file_get_uri (launch_parameters->file);
5436 local_file_path = g_filename_from_uri (file_uri, NULL, NULL);
5437 g_assert (local_file_path != NULL);
5438 g_free (file_uri);
5439
5440 quoted_path = g_shell_quote (local_file_path);
5441
5442 old_working_dir = change_to_view_directory (launch_parameters->directory_view);
5443
5444 selected_files = fm_directory_view_get_selection (launch_parameters->directory_view);
5445 set_script_environment_variables (launch_parameters->directory_view, selected_files);
5446
5447 parameters = get_file_names_as_parameter_array (selected_files,
5448 launch_parameters->directory_view->details->model);
5449
5450 screen = gtk_widget_get_screen (GTK_WIDGET (launch_parameters->directory_view));
5451
5452 name = caja_file_get_name (launch_parameters->file);
5453 /* FIXME: handle errors with dialog? Or leave up to each script? */
5454 window = fm_directory_view_get_containing_window (launch_parameters->directory_view);
5455 caja_debug_log (FALSE, CAJA_DEBUG_LOG_DOMAIN_USER,
5456 "directory view run_script_callback, window=%p, name=\"%s\", script_path=\"%s\" (omitting script parameters)",
5457 window, name, local_file_path);
5458 caja_launch_application_from_command_array (screen, name, quoted_path, FALSE,
5459 (const char * const *) parameters);
5460 g_free (local_file_path);
5461 g_free (name);
5462 g_strfreev (parameters);
5463
5464 caja_file_list_free (selected_files);
5465 unset_script_environment_variables ();
5466 g_chdir (old_working_dir);
5467 g_free (old_working_dir);
5468 g_free (quoted_path);
5469 }
5470
5471 static void
add_script_to_scripts_menus(FMDirectoryView * directory_view,CajaFile * file,const char * menu_path,const char * popup_path,const char * popup_bg_path)5472 add_script_to_scripts_menus (FMDirectoryView *directory_view,
5473 CajaFile *file,
5474 const char *menu_path,
5475 const char *popup_path,
5476 const char *popup_bg_path)
5477 {
5478 ScriptLaunchParameters *launch_parameters;
5479 char *tip;
5480 char *name;
5481 char *uri;
5482 char *action_name;
5483 char *escaped_label;
5484 cairo_surface_t *surface;
5485 GtkUIManager *ui_manager;
5486 GtkAction *action;
5487
5488 name = caja_file_get_display_name (file);
5489 uri = caja_file_get_uri (file);
5490 tip = g_strdup_printf (_("Run \"%s\" on any selected items"), name);
5491
5492 launch_parameters = script_launch_parameters_new (file, directory_view);
5493
5494 action_name = escape_action_name (uri, "script_");
5495 escaped_label = eel_str_double_underscores (name);
5496
5497 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
5498 action = gtk_action_new (action_name,
5499 escaped_label,
5500 tip,
5501 NULL);
5502 G_GNUC_END_IGNORE_DEPRECATIONS;
5503
5504 surface = get_menu_icon_for_file (file, GTK_WIDGET (directory_view));
5505 if (surface != NULL) {
5506 g_object_set_data_full (G_OBJECT (action), "menu-icon",
5507 surface,
5508 (GDestroyNotify)cairo_surface_destroy);
5509 }
5510
5511 g_signal_connect_data (action, "activate",
5512 G_CALLBACK (run_script_callback),
5513 launch_parameters,
5514 (GClosureNotify)script_launch_parameters_free, 0);
5515
5516 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
5517 gtk_action_group_add_action_with_accel (directory_view->details->scripts_action_group,
5518 action, NULL);
5519 G_GNUC_END_IGNORE_DEPRECATIONS;
5520 g_object_unref (action);
5521
5522 ui_manager = caja_window_info_get_ui_manager (directory_view->details->window);
5523
5524 gtk_ui_manager_add_ui (ui_manager,
5525 directory_view->details->scripts_merge_id,
5526 menu_path,
5527 action_name,
5528 action_name,
5529 GTK_UI_MANAGER_MENUITEM,
5530 FALSE);
5531 gtk_ui_manager_add_ui (ui_manager,
5532 directory_view->details->scripts_merge_id,
5533 popup_path,
5534 action_name,
5535 action_name,
5536 GTK_UI_MANAGER_MENUITEM,
5537 FALSE);
5538 gtk_ui_manager_add_ui (ui_manager,
5539 directory_view->details->scripts_merge_id,
5540 popup_bg_path,
5541 action_name,
5542 action_name,
5543 GTK_UI_MANAGER_MENUITEM,
5544 FALSE);
5545
5546 g_free (name);
5547 g_free (uri);
5548 g_free (tip);
5549 g_free (action_name);
5550 g_free (escaped_label);
5551 }
5552
5553 static void
add_submenu_to_directory_menus(FMDirectoryView * directory_view,GtkActionGroup * action_group,guint merge_id,CajaFile * file,const char * menu_path,const char * popup_path,const char * popup_bg_path)5554 add_submenu_to_directory_menus (FMDirectoryView *directory_view,
5555 GtkActionGroup *action_group,
5556 guint merge_id,
5557 CajaFile *file,
5558 const char *menu_path,
5559 const char *popup_path,
5560 const char *popup_bg_path)
5561 {
5562 char *name;
5563 cairo_surface_t *surface;
5564 char *uri;
5565 GtkUIManager *ui_manager;
5566
5567 ui_manager = caja_window_info_get_ui_manager (directory_view->details->window);
5568 uri = caja_file_get_uri (file);
5569 name = caja_file_get_display_name (file);
5570 surface = get_menu_icon_for_file (file, GTK_WIDGET (directory_view));
5571 add_submenu (ui_manager, action_group, merge_id, menu_path, uri, name, surface, TRUE);
5572 add_submenu (ui_manager, action_group, merge_id, popup_path, uri, name, surface, FALSE);
5573 add_submenu (ui_manager, action_group, merge_id, popup_bg_path, uri, name, surface, FALSE);
5574 if (surface) {
5575 cairo_surface_destroy (surface);
5576 }
5577 g_free (name);
5578 g_free (uri);
5579 }
5580
5581 static gboolean
directory_belongs_in_scripts_menu(const char * uri)5582 directory_belongs_in_scripts_menu (const char *uri)
5583 {
5584 int num_levels;
5585 int i;
5586
5587 if (!eel_str_has_prefix (uri, scripts_directory_uri)) {
5588 return FALSE;
5589 }
5590
5591 num_levels = 0;
5592 for (i = scripts_directory_uri_length; uri[i] != '\0'; i++) {
5593 if (uri[i] == '/') {
5594 num_levels++;
5595 }
5596 }
5597
5598 if (num_levels > MAX_MENU_LEVELS) {
5599 return FALSE;
5600 }
5601
5602 return TRUE;
5603 }
5604
5605 static gboolean
update_directory_in_scripts_menu(FMDirectoryView * view,CajaDirectory * directory)5606 update_directory_in_scripts_menu (FMDirectoryView *view, CajaDirectory *directory)
5607 {
5608 char *menu_path, *popup_path, *popup_bg_path;
5609 GList *file_list, *filtered, *node;
5610 gboolean any_scripts;
5611 CajaDirectory *dir;
5612 char *uri;
5613 char *escaped_path;
5614 CajaFile *file = NULL;
5615
5616 uri = caja_directory_get_uri (directory);
5617 escaped_path = escape_action_path (uri + scripts_directory_uri_length);
5618 g_free (uri);
5619 menu_path = g_strconcat (FM_DIRECTORY_VIEW_MENU_PATH_SCRIPTS_PLACEHOLDER,
5620 escaped_path,
5621 NULL);
5622 popup_path = g_strconcat (FM_DIRECTORY_VIEW_POPUP_PATH_SCRIPTS_PLACEHOLDER,
5623 escaped_path,
5624 NULL);
5625 popup_bg_path = g_strconcat (FM_DIRECTORY_VIEW_POPUP_PATH_BACKGROUND_SCRIPTS_PLACEHOLDER,
5626 escaped_path,
5627 NULL);
5628 g_free (escaped_path);
5629
5630 file_list = caja_directory_get_file_list (directory);
5631 filtered = caja_file_list_filter_hidden (file_list, FALSE);
5632 caja_file_list_free (file_list);
5633
5634 file_list = caja_file_list_sort_by_display_name (filtered);
5635
5636 any_scripts = FALSE;
5637 for (node = file_list; node != NULL; node = node->next) {
5638 file = node->data;
5639
5640 if (caja_file_is_launchable (file)) {
5641 add_script_to_scripts_menus (view, file, menu_path, popup_path, popup_bg_path);
5642 any_scripts = TRUE;
5643 } else if (caja_file_is_directory (file)) {
5644 uri = caja_file_get_uri (file);
5645 if (directory_belongs_in_scripts_menu (uri)) {
5646 dir = caja_directory_get_by_uri (uri);
5647 add_directory_to_scripts_directory_list (view, dir);
5648 caja_directory_unref (dir);
5649
5650 add_submenu_to_directory_menus (view,
5651 view->details->scripts_action_group,
5652 view->details->scripts_merge_id,
5653 file, menu_path, popup_path, popup_bg_path);
5654
5655 any_scripts = TRUE;
5656 }
5657 g_free (uri);
5658 }
5659 }
5660
5661 caja_file_list_free (file_list);
5662
5663 g_free (popup_path);
5664 g_free (popup_bg_path);
5665 g_free (menu_path);
5666
5667 return any_scripts;
5668 }
5669
5670 static void
update_scripts_menu(FMDirectoryView * view)5671 update_scripts_menu (FMDirectoryView *view)
5672 {
5673 gboolean any_scripts;
5674 GList *sorted_copy, *node;
5675 GtkUIManager *ui_manager;
5676 GtkAction *action;
5677 CajaDirectory *directory = NULL;
5678
5679 /* There is a race condition here. If we don't mark the scripts menu as
5680 valid before we begin our task then we can lose script menu updates that
5681 occur before we finish. */
5682 view->details->scripts_invalid = FALSE;
5683
5684 ui_manager = caja_window_info_get_ui_manager (view->details->window);
5685 caja_ui_unmerge_ui (ui_manager,
5686 &view->details->scripts_merge_id,
5687 &view->details->scripts_action_group);
5688
5689 caja_ui_prepare_merge_ui (ui_manager,
5690 "ScriptsGroup",
5691 &view->details->scripts_merge_id,
5692 &view->details->scripts_action_group);
5693
5694 /* As we walk through the directories, remove any that no longer belong. */
5695 any_scripts = FALSE;
5696 sorted_copy = caja_directory_list_sort_by_uri
5697 (caja_directory_list_copy (view->details->scripts_directory_list));
5698 for (node = sorted_copy; node != NULL; node = node->next) {
5699 char *uri;
5700
5701 directory = node->data;
5702
5703 uri = caja_directory_get_uri (directory);
5704 if (!directory_belongs_in_scripts_menu (uri)) {
5705 remove_directory_from_scripts_directory_list (view, directory);
5706 } else if (update_directory_in_scripts_menu (view, directory)) {
5707 any_scripts = TRUE;
5708 }
5709 g_free (uri);
5710 }
5711 caja_directory_list_free (sorted_copy);
5712
5713 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
5714 action = gtk_action_group_get_action (view->details->dir_action_group, FM_ACTION_SCRIPTS);
5715 gtk_action_set_visible (action, any_scripts);
5716 G_GNUC_END_IGNORE_DEPRECATIONS;
5717 }
5718
5719 static void
create_template_callback(GtkAction * action,gpointer callback_data)5720 create_template_callback (GtkAction *action, gpointer callback_data)
5721 {
5722 CreateTemplateParameters *parameters;
5723
5724 parameters = callback_data;
5725
5726 fm_directory_view_new_file (parameters->directory_view, NULL, parameters->file);
5727 }
5728
5729 static void
add_template_to_templates_menus(FMDirectoryView * directory_view,CajaFile * file,const char * menu_path,const char * popup_bg_path)5730 add_template_to_templates_menus (FMDirectoryView *directory_view,
5731 CajaFile *file,
5732 const char *menu_path,
5733 const char *popup_bg_path)
5734 {
5735 char *tmp, *tip, *uri, *name;
5736 char *escaped_label;
5737 cairo_surface_t *surface;
5738 char *action_name;
5739 CreateTemplateParameters *parameters;
5740 GtkUIManager *ui_manager;
5741 GtkAction *action;
5742
5743 tmp = caja_file_get_display_name (file);
5744 name = eel_filename_strip_extension (tmp);
5745 g_free (tmp);
5746
5747 uri = caja_file_get_uri (file);
5748 tip = g_strdup_printf (_("Create Document from template \"%s\""), name);
5749
5750 action_name = escape_action_name (uri, "template_");
5751 escaped_label = eel_str_double_underscores (name);
5752
5753 parameters = create_template_parameters_new (file, directory_view);
5754
5755 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
5756 action = gtk_action_new (action_name,
5757 escaped_label,
5758 tip,
5759 NULL);
5760 G_GNUC_END_IGNORE_DEPRECATIONS;
5761
5762 surface = get_menu_icon_for_file (file, GTK_WIDGET (directory_view));
5763 if (surface != NULL) {
5764 g_object_set_data_full (G_OBJECT (action), "menu-icon",
5765 surface,
5766 (GDestroyNotify)cairo_surface_destroy);
5767 }
5768
5769 g_signal_connect_data (action, "activate",
5770 G_CALLBACK (create_template_callback),
5771 parameters,
5772 (GClosureNotify)create_templates_parameters_free, 0);
5773
5774 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
5775 gtk_action_group_add_action (directory_view->details->templates_action_group,
5776 action);
5777 G_GNUC_END_IGNORE_DEPRECATIONS;
5778 g_object_unref (action);
5779
5780 ui_manager = caja_window_info_get_ui_manager (directory_view->details->window);
5781
5782 gtk_ui_manager_add_ui (ui_manager,
5783 directory_view->details->templates_merge_id,
5784 menu_path,
5785 action_name,
5786 action_name,
5787 GTK_UI_MANAGER_MENUITEM,
5788 FALSE);
5789
5790 gtk_ui_manager_add_ui (ui_manager,
5791 directory_view->details->templates_merge_id,
5792 popup_bg_path,
5793 action_name,
5794 action_name,
5795 GTK_UI_MANAGER_MENUITEM,
5796 FALSE);
5797
5798 g_free (escaped_label);
5799 g_free (name);
5800 g_free (tip);
5801 g_free (uri);
5802 g_free (action_name);
5803 }
5804
5805 static void
update_templates_directory(FMDirectoryView * view)5806 update_templates_directory (FMDirectoryView *view)
5807 {
5808 GList *node, *next;
5809
5810 for (node = view->details->templates_directory_list; node != NULL; node = next) {
5811 next = node->next;
5812 remove_directory_from_templates_directory_list (view, node->data);
5813 }
5814
5815 if (caja_should_use_templates_directory ()) {
5816 CajaDirectory *templates_directory;
5817 char *templates_uri;
5818
5819 templates_uri = caja_get_templates_directory_uri ();
5820 templates_directory = caja_directory_get_by_uri (templates_uri);
5821 g_free (templates_uri);
5822 add_directory_to_templates_directory_list (view, templates_directory);
5823 caja_directory_unref (templates_directory);
5824 }
5825 }
5826
5827 static void
user_dirs_changed(FMDirectoryView * view)5828 user_dirs_changed (FMDirectoryView *view)
5829 {
5830 update_templates_directory (view);
5831 view->details->templates_invalid = TRUE;
5832 schedule_update_menus (view);
5833 }
5834
5835 static gboolean
directory_belongs_in_templates_menu(const char * templates_directory_uri,const char * uri)5836 directory_belongs_in_templates_menu (const char *templates_directory_uri,
5837 const char *uri)
5838 {
5839 int num_levels;
5840 int i;
5841
5842 if (templates_directory_uri == NULL) {
5843 return FALSE;
5844 }
5845
5846 if (!g_str_has_prefix (uri, templates_directory_uri)) {
5847 return FALSE;
5848 }
5849
5850 num_levels = 0;
5851 for (i = strlen (templates_directory_uri); uri[i] != '\0'; i++) {
5852 if (uri[i] == '/') {
5853 num_levels++;
5854 }
5855 }
5856
5857 if (num_levels > MAX_MENU_LEVELS) {
5858 return FALSE;
5859 }
5860
5861 return TRUE;
5862 }
5863
5864 static gboolean
update_directory_in_templates_menu(FMDirectoryView * view,const char * templates_directory_uri,CajaDirectory * directory)5865 update_directory_in_templates_menu (FMDirectoryView *view,
5866 const char *templates_directory_uri,
5867 CajaDirectory *directory)
5868 {
5869 char *menu_path, *popup_bg_path;
5870 GList *file_list, *filtered, *node;
5871 gboolean any_templates;
5872 CajaDirectory *dir;
5873 char *escaped_path;
5874 char *uri;
5875 int num;
5876 CajaFile *file = NULL;
5877
5878 /* We know this directory belongs to the template dir, so it must exist */
5879 g_assert (templates_directory_uri);
5880
5881 uri = caja_directory_get_uri (directory);
5882 escaped_path = escape_action_path (uri + strlen (templates_directory_uri));
5883 g_free (uri);
5884 menu_path = g_strconcat (FM_DIRECTORY_VIEW_MENU_PATH_NEW_DOCUMENTS_PLACEHOLDER,
5885 escaped_path,
5886 NULL);
5887 popup_bg_path = g_strconcat (FM_DIRECTORY_VIEW_POPUP_PATH_BACKGROUND_NEW_DOCUMENTS_PLACEHOLDER,
5888 escaped_path,
5889 NULL);
5890 g_free (escaped_path);
5891
5892 file_list = caja_directory_get_file_list (directory);
5893 filtered = caja_file_list_filter_hidden (file_list, FALSE);
5894 caja_file_list_free (file_list);
5895
5896 file_list = caja_file_list_sort_by_display_name (filtered);
5897
5898 num = 0;
5899 any_templates = FALSE;
5900 for (node = file_list; num < TEMPLATE_LIMIT && node != NULL; node = node->next, num++) {
5901 file = node->data;
5902
5903 if (caja_file_is_directory (file)) {
5904 uri = caja_file_get_uri (file);
5905 if (directory_belongs_in_templates_menu (templates_directory_uri, uri)) {
5906 dir = caja_directory_get_by_uri (uri);
5907 add_directory_to_templates_directory_list (view, dir);
5908 caja_directory_unref (dir);
5909
5910 add_submenu_to_directory_menus (view,
5911 view->details->templates_action_group,
5912 view->details->templates_merge_id,
5913 file, menu_path, NULL, popup_bg_path);
5914
5915 any_templates = TRUE;
5916 }
5917 g_free (uri);
5918 } else if (caja_file_can_read (file)) {
5919 add_template_to_templates_menus (view, file, menu_path, popup_bg_path);
5920 any_templates = TRUE;
5921 }
5922 }
5923
5924 caja_file_list_free (file_list);
5925
5926 g_free (popup_bg_path);
5927 g_free (menu_path);
5928
5929 return any_templates;
5930 }
5931
5932
5933
5934 static void
update_templates_menu(FMDirectoryView * view)5935 update_templates_menu (FMDirectoryView *view)
5936 {
5937 gboolean any_templates;
5938 GList *sorted_copy, *node;
5939 GtkUIManager *ui_manager;
5940 GtkAction *action;
5941 char *templates_directory_uri;
5942 CajaDirectory *directory = NULL;
5943
5944 if (caja_should_use_templates_directory ()) {
5945 templates_directory_uri = caja_get_templates_directory_uri ();
5946 } else {
5947 templates_directory_uri = NULL;
5948 }
5949
5950 /* There is a race condition here. If we don't mark the scripts menu as
5951 valid before we begin our task then we can lose template menu updates that
5952 occur before we finish. */
5953 view->details->templates_invalid = FALSE;
5954
5955 ui_manager = caja_window_info_get_ui_manager (view->details->window);
5956 caja_ui_unmerge_ui (ui_manager,
5957 &view->details->templates_merge_id,
5958 &view->details->templates_action_group);
5959
5960 caja_ui_prepare_merge_ui (ui_manager,
5961 "TemplatesGroup",
5962 &view->details->templates_merge_id,
5963 &view->details->templates_action_group);
5964
5965 /* As we walk through the directories, remove any that no longer belong. */
5966 any_templates = FALSE;
5967 sorted_copy = caja_directory_list_sort_by_uri
5968 (caja_directory_list_copy (view->details->templates_directory_list));
5969 for (node = sorted_copy; node != NULL; node = node->next) {
5970 char *uri;
5971
5972 directory = node->data;
5973
5974 uri = caja_directory_get_uri (directory);
5975 if (!directory_belongs_in_templates_menu (templates_directory_uri, uri)) {
5976 remove_directory_from_templates_directory_list (view, directory);
5977 } else if (update_directory_in_templates_menu (view,
5978 templates_directory_uri,
5979 directory)) {
5980 any_templates = TRUE;
5981 }
5982 g_free (uri);
5983 }
5984 caja_directory_list_free (sorted_copy);
5985
5986 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
5987 action = gtk_action_group_get_action (view->details->dir_action_group, FM_ACTION_NO_TEMPLATES);
5988 gtk_action_set_visible (action, !any_templates);
5989 G_GNUC_END_IGNORE_DEPRECATIONS;
5990
5991 g_free (templates_directory_uri);
5992 }
5993
5994
5995 static void
action_open_scripts_folder_callback(GtkAction * action,gpointer callback_data)5996 action_open_scripts_folder_callback (GtkAction *action,
5997 gpointer callback_data)
5998 {
5999 FMDirectoryView *view;
6000
6001 view = FM_DIRECTORY_VIEW (callback_data);
6002
6003 open_location (view, scripts_directory_uri, CAJA_WINDOW_OPEN_ACCORDING_TO_MODE, 0);
6004
6005 eel_show_info_dialog_with_details
6006 (_("All executable files in this folder will appear in the "
6007 "Scripts menu."),
6008 _("Choosing a script from the menu will run "
6009 "that script with any selected items as input."),
6010 _("All executable files in this folder will appear in the "
6011 "Scripts menu. Choosing a script from the menu will run "
6012 "that script.\n\n"
6013 "When executed from a local folder, scripts will be passed "
6014 "the selected file names. When executed from a remote folder "
6015 "(e.g. a folder showing web or ftp content), scripts will "
6016 "be passed no parameters.\n\n"
6017 "In all cases, the following environment variables will be "
6018 "set by Caja, which the scripts may use:\n\n"
6019 "CAJA_SCRIPT_SELECTED_FILE_PATHS: newline-delimited paths for selected files (only if local)\n\n"
6020 "CAJA_SCRIPT_SELECTED_URIS: newline-delimited URIs for selected files\n\n"
6021 "CAJA_SCRIPT_CURRENT_URI: URI for current location\n\n"
6022 "CAJA_SCRIPT_WINDOW_GEOMETRY: position and size of current window\n\n"
6023 "CAJA_SCRIPT_NEXT_PANE_SELECTED_FILE_PATHS: newline-delimited paths for selected files in the inactive pane of a split-view window (only if local)\n\n"
6024 "CAJA_SCRIPT_NEXT_PANE_SELECTED_URIS: newline-delimited URIs for selected files in the inactive pane of a split-view window\n\n"
6025 "CAJA_SCRIPT_NEXT_PANE_CURRENT_URI: URI for current location in the inactive pane of a split-view window"),
6026 fm_directory_view_get_containing_window (view));
6027 }
6028
6029 static GtkMenu *
create_popup_menu(FMDirectoryView * view,const char * popup_path)6030 create_popup_menu (FMDirectoryView *view, const char *popup_path)
6031 {
6032 GtkWidget *menu;
6033
6034 menu = gtk_ui_manager_get_widget (caja_window_info_get_ui_manager (view->details->window),
6035 popup_path);
6036 gtk_menu_set_screen (GTK_MENU (menu),
6037 gtk_widget_get_screen (GTK_WIDGET (view)));
6038 gtk_widget_show (GTK_WIDGET (menu));
6039
6040 return GTK_MENU (menu);
6041 }
6042
6043 static void
copy_or_cut_files(FMDirectoryView * view,GList * clipboard_contents,gboolean cut)6044 copy_or_cut_files (FMDirectoryView *view,
6045 GList *clipboard_contents,
6046 gboolean cut)
6047 {
6048 int count;
6049 char *status_string;
6050 CajaClipboardInfo info;
6051 GtkTargetList *target_list;
6052 GtkTargetEntry *targets;
6053 int n_targets;
6054
6055 info.files = clipboard_contents;
6056 info.cut = cut;
6057
6058 target_list = gtk_target_list_new (NULL, 0);
6059 gtk_target_list_add (target_list, copied_files_atom, 0, 0);
6060 gtk_target_list_add_uri_targets (target_list, 0);
6061 gtk_target_list_add_text_targets (target_list, 0);
6062
6063 targets = gtk_target_table_new_from_list (target_list, &n_targets);
6064 gtk_target_list_unref (target_list);
6065
6066 gtk_clipboard_set_with_data (caja_clipboard_get (GTK_WIDGET (view)),
6067 targets, n_targets,
6068 caja_get_clipboard_callback, caja_clear_clipboard_callback,
6069 NULL);
6070 gtk_target_table_free (targets, n_targets);
6071
6072 caja_clipboard_monitor_set_clipboard_info (caja_clipboard_monitor_get (), &info);
6073
6074 count = g_list_length (clipboard_contents);
6075 if (count == 1) {
6076 char *name;
6077
6078 name = caja_file_get_display_name (clipboard_contents->data);
6079 if (cut) {
6080 status_string = g_strdup_printf (_("\"%s\" will be moved "
6081 "if you select the Paste command"),
6082 name);
6083 } else {
6084 status_string = g_strdup_printf (_("\"%s\" will be copied "
6085 "if you select the Paste command"),
6086 name);
6087 }
6088 g_free (name);
6089 } else {
6090 if (cut) {
6091 status_string = g_strdup_printf (ngettext("The %'d selected item will be moved "
6092 "if you select the Paste command",
6093 "The %'d selected items will be moved "
6094 "if you select the Paste command",
6095 count),
6096 count);
6097 } else {
6098 status_string = g_strdup_printf (ngettext("The %'d selected item will be copied "
6099 "if you select the Paste command",
6100 "The %'d selected items will be copied "
6101 "if you select the Paste command",
6102 count),
6103 count);
6104 }
6105 }
6106
6107 caja_window_slot_info_set_status (view->details->slot,
6108 status_string);
6109 g_free (status_string);
6110 }
6111
6112 static void
action_copy_files_callback(GtkAction * action,gpointer callback_data)6113 action_copy_files_callback (GtkAction *action,
6114 gpointer callback_data)
6115 {
6116 FMDirectoryView *view;
6117 GList *selection;
6118
6119 view = FM_DIRECTORY_VIEW (callback_data);
6120
6121 selection = fm_directory_view_get_selection_for_file_transfer (view);
6122 copy_or_cut_files (view, selection, FALSE);
6123 caja_file_list_free (selection);
6124 }
6125
6126 static void
move_copy_selection_to_location(FMDirectoryView * view,int copy_action,char * target_uri)6127 move_copy_selection_to_location (FMDirectoryView *view,
6128 int copy_action,
6129 char *target_uri)
6130 {
6131 GList *selection, *uris, *l;
6132
6133 selection = fm_directory_view_get_selection_for_file_transfer (view);
6134 if (selection == NULL) {
6135 return;
6136 }
6137
6138 uris = NULL;
6139 for (l = selection; l != NULL; l = l->next) {
6140 uris = g_list_prepend (uris,
6141 caja_file_get_uri ((CajaFile *) l->data));
6142 }
6143 uris = g_list_reverse (uris);
6144
6145 fm_directory_view_move_copy_items (uris, NULL, target_uri,
6146 copy_action,
6147 0, 0,
6148 view);
6149
6150 g_list_free_full (uris, g_free);
6151 caja_file_list_free (selection);
6152 }
6153
6154 static void
move_copy_selection_to_next_pane(FMDirectoryView * view,int copy_action)6155 move_copy_selection_to_next_pane (FMDirectoryView *view,
6156 int copy_action)
6157 {
6158 CajaWindowSlotInfo *slot;
6159 char *dest_location;
6160
6161 slot = caja_window_info_get_extra_slot (fm_directory_view_get_caja_window (view));
6162 g_return_if_fail (slot != NULL);
6163
6164 dest_location = caja_window_slot_info_get_current_location (slot);
6165 g_return_if_fail (dest_location != NULL);
6166
6167 move_copy_selection_to_location (view, copy_action, dest_location);
6168 }
6169
6170 static void
action_copy_to_next_pane_callback(GtkAction * action,gpointer callback_data)6171 action_copy_to_next_pane_callback (GtkAction *action, gpointer callback_data)
6172 {
6173 FMDirectoryView *view;
6174
6175 view = FM_DIRECTORY_VIEW (callback_data);
6176 move_copy_selection_to_next_pane (view,
6177 GDK_ACTION_COPY);
6178 }
6179
6180 static void
action_move_to_next_pane_callback(GtkAction * action,gpointer callback_data)6181 action_move_to_next_pane_callback (GtkAction *action, gpointer callback_data)
6182 {
6183 CajaWindowSlotInfo *slot;
6184 char *dest_location;
6185 FMDirectoryView *view;
6186
6187 view = FM_DIRECTORY_VIEW (callback_data);
6188
6189 slot = caja_window_info_get_extra_slot (fm_directory_view_get_caja_window (view));
6190 g_return_if_fail (slot != NULL);
6191
6192 dest_location = caja_window_slot_info_get_current_location (slot);
6193 g_return_if_fail (dest_location != NULL);
6194
6195 move_copy_selection_to_location (view, GDK_ACTION_MOVE, dest_location);
6196 }
6197
6198 static void
action_copy_to_home_callback(GtkAction * action,gpointer callback_data)6199 action_copy_to_home_callback (GtkAction *action, gpointer callback_data)
6200 {
6201 FMDirectoryView *view;
6202 char *dest_location;
6203
6204 view = FM_DIRECTORY_VIEW (callback_data);
6205
6206 dest_location = caja_get_home_directory_uri ();
6207 move_copy_selection_to_location (view, GDK_ACTION_COPY, dest_location);
6208 g_free (dest_location);
6209 }
6210
6211 static void
action_move_to_home_callback(GtkAction * action,gpointer callback_data)6212 action_move_to_home_callback (GtkAction *action, gpointer callback_data)
6213 {
6214 FMDirectoryView *view;
6215 char *dest_location;
6216
6217 view = FM_DIRECTORY_VIEW (callback_data);
6218
6219 dest_location = caja_get_home_directory_uri ();
6220 move_copy_selection_to_location (view, GDK_ACTION_MOVE, dest_location);
6221 g_free (dest_location);
6222 }
6223
6224 static void
action_copy_to_desktop_callback(GtkAction * action,gpointer callback_data)6225 action_copy_to_desktop_callback (GtkAction *action, gpointer callback_data)
6226 {
6227 FMDirectoryView *view;
6228 char *dest_location;
6229
6230 view = FM_DIRECTORY_VIEW (callback_data);
6231
6232 dest_location = caja_get_desktop_directory_uri ();
6233 move_copy_selection_to_location (view, GDK_ACTION_COPY, dest_location);
6234 g_free (dest_location);
6235 }
6236
6237 static void
action_move_to_desktop_callback(GtkAction * action,gpointer callback_data)6238 action_move_to_desktop_callback (GtkAction *action, gpointer callback_data)
6239 {
6240 FMDirectoryView *view;
6241 char *dest_location;
6242
6243 view = FM_DIRECTORY_VIEW (callback_data);
6244
6245 dest_location = caja_get_desktop_directory_uri ();
6246 move_copy_selection_to_location (view, GDK_ACTION_MOVE, dest_location);
6247 g_free (dest_location);
6248 }
6249
6250 static void
action_cut_files_callback(GtkAction * action,gpointer callback_data)6251 action_cut_files_callback (GtkAction *action,
6252 gpointer callback_data)
6253 {
6254 FMDirectoryView *view;
6255 GList *selection;
6256
6257 view = FM_DIRECTORY_VIEW (callback_data);
6258
6259 selection = fm_directory_view_get_selection_for_file_transfer (view);
6260 copy_or_cut_files (view, selection, TRUE);
6261 caja_file_list_free (selection);
6262 }
6263
6264 static void
paste_clipboard_data(FMDirectoryView * view,GtkSelectionData * selection_data,char * destination_uri)6265 paste_clipboard_data (FMDirectoryView *view,
6266 GtkSelectionData *selection_data,
6267 char *destination_uri)
6268 {
6269 gboolean cut;
6270 GList *item_uris;
6271
6272 cut = FALSE;
6273 item_uris = caja_clipboard_get_uri_list_from_selection_data (selection_data, &cut,
6274 copied_files_atom);
6275
6276 if (item_uris == NULL|| destination_uri == NULL) {
6277 caja_window_slot_info_set_status (view->details->slot,
6278 _("There is nothing on the clipboard to paste."));
6279 } else {
6280 fm_directory_view_move_copy_items (item_uris, NULL, destination_uri,
6281 cut ? GDK_ACTION_MOVE : GDK_ACTION_COPY,
6282 0, 0,
6283 view);
6284
6285 /* If items are cut then remove from clipboard */
6286 if (cut) {
6287 gtk_clipboard_clear (caja_clipboard_get (GTK_WIDGET (view)));
6288 }
6289
6290 g_list_free_full (item_uris, g_free);
6291 }
6292 }
6293
6294 static void
paste_clipboard_received_callback(GtkClipboard * clipboard,GtkSelectionData * selection_data,gpointer data)6295 paste_clipboard_received_callback (GtkClipboard *clipboard,
6296 GtkSelectionData *selection_data,
6297 gpointer data)
6298 {
6299 FMDirectoryView *view;
6300 char *view_uri;
6301
6302 view = FM_DIRECTORY_VIEW (data);
6303
6304 view_uri = fm_directory_view_get_backing_uri (view);
6305
6306 if (view->details->window != NULL) {
6307 paste_clipboard_data (view, selection_data, view_uri);
6308 }
6309
6310 g_free (view_uri);
6311
6312 g_object_unref (view);
6313 }
6314
6315 typedef struct {
6316 FMDirectoryView *view;
6317 CajaFile *target;
6318 } PasteIntoData;
6319
6320 static void
paste_into_clipboard_received_callback(GtkClipboard * clipboard,GtkSelectionData * selection_data,gpointer callback_data)6321 paste_into_clipboard_received_callback (GtkClipboard *clipboard,
6322 GtkSelectionData *selection_data,
6323 gpointer callback_data)
6324 {
6325 PasteIntoData *data;
6326 FMDirectoryView *view;
6327
6328 data = (PasteIntoData *) callback_data;
6329
6330 view = FM_DIRECTORY_VIEW (data->view);
6331
6332 if (view->details->window != NULL) {
6333 char *directory_uri;
6334
6335 directory_uri = caja_file_get_activation_uri (data->target);
6336
6337 paste_clipboard_data (view, selection_data, directory_uri);
6338
6339 g_free (directory_uri);
6340 }
6341
6342 g_object_unref (view);
6343 caja_file_unref (data->target);
6344 g_free (data);
6345 }
6346
6347 static void
action_paste_files_callback(GtkAction * action,gpointer callback_data)6348 action_paste_files_callback (GtkAction *action,
6349 gpointer callback_data)
6350 {
6351 FMDirectoryView *view;
6352
6353 view = FM_DIRECTORY_VIEW (callback_data);
6354
6355 g_object_ref (view);
6356 gtk_clipboard_request_contents (caja_clipboard_get (GTK_WIDGET (view)),
6357 copied_files_atom,
6358 paste_clipboard_received_callback,
6359 view);
6360 }
6361
6362 static void
paste_into(FMDirectoryView * view,CajaFile * target)6363 paste_into (FMDirectoryView *view,
6364 CajaFile *target)
6365 {
6366 PasteIntoData *data;
6367
6368 g_assert (FM_IS_DIRECTORY_VIEW (view));
6369 g_assert (CAJA_IS_FILE (target));
6370
6371 data = g_new (PasteIntoData, 1);
6372
6373 data->view = g_object_ref (view);
6374 data->target = caja_file_ref (target);
6375
6376 gtk_clipboard_request_contents (caja_clipboard_get (GTK_WIDGET (view)),
6377 copied_files_atom,
6378 paste_into_clipboard_received_callback,
6379 data);
6380 }
6381
6382 static void
action_paste_files_into_callback(GtkAction * action,gpointer callback_data)6383 action_paste_files_into_callback (GtkAction *action,
6384 gpointer callback_data)
6385 {
6386 FMDirectoryView *view;
6387 GList *selection;
6388
6389 view = FM_DIRECTORY_VIEW (callback_data);
6390 selection = fm_directory_view_get_selection (view);
6391 if (selection != NULL) {
6392 paste_into (view, CAJA_FILE (selection->data));
6393 caja_file_list_free (selection);
6394 }
6395
6396 }
6397
6398 static void
real_action_undo(FMDirectoryView * view)6399 real_action_undo (FMDirectoryView *view)
6400 {
6401 CajaUndoStackManager *manager = caja_undostack_manager_instance ();
6402
6403 /* Disable menus because they are in an untrustworthy status */
6404 view->details->undo_active = FALSE;
6405 view->details->redo_active = FALSE;
6406 fm_directory_view_update_menus (view);
6407
6408 caja_undostack_manager_undo (manager, GTK_WIDGET (view), finish_undoredo_callback);
6409 }
6410
6411 static void
real_action_redo(FMDirectoryView * view)6412 real_action_redo (FMDirectoryView *view)
6413 {
6414 CajaUndoStackManager *manager = caja_undostack_manager_instance ();
6415
6416 /* Disable menus because they are in an untrustworthy status */
6417 view->details->undo_active = FALSE;
6418 view->details->redo_active = FALSE;
6419 fm_directory_view_update_menus (view);
6420
6421 caja_undostack_manager_redo (manager, GTK_WIDGET (view), finish_undoredo_callback);
6422 }
6423
6424 static void
real_action_rename(FMDirectoryView * view,gboolean select_all)6425 real_action_rename (FMDirectoryView *view,
6426 gboolean select_all)
6427 {
6428 GList *selection;
6429
6430 g_assert (FM_IS_DIRECTORY_VIEW (view));
6431
6432 selection = fm_directory_view_get_selection (view);
6433
6434 if (selection_not_empty_in_menu_callback (view, selection)) {
6435 CajaFile *file;
6436
6437 file = CAJA_FILE (selection->data);
6438
6439 if (!select_all) {
6440 /* directories don't have a file extension, so
6441 * they are always pre-selected as a whole */
6442 select_all = caja_file_is_directory (file);
6443 }
6444 EEL_CALL_METHOD (FM_DIRECTORY_VIEW_CLASS, view, start_renaming_file, (view, file, select_all));
6445 }
6446
6447 caja_file_list_free (selection);
6448 }
6449
6450 static void
action_rename_callback(GtkAction * action,gpointer callback_data)6451 action_rename_callback (GtkAction *action,
6452 gpointer callback_data)
6453 {
6454 real_action_rename (FM_DIRECTORY_VIEW (callback_data), FALSE);
6455 }
6456
6457 static void
action_rename_select_all_callback(GtkAction * action,gpointer callback_data)6458 action_rename_select_all_callback (GtkAction *action,
6459 gpointer callback_data)
6460 {
6461 real_action_rename (FM_DIRECTORY_VIEW (callback_data), TRUE);
6462 }
6463
6464 static void
file_mount_callback(CajaFile * file,GFile * result_location,GError * error,gpointer callback_data)6465 file_mount_callback (CajaFile *file,
6466 GFile *result_location,
6467 GError *error,
6468 gpointer callback_data)
6469 {
6470 if (error != NULL &&
6471 (error->domain != G_IO_ERROR ||
6472 (error->code != G_IO_ERROR_CANCELLED &&
6473 error->code != G_IO_ERROR_FAILED_HANDLED &&
6474 error->code != G_IO_ERROR_ALREADY_MOUNTED))) {
6475 eel_show_error_dialog (_("Unable to mount location"),
6476 error->message, NULL);
6477 }
6478 }
6479
6480 static void
file_unmount_callback(CajaFile * file,GFile * result_location,GError * error,gpointer callback_data)6481 file_unmount_callback (CajaFile *file,
6482 GFile *result_location,
6483 GError *error,
6484 gpointer callback_data)
6485 {
6486 FMDirectoryView *view;
6487
6488 view = FM_DIRECTORY_VIEW (callback_data);
6489 fm_directory_view_set_initiated_unmount (view, FALSE);
6490 g_object_unref (view);
6491
6492 if (error != NULL &&
6493 (error->domain != G_IO_ERROR ||
6494 (error->code != G_IO_ERROR_CANCELLED &&
6495 error->code != G_IO_ERROR_FAILED_HANDLED))) {
6496 eel_show_error_dialog (_("Unable to unmount location"),
6497 error->message, NULL);
6498 }
6499 }
6500
6501 static void
file_eject_callback(CajaFile * file,GFile * result_location,GError * error,gpointer callback_data)6502 file_eject_callback (CajaFile *file,
6503 GFile *result_location,
6504 GError *error,
6505 gpointer callback_data)
6506 {
6507 FMDirectoryView *view;
6508
6509 view = FM_DIRECTORY_VIEW (callback_data);
6510 fm_directory_view_set_initiated_unmount (view, FALSE);
6511 g_object_unref (view);
6512
6513 if (error != NULL &&
6514 (error->domain != G_IO_ERROR ||
6515 (error->code != G_IO_ERROR_CANCELLED &&
6516 error->code != G_IO_ERROR_FAILED_HANDLED))) {
6517 eel_show_error_dialog (_("Unable to eject location"),
6518 error->message, NULL);
6519 }
6520 }
6521
6522 static void
file_stop_callback(CajaFile * file,GFile * result_location,GError * error,gpointer callback_data)6523 file_stop_callback (CajaFile *file,
6524 GFile *result_location,
6525 GError *error,
6526 gpointer callback_data)
6527 {
6528 if (error != NULL &&
6529 (error->domain != G_IO_ERROR ||
6530 (error->code != G_IO_ERROR_CANCELLED &&
6531 error->code != G_IO_ERROR_FAILED_HANDLED))) {
6532 eel_show_error_dialog (_("Unable to stop drive"),
6533 error->message, NULL);
6534 }
6535 }
6536
6537 static void
action_mount_volume_callback(GtkAction * action,gpointer data)6538 action_mount_volume_callback (GtkAction *action,
6539 gpointer data)
6540 {
6541 GList *selection, *l;
6542 FMDirectoryView *view;
6543 GMountOperation *mount_op;
6544 CajaFile *file = NULL;
6545
6546 view = FM_DIRECTORY_VIEW (data);
6547
6548 selection = fm_directory_view_get_selection (view);
6549 for (l = selection; l != NULL; l = l->next) {
6550 file = CAJA_FILE (l->data);
6551
6552 if (caja_file_can_mount (file)) {
6553 mount_op = gtk_mount_operation_new (fm_directory_view_get_containing_window (view));
6554 g_mount_operation_set_password_save (mount_op, G_PASSWORD_SAVE_FOR_SESSION);
6555 caja_file_mount (file, mount_op, NULL,
6556 file_mount_callback, NULL);
6557 g_object_unref (mount_op);
6558 }
6559 }
6560 caja_file_list_free (selection);
6561 }
6562
6563 static void
action_unmount_volume_callback(GtkAction * action,gpointer data)6564 action_unmount_volume_callback (GtkAction *action,
6565 gpointer data)
6566 {
6567 GList *selection, *l;
6568 FMDirectoryView *view;
6569 CajaFile *file = NULL;
6570
6571 view = FM_DIRECTORY_VIEW (data);
6572
6573 selection = fm_directory_view_get_selection (view);
6574
6575 for (l = selection; l != NULL; l = l->next) {
6576 file = CAJA_FILE (l->data);
6577 if (caja_file_can_unmount (file)) {
6578 GMountOperation *mount_op;
6579 mount_op = gtk_mount_operation_new (fm_directory_view_get_containing_window (view));
6580 fm_directory_view_set_initiated_unmount (view, TRUE);
6581 caja_file_unmount (file, mount_op, NULL,
6582 file_unmount_callback, g_object_ref (view));
6583 g_object_unref (mount_op);
6584 }
6585 }
6586 caja_file_list_free (selection);
6587 }
6588
6589 static void
action_format_volume_callback(GtkAction * action,gpointer data)6590 action_format_volume_callback (GtkAction *action,
6591 gpointer data)
6592 {
6593 #ifdef TODO_GIO
6594 GList *selection, *l;
6595 FMDirectoryView *view;
6596 CajaFile *file = NULL;
6597
6598 view = FM_DIRECTORY_VIEW (data);
6599
6600 selection = fm_directory_view_get_selection (view);
6601 for (l = selection; l != NULL; l = l->next) {
6602 file = CAJA_FILE (l->data);
6603
6604 if (something) {
6605 g_spawn_command_line_async ("gfloppy", NULL);
6606 }
6607 }
6608 caja_file_list_free (selection);
6609 #endif
6610 }
6611
6612 static void
action_eject_volume_callback(GtkAction * action,gpointer data)6613 action_eject_volume_callback (GtkAction *action,
6614 gpointer data)
6615 {
6616 GList *selection, *l;
6617 FMDirectoryView *view;
6618 CajaFile *file = NULL;
6619
6620 view = FM_DIRECTORY_VIEW (data);
6621
6622 selection = fm_directory_view_get_selection (view);
6623 for (l = selection; l != NULL; l = l->next) {
6624 file = CAJA_FILE (l->data);
6625
6626 if (caja_file_can_eject (file)) {
6627 GMountOperation *mount_op;
6628 mount_op = gtk_mount_operation_new (fm_directory_view_get_containing_window (view));
6629 fm_directory_view_set_initiated_unmount (view, TRUE);
6630 caja_file_eject (file, mount_op, NULL,
6631 file_eject_callback, g_object_ref (view));
6632 g_object_unref (mount_op);
6633 }
6634 }
6635 caja_file_list_free (selection);
6636 }
6637
6638 static void
file_start_callback(CajaFile * file,GFile * result_location,GError * error,gpointer callback_data)6639 file_start_callback (CajaFile *file,
6640 GFile *result_location,
6641 GError *error,
6642 gpointer callback_data)
6643 {
6644 if (error != NULL &&
6645 (error->domain != G_IO_ERROR ||
6646 (error->code != G_IO_ERROR_CANCELLED &&
6647 error->code != G_IO_ERROR_FAILED_HANDLED &&
6648 error->code != G_IO_ERROR_ALREADY_MOUNTED))) {
6649 eel_show_error_dialog (_("Unable to start location"),
6650 error->message, NULL);
6651 }
6652 }
6653
6654 static void
action_start_volume_callback(GtkAction * action,gpointer data)6655 action_start_volume_callback (GtkAction *action,
6656 gpointer data)
6657 {
6658 GList *selection, *l;
6659 FMDirectoryView *view;
6660 GMountOperation *mount_op;
6661 CajaFile *file = NULL;
6662
6663 view = FM_DIRECTORY_VIEW (data);
6664
6665 selection = fm_directory_view_get_selection (view);
6666 for (l = selection; l != NULL; l = l->next) {
6667 file = CAJA_FILE (l->data);
6668
6669 if (caja_file_can_start (file) || caja_file_can_start_degraded (file)) {
6670 mount_op = gtk_mount_operation_new (fm_directory_view_get_containing_window (view));
6671 caja_file_start (file, mount_op, NULL,
6672 file_start_callback, NULL);
6673 g_object_unref (mount_op);
6674 }
6675 }
6676 caja_file_list_free (selection);
6677 }
6678
6679 static void
action_stop_volume_callback(GtkAction * action,gpointer data)6680 action_stop_volume_callback (GtkAction *action,
6681 gpointer data)
6682 {
6683 GList *selection, *l;
6684 FMDirectoryView *view;
6685 CajaFile *file = NULL;
6686
6687 view = FM_DIRECTORY_VIEW (data);
6688
6689 selection = fm_directory_view_get_selection (view);
6690 for (l = selection; l != NULL; l = l->next) {
6691 file = CAJA_FILE (l->data);
6692
6693 if (caja_file_can_stop (file)) {
6694 GMountOperation *mount_op;
6695 mount_op = gtk_mount_operation_new (fm_directory_view_get_containing_window (view));
6696 caja_file_stop (file, mount_op, NULL,
6697 file_stop_callback, NULL);
6698 g_object_unref (mount_op);
6699 }
6700 }
6701 caja_file_list_free (selection);
6702 }
6703
6704 static void
action_detect_media_callback(GtkAction * action,gpointer data)6705 action_detect_media_callback (GtkAction *action,
6706 gpointer data)
6707 {
6708 GList *selection, *l;
6709 FMDirectoryView *view;
6710 CajaFile *file = NULL;
6711
6712 view = FM_DIRECTORY_VIEW (data);
6713
6714 selection = fm_directory_view_get_selection (view);
6715 for (l = selection; l != NULL; l = l->next) {
6716 file = CAJA_FILE (l->data);
6717
6718 if (caja_file_can_poll_for_media (file) && !caja_file_is_media_check_automatic (file)) {
6719 caja_file_poll_for_media (file);
6720 }
6721 }
6722 caja_file_list_free (selection);
6723 }
6724
6725 static void
action_self_mount_volume_callback(GtkAction * action,gpointer data)6726 action_self_mount_volume_callback (GtkAction *action,
6727 gpointer data)
6728 {
6729 CajaFile *file;
6730 FMDirectoryView *view;
6731 GMountOperation *mount_op;
6732
6733 view = FM_DIRECTORY_VIEW (data);
6734
6735 file = fm_directory_view_get_directory_as_file (view);
6736 if (file == NULL) {
6737 return;
6738 }
6739
6740 mount_op = gtk_mount_operation_new (fm_directory_view_get_containing_window (view));
6741 g_mount_operation_set_password_save (mount_op, G_PASSWORD_SAVE_FOR_SESSION);
6742 caja_file_mount (file, mount_op, NULL, file_mount_callback, NULL);
6743 g_object_unref (mount_op);
6744 }
6745
6746 static void
action_self_unmount_volume_callback(GtkAction * action,gpointer data)6747 action_self_unmount_volume_callback (GtkAction *action,
6748 gpointer data)
6749 {
6750 CajaFile *file;
6751 FMDirectoryView *view;
6752 GMountOperation *mount_op;
6753
6754 view = FM_DIRECTORY_VIEW (data);
6755
6756 file = fm_directory_view_get_directory_as_file (view);
6757 if (file == NULL) {
6758 return;
6759 }
6760
6761 mount_op = gtk_mount_operation_new (fm_directory_view_get_containing_window (view));
6762 fm_directory_view_set_initiated_unmount (view, TRUE);
6763 caja_file_unmount (file, mount_op, NULL, file_unmount_callback, g_object_ref (view));
6764 g_object_unref (mount_op);
6765 }
6766
6767 static void
action_self_eject_volume_callback(GtkAction * action,gpointer data)6768 action_self_eject_volume_callback (GtkAction *action,
6769 gpointer data)
6770 {
6771 CajaFile *file;
6772 FMDirectoryView *view;
6773 GMountOperation *mount_op;
6774
6775 view = FM_DIRECTORY_VIEW (data);
6776
6777 file = fm_directory_view_get_directory_as_file (view);
6778 if (file == NULL) {
6779 return;
6780 }
6781
6782 mount_op = gtk_mount_operation_new (fm_directory_view_get_containing_window (view));
6783 fm_directory_view_set_initiated_unmount (view, TRUE);
6784 caja_file_eject (file, mount_op, NULL, file_eject_callback, g_object_ref (view));
6785 g_object_unref (mount_op);
6786 }
6787
6788 static void
action_self_format_volume_callback(GtkAction * action,gpointer data)6789 action_self_format_volume_callback (GtkAction *action,
6790 gpointer data)
6791 {
6792 CajaFile *file;
6793 FMDirectoryView *view;
6794
6795 view = FM_DIRECTORY_VIEW (data);
6796
6797 file = fm_directory_view_get_directory_as_file (view);
6798 if (file == NULL) {
6799 return;
6800 }
6801
6802 #ifdef TODO_GIO
6803 if (something) {
6804 g_spawn_command_line_async ("gfloppy", NULL);
6805 }
6806 #endif
6807 }
6808
6809 static void
action_self_start_volume_callback(GtkAction * action,gpointer data)6810 action_self_start_volume_callback (GtkAction *action,
6811 gpointer data)
6812 {
6813 CajaFile *file;
6814 FMDirectoryView *view;
6815 GMountOperation *mount_op;
6816
6817 view = FM_DIRECTORY_VIEW (data);
6818
6819 file = fm_directory_view_get_directory_as_file (view);
6820 if (file == NULL) {
6821 return;
6822 }
6823
6824 mount_op = gtk_mount_operation_new (fm_directory_view_get_containing_window (view));
6825 caja_file_start (file, mount_op, NULL, file_start_callback, NULL);
6826 g_object_unref (mount_op);
6827 }
6828
6829 static void
action_self_stop_volume_callback(GtkAction * action,gpointer data)6830 action_self_stop_volume_callback (GtkAction *action,
6831 gpointer data)
6832 {
6833 CajaFile *file;
6834 FMDirectoryView *view;
6835 GMountOperation *mount_op;
6836
6837 view = FM_DIRECTORY_VIEW (data);
6838
6839 file = fm_directory_view_get_directory_as_file (view);
6840 if (file == NULL) {
6841 return;
6842 }
6843
6844 mount_op = gtk_mount_operation_new (fm_directory_view_get_containing_window (view));
6845 caja_file_stop (file, mount_op, NULL,
6846 file_stop_callback, NULL);
6847 g_object_unref (mount_op);
6848 }
6849
6850 static void
action_self_detect_media_callback(GtkAction * action,gpointer data)6851 action_self_detect_media_callback (GtkAction *action,
6852 gpointer data)
6853 {
6854 CajaFile *file;
6855 FMDirectoryView *view;
6856
6857 view = FM_DIRECTORY_VIEW (data);
6858
6859 file = fm_directory_view_get_directory_as_file (view);
6860 if (file == NULL) {
6861 return;
6862 }
6863
6864 caja_file_poll_for_media (file);
6865 }
6866
6867 static void
action_location_mount_volume_callback(GtkAction * action,gpointer data)6868 action_location_mount_volume_callback (GtkAction *action,
6869 gpointer data)
6870 {
6871 CajaFile *file;
6872 FMDirectoryView *view;
6873 GMountOperation *mount_op;
6874
6875 view = FM_DIRECTORY_VIEW (data);
6876
6877 file = view->details->location_popup_directory_as_file;
6878 if (file == NULL) {
6879 return;
6880 }
6881
6882 mount_op = gtk_mount_operation_new (fm_directory_view_get_containing_window (view));
6883 g_mount_operation_set_password_save (mount_op, G_PASSWORD_SAVE_FOR_SESSION);
6884 caja_file_mount (file, mount_op, NULL, file_mount_callback, NULL);
6885 g_object_unref (mount_op);
6886 }
6887
6888 static void
action_location_unmount_volume_callback(GtkAction * action,gpointer data)6889 action_location_unmount_volume_callback (GtkAction *action,
6890 gpointer data)
6891 {
6892 CajaFile *file;
6893 FMDirectoryView *view;
6894 GMountOperation *mount_op;
6895
6896 view = FM_DIRECTORY_VIEW (data);
6897
6898 file = view->details->location_popup_directory_as_file;
6899 if (file == NULL) {
6900 return;
6901 }
6902
6903 mount_op = gtk_mount_operation_new (fm_directory_view_get_containing_window (view));
6904 fm_directory_view_set_initiated_unmount (view, TRUE);
6905 caja_file_unmount (file, mount_op, NULL,
6906 file_unmount_callback, g_object_ref (view));
6907 g_object_unref (mount_op);
6908 }
6909
6910 static void
action_location_eject_volume_callback(GtkAction * action,gpointer data)6911 action_location_eject_volume_callback (GtkAction *action,
6912 gpointer data)
6913 {
6914 CajaFile *file;
6915 FMDirectoryView *view;
6916 GMountOperation *mount_op;
6917
6918 view = FM_DIRECTORY_VIEW (data);
6919
6920 file = view->details->location_popup_directory_as_file;
6921 if (file == NULL) {
6922 return;
6923 }
6924
6925 mount_op = gtk_mount_operation_new (fm_directory_view_get_containing_window (view));
6926 fm_directory_view_set_initiated_unmount (view, TRUE);
6927 caja_file_eject (file, mount_op, NULL,
6928 file_eject_callback, g_object_ref (view));
6929 g_object_unref (mount_op);
6930 }
6931
6932 static void
action_location_format_volume_callback(GtkAction * action,gpointer data)6933 action_location_format_volume_callback (GtkAction *action,
6934 gpointer data)
6935 {
6936 CajaFile *file;
6937 FMDirectoryView *view;
6938
6939 view = FM_DIRECTORY_VIEW (data);
6940
6941 file = view->details->location_popup_directory_as_file;
6942 if (file == NULL) {
6943 return;
6944 }
6945
6946 #ifdef TODO_GIO
6947 if (something) {
6948 g_spawn_command_line_async ("gfloppy", NULL);
6949 }
6950 #endif
6951 }
6952
6953 static void
action_location_start_volume_callback(GtkAction * action,gpointer data)6954 action_location_start_volume_callback (GtkAction *action,
6955 gpointer data)
6956 {
6957 CajaFile *file;
6958 FMDirectoryView *view;
6959 GMountOperation *mount_op;
6960
6961 view = FM_DIRECTORY_VIEW (data);
6962
6963 file = view->details->location_popup_directory_as_file;
6964 if (file == NULL) {
6965 return;
6966 }
6967
6968 mount_op = gtk_mount_operation_new (fm_directory_view_get_containing_window (view));
6969 caja_file_start (file, mount_op, NULL, file_start_callback, NULL);
6970 g_object_unref (mount_op);
6971 }
6972
6973 static void
action_location_stop_volume_callback(GtkAction * action,gpointer data)6974 action_location_stop_volume_callback (GtkAction *action,
6975 gpointer data)
6976 {
6977 CajaFile *file;
6978 FMDirectoryView *view;
6979 GMountOperation *mount_op;
6980
6981 view = FM_DIRECTORY_VIEW (data);
6982
6983 file = view->details->location_popup_directory_as_file;
6984 if (file == NULL) {
6985 return;
6986 }
6987
6988 mount_op = gtk_mount_operation_new (fm_directory_view_get_containing_window (view));
6989 caja_file_stop (file, mount_op, NULL,
6990 file_stop_callback, NULL);
6991 g_object_unref (mount_op);
6992 }
6993
6994 static void
action_location_detect_media_callback(GtkAction * action,gpointer data)6995 action_location_detect_media_callback (GtkAction *action,
6996 gpointer data)
6997 {
6998 CajaFile *file;
6999 FMDirectoryView *view;
7000
7001 view = FM_DIRECTORY_VIEW (data);
7002
7003 file = view->details->location_popup_directory_as_file;
7004 if (file == NULL) {
7005 return;
7006 }
7007
7008 caja_file_poll_for_media (file);
7009 }
7010
7011 static void
connect_to_server_response_callback(GtkDialog * dialog,int response_id,gpointer data)7012 connect_to_server_response_callback (GtkDialog *dialog,
7013 int response_id,
7014 gpointer data)
7015 {
7016 #ifdef GIO_CONVERSION_DONE
7017 GtkEntry *entry;
7018 char *uri;
7019 const char *name;
7020 char *icon;
7021
7022 entry = GTK_ENTRY (data);
7023
7024 switch (response_id) {
7025 case GTK_RESPONSE_OK:
7026 uri = g_object_get_data (G_OBJECT (dialog), "link-uri");
7027 icon = g_object_get_data (G_OBJECT (dialog), "link-icon");
7028 name = gtk_entry_get_text (entry);
7029 mate_vfs_connect_to_server (uri, (char *)name, icon);
7030 gtk_widget_destroy (GTK_WIDGET (dialog));
7031 break;
7032 case GTK_RESPONSE_NONE:
7033 case GTK_RESPONSE_DELETE_EVENT:
7034 case GTK_RESPONSE_CANCEL:
7035 gtk_widget_destroy (GTK_WIDGET (dialog));
7036 break;
7037 default :
7038 g_assert_not_reached ();
7039 }
7040 #endif
7041 /* FIXME: the above code should make a server connection permanent */
7042 gtk_widget_destroy (GTK_WIDGET (dialog));
7043 }
7044
7045 static void
entry_activate_callback(GtkEntry * entry,gpointer user_data)7046 entry_activate_callback (GtkEntry *entry,
7047 gpointer user_data)
7048 {
7049 GtkDialog *dialog;
7050
7051 dialog = GTK_DIALOG (user_data);
7052 gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
7053 }
7054
7055 static void
action_connect_to_server_link_callback(GtkAction * action,gpointer data)7056 action_connect_to_server_link_callback (GtkAction *action,
7057 gpointer data)
7058 {
7059 CajaFile *file;
7060 GList *selection;
7061 FMDirectoryView *view;
7062 char *uri;
7063 CajaIconInfo *icon;
7064 const char *icon_name;
7065 char *name;
7066 gint scale;
7067
7068 view = FM_DIRECTORY_VIEW (data);
7069
7070 selection = fm_directory_view_get_selection (view);
7071
7072 if (!eel_g_list_exactly_one_item (selection)) {
7073 caja_file_list_free (selection);
7074 return;
7075 }
7076
7077 file = CAJA_FILE (selection->data);
7078 scale = gtk_widget_get_scale_factor (GTK_WIDGET (view));
7079
7080 uri = caja_file_get_activation_uri (file);
7081 icon = caja_file_get_icon (file, CAJA_ICON_SIZE_STANDARD, scale, 0);
7082 icon_name = caja_icon_info_get_used_name (icon);
7083 name = caja_file_get_display_name (file);
7084
7085 if (uri != NULL) {
7086 GtkWidget *dialog;
7087 GtkWidget *label;
7088 GtkWidget *entry;
7089 GtkWidget *box;
7090 char *title;
7091
7092 title = g_strdup_printf (_("Connect to Server %s"), name);
7093
7094 dialog = gtk_dialog_new ();
7095 gtk_window_set_title (GTK_WINDOW (dialog), title);
7096 gtk_window_set_transient_for (GTK_WINDOW (dialog), fm_directory_view_get_containing_window (view));
7097
7098 eel_dialog_add_button (GTK_DIALOG (dialog),
7099 _("_Cancel"),
7100 "process-stop",
7101 GTK_RESPONSE_CANCEL);
7102
7103 gtk_dialog_add_button (GTK_DIALOG (dialog),
7104 _("_Connect"),
7105 GTK_RESPONSE_OK);
7106
7107 g_object_set_data_full (G_OBJECT (dialog), "link-uri", g_strdup (uri), g_free);
7108 g_object_set_data_full (G_OBJECT (dialog), "link-icon", g_strdup (icon_name), g_free);
7109
7110 gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
7111 gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 2);
7112
7113 box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
7114 gtk_widget_show (box);
7115 gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
7116 box, TRUE, TRUE, 0);
7117
7118 label = gtk_label_new_with_mnemonic (_("Link _name:"));
7119 gtk_widget_show (label);
7120
7121 gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 12);
7122
7123 entry = gtk_entry_new ();
7124 if (name) {
7125 gtk_entry_set_text (GTK_ENTRY (entry), name);
7126 }
7127 g_signal_connect (entry,
7128 "activate",
7129 G_CALLBACK (entry_activate_callback),
7130 dialog);
7131
7132 gtk_widget_show (entry);
7133 gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
7134
7135 gtk_box_pack_start (GTK_BOX (box), entry, TRUE, TRUE, 12);
7136
7137 gtk_dialog_set_default_response (GTK_DIALOG (dialog),
7138 GTK_RESPONSE_OK);
7139 g_signal_connect (dialog, "response",
7140 G_CALLBACK (connect_to_server_response_callback),
7141 entry);
7142 gtk_widget_show (dialog);
7143 }
7144
7145 g_free (uri);
7146 g_object_unref (icon);
7147 g_free (name);
7148 }
7149
7150 static void
action_location_open_alternate_callback(GtkAction * action,gpointer callback_data)7151 action_location_open_alternate_callback (GtkAction *action,
7152 gpointer callback_data)
7153 {
7154 FMDirectoryView *view;
7155 CajaFile *file;
7156
7157 view = FM_DIRECTORY_VIEW (callback_data);
7158
7159 file = view->details->location_popup_directory_as_file;
7160 if (file == NULL) {
7161 return;
7162 }
7163
7164 fm_directory_view_activate_file (view,
7165 file,
7166 CAJA_WINDOW_OPEN_IN_NAVIGATION,
7167 0);
7168 }
7169
7170 static void
action_location_open_in_new_tab_callback(GtkAction * action,gpointer callback_data)7171 action_location_open_in_new_tab_callback (GtkAction *action,
7172 gpointer callback_data)
7173 {
7174 FMDirectoryView *view;
7175 CajaFile *file;
7176
7177 view = FM_DIRECTORY_VIEW (callback_data);
7178
7179 file = view->details->location_popup_directory_as_file;
7180 if (file == NULL) {
7181 return;
7182 }
7183
7184 fm_directory_view_activate_file (view,
7185 file,
7186 CAJA_WINDOW_OPEN_ACCORDING_TO_MODE,
7187 CAJA_WINDOW_OPEN_FLAG_NEW_TAB);
7188 }
7189
7190 static void
action_location_open_folder_window_callback(GtkAction * action,gpointer callback_data)7191 action_location_open_folder_window_callback (GtkAction *action,
7192 gpointer callback_data)
7193 {
7194 FMDirectoryView *view;
7195 CajaFile *file;
7196
7197 view = FM_DIRECTORY_VIEW (callback_data);
7198
7199 file = view->details->location_popup_directory_as_file;
7200 g_return_if_fail (file != NULL);
7201
7202 fm_directory_view_activate_file (view,
7203 file,
7204 CAJA_WINDOW_OPEN_IN_SPATIAL,
7205 0);
7206 }
7207
7208 static void
action_location_cut_callback(GtkAction * action,gpointer callback_data)7209 action_location_cut_callback (GtkAction *action,
7210 gpointer callback_data)
7211 {
7212 FMDirectoryView *view;
7213 CajaFile *file;
7214 GList *files;
7215
7216 view = FM_DIRECTORY_VIEW (callback_data);
7217
7218 file = view->details->location_popup_directory_as_file;
7219 g_return_if_fail (file != NULL);
7220
7221 files = g_list_append (NULL, file);
7222 copy_or_cut_files (view, files, TRUE);
7223 g_list_free (files);
7224 }
7225
7226 static void
action_location_copy_callback(GtkAction * action,gpointer callback_data)7227 action_location_copy_callback (GtkAction *action,
7228 gpointer callback_data)
7229 {
7230 FMDirectoryView *view;
7231 CajaFile *file;
7232 GList *files;
7233
7234 view = FM_DIRECTORY_VIEW (callback_data);
7235
7236 file = view->details->location_popup_directory_as_file;
7237 g_return_if_fail (file != NULL);
7238
7239 files = g_list_append (NULL, file);
7240 copy_or_cut_files (view, files, FALSE);
7241 g_list_free (files);
7242 }
7243
7244 static void
action_location_paste_files_into_callback(GtkAction * action,gpointer callback_data)7245 action_location_paste_files_into_callback (GtkAction *action,
7246 gpointer callback_data)
7247 {
7248 FMDirectoryView *view;
7249 CajaFile *file;
7250
7251 view = FM_DIRECTORY_VIEW (callback_data);
7252
7253 file = view->details->location_popup_directory_as_file;
7254 g_return_if_fail (file != NULL);
7255
7256 paste_into (view, file);
7257 }
7258
7259 static void
action_location_trash_callback(GtkAction * action,gpointer callback_data)7260 action_location_trash_callback (GtkAction *action,
7261 gpointer callback_data)
7262 {
7263 FMDirectoryView *view;
7264 CajaFile *file;
7265 GList *files;
7266
7267 view = FM_DIRECTORY_VIEW (callback_data);
7268
7269 file = view->details->location_popup_directory_as_file;
7270 g_return_if_fail (file != NULL);
7271
7272 files = g_list_append (NULL, file);
7273 trash_or_delete_files (fm_directory_view_get_containing_window (view),
7274 files, TRUE,
7275 view);
7276 g_list_free (files);
7277 }
7278
7279 static void
action_location_delete_callback(GtkAction * action,gpointer callback_data)7280 action_location_delete_callback (GtkAction *action,
7281 gpointer callback_data)
7282 {
7283 FMDirectoryView *view;
7284 CajaFile *file;
7285 GFile *location;
7286 GList *files;
7287
7288 view = FM_DIRECTORY_VIEW (callback_data);
7289
7290 file = view->details->location_popup_directory_as_file;
7291 g_return_if_fail (file != NULL);
7292
7293 location = caja_file_get_location (file);
7294
7295 files = g_list_append (NULL, location);
7296 caja_file_operations_delete (files, fm_directory_view_get_containing_window (view),
7297 NULL, NULL);
7298
7299 g_list_free_full (files, g_object_unref);
7300 }
7301
7302 static void
action_location_restore_from_trash_callback(GtkAction * action,gpointer callback_data)7303 action_location_restore_from_trash_callback (GtkAction *action,
7304 gpointer callback_data)
7305 {
7306 FMDirectoryView *view;
7307 CajaFile *file;
7308 GList l;
7309
7310 view = FM_DIRECTORY_VIEW (callback_data);
7311 file = view->details->location_popup_directory_as_file;
7312
7313 l.prev = NULL;
7314 l.next = NULL;
7315 l.data = file;
7316 caja_restore_files_from_trash (&l,
7317 fm_directory_view_get_containing_window (view));
7318 }
7319
7320 static void
fm_directory_view_init_show_hidden_files(FMDirectoryView * view)7321 fm_directory_view_init_show_hidden_files (FMDirectoryView *view)
7322 {
7323 CajaWindowShowHiddenFilesMode mode;
7324 gboolean show_hidden_changed;
7325 gboolean show_hidden_default_setting;
7326
7327 if (view->details->ignore_hidden_file_preferences) {
7328 return;
7329 }
7330
7331 show_hidden_changed = FALSE;
7332 mode = caja_window_info_get_hidden_files_mode (view->details->window);
7333
7334 if (mode == CAJA_WINDOW_SHOW_HIDDEN_FILES_DEFAULT) {
7335 show_hidden_default_setting = g_settings_get_boolean (caja_preferences, CAJA_PREFERENCES_SHOW_HIDDEN_FILES);
7336 if (show_hidden_default_setting != view->details->show_hidden_files) {
7337 view->details->show_hidden_files = show_hidden_default_setting;
7338 show_hidden_changed = TRUE;
7339 }
7340 } else {
7341 if (mode == CAJA_WINDOW_SHOW_HIDDEN_FILES_ENABLE) {
7342 show_hidden_changed = !view->details->show_hidden_files;
7343 view->details->show_hidden_files = TRUE;
7344 } else {
7345 show_hidden_changed = view->details->show_hidden_files;
7346 view->details->show_hidden_files = FALSE;
7347 }
7348 }
7349
7350 if (show_hidden_changed && (view->details->model != NULL)) {
7351 load_directory (view, view->details->model);
7352 }
7353
7354 }
7355
7356 static void
fm_directory_view_init_show_backup_files(FMDirectoryView * view)7357 fm_directory_view_init_show_backup_files (FMDirectoryView *view)
7358 {
7359 CajaWindowShowBackupFilesMode mode;
7360 gboolean show_backup_changed;
7361 gboolean show_backup_default_setting;
7362
7363 show_backup_changed = FALSE;
7364 mode = caja_window_info_get_backup_files_mode (view->details->window);
7365
7366 if (mode == CAJA_WINDOW_SHOW_BACKUP_FILES_DEFAULT) {
7367 show_backup_default_setting = g_settings_get_boolean (caja_preferences, CAJA_PREFERENCES_SHOW_BACKUP_FILES);
7368 if (show_backup_default_setting != view->details->show_backup_files) {
7369 view->details->show_backup_files = show_backup_default_setting;
7370 show_backup_changed = TRUE;
7371 }
7372 } else {
7373 if (mode == CAJA_WINDOW_SHOW_BACKUP_FILES_ENABLE) {
7374 show_backup_changed = !view->details->show_backup_files;
7375 view->details->show_backup_files = TRUE;
7376 } else {
7377 show_backup_changed = view->details->show_backup_files;
7378 view->details->show_backup_files = FALSE;
7379 }
7380 }
7381
7382 if (show_backup_changed && (view->details->model != NULL)) {
7383 load_directory (view, view->details->model);
7384 }
7385
7386 }
7387
7388 static const GtkActionEntry directory_view_entries[] = {
7389 /* name, icon name, label */ { "New Documents", "document-new", N_("Create _Document"),
7390 NULL, NULL, NULL },
7391 /* name, icon name, label */ { "Open With", NULL, N_("Open Wit_h"),
7392 NULL, N_("Choose a program with which to open the selected item"), NULL },
7393 /* name, icon name */ { "Properties", "document-properties",
7394 /* label, accelerator */ N_("_Properties"), "<alt>Return",
7395 /* tooltip */ N_("View or modify the properties of each selected item"),
7396 G_CALLBACK (action_properties_callback) },
7397 /* name, icon name */ { "PropertiesAccel", NULL,
7398 /* label, accelerator */ "PropertiesAccel", "<control>I",
7399 /* tooltip */ NULL,
7400 G_CALLBACK (action_properties_callback) },
7401 /* name, icon name */ { "New Folder", "folder-new",
7402 /* label, accelerator */ N_("Create _Folder"), "<control><shift>N",
7403 /* tooltip */ N_("Create a new empty folder inside this folder"),
7404 G_CALLBACK (action_new_folder_callback) },
7405 /* name, icon name, label */ { "No Templates", NULL, N_("No templates installed"), NULL, NULL, NULL },
7406 /* name, icon name */ { "New Empty File", NULL,
7407 /* Translators: this is used to indicate that a file doesn't contain anything */
7408 /* label, accelerator */ N_("_Empty File"), NULL,
7409 /* tooltip */ N_("Create a new empty file inside this folder"),
7410 G_CALLBACK (action_new_empty_file_callback) },
7411 /* name, icon name */ { "New Launcher", NULL,
7412 /* label, accelerator */ N_("Create L_auncher..."), NULL,
7413 /* tooltip */ N_("Create a new launcher"),
7414 G_CALLBACK (action_new_launcher_callback) },
7415 /* name, icon name */ { "Open", NULL,
7416 /* label, accelerator */ N_("_Open"), "<control>o",
7417 /* tooltip */ N_("Open the selected item in this window"),
7418 G_CALLBACK (action_open_callback) },
7419 /* name, icon name */ { "OpenAccel", NULL,
7420 /* label, accelerator */ "OpenAccel", "<alt>Down",
7421 /* tooltip */ NULL,
7422 G_CALLBACK (action_open_callback) },
7423 /* name, icon name */ { "OpenAlternate", NULL,
7424 /* label, accelerator */ N_("Open in Navigation Window"), "<control><shift>w",
7425 /* tooltip */ N_("Open each selected item in a navigation window"),
7426 G_CALLBACK (action_open_alternate_callback) },
7427 /* name, icon name */ { "OpenInNewTab", NULL,
7428 /* label, accelerator */ N_("Open in New _Tab"), "<control><shift>o",
7429 /* tooltip */ N_("Open each selected item in a new tab"),
7430 G_CALLBACK (action_open_new_tab_callback) },
7431 /* name, icon name */ { "OpenFolderWindow", NULL,
7432 /* label, accelerator */ N_("Open in _Folder Window"), NULL,
7433 /* tooltip */ N_("Open each selected item in a folder window"),
7434 G_CALLBACK (action_open_folder_window_callback) },
7435 /* name, icon name */ { "OtherApplication1", NULL,
7436 /* label, accelerator */ N_("Other _Application..."), NULL,
7437 /* tooltip */ N_("Choose another application with which to open the selected item"),
7438 G_CALLBACK (action_other_application_callback) },
7439 /* name, icon name */ { "OtherApplication2", NULL,
7440 /* label, accelerator */ N_("Open With Other _Application..."), NULL,
7441 /* tooltip */ N_("Choose another application with which to open the selected item"),
7442 G_CALLBACK (action_other_application_callback) },
7443 /* name, icon name */ { "Open Scripts Folder", NULL,
7444 /* label, accelerator */ N_("_Open Scripts Folder"), NULL,
7445 /* tooltip */ N_("Show the folder containing the scripts that appear in this menu"),
7446 G_CALLBACK (action_open_scripts_folder_callback) },
7447 /* name, icon name */ { "Empty Trash", CAJA_ICON_TRASH,
7448 /* label, accelerator */ N_("E_mpty Trash"), NULL,
7449 /* tooltip */ N_("Delete all items in the Trash"),
7450 G_CALLBACK (action_empty_trash_callback) },
7451 /* name, icon name */ { "Cut", "edit-cut",
7452 /* label, accelerator */ N_("Cu_t"), "<control>X",
7453 /* tooltip */ N_("Prepare the selected files to be moved with a Paste command"),
7454 G_CALLBACK (action_cut_files_callback) },
7455 /* name, icon name */ { "Copy", "edit-copy",
7456 /* label, accelerator */ N_("_Copy"), "<control>C",
7457 /* tooltip */ N_("Prepare the selected files to be copied with a Paste command"),
7458 G_CALLBACK (action_copy_files_callback) },
7459 /* name, icon name */ { "Paste", "edit-paste",
7460 /* label, accelerator */ N_("_Paste"), "<control>V",
7461 /* tooltip */ N_("Move or copy files previously selected by a Cut or Copy command"),
7462 G_CALLBACK (action_paste_files_callback) },
7463 /* We make accelerator "" instead of null here to not inherit the stock
7464 accelerator for paste */
7465 /* name, icon name */ { "Paste Files Into", "edit-paste",
7466 /* label, accelerator */ N_("_Paste Into Folder"), "",
7467 /* tooltip */ N_("Move or copy files previously selected by a Cut or Copy command into the selected folder"),
7468 G_CALLBACK (action_paste_files_into_callback) },
7469 /* name, icon name, label */ { "CopyToMenu", NULL, N_("Cop_y to"),
7470 NULL, NULL, NULL },
7471 /* name, icon name, label */ { "MoveToMenu", NULL, N_("M_ove to"),
7472 NULL, NULL, NULL },
7473 /* name, icon name */ { "Select All", NULL,
7474 /* label, accelerator */ N_("Select _All"), "<control>A",
7475 /* tooltip */ N_("Select all items in this window"),
7476 G_CALLBACK (action_select_all_callback) },
7477 /* name, icon name */ { "Select Pattern", NULL,
7478 /* label, accelerator */ N_("Select I_tems Matching..."), "<control>S",
7479 /* tooltip */ N_("Select items in this window matching a given pattern"),
7480 G_CALLBACK (action_select_pattern_callback) },
7481 /* name, icon name */ { "Invert Selection", NULL,
7482 /* label, accelerator */ N_("_Invert Selection"), "<control><shift>I",
7483 /* tooltip */ N_("Select all and only the items that are not currently selected"),
7484 G_CALLBACK (action_invert_selection_callback) },
7485 /* name, icon name */ { "Duplicate", NULL,
7486 /* label, accelerator */ N_("D_uplicate"), NULL,
7487 /* tooltip */ N_("Duplicate each selected item"),
7488 G_CALLBACK (action_duplicate_callback) },
7489 /* name, icon name */ { "Create Link", NULL,
7490 /* label, accelerator */ N_("Ma_ke Link"), "<control>M",
7491 /* tooltip */ N_("Create a symbolic link for each selected item"),
7492 G_CALLBACK (action_create_link_callback) },
7493 /* name, icon name */ { "Rename", NULL,
7494 /* label, accelerator */ N_("_Rename..."), "F2",
7495 /* tooltip */ N_("Rename selected item"),
7496 G_CALLBACK (action_rename_callback) },
7497 /* name, icon name */ { "RenameSelectAll", NULL,
7498 /* label, accelerator */ "RenameSelectAll", "<shift>F2",
7499 /* tooltip */ NULL,
7500 G_CALLBACK (action_rename_select_all_callback) },
7501 /* name, icon name */ { "Trash", NULL,
7502 /* label, accelerator */ N_("Mo_ve to Trash"), NULL,
7503 /* tooltip */ N_("Move each selected item to the Trash"),
7504 G_CALLBACK (action_trash_callback) },
7505 /* name, icon name */ { "Delete", NULL,
7506 /* label, accelerator */ N_("_Delete"), NULL,
7507 /* tooltip */ N_("Delete each selected item, without moving to the Trash"),
7508 G_CALLBACK (action_delete_callback) },
7509 /* name, icon name */ { "Restore From Trash", NULL,
7510 /* label, accelerator */ N_("_Restore"), NULL,
7511 NULL,
7512 G_CALLBACK (action_restore_from_trash_callback) },
7513 /* name, icon name */ { FM_ACTION_UNDO, "edit-undo",
7514 /* label, accelerator */ N_("_Undo"), "<control>Z",
7515 /* tooltip */ N_("Undo the last action"),
7516 G_CALLBACK (action_undo_callback) },
7517 /* name, icon name */ { FM_ACTION_REDO, "edit-redo",
7518 /* label, accelerator */ N_("_Redo"), "<control>Y",
7519 /* tooltip */ N_("Redo the last undone action"),
7520 G_CALLBACK (action_redo_callback) },
7521
7522 /*
7523 * multiview-TODO: decide whether "Reset to Defaults" should
7524 * be window-wide, and not just view-wide.
7525 * Since this also resets the "Show hidden files" mode,
7526 * it is a mixture of both ATM.
7527 */
7528 /* name, icon name */ { "Reset to Defaults", NULL,
7529 /* label, accelerator */ N_("Reset View to _Defaults"), NULL,
7530 /* tooltip */ N_("Reset sorting order and zoom level to match preferences for this view"),
7531 G_CALLBACK (action_reset_to_defaults_callback) },
7532 /* name, icon name */ { "Connect To Server Link", NULL,
7533 /* label, accelerator */ N_("Connect To This Server"), NULL,
7534 /* tooltip */ N_("Make a permanent connection to this server"),
7535 G_CALLBACK (action_connect_to_server_link_callback) },
7536 /* name, icon name */ { "Mount Volume", NULL,
7537 /* label, accelerator */ N_("_Mount"), NULL,
7538 /* tooltip */ N_("Mount the selected volume"),
7539 G_CALLBACK (action_mount_volume_callback) },
7540 /* name, icon name */ { "Unmount Volume", NULL,
7541 /* label, accelerator */ N_("_Unmount"), NULL,
7542 /* tooltip */ N_("Unmount the selected volume"),
7543 G_CALLBACK (action_unmount_volume_callback) },
7544 /* name, icon name */ { "Eject Volume", NULL,
7545 /* label, accelerator */ N_("_Eject"), NULL,
7546 /* tooltip */ N_("Eject the selected volume"),
7547 G_CALLBACK (action_eject_volume_callback) },
7548 /* name, icon name */ { "Format Volume", NULL,
7549 /* label, accelerator */ N_("_Format"), NULL,
7550 /* tooltip */ N_("Format the selected volume"),
7551 G_CALLBACK (action_format_volume_callback) },
7552 /* name, icon name */ { "Start Volume", NULL,
7553 /* label, accelerator */ N_("_Start"), NULL,
7554 /* tooltip */ N_("Start the selected volume"),
7555 G_CALLBACK (action_start_volume_callback) },
7556 /* name, icon name */ { "Stop Volume", NULL,
7557 /* label, accelerator */ N_("_Stop"), NULL,
7558 /* tooltip */ N_("Stop the selected volume"),
7559 G_CALLBACK (action_stop_volume_callback) },
7560 /* name, icon name */ { "Poll", NULL,
7561 /* label, accelerator */ N_("_Detect Media"), NULL,
7562 /* tooltip */ N_("Detect media in the selected drive"),
7563 G_CALLBACK (action_detect_media_callback) },
7564 /* name, icon name */ { "Self Mount Volume", NULL,
7565 /* label, accelerator */ N_("_Mount"), NULL,
7566 /* tooltip */ N_("Mount the volume associated with the open folder"),
7567 G_CALLBACK (action_self_mount_volume_callback) },
7568 /* name, icon name */ { "Self Unmount Volume", NULL,
7569 /* label, accelerator */ N_("_Unmount"), NULL,
7570 /* tooltip */ N_("Unmount the volume associated with the open folder"),
7571 G_CALLBACK (action_self_unmount_volume_callback) },
7572 /* name, icon name */ { "Self Eject Volume", NULL,
7573 /* label, accelerator */ N_("_Eject"), NULL,
7574 /* tooltip */ N_("Eject the volume associated with the open folder"),
7575 G_CALLBACK (action_self_eject_volume_callback) },
7576 /* name, icon name */ { "Self Format Volume", NULL,
7577 /* label, accelerator */ N_("_Format"), NULL,
7578 /* tooltip */ N_("Format the volume associated with the open folder"),
7579 G_CALLBACK (action_self_format_volume_callback) },
7580 /* name, icon name */ { "Self Start Volume", NULL,
7581 /* label, accelerator */ N_("_Start"), NULL,
7582 /* tooltip */ N_("Start the volume associated with the open folder"),
7583 G_CALLBACK (action_self_start_volume_callback) },
7584 /* name, icon name */ { "Self Stop Volume", NULL,
7585 /* label, accelerator */ N_("_Stop"), NULL,
7586 /* tooltip */ N_("Stop the volume associated with the open folder"),
7587 G_CALLBACK (action_self_stop_volume_callback) },
7588 /* name, icon name */ { "Self Poll", NULL,
7589 /* label, accelerator */ N_("_Detect Media"), NULL,
7590 /* tooltip */ N_("Detect media in the selected drive"),
7591 G_CALLBACK (action_self_detect_media_callback) },
7592 /* name, icon name */ { "OpenCloseParent", NULL,
7593 /* label, accelerator */ N_("Open File and Close window"), "<alt><shift>Down",
7594 /* tooltip */ NULL,
7595 G_CALLBACK (action_open_close_parent_callback) },
7596 /* name, icon name */ { "Save Search", NULL,
7597 /* label, accelerator */ N_("Sa_ve Search"), NULL,
7598 /* tooltip */ N_("Save the edited search"),
7599 G_CALLBACK (action_save_search_callback) },
7600 /* name, icon name */ { "Save Search As", NULL,
7601 /* label, accelerator */ N_("Sa_ve Search As..."), NULL,
7602 /* tooltip */ N_("Save the current search as a file"),
7603 G_CALLBACK (action_save_search_as_callback) },
7604
7605 /* Location-specific actions */
7606 /* name, icon name */ { FM_ACTION_LOCATION_OPEN_ALTERNATE, NULL,
7607 /* label, accelerator */ N_("Open in Navigation Window"), "",
7608 /* tooltip */ N_("Open this folder in a navigation window"),
7609 G_CALLBACK (action_location_open_alternate_callback) },
7610 /* name, icon name */ { FM_ACTION_LOCATION_OPEN_IN_NEW_TAB, NULL,
7611 /* label, accelerator */ N_("Open in New _Tab"), "",
7612 /* tooltip */ N_("Open this folder in a new tab"),
7613 G_CALLBACK (action_location_open_in_new_tab_callback) },
7614
7615 /* name, icon name */ { FM_ACTION_LOCATION_OPEN_FOLDER_WINDOW, NULL,
7616 /* label, accelerator */ N_("Open in _Folder Window"), "",
7617 /* tooltip */ N_("Open this folder in a folder window"),
7618 G_CALLBACK (action_location_open_folder_window_callback) },
7619
7620 /* name, icon name */ { FM_ACTION_LOCATION_CUT, "edit-cut",
7621 /* label, accelerator */ N_("Cu_t"), "",
7622 /* tooltip */ N_("Prepare this folder to be moved with a Paste command"),
7623 G_CALLBACK (action_location_cut_callback) },
7624 /* name, icon name */ { FM_ACTION_LOCATION_COPY, "edit-copy",
7625 /* label, accelerator */ N_("_Copy"), "",
7626 /* tooltip */ N_("Prepare this folder to be copied with a Paste command"),
7627 G_CALLBACK (action_location_copy_callback) },
7628 /* name, icon name */ { FM_ACTION_LOCATION_PASTE_FILES_INTO, "edit-paste",
7629 /* label, accelerator */ N_("_Paste Into Folder"), "",
7630 /* tooltip */ N_("Move or copy files previously selected by a Cut or Copy command into this folder"),
7631 G_CALLBACK (action_location_paste_files_into_callback) },
7632
7633 /* name, icon name */ { FM_ACTION_LOCATION_TRASH, NULL,
7634 /* label, accelerator */ N_("Mo_ve to Trash"), "",
7635 /* tooltip */ N_("Move this folder to the Trash"),
7636 G_CALLBACK (action_location_trash_callback) },
7637 /* name, icon name */ { FM_ACTION_LOCATION_DELETE, CAJA_ICON_DELETE,
7638 /* label, accelerator */ N_("_Delete"), "",
7639 /* tooltip */ N_("Delete this folder, without moving to the Trash"),
7640 G_CALLBACK (action_location_delete_callback) },
7641 /* name, icon name */ { FM_ACTION_LOCATION_RESTORE_FROM_TRASH, NULL,
7642 /* label, accelerator */ N_("_Restore"), NULL, NULL,
7643 G_CALLBACK (action_location_restore_from_trash_callback) },
7644
7645 /* name, icon name */ { "Location Mount Volume", NULL,
7646 /* label, accelerator */ N_("_Mount"), NULL,
7647 /* tooltip */ N_("Mount the volume associated with this folder"),
7648 G_CALLBACK (action_location_mount_volume_callback) },
7649 /* name, icon name */ { "Location Unmount Volume", NULL,
7650 /* label, accelerator */ N_("_Unmount"), NULL,
7651 /* tooltip */ N_("Unmount the volume associated with this folder"),
7652 G_CALLBACK (action_location_unmount_volume_callback) },
7653 /* name, icon name */ { "Location Eject Volume", NULL,
7654 /* label, accelerator */ N_("_Eject"), NULL,
7655 /* tooltip */ N_("Eject the volume associated with this folder"),
7656 G_CALLBACK (action_location_eject_volume_callback) },
7657 /* name, icon name */ { "Location Format Volume", NULL,
7658 /* label, accelerator */ N_("_Format"), NULL,
7659 /* tooltip */ N_("Format the volume associated with this folder"),
7660 G_CALLBACK (action_location_format_volume_callback) },
7661 /* name, icon name */ { "Location Start Volume", NULL,
7662 /* label, accelerator */ N_("_Start"), NULL,
7663 /* tooltip */ N_("Start the volume associated with this folder"),
7664 G_CALLBACK (action_location_start_volume_callback) },
7665 /* name, icon name */ { "Location Stop Volume", NULL,
7666 /* label, accelerator */ N_("_Stop"), NULL,
7667 /* tooltip */ N_("Stop the volume associated with this folder"),
7668 G_CALLBACK (action_location_stop_volume_callback) },
7669 /* name, icon name */ { "Location Poll", NULL,
7670 /* label, accelerator */ N_("_Detect Media"), NULL,
7671 /* tooltip */ N_("Detect media in the selected drive"),
7672 G_CALLBACK (action_location_detect_media_callback) },
7673
7674 /* name, icon name */ { "LocationProperties", "document-properties",
7675 /* label, accelerator */ N_("_Properties"), NULL,
7676 /* tooltip */ N_("View or modify the properties of this folder"),
7677 G_CALLBACK (action_location_properties_callback) },
7678
7679 /* name, icon name, label */ {FM_ACTION_COPY_TO_NEXT_PANE, NULL, N_("_Other pane"),
7680 NULL, N_("Copy the current selection to the other pane in the window"),
7681 G_CALLBACK (action_copy_to_next_pane_callback) },
7682 /* name, icon name, label */ {FM_ACTION_MOVE_TO_NEXT_PANE, NULL, N_("_Other pane"),
7683 NULL, N_("Move the current selection to the other pane in the window"),
7684 G_CALLBACK (action_move_to_next_pane_callback) },
7685 /* name, icon name, label */ {FM_ACTION_COPY_TO_HOME, CAJA_ICON_HOME,
7686 N_("_Home Folder"), NULL,
7687 N_("Copy the current selection to the home folder"),
7688 G_CALLBACK (action_copy_to_home_callback) },
7689 /* name, icon name, label */ {FM_ACTION_MOVE_TO_HOME, CAJA_ICON_HOME,
7690 N_("_Home Folder"), NULL,
7691 N_("Move the current selection to the home folder"),
7692 G_CALLBACK (action_move_to_home_callback) },
7693 /* name, icon name, label */ {FM_ACTION_COPY_TO_DESKTOP, CAJA_ICON_DESKTOP,
7694 N_("_Desktop"), NULL,
7695 N_("Copy the current selection to the desktop"),
7696 G_CALLBACK (action_copy_to_desktop_callback) },
7697 /* name, icon name, label */ {FM_ACTION_MOVE_TO_DESKTOP, CAJA_ICON_DESKTOP,
7698 N_("_Desktop"), NULL,
7699 N_("Move the current selection to the desktop"),
7700 G_CALLBACK (action_move_to_desktop_callback) },
7701 };
7702
7703 static void
connect_proxy(FMDirectoryView * view,GtkAction * action,GtkWidget * proxy,GtkActionGroup * action_group)7704 connect_proxy (FMDirectoryView *view,
7705 GtkAction *action,
7706 GtkWidget *proxy,
7707 GtkActionGroup *action_group)
7708 {
7709 const gchar *action_name;
7710
7711 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
7712 action_name = gtk_action_get_name (action);
7713 G_GNUC_END_IGNORE_DEPRECATIONS;
7714
7715 if (strcmp (action_name, FM_ACTION_NEW_EMPTY_FILE) == 0 &&
7716 GTK_IS_IMAGE_MENU_ITEM (proxy)) {
7717 cairo_surface_t *surface;
7718
7719 surface = get_menu_icon ("text-x-generic", GTK_WIDGET (view));
7720
7721 if (surface != NULL) {
7722 GtkWidget *image;
7723
7724 image = gtk_image_new_from_surface (surface);
7725 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (proxy), image);
7726
7727 cairo_surface_destroy (surface);
7728 }
7729 }
7730 }
7731
7732 static void
pre_activate(FMDirectoryView * view,GtkAction * action,GtkActionGroup * action_group)7733 pre_activate (FMDirectoryView *view,
7734 GtkAction *action,
7735 GtkActionGroup *action_group)
7736 {
7737 GdkEvent *event;
7738 GtkWidget *proxy;
7739 gboolean activated_from_popup;
7740
7741 /* check whether action was activated through a popup menu.
7742 * If not, unset the last stored context menu popup position */
7743 activated_from_popup = FALSE;
7744
7745 event = gtk_get_current_event ();
7746 proxy = gtk_get_event_widget (event);
7747
7748 if (proxy != NULL) {
7749 GtkWidget *toplevel;
7750 GdkWindowTypeHint hint;
7751
7752 toplevel = gtk_widget_get_toplevel (proxy);
7753
7754 if (GTK_IS_WINDOW (toplevel)) {
7755 hint = gtk_window_get_type_hint (GTK_WINDOW (toplevel));
7756
7757 if (hint == GDK_WINDOW_TYPE_HINT_POPUP_MENU) {
7758 activated_from_popup = TRUE;
7759 }
7760 }
7761 }
7762
7763 if (!activated_from_popup) {
7764 update_context_menu_position_from_event (view, NULL);
7765 }
7766 }
7767
7768 static void
real_merge_menus(FMDirectoryView * view)7769 real_merge_menus (FMDirectoryView *view)
7770 {
7771 GtkActionGroup *action_group;
7772 GtkUIManager *ui_manager;
7773 GtkAction *action;
7774 const char *ui;
7775 char *tooltip;
7776
7777 ui_manager = caja_window_info_get_ui_manager (view->details->window);
7778
7779 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
7780 action_group = gtk_action_group_new ("DirViewActions");
7781 #ifdef ENABLE_NLS
7782 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
7783 #endif /* ENABLE_NLS */
7784 view->details->dir_action_group = action_group;
7785 gtk_action_group_add_actions (action_group,
7786 directory_view_entries, G_N_ELEMENTS (directory_view_entries),
7787 view);
7788 G_GNUC_END_IGNORE_DEPRECATIONS;
7789
7790 /* Translators: %s is a directory */
7791 tooltip = g_strdup_printf(_("Run or manage scripts from %s"), "~/.config/caja/scripts");
7792 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
7793 /* Create a script action here specially because its tooltip is dynamic */
7794 action = gtk_action_new ("Scripts", _("_Scripts"), tooltip, NULL);
7795 gtk_action_group_add_action (action_group, action);
7796 g_object_unref (action);
7797 g_free (tooltip);
7798
7799 action = gtk_action_group_get_action (action_group, FM_ACTION_NO_TEMPLATES);
7800 gtk_action_set_sensitive (action, FALSE);
7801 G_GNUC_END_IGNORE_DEPRECATIONS;
7802
7803 g_signal_connect_object (action_group, "connect-proxy",
7804 G_CALLBACK (connect_proxy), G_OBJECT (view),
7805 G_CONNECT_SWAPPED);
7806 g_signal_connect_object (action_group, "pre-activate",
7807 G_CALLBACK (pre_activate), G_OBJECT (view),
7808 G_CONNECT_SWAPPED);
7809
7810 /* Insert action group at end so clipboard action group ends up before it */
7811 gtk_ui_manager_insert_action_group (ui_manager, action_group, -1);
7812 g_object_unref (action_group); /* owned by ui manager */
7813
7814 ui = caja_ui_string_get ("caja-directory-view-ui.xml");
7815 view->details->dir_merge_id = gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, NULL);
7816 g_signal_connect_object (fm_directory_view_get_background (view), "settings_changed",
7817 G_CALLBACK (schedule_update_menus), G_OBJECT (view),
7818 G_CONNECT_SWAPPED);
7819 view->details->scripts_invalid = TRUE;
7820 view->details->templates_invalid = TRUE;
7821 }
7822
7823
7824 static gboolean
can_paste_into_file(CajaFile * file)7825 can_paste_into_file (CajaFile *file)
7826 {
7827 if (caja_file_is_directory (file) &&
7828 caja_file_can_write (file)) {
7829 return TRUE;
7830 }
7831 if (caja_file_has_activation_uri (file)) {
7832 GFile *location;
7833 CajaFile *activation_file;
7834 gboolean res;
7835
7836 location = caja_file_get_activation_location (file);
7837 activation_file = caja_file_get (location);
7838 g_object_unref (location);
7839
7840 /* The target location might not have data for it read yet,
7841 and we can't want to do sync I/O, so treat the unknown
7842 case as can-write */
7843 res = (caja_file_get_file_type (activation_file) == G_FILE_TYPE_UNKNOWN) ||
7844 (caja_file_get_file_type (activation_file) == G_FILE_TYPE_DIRECTORY &&
7845 caja_file_can_write (activation_file));
7846
7847 caja_file_unref (activation_file);
7848
7849 return res;
7850 }
7851
7852 return FALSE;
7853 }
7854
7855 static void
clipboard_targets_received(GtkClipboard * clipboard,GdkAtom * targets,int n_targets,gpointer user_data)7856 clipboard_targets_received (GtkClipboard *clipboard,
7857 GdkAtom *targets,
7858 int n_targets,
7859 gpointer user_data)
7860 {
7861 FMDirectoryView *view;
7862 gboolean can_paste;
7863 GList *selection;
7864 int count;
7865 GtkAction *action;
7866
7867 view = FM_DIRECTORY_VIEW (user_data);
7868 can_paste = FALSE;
7869
7870 if (view->details->window == NULL ||
7871 !view->details->active) {
7872 /* We've been destroyed or became inactive since call */
7873 g_object_unref (view);
7874 return;
7875 }
7876
7877 if (targets) {
7878 int i;
7879
7880 for (i=0; i < n_targets; i++) {
7881 if (targets[i] == copied_files_atom) {
7882 can_paste = TRUE;
7883 }
7884 }
7885 }
7886
7887
7888 selection = fm_directory_view_get_selection (view);
7889 count = g_list_length (selection);
7890
7891 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
7892 action = gtk_action_group_get_action (view->details->dir_action_group,
7893 FM_ACTION_PASTE);
7894 gtk_action_set_sensitive (action,
7895 can_paste && !fm_directory_view_is_read_only (view));
7896
7897 action = gtk_action_group_get_action (view->details->dir_action_group,
7898 FM_ACTION_PASTE_FILES_INTO);
7899 gtk_action_set_sensitive (action,
7900 can_paste && count == 1 &&
7901 can_paste_into_file (CAJA_FILE (selection->data)));
7902
7903 action = gtk_action_group_get_action (view->details->dir_action_group,
7904 FM_ACTION_LOCATION_PASTE_FILES_INTO);
7905 G_GNUC_END_IGNORE_DEPRECATIONS;
7906 g_object_set_data (G_OBJECT (action),
7907 "can-paste-according-to-clipboard",
7908 GINT_TO_POINTER (can_paste));
7909 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
7910 gtk_action_set_sensitive (action,
7911 GPOINTER_TO_INT (g_object_get_data (G_OBJECT (action),
7912 "can-paste-according-to-clipboard")) &&
7913 GPOINTER_TO_INT (g_object_get_data (G_OBJECT (action),
7914 "can-paste-according-to-destination")));
7915 G_GNUC_END_IGNORE_DEPRECATIONS;
7916
7917 caja_file_list_free (selection);
7918
7919 g_object_unref (view);
7920 }
7921
7922 static gboolean
showing_trash_directory(FMDirectoryView * view)7923 showing_trash_directory (FMDirectoryView *view)
7924 {
7925 CajaFile *file;
7926
7927 file = fm_directory_view_get_directory_as_file (view);
7928 if (file != NULL) {
7929 return caja_file_is_in_trash (file);
7930 }
7931 return FALSE;
7932 }
7933
7934 static gboolean
should_show_empty_trash(FMDirectoryView * view)7935 should_show_empty_trash (FMDirectoryView *view)
7936 {
7937 return (showing_trash_directory (view) || caja_window_info_get_window_type (view->details->window) == CAJA_WINDOW_NAVIGATION);
7938 }
7939
7940 static gboolean
file_list_all_are_folders(GList * file_list)7941 file_list_all_are_folders (GList *file_list)
7942 {
7943 GList *l;
7944 char *activation_uri;
7945 gboolean is_dir;
7946 CajaFile *linked_file;
7947 CajaFile *file = NULL;
7948
7949 for (l = file_list; l != NULL; l = l->next) {
7950 file = CAJA_FILE (l->data);
7951 if (caja_file_is_caja_link (file) &&
7952 !CAJA_IS_DESKTOP_ICON_FILE (file)) {
7953 if (caja_file_is_launcher (file)) {
7954 return FALSE;
7955 }
7956
7957 activation_uri = caja_file_get_activation_uri (file);
7958
7959 if (activation_uri == NULL) {
7960 g_free (activation_uri);
7961 return FALSE;
7962 }
7963
7964 linked_file = caja_file_get_existing_by_uri (activation_uri);
7965
7966 /* We might not actually know the type of the linked file yet,
7967 * however we don't want to schedule a read, since that might do things
7968 * like ask for password etc. This is a bit unfortunate, but I don't
7969 * know any way around it, so we do various heuristics here
7970 * to get things mostly right
7971 */
7972 is_dir =
7973 (linked_file != NULL &&
7974 caja_file_is_directory (linked_file)) ||
7975 (activation_uri != NULL &&
7976 activation_uri[strlen (activation_uri) - 1] == '/');
7977
7978 caja_file_unref (linked_file);
7979 g_free (activation_uri);
7980
7981 if (!is_dir) {
7982 return FALSE;
7983 }
7984 } else if (!(caja_file_is_directory (file) ||
7985 CAJA_IS_DESKTOP_ICON_FILE (file))) {
7986 return FALSE;
7987 }
7988 }
7989 return TRUE;
7990 }
7991
7992 static void
file_should_show_foreach(CajaFile * file,gboolean * show_mount,gboolean * show_unmount,gboolean * show_eject,gboolean * show_connect,gboolean * show_format,gboolean * show_start,gboolean * show_stop,gboolean * show_poll,GDriveStartStopType * start_stop_type)7993 file_should_show_foreach (CajaFile *file,
7994 gboolean *show_mount,
7995 gboolean *show_unmount,
7996 gboolean *show_eject,
7997 gboolean *show_connect,
7998 gboolean *show_format,
7999 gboolean *show_start,
8000 gboolean *show_stop,
8001 gboolean *show_poll,
8002 GDriveStartStopType *start_stop_type)
8003 {
8004 *show_mount = FALSE;
8005 *show_unmount = FALSE;
8006 *show_eject = FALSE;
8007 *show_connect = FALSE;
8008 *show_format = FALSE;
8009 *show_start = FALSE;
8010 *show_stop = FALSE;
8011 *show_poll = FALSE;
8012
8013 if (caja_file_can_eject (file)) {
8014 *show_eject = TRUE;
8015 }
8016
8017 if (caja_file_can_mount (file)) {
8018 *show_mount = TRUE;
8019
8020 #ifdef TODO_GIO
8021 if (something &&
8022 g_find_program_in_path ("gfloppy")) {
8023 *show_format = TRUE;
8024 }
8025 #endif
8026 }
8027
8028 if (caja_file_can_start (file) || caja_file_can_start_degraded (file)) {
8029 *show_start = TRUE;
8030 }
8031
8032 if (caja_file_can_stop (file)) {
8033 *show_stop = TRUE;
8034 }
8035
8036 /* Dot not show both Unmount and Eject/Safe Removal; too confusing to
8037 * have too many menu entries */
8038 if (caja_file_can_unmount (file) && !*show_eject && !*show_stop) {
8039 *show_unmount = TRUE;
8040 }
8041
8042 if (caja_file_can_poll_for_media (file) && !caja_file_is_media_check_automatic (file)) {
8043 *show_poll = TRUE;
8044 }
8045
8046 *start_stop_type = caja_file_get_start_stop_type (file);
8047
8048 if (caja_file_is_caja_link (file)) {
8049 char *uri;
8050
8051 uri = caja_file_get_activation_uri (file);
8052 if (uri != NULL &&
8053 (eel_istr_has_prefix (uri, "ftp:") ||
8054 eel_istr_has_prefix (uri, "ssh:") ||
8055 eel_istr_has_prefix (uri, "sftp:") ||
8056 eel_istr_has_prefix (uri, "dav:") ||
8057 eel_istr_has_prefix (uri, "davs:"))) {
8058 *show_connect = TRUE;
8059 }
8060 g_free (uri);
8061 }
8062 }
8063
8064 static void
file_should_show_self(CajaFile * file,gboolean * show_mount,gboolean * show_unmount,gboolean * show_eject,gboolean * show_format,gboolean * show_start,gboolean * show_stop,gboolean * show_poll,GDriveStartStopType * start_stop_type)8065 file_should_show_self (CajaFile *file,
8066 gboolean *show_mount,
8067 gboolean *show_unmount,
8068 gboolean *show_eject,
8069 gboolean *show_format,
8070 gboolean *show_start,
8071 gboolean *show_stop,
8072 gboolean *show_poll,
8073 GDriveStartStopType *start_stop_type)
8074 {
8075 *show_mount = FALSE;
8076 *show_unmount = FALSE;
8077 *show_eject = FALSE;
8078 *show_format = FALSE;
8079 *show_start = FALSE;
8080 *show_stop = FALSE;
8081 *show_poll = FALSE;
8082
8083 if (file == NULL) {
8084 return;
8085 }
8086
8087 if (caja_file_can_eject (file)) {
8088 *show_eject = TRUE;
8089 }
8090
8091 if (caja_file_can_mount (file)) {
8092 *show_mount = TRUE;
8093 }
8094
8095 #ifdef TODO_GIO
8096 if (something && g_find_program_in_path ("gfloppy")) {
8097 *show_format = TRUE;
8098 }
8099 #endif
8100
8101 if (caja_file_can_start (file) || caja_file_can_start_degraded (file)) {
8102 *show_start = TRUE;
8103 }
8104
8105 if (caja_file_can_stop (file)) {
8106 *show_stop = TRUE;
8107 }
8108
8109 /* Dot not show both Unmount and Eject/Safe Removal; too confusing to
8110 * have too many menu entries */
8111 if (caja_file_can_unmount (file) && !*show_eject && !*show_stop) {
8112 *show_unmount = TRUE;
8113 }
8114
8115 if (caja_file_can_poll_for_media (file) && !caja_file_is_media_check_automatic (file)) {
8116 *show_poll = TRUE;
8117 }
8118
8119 *start_stop_type = caja_file_get_start_stop_type (file);
8120
8121 }
8122
8123 static gboolean
files_are_all_directories(GList * files)8124 files_are_all_directories (GList *files)
8125 {
8126 GList *l;
8127 gboolean all_directories;
8128 CajaFile *file = NULL;
8129
8130 all_directories = TRUE;
8131
8132 for (l = files; l != NULL; l = l->next) {
8133 file = CAJA_FILE (l->data);
8134 all_directories &= caja_file_is_directory (file);
8135 }
8136
8137 return all_directories;
8138 }
8139
8140 static gboolean
files_is_none_directory(GList * files)8141 files_is_none_directory (GList *files)
8142 {
8143 GList *l;
8144 gboolean no_directory;
8145 CajaFile *file = NULL;
8146
8147 no_directory = TRUE;
8148
8149 for (l = files; l != NULL; l = l->next) {
8150 file = CAJA_FILE (l->data);
8151 no_directory &= !caja_file_is_directory (file);
8152 }
8153
8154 return no_directory;
8155 }
8156
8157 static void
update_restore_from_trash_action(GtkAction * action,GList * files,gboolean is_self)8158 update_restore_from_trash_action (GtkAction *action,
8159 GList *files,
8160 gboolean is_self)
8161 {
8162 CajaFile *original_file;
8163 CajaFile *original_dir;
8164 GHashTable *original_dirs_hash;
8165 GList *original_dirs;
8166 GFile *original_location;
8167 char *original_name;
8168
8169 original_file = NULL;
8170 original_dir = NULL;
8171 original_dirs = NULL;
8172 original_dirs_hash = NULL;
8173 original_location = NULL;
8174 original_name = NULL;
8175
8176 if (files != NULL) {
8177 if (g_list_length (files) == 1) {
8178 original_file = caja_file_get_trash_original_file (files->data);
8179 } else {
8180 original_dirs_hash = caja_trashed_files_get_original_directories (files, NULL);
8181 if (original_dirs_hash != NULL) {
8182 original_dirs = g_hash_table_get_keys (original_dirs_hash);
8183 if (g_list_length (original_dirs) == 1) {
8184 original_dir = caja_file_ref (CAJA_FILE (original_dirs->data));
8185 }
8186 }
8187 }
8188 }
8189
8190 if (original_file != NULL || original_dirs != NULL) {
8191 char *tooltip;
8192
8193 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
8194 gtk_action_set_visible (action, TRUE);
8195 G_GNUC_END_IGNORE_DEPRECATIONS;
8196
8197 if (original_file != NULL) {
8198 original_location = caja_file_get_location (original_file);
8199 } else if (original_dir != NULL) {
8200 original_location = caja_file_get_location (original_dir);
8201 }
8202
8203 if (original_location != NULL) {
8204 original_name = g_file_get_parse_name (original_location);
8205 }
8206
8207 if (is_self) {
8208 g_assert (g_list_length (files) == 1);
8209 g_assert (original_location != NULL);
8210 tooltip = g_strdup_printf (_("Move the open folder out of the trash to \"%s\""), original_name);
8211 } else if (files_are_all_directories (files)) {
8212 if (original_name != NULL) {
8213 tooltip = g_strdup_printf (ngettext ("Move the selected folder out of the trash to \"%s\"",
8214 "Move the selected folders out of the trash to \"%s\"",
8215 g_list_length (files)), original_name);
8216 } else {
8217 tooltip = g_strdup_printf (ngettext ("Move the selected folder out of the trash",
8218 "Move the selected folders out of the trash",
8219 g_list_length (files)));
8220 }
8221 } else if (files_is_none_directory (files)) {
8222 if (original_name != NULL) {
8223 tooltip = g_strdup_printf (ngettext ("Move the selected file out of the trash to \"%s\"",
8224 "Move the selected files out of the trash to \"%s\"",
8225 g_list_length (files)), original_name);
8226 } else {
8227 tooltip = g_strdup_printf (ngettext ("Move the selected file out of the trash",
8228 "Move the selected files out of the trash",
8229 g_list_length (files)));
8230 }
8231 } else {
8232 if (original_name != NULL) {
8233 tooltip = g_strdup_printf (ngettext ("Move the selected item out of the trash to \"%s\"",
8234 "Move the selected items out of the trash to \"%s\"",
8235 g_list_length (files)), original_name);
8236 } else {
8237 tooltip = g_strdup_printf (ngettext ("Move the selected item out of the trash",
8238 "Move the selected items out of the trash",
8239 g_list_length (files)));
8240 }
8241 }
8242 g_free (original_name);
8243
8244 g_object_set (action, "tooltip", tooltip, NULL);
8245
8246 if (original_location != NULL) {
8247 g_object_unref (original_location);
8248 }
8249 } else {
8250 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
8251 gtk_action_set_visible (action, FALSE);
8252 G_GNUC_END_IGNORE_DEPRECATIONS;
8253 }
8254
8255 caja_file_unref (original_file);
8256 caja_file_unref (original_dir);
8257 g_list_free (original_dirs);
8258
8259 if (original_dirs_hash != NULL) {
8260 g_hash_table_destroy (original_dirs_hash);
8261 }
8262 }
8263
8264 static void
real_update_menus_volumes(FMDirectoryView * view,GList * selection,gint selection_count)8265 real_update_menus_volumes (FMDirectoryView *view,
8266 GList *selection,
8267 gint selection_count)
8268 {
8269 GList *l;
8270 CajaFile *file;
8271 gboolean show_mount;
8272 gboolean show_unmount;
8273 gboolean show_eject;
8274 gboolean show_connect;
8275 gboolean show_format;
8276 gboolean show_start;
8277 gboolean show_stop;
8278 gboolean show_poll;
8279 GDriveStartStopType start_stop_type;
8280 gboolean show_self_mount;
8281 gboolean show_self_unmount;
8282 gboolean show_self_eject;
8283 gboolean show_self_format;
8284 gboolean show_self_start;
8285 gboolean show_self_stop;
8286 gboolean show_self_poll;
8287 GDriveStartStopType self_start_stop_type;
8288 GtkAction *action;
8289
8290 show_mount = (selection != NULL);
8291 show_unmount = (selection != NULL);
8292 show_eject = (selection != NULL);
8293 show_connect = (selection != NULL && selection_count == 1);
8294 show_format = (selection != NULL && selection_count == 1);
8295 show_start = (selection != NULL && selection_count == 1);
8296 show_stop = (selection != NULL && selection_count == 1);
8297 show_poll = (selection != NULL && selection_count == 1);
8298 start_stop_type = G_DRIVE_START_STOP_TYPE_UNKNOWN;
8299 self_start_stop_type = G_DRIVE_START_STOP_TYPE_UNKNOWN;
8300
8301 for (l = selection; l != NULL && (show_mount || show_unmount
8302 || show_eject || show_connect
8303 || show_format || show_start
8304 || show_stop || show_poll);
8305 l = l->next) {
8306 gboolean show_mount_one;
8307 gboolean show_unmount_one;
8308 gboolean show_eject_one;
8309 gboolean show_connect_one;
8310 gboolean show_format_one;
8311 gboolean show_start_one;
8312 gboolean show_stop_one;
8313 gboolean show_poll_one;
8314
8315 file = CAJA_FILE (l->data);
8316 file_should_show_foreach (file,
8317 &show_mount_one,
8318 &show_unmount_one,
8319 &show_eject_one,
8320 &show_connect_one,
8321 &show_format_one,
8322 &show_start_one,
8323 &show_stop_one,
8324 &show_poll_one,
8325 &start_stop_type);
8326
8327 show_mount &= show_mount_one;
8328 show_unmount &= show_unmount_one;
8329 show_eject &= show_eject_one;
8330 show_connect &= show_connect_one;
8331 show_format &= show_format_one;
8332 show_start &= show_start_one;
8333 show_stop &= show_stop_one;
8334 show_poll &= show_poll_one;
8335 }
8336
8337 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
8338 action = gtk_action_group_get_action (view->details->dir_action_group,
8339 FM_ACTION_CONNECT_TO_SERVER_LINK);
8340 gtk_action_set_visible (action, show_connect);
8341
8342 action = gtk_action_group_get_action (view->details->dir_action_group,
8343 FM_ACTION_MOUNT_VOLUME);
8344 gtk_action_set_visible (action, show_mount);
8345
8346 action = gtk_action_group_get_action (view->details->dir_action_group,
8347 FM_ACTION_UNMOUNT_VOLUME);
8348 gtk_action_set_visible (action, show_unmount);
8349
8350 action = gtk_action_group_get_action (view->details->dir_action_group,
8351 FM_ACTION_EJECT_VOLUME);
8352 gtk_action_set_visible (action, show_eject);
8353
8354 action = gtk_action_group_get_action (view->details->dir_action_group,
8355 FM_ACTION_FORMAT_VOLUME);
8356 gtk_action_set_visible (action, show_format);
8357
8358 action = gtk_action_group_get_action (view->details->dir_action_group,
8359 FM_ACTION_START_VOLUME);
8360 gtk_action_set_visible (action, show_start);
8361 if (show_start) {
8362 switch (start_stop_type) {
8363 default:
8364 case G_DRIVE_START_STOP_TYPE_UNKNOWN:
8365 gtk_action_set_label (action, _("_Start"));
8366 gtk_action_set_tooltip (action, _("Start the selected drive"));
8367 break;
8368 case G_DRIVE_START_STOP_TYPE_SHUTDOWN:
8369 gtk_action_set_label (action, _("_Start"));
8370 gtk_action_set_tooltip (action, _("Start the selected drive"));
8371 break;
8372 case G_DRIVE_START_STOP_TYPE_NETWORK:
8373 gtk_action_set_label (action, _("_Connect"));
8374 gtk_action_set_tooltip (action, _("Connect to the selected drive"));
8375 break;
8376 case G_DRIVE_START_STOP_TYPE_MULTIDISK:
8377 gtk_action_set_label (action, _("_Start Multi-disk Drive"));
8378 gtk_action_set_tooltip (action, _("Start the selected multi-disk drive"));
8379 break;
8380 case G_DRIVE_START_STOP_TYPE_PASSWORD:
8381 gtk_action_set_label (action, _("U_nlock Drive"));
8382 gtk_action_set_tooltip (action, _("Unlock the selected drive"));
8383 break;
8384 }
8385 }
8386
8387 action = gtk_action_group_get_action (view->details->dir_action_group,
8388 FM_ACTION_STOP_VOLUME);
8389 gtk_action_set_visible (action, show_stop);
8390 if (show_stop) {
8391 switch (start_stop_type) {
8392 default:
8393 case G_DRIVE_START_STOP_TYPE_UNKNOWN:
8394 gtk_action_set_label (action, _("_Stop"));
8395 gtk_action_set_tooltip (action, _("Stop the selected drive"));
8396 break;
8397 case G_DRIVE_START_STOP_TYPE_SHUTDOWN:
8398 gtk_action_set_label (action, _("_Safely Remove Drive"));
8399 gtk_action_set_tooltip (action, _("Safely remove the selected drive"));
8400 break;
8401 case G_DRIVE_START_STOP_TYPE_NETWORK:
8402 gtk_action_set_label (action, _("_Disconnect"));
8403 gtk_action_set_tooltip (action, _("Disconnect the selected drive"));
8404 break;
8405 case G_DRIVE_START_STOP_TYPE_MULTIDISK:
8406 gtk_action_set_label (action, _("_Stop Multi-disk Drive"));
8407 gtk_action_set_tooltip (action, _("Stop the selected multi-disk drive"));
8408 break;
8409 case G_DRIVE_START_STOP_TYPE_PASSWORD:
8410 gtk_action_set_label (action, _("_Lock Drive"));
8411 gtk_action_set_tooltip (action, _("Lock the selected drive"));
8412 break;
8413 }
8414 }
8415
8416 action = gtk_action_group_get_action (view->details->dir_action_group,
8417 FM_ACTION_POLL);
8418 gtk_action_set_visible (action, show_poll);
8419 G_GNUC_END_IGNORE_DEPRECATIONS;
8420
8421 show_self_mount = show_self_unmount = show_self_eject =
8422 show_self_format = show_self_start = show_self_stop = show_self_poll = FALSE;
8423
8424 file = fm_directory_view_get_directory_as_file (view);
8425 file_should_show_self (file,
8426 &show_self_mount,
8427 &show_self_unmount,
8428 &show_self_eject,
8429 &show_self_format,
8430 &show_self_start,
8431 &show_self_stop,
8432 &show_self_poll,
8433 &self_start_stop_type);
8434
8435 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
8436 action = gtk_action_group_get_action (view->details->dir_action_group,
8437 FM_ACTION_SELF_MOUNT_VOLUME);
8438 gtk_action_set_visible (action, show_self_mount);
8439
8440 action = gtk_action_group_get_action (view->details->dir_action_group,
8441 FM_ACTION_SELF_UNMOUNT_VOLUME);
8442 gtk_action_set_visible (action, show_self_unmount);
8443
8444 action = gtk_action_group_get_action (view->details->dir_action_group,
8445 FM_ACTION_SELF_EJECT_VOLUME);
8446 gtk_action_set_visible (action, show_self_eject);
8447
8448 action = gtk_action_group_get_action (view->details->dir_action_group,
8449 FM_ACTION_SELF_FORMAT_VOLUME);
8450 gtk_action_set_visible (action, show_self_format);
8451
8452 action = gtk_action_group_get_action (view->details->dir_action_group,
8453 FM_ACTION_SELF_START_VOLUME);
8454 gtk_action_set_visible (action, show_self_start);
8455 if (show_self_start) {
8456 switch (self_start_stop_type) {
8457 default:
8458 case G_DRIVE_START_STOP_TYPE_UNKNOWN:
8459 gtk_action_set_label (action, _("_Start"));
8460 gtk_action_set_tooltip (action, _("Start the drive associated with the open folder"));
8461 break;
8462 case G_DRIVE_START_STOP_TYPE_SHUTDOWN:
8463 gtk_action_set_label (action, _("_Start"));
8464 gtk_action_set_tooltip (action, _("Start the drive associated with the open folder"));
8465 break;
8466 case G_DRIVE_START_STOP_TYPE_NETWORK:
8467 gtk_action_set_label (action, _("_Connect"));
8468 gtk_action_set_tooltip (action, _("Connect to the drive associated with the open folder"));
8469 break;
8470 case G_DRIVE_START_STOP_TYPE_MULTIDISK:
8471 gtk_action_set_label (action, _("_Start Multi-disk Drive"));
8472 gtk_action_set_tooltip (action, _("Start the multi-disk drive associated with the open folder"));
8473 break;
8474 case G_DRIVE_START_STOP_TYPE_PASSWORD:
8475 gtk_action_set_label (action, _("_Unlock Drive"));
8476 gtk_action_set_tooltip (action, _("Unlock the drive associated with the open folder"));
8477 break;
8478 }
8479 }
8480
8481 action = gtk_action_group_get_action (view->details->dir_action_group,
8482 FM_ACTION_SELF_STOP_VOLUME);
8483 gtk_action_set_visible (action, show_self_stop);
8484 if (show_self_stop) {
8485 switch (self_start_stop_type) {
8486 default:
8487 case G_DRIVE_START_STOP_TYPE_UNKNOWN:
8488 gtk_action_set_label (action, _("_Stop"));
8489 gtk_action_set_tooltip (action, _("_Stop the drive associated with the open folder"));
8490 break;
8491 case G_DRIVE_START_STOP_TYPE_SHUTDOWN:
8492 gtk_action_set_label (action, _("_Safely Remove Drive"));
8493 gtk_action_set_tooltip (action, _("Safely remove the drive associated with the open folder"));
8494 break;
8495 case G_DRIVE_START_STOP_TYPE_NETWORK:
8496 gtk_action_set_label (action, _("_Disconnect"));
8497 gtk_action_set_tooltip (action, _("Disconnect the drive associated with the open folder"));
8498 break;
8499 case G_DRIVE_START_STOP_TYPE_MULTIDISK:
8500 gtk_action_set_label (action, _("_Stop Multi-disk Drive"));
8501 gtk_action_set_tooltip (action, _("Stop the multi-disk drive associated with the open folder"));
8502 break;
8503 case G_DRIVE_START_STOP_TYPE_PASSWORD:
8504 gtk_action_set_label (action, _("_Lock Drive"));
8505 gtk_action_set_tooltip (action, _("Lock the drive associated with the open folder"));
8506 break;
8507 }
8508 }
8509
8510 action = gtk_action_group_get_action (view->details->dir_action_group,
8511 FM_ACTION_SELF_POLL);
8512 gtk_action_set_visible (action, show_self_poll);
8513 G_GNUC_END_IGNORE_DEPRECATIONS;
8514
8515 }
8516
8517 static void
real_update_location_menu_volumes(FMDirectoryView * view)8518 real_update_location_menu_volumes (FMDirectoryView *view)
8519 {
8520 GtkAction *action;
8521 CajaFile *file;
8522 gboolean show_mount;
8523 gboolean show_unmount;
8524 gboolean show_eject;
8525 gboolean show_connect;
8526 gboolean show_format;
8527 gboolean show_start;
8528 gboolean show_stop;
8529 gboolean show_poll;
8530 GDriveStartStopType start_stop_type;
8531
8532 g_assert (FM_IS_DIRECTORY_VIEW (view));
8533 g_assert (CAJA_IS_FILE (view->details->location_popup_directory_as_file));
8534
8535 file = CAJA_FILE (view->details->location_popup_directory_as_file);
8536 file_should_show_foreach (file,
8537 &show_mount,
8538 &show_unmount,
8539 &show_eject,
8540 &show_connect,
8541 &show_format,
8542 &show_start,
8543 &show_stop,
8544 &show_poll,
8545 &start_stop_type);
8546
8547 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
8548 action = gtk_action_group_get_action (view->details->dir_action_group,
8549 FM_ACTION_LOCATION_MOUNT_VOLUME);
8550 gtk_action_set_visible (action, show_mount);
8551
8552 action = gtk_action_group_get_action (view->details->dir_action_group,
8553 FM_ACTION_LOCATION_UNMOUNT_VOLUME);
8554 gtk_action_set_visible (action, show_unmount);
8555
8556 action = gtk_action_group_get_action (view->details->dir_action_group,
8557 FM_ACTION_LOCATION_EJECT_VOLUME);
8558 gtk_action_set_visible (action, show_eject);
8559
8560 action = gtk_action_group_get_action (view->details->dir_action_group,
8561 FM_ACTION_LOCATION_FORMAT_VOLUME);
8562 gtk_action_set_visible (action, show_format);
8563
8564 action = gtk_action_group_get_action (view->details->dir_action_group,
8565 FM_ACTION_LOCATION_START_VOLUME);
8566 gtk_action_set_visible (action, show_start);
8567 if (show_start) {
8568 switch (start_stop_type) {
8569 default:
8570 case G_DRIVE_START_STOP_TYPE_UNKNOWN:
8571 gtk_action_set_label (action, _("_Start"));
8572 gtk_action_set_tooltip (action, _("Start the selected drive"));
8573 break;
8574 case G_DRIVE_START_STOP_TYPE_SHUTDOWN:
8575 gtk_action_set_label (action, _("_Start"));
8576 gtk_action_set_tooltip (action, _("Start the selected drive"));
8577 break;
8578 case G_DRIVE_START_STOP_TYPE_NETWORK:
8579 gtk_action_set_label (action, _("_Connect"));
8580 gtk_action_set_tooltip (action, _("Connect to the selected drive"));
8581 break;
8582 case G_DRIVE_START_STOP_TYPE_MULTIDISK:
8583 gtk_action_set_label (action, _("_Start Multi-disk Drive"));
8584 gtk_action_set_tooltip (action, _("Start the selected multi-disk drive"));
8585 break;
8586 case G_DRIVE_START_STOP_TYPE_PASSWORD:
8587 gtk_action_set_label (action, _("_Unlock Drive"));
8588 gtk_action_set_tooltip (action, _("Unlock the selected drive"));
8589 break;
8590 }
8591 }
8592
8593 action = gtk_action_group_get_action (view->details->dir_action_group,
8594 FM_ACTION_LOCATION_STOP_VOLUME);
8595 gtk_action_set_visible (action, show_stop);
8596 if (show_stop) {
8597 switch (start_stop_type) {
8598 default:
8599 case G_DRIVE_START_STOP_TYPE_UNKNOWN:
8600 gtk_action_set_label (action, _("_Stop"));
8601 gtk_action_set_tooltip (action, _("Stop the selected volume"));
8602 break;
8603 case G_DRIVE_START_STOP_TYPE_SHUTDOWN:
8604 gtk_action_set_label (action, _("_Safely Remove Drive"));
8605 gtk_action_set_tooltip (action, _("Safely remove the selected drive"));
8606 break;
8607 case G_DRIVE_START_STOP_TYPE_NETWORK:
8608 gtk_action_set_label (action, _("_Disconnect"));
8609 gtk_action_set_tooltip (action, _("Disconnect the selected drive"));
8610 break;
8611 case G_DRIVE_START_STOP_TYPE_MULTIDISK:
8612 gtk_action_set_label (action, _("_Stop Multi-disk Drive"));
8613 gtk_action_set_tooltip (action, _("Stop the selected multi-disk drive"));
8614 break;
8615 case G_DRIVE_START_STOP_TYPE_PASSWORD:
8616 gtk_action_set_label (action, _("_Lock Drive"));
8617 gtk_action_set_tooltip (action, _("Lock the selected drive"));
8618 break;
8619 }
8620 }
8621
8622 action = gtk_action_group_get_action (view->details->dir_action_group,
8623 FM_ACTION_LOCATION_POLL);
8624 gtk_action_set_visible (action, show_poll);
8625 G_GNUC_END_IGNORE_DEPRECATIONS;
8626 }
8627
8628 /* TODO: we should split out this routine into two functions:
8629 * Update on clipboard changes
8630 * Update on selection changes
8631 */
8632 static void
real_update_paste_menu(FMDirectoryView * view,GList * selection,gint selection_count)8633 real_update_paste_menu (FMDirectoryView *view,
8634 GList *selection,
8635 gint selection_count)
8636 {
8637 gboolean can_paste_files_into;
8638 gboolean selection_is_read_only;
8639 gboolean is_read_only;
8640 GtkAction *action;
8641
8642 selection_is_read_only = selection_count == 1 &&
8643 (!caja_file_can_write (CAJA_FILE (selection->data)) &&
8644 !caja_file_has_activation_uri (CAJA_FILE (selection->data)));
8645
8646 is_read_only = fm_directory_view_is_read_only (view);
8647
8648 can_paste_files_into = (selection_count == 1 &&
8649 can_paste_into_file (CAJA_FILE (selection->data)));
8650
8651 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
8652 action = gtk_action_group_get_action (view->details->dir_action_group,
8653 FM_ACTION_PASTE);
8654 gtk_action_set_sensitive (action, !is_read_only);
8655
8656 action = gtk_action_group_get_action (view->details->dir_action_group,
8657 FM_ACTION_PASTE_FILES_INTO);
8658 gtk_action_set_visible (action, can_paste_files_into);
8659 gtk_action_set_sensitive (action, !selection_is_read_only);
8660 G_GNUC_END_IGNORE_DEPRECATIONS;
8661
8662 /* Ask the clipboard */
8663 g_object_ref (view); /* Need to keep the object alive until we get the reply */
8664 gtk_clipboard_request_targets (caja_clipboard_get (GTK_WIDGET (view)),
8665 clipboard_targets_received,
8666 view);
8667 }
8668
8669 static void
real_update_location_menu(FMDirectoryView * view)8670 real_update_location_menu (FMDirectoryView *view)
8671 {
8672 GtkAction *action;
8673 CajaFile *file;
8674 gboolean is_special_link;
8675 gboolean is_desktop_or_home_dir;
8676 gboolean can_delete_file, show_delete;
8677 gboolean show_separate_delete_command;
8678 gboolean show_open_folder_window;
8679 gboolean show_open_in_new_tab;
8680 GList l;
8681 char *label;
8682 char *tip;
8683
8684 show_open_folder_window = FALSE;
8685 show_open_in_new_tab = FALSE;
8686
8687 if (caja_window_info_get_window_type (view->details->window) == CAJA_WINDOW_NAVIGATION) {
8688 if (g_settings_get_boolean (caja_preferences, CAJA_PREFERENCES_ALWAYS_USE_BROWSER)) {
8689 label = _("Open in New _Window");
8690 } else {
8691 label = _("Browse in New _Window");
8692 show_open_folder_window = TRUE;
8693 }
8694
8695 show_open_in_new_tab = TRUE;
8696 } else {
8697 label = g_strdup (ngettext ("_Browse Folder",
8698 "_Browse Folders", 1));
8699 }
8700 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
8701 action = gtk_action_group_get_action (view->details->dir_action_group,
8702 FM_ACTION_LOCATION_OPEN_ALTERNATE);
8703 g_object_set (action,
8704 "label", label,
8705 NULL);
8706
8707 action = gtk_action_group_get_action (view->details->dir_action_group,
8708 FM_ACTION_LOCATION_OPEN_IN_NEW_TAB);
8709 gtk_action_set_visible (action, show_open_in_new_tab);
8710 G_GNUC_END_IGNORE_DEPRECATIONS;
8711
8712 if (show_open_in_new_tab) {
8713 if (g_settings_get_boolean (caja_preferences, CAJA_PREFERENCES_ALWAYS_USE_BROWSER)) {
8714 label = _("Open in New _Tab");
8715 } else {
8716 label = _("Browse in New _Tab");
8717 }
8718 g_object_set (action,
8719 "label", label,
8720 NULL);
8721 }
8722
8723 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
8724 action = gtk_action_group_get_action (view->details->dir_action_group,
8725 FM_ACTION_LOCATION_OPEN_FOLDER_WINDOW);
8726 gtk_action_set_visible (action, show_open_folder_window);
8727 G_GNUC_END_IGNORE_DEPRECATIONS;
8728
8729 file = view->details->location_popup_directory_as_file;
8730 g_assert (CAJA_IS_FILE (file));
8731 g_assert (caja_file_check_if_ready (file, CAJA_FILE_ATTRIBUTE_INFO |
8732 CAJA_FILE_ATTRIBUTE_MOUNT |
8733 CAJA_FILE_ATTRIBUTE_FILESYSTEM_INFO));
8734
8735 is_special_link = CAJA_IS_DESKTOP_ICON_FILE (file);
8736 is_desktop_or_home_dir = caja_file_is_home (file)
8737 || caja_file_is_desktop_directory (file);
8738
8739 can_delete_file =
8740 caja_file_can_delete (file) &&
8741 !is_special_link &&
8742 !is_desktop_or_home_dir;
8743
8744 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
8745 action = gtk_action_group_get_action (view->details->dir_action_group,
8746 FM_ACTION_LOCATION_CUT);
8747 gtk_action_set_sensitive (action, can_delete_file);
8748
8749 action = gtk_action_group_get_action (view->details->dir_action_group,
8750 FM_ACTION_LOCATION_PASTE_FILES_INTO);
8751 G_GNUC_END_IGNORE_DEPRECATIONS;
8752 g_object_set_data (G_OBJECT (action),
8753 "can-paste-according-to-destination",
8754 GINT_TO_POINTER (can_paste_into_file (file)));
8755 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
8756 gtk_action_set_sensitive (action,
8757 GPOINTER_TO_INT (g_object_get_data (G_OBJECT (action),
8758 "can-paste-according-to-clipboard")) &&
8759 GPOINTER_TO_INT (g_object_get_data (G_OBJECT (action),
8760 "can-paste-according-to-destination")));
8761 G_GNUC_END_IGNORE_DEPRECATIONS;
8762
8763 show_delete = TRUE;
8764
8765 if (file != NULL &&
8766 caja_file_is_in_trash (file)) {
8767 if (caja_file_is_self_owned (file)) {
8768 show_delete = FALSE;
8769 }
8770
8771 label = _("_Delete Permanently");
8772 tip = _("Delete the open folder permanently");
8773 show_separate_delete_command = FALSE;
8774 } else {
8775 label = _("Mo_ve to Trash");
8776 tip = _("Move the open folder to the Trash");
8777 show_separate_delete_command = g_settings_get_boolean (caja_preferences, CAJA_PREFERENCES_ENABLE_DELETE);
8778 }
8779
8780 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
8781 action = gtk_action_group_get_action (view->details->dir_action_group,
8782 FM_ACTION_LOCATION_TRASH);
8783 g_object_set (action,
8784 "label", label,
8785 "tooltip", tip,
8786 "icon-name", (file != NULL &&
8787 caja_file_is_in_trash (file)) ?
8788 CAJA_ICON_DELETE : CAJA_ICON_TRASH_FULL,
8789 NULL);
8790 gtk_action_set_sensitive (action, can_delete_file);
8791 gtk_action_set_visible (action, show_delete);
8792
8793 action = gtk_action_group_get_action (view->details->dir_action_group,
8794 FM_ACTION_LOCATION_DELETE);
8795 gtk_action_set_visible (action, show_separate_delete_command);
8796 if (show_separate_delete_command) {
8797 gtk_action_set_sensitive (action, can_delete_file);
8798 g_object_set (action,
8799 "icon-name", CAJA_ICON_DELETE,
8800 "sensitive", can_delete_file,
8801 NULL);
8802 }
8803
8804 action = gtk_action_group_get_action (view->details->dir_action_group,
8805 FM_ACTION_LOCATION_RESTORE_FROM_TRASH);
8806 G_GNUC_END_IGNORE_DEPRECATIONS;
8807 l.prev = NULL;
8808 l.next = NULL;
8809 l.data = file;
8810 update_restore_from_trash_action (action, &l, TRUE);
8811
8812 real_update_location_menu_volumes (view);
8813
8814 /* we silently assume that fm_directory_view_supports_properties always returns the same value.
8815 * Therefore, we don't update the sensitivity of FM_ACTION_LOCATION_PROPERTIES */
8816 }
8817
8818 static void
clipboard_changed_callback(CajaClipboardMonitor * monitor,FMDirectoryView * view)8819 clipboard_changed_callback (CajaClipboardMonitor *monitor, FMDirectoryView *view)
8820 {
8821 GList *selection;
8822 gint selection_count;
8823
8824 if (!view->details->active) {
8825 return;
8826 }
8827
8828 selection = fm_directory_view_get_selection (view);
8829 selection_count = g_list_length (selection);
8830
8831 real_update_paste_menu (view, selection, selection_count);
8832
8833 caja_file_list_free (selection);
8834
8835 }
8836
8837 static gboolean
can_delete_all(GList * files)8838 can_delete_all (GList *files)
8839 {
8840 GList *l;
8841 CajaFile *file = NULL;
8842
8843 for (l = files; l != NULL; l = l->next) {
8844 file = l->data;
8845 if (!caja_file_can_delete (file)) {
8846 return FALSE;
8847 }
8848 }
8849 return TRUE;
8850 }
8851
8852 static gboolean
has_writable_extra_pane(FMDirectoryView * view)8853 has_writable_extra_pane (FMDirectoryView *view)
8854 {
8855 FMDirectoryView *other_view;
8856
8857 other_view = get_directory_view_of_extra_pane (view);
8858 if (other_view != NULL) {
8859 return !fm_directory_view_is_read_only (other_view);
8860 }
8861 return FALSE;
8862 }
8863
8864 static void
real_update_menus(FMDirectoryView * view)8865 real_update_menus (FMDirectoryView *view)
8866 {
8867 GList *selection, *l;
8868 gint selection_count;
8869 const char *tip, *label;
8870 char *label_with_underscore;
8871 gboolean selection_contains_special_link;
8872 gboolean selection_contains_desktop_or_home_dir;
8873 gboolean can_create_files;
8874 gboolean can_delete_files;
8875 gboolean can_copy_files;
8876 gboolean can_link_files;
8877 gboolean can_duplicate_files;
8878 gboolean show_separate_delete_command;
8879 gboolean vfolder_directory;
8880 gboolean disable_command_line;
8881 gboolean show_open_alternate;
8882 gboolean can_open;
8883 gboolean show_app;
8884 gboolean show_save_search;
8885 gboolean save_search_sensitive;
8886 gboolean show_save_search_as;
8887 gboolean show_open_folder_window;
8888 GtkAction *action;
8889 GAppInfo *app;
8890 GIcon *app_icon;
8891 GtkWidget *menuitem;
8892 gboolean next_pane_is_writable;
8893 gboolean show_properties;
8894
8895 selection = fm_directory_view_get_selection (view);
8896 selection_count = g_list_length (selection);
8897
8898 selection_contains_special_link = special_link_in_selection (view);
8899 selection_contains_desktop_or_home_dir = desktop_or_home_dir_in_selection (view);
8900
8901 can_create_files = fm_directory_view_supports_creating_files (view);
8902 can_delete_files =
8903 can_delete_all (selection) &&
8904 selection_count != 0 &&
8905 !selection_contains_special_link &&
8906 !selection_contains_desktop_or_home_dir;
8907 can_copy_files = selection_count != 0
8908 && !selection_contains_special_link;
8909
8910 can_duplicate_files = can_create_files && can_copy_files;
8911 can_link_files = can_create_files && can_copy_files;
8912
8913 vfolder_directory = we_are_in_vfolder_desktop_dir (view);
8914
8915 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
8916 action = gtk_action_group_get_action (view->details->dir_action_group,
8917 FM_ACTION_RENAME);
8918 gtk_action_set_sensitive (action,
8919 selection_count == 1 &&
8920 fm_directory_view_can_rename_file (view, selection->data));
8921
8922 action = gtk_action_group_get_action (view->details->dir_action_group,
8923 FM_ACTION_NEW_FOLDER);
8924 gtk_action_set_sensitive (action, can_create_files);
8925
8926 action = gtk_action_group_get_action (view->details->dir_action_group,
8927 FM_ACTION_OPEN);
8928 gtk_action_set_sensitive (action, selection_count != 0);
8929 G_GNUC_END_IGNORE_DEPRECATIONS;
8930
8931 can_open = show_app = selection_count != 0;
8932
8933 for (l = selection; l != NULL; l = l->next) {
8934 CajaFile *file;
8935
8936 file = CAJA_FILE (l->data);
8937
8938 /* Double-check if the files' MIME types have changed before we
8939 commit to a choice of applications for them. This can happen
8940 if, for instance, a file was originally created with 0 bytes
8941 and then content was added to it later-- it will change from
8942 plaintext to something else. */
8943 caja_file_refresh_info (file);
8944
8945 if (!caja_mime_file_opens_in_external_app (file)) {
8946 show_app = FALSE;
8947 }
8948
8949 if (!show_app) {
8950 break;
8951 }
8952 }
8953
8954 label_with_underscore = NULL;
8955
8956 app = NULL;
8957 app_icon = NULL;
8958
8959 if (can_open && show_app) {
8960 app = caja_mime_get_default_application_for_files (selection);
8961 }
8962
8963 if (app != NULL) {
8964 char *escaped_app;
8965
8966 escaped_app = eel_str_double_underscores (g_app_info_get_display_name (app));
8967 label_with_underscore = g_strdup_printf (_("_Open With %s"),
8968 escaped_app);
8969
8970 app_icon = g_app_info_get_icon (app);
8971 if (app_icon != NULL) {
8972 g_object_ref (app_icon);
8973 }
8974
8975 g_free (escaped_app);
8976 g_object_unref (app);
8977 }
8978
8979 g_object_set (action, "label",
8980 label_with_underscore ? label_with_underscore : _("_Open"),
8981 NULL);
8982
8983 menuitem = gtk_ui_manager_get_widget (
8984 caja_window_info_get_ui_manager (view->details->window),
8985 FM_DIRECTORY_VIEW_MENU_PATH_OPEN);
8986
8987 /* Only force displaying the icon if it is an application icon */
8988 gtk_image_menu_item_set_always_show_image (
8989 GTK_IMAGE_MENU_ITEM (menuitem), app_icon != NULL);
8990
8991 menuitem = gtk_ui_manager_get_widget (
8992 caja_window_info_get_ui_manager (view->details->window),
8993 FM_DIRECTORY_VIEW_POPUP_PATH_OPEN);
8994
8995 /* Only force displaying the icon if it is an application icon */
8996 gtk_image_menu_item_set_always_show_image (
8997 GTK_IMAGE_MENU_ITEM (menuitem), app_icon != NULL);
8998
8999 if (app_icon == NULL) {
9000 app_icon = g_themed_icon_new ("document-open");
9001 }
9002
9003 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
9004 gtk_action_set_gicon (action, app_icon);
9005 g_object_unref (app_icon);
9006
9007 gtk_action_set_visible (action, can_open);
9008 G_GNUC_END_IGNORE_DEPRECATIONS;
9009
9010 g_free (label_with_underscore);
9011
9012 show_open_alternate = file_list_all_are_folders (selection) &&
9013 selection_count > 0 &&
9014 !(caja_window_info_get_window_type (view->details->window) == CAJA_WINDOW_DESKTOP &&
9015 g_settings_get_boolean (caja_preferences, CAJA_PREFERENCES_ALWAYS_USE_BROWSER));
9016 show_open_folder_window = FALSE;
9017 if (caja_window_info_get_window_type (view->details->window) == CAJA_WINDOW_NAVIGATION) {
9018 if (g_settings_get_boolean (caja_preferences, CAJA_PREFERENCES_ALWAYS_USE_BROWSER)) {
9019 if (selection_count == 0 || selection_count == 1) {
9020 label_with_underscore = g_strdup (_("Open in New _Window"));
9021 } else {
9022 label_with_underscore = g_strdup_printf (ngettext("Open in %'d New _Window",
9023 "Open in %'d New _Windows",
9024 selection_count),
9025 selection_count);
9026 }
9027 } else {
9028 if (selection_count == 0 || selection_count == 1) {
9029 label_with_underscore = g_strdup (_("Browse in New _Window"));
9030 } else {
9031 label_with_underscore = g_strdup_printf (ngettext("Browse in %'d New _Window",
9032 "Browse in %'d New _Windows",
9033 selection_count),
9034 selection_count);
9035 }
9036 show_open_folder_window = show_open_alternate;
9037 }
9038 } else {
9039 label_with_underscore = g_strdup (ngettext ("_Browse Folder",
9040 "_Browse Folders",
9041 selection_count));
9042 }
9043
9044 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
9045 action = gtk_action_group_get_action (view->details->dir_action_group,
9046 FM_ACTION_OPEN_ALTERNATE);
9047 g_object_set (action, "label",
9048 label_with_underscore,
9049 NULL);
9050 g_free (label_with_underscore);
9051
9052 gtk_action_set_sensitive (action, selection_count != 0);
9053 gtk_action_set_visible (action, show_open_alternate);
9054 G_GNUC_END_IGNORE_DEPRECATIONS;
9055
9056 /* Open in New Tab action */
9057 if (caja_window_info_get_window_type (view->details->window) == CAJA_WINDOW_NAVIGATION) {
9058
9059 if (g_settings_get_boolean (caja_preferences, CAJA_PREFERENCES_ALWAYS_USE_BROWSER)) {
9060 if (selection_count == 0 || selection_count == 1) {
9061 label_with_underscore = g_strdup (_("Open in New _Tab"));
9062 } else {
9063 label_with_underscore = g_strdup_printf (ngettext("Open in %'d New _Tab",
9064 "Open in %'d New _Tabs",
9065 selection_count),
9066 selection_count);
9067 }
9068 } else {
9069 if (selection_count == 0 || selection_count == 1) {
9070 label_with_underscore = g_strdup (_("Browse in New _Tab"));
9071 } else {
9072 label_with_underscore = g_strdup_printf (ngettext("Browse in %'d New _Tab",
9073 "Browse in %'d New _Tabs",
9074 selection_count),
9075 selection_count);
9076 }
9077 }
9078 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
9079 action = gtk_action_group_get_action (view->details->dir_action_group,
9080 FM_ACTION_OPEN_IN_NEW_TAB);
9081 gtk_action_set_sensitive (action, selection_count != 0);
9082 gtk_action_set_visible (action, show_open_alternate);
9083 g_object_set (action, "label",
9084 label_with_underscore,
9085 NULL);
9086 g_free (label_with_underscore);
9087 } else {
9088 action = gtk_action_group_get_action (view->details->dir_action_group,
9089 FM_ACTION_OPEN_IN_NEW_TAB);
9090 gtk_action_set_visible (action, FALSE);
9091 G_GNUC_END_IGNORE_DEPRECATIONS;
9092 }
9093
9094 /* next pane actions, only in navigation mode */
9095 if (caja_window_info_get_window_type (view->details->window) != CAJA_WINDOW_NAVIGATION) {
9096 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
9097 action = gtk_action_group_get_action (view->details->dir_action_group,
9098 FM_ACTION_COPY_TO_NEXT_PANE);
9099 gtk_action_set_visible (action, FALSE);
9100 action = gtk_action_group_get_action (view->details->dir_action_group,
9101 FM_ACTION_MOVE_TO_NEXT_PANE);
9102 gtk_action_set_visible (action, FALSE);
9103 }
9104
9105 action = gtk_action_group_get_action (view->details->dir_action_group,
9106 FM_ACTION_OPEN_FOLDER_WINDOW);
9107 gtk_action_set_visible (action, show_open_folder_window);
9108 G_GNUC_END_IGNORE_DEPRECATIONS;
9109
9110 /* Broken into its own function just for convenience */
9111 reset_open_with_menu (view, selection);
9112 reset_extension_actions_menu (view, selection);
9113
9114 if (all_selected_items_in_trash (view)) {
9115 label = _("_Delete Permanently");
9116 tip = _("Delete all selected items permanently");
9117 show_separate_delete_command = FALSE;
9118 } else {
9119 label = _("Mo_ve to Trash");
9120 tip = _("Move each selected item to the Trash");
9121 show_separate_delete_command = g_settings_get_boolean (caja_preferences, CAJA_PREFERENCES_ENABLE_DELETE);
9122 }
9123
9124 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
9125 action = gtk_action_group_get_action (view->details->dir_action_group,
9126 FM_ACTION_TRASH);
9127 g_object_set (action,
9128 "label", label,
9129 "tooltip", tip,
9130 "icon-name", all_selected_items_in_trash (view) ?
9131 CAJA_ICON_DELETE : CAJA_ICON_TRASH_FULL,
9132 NULL);
9133 gtk_action_set_sensitive (action, can_delete_files);
9134
9135 action = gtk_action_group_get_action (view->details->dir_action_group,
9136 FM_ACTION_DELETE);
9137 gtk_action_set_visible (action, show_separate_delete_command);
9138
9139 if (show_separate_delete_command) {
9140 g_object_set (action,
9141 "label", _("_Delete"),
9142 "icon-name", CAJA_ICON_DELETE,
9143 NULL);
9144 }
9145 gtk_action_set_sensitive (action, can_delete_files);
9146
9147
9148 action = gtk_action_group_get_action (view->details->dir_action_group,
9149 FM_ACTION_RESTORE_FROM_TRASH);
9150 update_restore_from_trash_action (action, selection, FALSE);
9151
9152 action = gtk_action_group_get_action (view->details->dir_action_group,
9153 FM_ACTION_DUPLICATE);
9154 gtk_action_set_sensitive (action, can_duplicate_files);
9155
9156 action = gtk_action_group_get_action (view->details->dir_action_group,
9157 FM_ACTION_CREATE_LINK);
9158 gtk_action_set_sensitive (action, can_link_files);
9159 G_GNUC_END_IGNORE_DEPRECATIONS;
9160 g_object_set (action, "label",
9161 ngettext ("Ma_ke Link",
9162 "Ma_ke Links",
9163 selection_count),
9164 NULL);
9165
9166 show_properties = (!FM_IS_DESKTOP_ICON_VIEW (view) || selection_count > 0) &&
9167 fm_directory_view_supports_properties (view);
9168
9169 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
9170 action = gtk_action_group_get_action (view->details->dir_action_group,
9171 FM_ACTION_PROPERTIES);
9172
9173 gtk_action_set_sensitive (action, show_properties);
9174
9175 if (selection_count == 0) {
9176 gtk_action_set_tooltip (action, _("View or modify the properties of the open folder"));
9177 } else {
9178 gtk_action_set_tooltip (action, _("View or modify the properties of each selected item"));
9179 }
9180
9181 gtk_action_set_visible (action, show_properties);
9182
9183 action = gtk_action_group_get_action (view->details->dir_action_group,
9184 FM_ACTION_PROPERTIES_ACCEL);
9185
9186 gtk_action_set_sensitive (action, show_properties);
9187
9188 action = gtk_action_group_get_action (view->details->dir_action_group,
9189 FM_ACTION_EMPTY_TRASH);
9190 g_object_set (action,
9191 "label", _("E_mpty Trash"),
9192 NULL);
9193 gtk_action_set_sensitive (action, !caja_trash_monitor_is_empty ());
9194 gtk_action_set_visible (action, should_show_empty_trash (view));
9195 G_GNUC_END_IGNORE_DEPRECATIONS;
9196
9197 show_save_search = FALSE;
9198 save_search_sensitive = FALSE;
9199 show_save_search_as = FALSE;
9200 if (view->details->model &&
9201 CAJA_IS_SEARCH_DIRECTORY (view->details->model)) {
9202 CajaSearchDirectory *search;
9203
9204 search = CAJA_SEARCH_DIRECTORY (view->details->model);
9205 if (caja_search_directory_is_saved_search (search)) {
9206 show_save_search = TRUE;
9207 save_search_sensitive = caja_search_directory_is_modified (search);
9208 } else {
9209 show_save_search_as = TRUE;
9210 }
9211 }
9212 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
9213 action = gtk_action_group_get_action (view->details->dir_action_group,
9214 FM_ACTION_SAVE_SEARCH);
9215 gtk_action_set_visible (action, show_save_search);
9216 gtk_action_set_sensitive (action, save_search_sensitive);
9217 action = gtk_action_group_get_action (view->details->dir_action_group,
9218 FM_ACTION_SAVE_SEARCH_AS);
9219 gtk_action_set_visible (action, show_save_search_as);
9220
9221
9222 action = gtk_action_group_get_action (view->details->dir_action_group,
9223 FM_ACTION_SELECT_ALL);
9224 gtk_action_set_sensitive (action, !fm_directory_view_is_empty (view));
9225
9226 action = gtk_action_group_get_action (view->details->dir_action_group,
9227 FM_ACTION_SELECT_PATTERN);
9228 gtk_action_set_sensitive (action, !fm_directory_view_is_empty (view));
9229
9230 action = gtk_action_group_get_action (view->details->dir_action_group,
9231 FM_ACTION_INVERT_SELECTION);
9232 gtk_action_set_sensitive (action, !fm_directory_view_is_empty (view));
9233
9234 action = gtk_action_group_get_action (view->details->dir_action_group,
9235 FM_ACTION_CUT);
9236 gtk_action_set_sensitive (action, can_delete_files);
9237
9238 action = gtk_action_group_get_action (view->details->dir_action_group,
9239 FM_ACTION_COPY);
9240 gtk_action_set_sensitive (action, can_copy_files);
9241 G_GNUC_END_IGNORE_DEPRECATIONS;
9242
9243 real_update_paste_menu (view, selection, selection_count);
9244
9245 disable_command_line = g_settings_get_boolean (mate_lockdown_preferences, CAJA_PREFERENCES_LOCKDOWN_COMMAND_LINE);
9246 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
9247 action = gtk_action_group_get_action (view->details->dir_action_group,
9248 FM_ACTION_NEW_LAUNCHER);
9249 gtk_action_set_visible (action, vfolder_directory && !disable_command_line);
9250 gtk_action_set_sensitive (action, can_create_files);
9251 G_GNUC_END_IGNORE_DEPRECATIONS;
9252
9253 real_update_menus_volumes (view, selection, selection_count);
9254
9255 undo_update_menu (view);
9256
9257 caja_file_list_free (selection);
9258
9259 if (view->details->scripts_invalid) {
9260 update_scripts_menu (view);
9261 }
9262
9263 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
9264 action = gtk_action_group_get_action (view->details->dir_action_group,
9265 FM_ACTION_NEW_DOCUMENTS);
9266 gtk_action_set_sensitive (action, can_create_files);
9267 G_GNUC_END_IGNORE_DEPRECATIONS;
9268
9269 if (can_create_files && view->details->templates_invalid) {
9270 update_templates_menu (view);
9271 }
9272
9273 next_pane_is_writable = has_writable_extra_pane (view);
9274
9275 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
9276 /* next pane: works if file is copyable, and next pane is writable */
9277 action = gtk_action_group_get_action (view->details->dir_action_group,
9278 FM_ACTION_COPY_TO_NEXT_PANE);
9279 gtk_action_set_sensitive (action, can_copy_files && next_pane_is_writable);
9280
9281 /* move to next pane: works if file is cuttable, and next pane is writable */
9282 action = gtk_action_group_get_action (view->details->dir_action_group,
9283 FM_ACTION_MOVE_TO_NEXT_PANE);
9284 gtk_action_set_sensitive (action, can_delete_files && next_pane_is_writable);
9285
9286
9287 action = gtk_action_group_get_action (view->details->dir_action_group,
9288 FM_ACTION_COPY_TO_HOME);
9289 gtk_action_set_sensitive (action, can_copy_files);
9290 action = gtk_action_group_get_action (view->details->dir_action_group,
9291 FM_ACTION_COPY_TO_DESKTOP);
9292 gtk_action_set_sensitive (action, can_copy_files);
9293
9294 action = gtk_action_group_get_action (view->details->dir_action_group,
9295 FM_ACTION_MOVE_TO_HOME);
9296 gtk_action_set_sensitive (action, can_delete_files);
9297 action = gtk_action_group_get_action (view->details->dir_action_group,
9298 FM_ACTION_MOVE_TO_DESKTOP);
9299 gtk_action_set_sensitive (action, can_delete_files);
9300
9301 action = gtk_action_group_get_action (view->details->dir_action_group,
9302 "CopyToMenu");
9303 gtk_action_set_sensitive (action, can_copy_files);
9304 action = gtk_action_group_get_action (view->details->dir_action_group,
9305 "MoveToMenu");
9306 gtk_action_set_sensitive (action, can_delete_files);
9307 G_GNUC_END_IGNORE_DEPRECATIONS;
9308 }
9309
9310 /**
9311 * fm_directory_view_pop_up_selection_context_menu
9312 *
9313 * Pop up a context menu appropriate to the selected items.
9314 * @view: FMDirectoryView of interest.
9315 * @event: The event that triggered this context menu.
9316 *
9317 * Return value: CajaDirectory for this view.
9318 *
9319 **/
9320 void
fm_directory_view_pop_up_selection_context_menu(FMDirectoryView * view,GdkEventButton * event)9321 fm_directory_view_pop_up_selection_context_menu (FMDirectoryView *view,
9322 GdkEventButton *event)
9323 {
9324 g_assert (FM_IS_DIRECTORY_VIEW (view));
9325
9326 /* Make the context menu items not flash as they update to proper disabled,
9327 * etc. states by forcing menus to update now.
9328 */
9329 update_menus_if_pending (view);
9330
9331 update_context_menu_position_from_event (view, event);
9332
9333 /* FIXME: passing event from here won't work
9334 * for gtk_menu_popup_at_pointer (in eel_pop_up_context_menu() )
9335 * if the menu is being triggered from here by the menu key
9336 */
9337 eel_pop_up_context_menu (create_popup_menu
9338 (view, FM_DIRECTORY_VIEW_POPUP_PATH_SELECTION),
9339 NULL);
9340 }
9341
9342 /**
9343 * fm_directory_view_pop_up_background_context_menu
9344 *
9345 * Pop up a context menu appropriate to the view globally at the last right click location.
9346 * @view: FMDirectoryView of interest.
9347 *
9348 * Return value: CajaDirectory for this view.
9349 *
9350 **/
9351 void
fm_directory_view_pop_up_background_context_menu(FMDirectoryView * view,GdkEventButton * event)9352 fm_directory_view_pop_up_background_context_menu (FMDirectoryView *view,
9353 GdkEventButton *event)
9354 {
9355 g_assert (FM_IS_DIRECTORY_VIEW (view));
9356
9357 /* Make the context menu items not flash as they update to proper disabled,
9358 * etc. states by forcing menus to update now.
9359 */
9360 update_menus_if_pending (view);
9361
9362 update_context_menu_position_from_event (view, event);
9363
9364 eel_pop_up_context_menu (create_popup_menu
9365 (view, FM_DIRECTORY_VIEW_POPUP_PATH_BACKGROUND),
9366 event);
9367 }
9368
9369 static void
real_pop_up_location_context_menu(FMDirectoryView * view)9370 real_pop_up_location_context_menu (FMDirectoryView *view)
9371 {
9372 /* always update the menu before showing it. Shouldn't be too expensive. */
9373 real_update_location_menu (view);
9374
9375 update_context_menu_position_from_event (view, view->details->location_popup_event);
9376
9377 eel_pop_up_context_menu (create_popup_menu
9378 (view, FM_DIRECTORY_VIEW_POPUP_PATH_LOCATION),
9379 view->details->location_popup_event);
9380 }
9381
9382 static void
location_popup_file_attributes_ready(CajaFile * file,gpointer data)9383 location_popup_file_attributes_ready (CajaFile *file,
9384 gpointer data)
9385 {
9386 FMDirectoryView *view;
9387
9388 view = FM_DIRECTORY_VIEW (data);
9389 g_assert (FM_IS_DIRECTORY_VIEW (view));
9390
9391 g_assert (file == view->details->location_popup_directory_as_file);
9392
9393 real_pop_up_location_context_menu (view);
9394 }
9395
9396 static void
unschedule_pop_up_location_context_menu(FMDirectoryView * view)9397 unschedule_pop_up_location_context_menu (FMDirectoryView *view)
9398 {
9399 if (view->details->location_popup_directory_as_file != NULL) {
9400 g_assert (CAJA_IS_FILE (view->details->location_popup_directory_as_file));
9401 caja_file_cancel_call_when_ready (view->details->location_popup_directory_as_file,
9402 location_popup_file_attributes_ready,
9403 view);
9404 caja_file_unref (view->details->location_popup_directory_as_file);
9405 view->details->location_popup_directory_as_file = NULL;
9406 }
9407 }
9408
9409 static void
schedule_pop_up_location_context_menu(FMDirectoryView * view,GdkEventButton * event,CajaFile * file)9410 schedule_pop_up_location_context_menu (FMDirectoryView *view,
9411 GdkEventButton *event,
9412 CajaFile *file)
9413 {
9414 g_assert (CAJA_IS_FILE (file));
9415
9416 if (view->details->location_popup_event != NULL) {
9417 gdk_event_free ((GdkEvent *) view->details->location_popup_event);
9418 }
9419 view->details->location_popup_event = (GdkEventButton *) gdk_event_copy ((GdkEvent *)event);
9420
9421 if (file == view->details->location_popup_directory_as_file) {
9422 if (caja_file_check_if_ready (file, CAJA_FILE_ATTRIBUTE_INFO |
9423 CAJA_FILE_ATTRIBUTE_MOUNT |
9424 CAJA_FILE_ATTRIBUTE_FILESYSTEM_INFO)) {
9425 real_pop_up_location_context_menu (view);
9426 }
9427 } else {
9428 unschedule_pop_up_location_context_menu (view);
9429
9430 view->details->location_popup_directory_as_file = caja_file_ref (file);
9431 caja_file_call_when_ready (view->details->location_popup_directory_as_file,
9432 CAJA_FILE_ATTRIBUTE_INFO |
9433 CAJA_FILE_ATTRIBUTE_MOUNT |
9434 CAJA_FILE_ATTRIBUTE_FILESYSTEM_INFO,
9435 location_popup_file_attributes_ready,
9436 view);
9437 }
9438 }
9439
9440 /**
9441 * fm_directory_view_pop_up_location_context_menu
9442 *
9443 * Pop up a context menu appropriate to the view globally.
9444 * @view: FMDirectoryView of interest.
9445 * @event: GdkEventButton triggering the popup.
9446 * @location: The location the popup-menu should be created for,
9447 * or NULL for the currently displayed location.
9448 *
9449 **/
9450 void
fm_directory_view_pop_up_location_context_menu(FMDirectoryView * view,GdkEventButton * event,const char * location)9451 fm_directory_view_pop_up_location_context_menu (FMDirectoryView *view,
9452 GdkEventButton *event,
9453 const char *location)
9454 {
9455 CajaFile *file;
9456
9457 g_assert (FM_IS_DIRECTORY_VIEW (view));
9458
9459 if (location != NULL) {
9460 file = caja_file_get_by_uri (location);
9461 } else {
9462 file = caja_file_ref (view->details->directory_as_file);
9463 }
9464
9465 if (file != NULL) {
9466 schedule_pop_up_location_context_menu (view, event, file);
9467 caja_file_unref (file);
9468 }
9469 }
9470
9471 static void
fm_directory_view_drop_proxy_received_uris(FMDirectoryView * view,const GList * source_uri_list,const char * target_uri,GdkDragAction action)9472 fm_directory_view_drop_proxy_received_uris (FMDirectoryView *view,
9473 const GList *source_uri_list,
9474 const char *target_uri,
9475 GdkDragAction action)
9476 {
9477 char *container_uri;
9478
9479 container_uri = NULL;
9480 if (target_uri == NULL) {
9481 container_uri = fm_directory_view_get_backing_uri (view);
9482 g_assert (container_uri != NULL);
9483 }
9484
9485 if (action == GDK_ACTION_ASK) {
9486 action = caja_drag_drop_action_ask
9487 (GTK_WIDGET (view),
9488 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK);
9489 if (action == 0) {
9490 return;
9491 }
9492 }
9493
9494 caja_clipboard_clear_if_colliding_uris (GTK_WIDGET (view),
9495 source_uri_list,
9496 fm_directory_view_get_copied_files_atom (view));
9497
9498 fm_directory_view_move_copy_items (source_uri_list, NULL,
9499 target_uri != NULL ? target_uri : container_uri,
9500 action, 0, 0, view);
9501
9502 g_free (container_uri);
9503 }
9504
9505 static void
fm_directory_view_drop_proxy_received_netscape_url(FMDirectoryView * view,const char * netscape_url,const char * target_uri,GdkDragAction action)9506 fm_directory_view_drop_proxy_received_netscape_url (FMDirectoryView *view,
9507 const char *netscape_url,
9508 const char *target_uri,
9509 GdkDragAction action)
9510 {
9511 fm_directory_view_handle_netscape_url_drop (view,
9512 netscape_url,
9513 target_uri,
9514 action, 0, 0);
9515 }
9516
9517 static void
schedule_update_menus(FMDirectoryView * view)9518 schedule_update_menus (FMDirectoryView *view)
9519 {
9520 g_assert (FM_IS_DIRECTORY_VIEW (view));
9521
9522 /* Don't schedule updates after destroy (#349551),
9523 * or if we are not active.
9524 */
9525 if (view->details->window == NULL ||
9526 !view->details->active) {
9527 return;
9528 }
9529
9530 view->details->menu_states_untrustworthy = TRUE;
9531
9532 /* Schedule a menu update with the current update interval */
9533 if (view->details->update_menus_timeout_id == 0) {
9534 view->details->update_menus_timeout_id
9535 = g_timeout_add (view->details->update_interval, update_menus_timeout_callback, view);
9536 }
9537 }
9538
9539 static void
remove_update_status_idle_callback(FMDirectoryView * view)9540 remove_update_status_idle_callback (FMDirectoryView *view)
9541 {
9542 if (view->details->update_status_idle_id != 0) {
9543 g_source_remove (view->details->update_status_idle_id);
9544 view->details->update_status_idle_id = 0;
9545 }
9546 }
9547
9548 static gboolean
update_status_idle_callback(gpointer data)9549 update_status_idle_callback (gpointer data)
9550 {
9551 FMDirectoryView *view;
9552
9553 view = FM_DIRECTORY_VIEW (data);
9554 fm_directory_view_display_selection_info (view);
9555 view->details->update_status_idle_id = 0;
9556 return FALSE;
9557 }
9558
9559 static void
schedule_update_status(FMDirectoryView * view)9560 schedule_update_status (FMDirectoryView *view)
9561 {
9562 g_assert (FM_IS_DIRECTORY_VIEW (view));
9563
9564 /* Make sure we haven't already destroyed it */
9565 if (view->details->window == NULL) {
9566 return;
9567 }
9568
9569 if (view->details->loading) {
9570 /* Don't update status bar while loading the dir */
9571 return;
9572 }
9573
9574 if (view->details->update_status_idle_id == 0) {
9575 view->details->update_status_idle_id =
9576 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE - 20,
9577 update_status_idle_callback, view, NULL);
9578 }
9579 }
9580
9581 /**
9582 * fm_directory_view_notify_selection_changed:
9583 *
9584 * Notify this view that the selection has changed. This is normally
9585 * called only by subclasses.
9586 * @view: FMDirectoryView whose selection has changed.
9587 *
9588 **/
9589 void
fm_directory_view_notify_selection_changed(FMDirectoryView * view)9590 fm_directory_view_notify_selection_changed (FMDirectoryView *view)
9591 {
9592 g_return_if_fail (FM_IS_DIRECTORY_VIEW (view));
9593
9594 if (caja_debug_log_is_domain_enabled (CAJA_DEBUG_LOG_DOMAIN_USER)) {
9595 GList *selection;
9596 GtkWindow *window;
9597
9598 selection = fm_directory_view_get_selection (view);
9599
9600 window = fm_directory_view_get_containing_window (view);
9601 caja_debug_log_with_file_list (FALSE, CAJA_DEBUG_LOG_DOMAIN_USER, selection,
9602 "selection changed in window %p",
9603 window);
9604 caja_file_list_free (selection);
9605 }
9606
9607 view->details->selection_was_removed = FALSE;
9608
9609 if (!view->details->selection_change_is_due_to_shell) {
9610 view->details->send_selection_change_to_shell = TRUE;
9611 }
9612
9613 /* Schedule a display of the new selection. */
9614 if (view->details->display_selection_idle_id == 0) {
9615 view->details->display_selection_idle_id
9616 = g_idle_add (display_selection_info_idle_callback,
9617 view);
9618 }
9619
9620 if (view->details->batching_selection_level != 0) {
9621 view->details->selection_changed_while_batched = TRUE;
9622 } else {
9623 /* Here is the work we do only when we're not
9624 * batching selection changes. In other words, it's the slower
9625 * stuff that we don't want to slow down selection techniques
9626 * such as rubberband-selecting in icon view.
9627 */
9628
9629 /* Schedule an update of menu item states to match selection */
9630 schedule_update_menus (view);
9631 }
9632 }
9633
9634 static void
file_changed_callback(CajaFile * file,gpointer callback_data)9635 file_changed_callback (CajaFile *file, gpointer callback_data)
9636 {
9637 FMDirectoryView *view = FM_DIRECTORY_VIEW (callback_data);
9638
9639 schedule_changes (view);
9640
9641 schedule_update_menus (view);
9642 schedule_update_status (view);
9643
9644 /* We might have different capabilities, so we need to update
9645 * relative icon emblems . (Writeable etc).
9646 * Don't do this for trash, as it never changes writability
9647 * but does change a lot for the file count attribute.
9648 */
9649 if (!caja_file_is_in_trash (file)) {
9650 EEL_CALL_METHOD
9651 (FM_DIRECTORY_VIEW_CLASS, view, emblems_changed, (view));
9652 }
9653 }
9654
9655 /**
9656 * load_directory:
9657 *
9658 * Switch the displayed location to a new uri. If the uri is not valid,
9659 * the location will not be switched; user feedback will be provided instead.
9660 * @view: FMDirectoryView whose location will be changed.
9661 * @uri: A string representing the uri to switch to.
9662 *
9663 **/
9664 static void
load_directory(FMDirectoryView * view,CajaDirectory * directory)9665 load_directory (FMDirectoryView *view,
9666 CajaDirectory *directory)
9667 {
9668 CajaDirectory *old_directory;
9669 CajaFile *old_file;
9670 CajaFileAttributes attributes;
9671
9672 g_assert (FM_IS_DIRECTORY_VIEW (view));
9673 g_assert (CAJA_IS_DIRECTORY (directory));
9674
9675 fm_directory_view_stop (view);
9676 fm_directory_view_clear (view);
9677
9678 view->details->loading = TRUE;
9679
9680 /* Update menus when directory is empty, before going to new
9681 * location, so they won't have any false lingering knowledge
9682 * of old selection.
9683 */
9684 schedule_update_menus (view);
9685
9686 while (view->details->subdirectory_list != NULL) {
9687 fm_directory_view_remove_subdirectory (view,
9688 view->details->subdirectory_list->data);
9689 }
9690
9691 disconnect_model_handlers (view);
9692
9693 old_directory = view->details->model;
9694 caja_directory_ref (directory);
9695 view->details->model = directory;
9696 caja_directory_unref (old_directory);
9697
9698 old_file = view->details->directory_as_file;
9699 view->details->directory_as_file =
9700 caja_directory_get_corresponding_file (directory);
9701 caja_file_unref (old_file);
9702
9703 view->details->reported_load_error = FALSE;
9704
9705 /* FIXME bugzilla.gnome.org 45062: In theory, we also need to monitor metadata here (as
9706 * well as doing a call when ready), in case external forces
9707 * change the directory's file metadata.
9708 */
9709 attributes =
9710 CAJA_FILE_ATTRIBUTE_INFO |
9711 CAJA_FILE_ATTRIBUTE_MOUNT |
9712 CAJA_FILE_ATTRIBUTE_FILESYSTEM_INFO;
9713 view->details->metadata_for_directory_as_file_pending = TRUE;
9714 view->details->metadata_for_files_in_directory_pending = TRUE;
9715 caja_file_call_when_ready
9716 (view->details->directory_as_file,
9717 attributes,
9718 metadata_for_directory_as_file_ready_callback, view);
9719 caja_directory_call_when_ready
9720 (view->details->model,
9721 attributes,
9722 FALSE,
9723 metadata_for_files_in_directory_ready_callback, view);
9724
9725 /* If capabilities change, then we need to update the menus
9726 * because of New Folder, and relative emblems.
9727 */
9728 attributes =
9729 CAJA_FILE_ATTRIBUTE_INFO |
9730 CAJA_FILE_ATTRIBUTE_FILESYSTEM_INFO;
9731 caja_file_monitor_add (view->details->directory_as_file,
9732 &view->details->directory_as_file,
9733 attributes);
9734
9735 view->details->file_changed_handler_id = g_signal_connect
9736 (view->details->directory_as_file, "changed",
9737 G_CALLBACK (file_changed_callback), view);
9738 }
9739
9740 static void
finish_loading(FMDirectoryView * view)9741 finish_loading (FMDirectoryView *view)
9742 {
9743 CajaFileAttributes attributes;
9744
9745 caja_window_info_report_load_underway (view->details->window,
9746 CAJA_VIEW (view));
9747
9748 /* Tell interested parties that we've begun loading this directory now.
9749 * Subclasses use this to know that the new metadata is now available.
9750 */
9751 fm_directory_view_begin_loading (view);
9752
9753 /* Assume we have now all information to show window */
9754 caja_window_info_view_visible (view->details->window, CAJA_VIEW (view));
9755
9756 if (caja_directory_are_all_files_seen (view->details->model)) {
9757 /* Unschedule a pending update and schedule a new one with the minimal
9758 * update interval. This gives the view a short chance at gathering the
9759 * (cached) deep counts.
9760 */
9761 unschedule_display_of_pending_files (view);
9762 schedule_timeout_display_of_pending_files (view, UPDATE_INTERVAL_MIN);
9763 }
9764
9765 /* Start loading. */
9766
9767 /* Connect handlers to learn about loading progress. */
9768 view->details->done_loading_handler_id = g_signal_connect
9769 (view->details->model, "done_loading",
9770 G_CALLBACK (done_loading_callback), view);
9771 view->details->load_error_handler_id = g_signal_connect
9772 (view->details->model, "load_error",
9773 G_CALLBACK (load_error_callback), view);
9774
9775 /* Monitor the things needed to get the right icon. Also
9776 * monitor a directory's item count because the "size"
9777 * attribute is based on that, and the file's metadata
9778 * and possible custom name.
9779 */
9780 attributes =
9781 CAJA_FILE_ATTRIBUTES_FOR_ICON |
9782 CAJA_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT |
9783 CAJA_FILE_ATTRIBUTE_INFO |
9784 CAJA_FILE_ATTRIBUTE_LINK_INFO |
9785 CAJA_FILE_ATTRIBUTE_MOUNT |
9786 CAJA_FILE_ATTRIBUTE_EXTENSION_INFO;
9787
9788 caja_directory_file_monitor_add (view->details->model,
9789 &view->details->model,
9790 view->details->show_hidden_files,
9791 attributes,
9792 files_added_callback, view);
9793
9794 view->details->files_added_handler_id = g_signal_connect
9795 (view->details->model, "files_added",
9796 G_CALLBACK (files_added_callback), view);
9797 view->details->files_changed_handler_id = g_signal_connect
9798 (view->details->model, "files_changed",
9799 G_CALLBACK (files_changed_callback), view);
9800 }
9801
9802 static void
finish_loading_if_all_metadata_loaded(FMDirectoryView * view)9803 finish_loading_if_all_metadata_loaded (FMDirectoryView *view)
9804 {
9805 if (!view->details->metadata_for_directory_as_file_pending &&
9806 !view->details->metadata_for_files_in_directory_pending) {
9807 finish_loading (view);
9808 }
9809 }
9810
9811 static void
metadata_for_directory_as_file_ready_callback(CajaFile * file,gpointer callback_data)9812 metadata_for_directory_as_file_ready_callback (CajaFile *file,
9813 gpointer callback_data)
9814 {
9815 FMDirectoryView *view;
9816
9817 view = callback_data;
9818
9819 g_assert (FM_IS_DIRECTORY_VIEW (view));
9820 g_assert (view->details->directory_as_file == file);
9821 g_assert (view->details->metadata_for_directory_as_file_pending);
9822
9823 view->details->metadata_for_directory_as_file_pending = FALSE;
9824
9825 finish_loading_if_all_metadata_loaded (view);
9826 }
9827
9828 static void
metadata_for_files_in_directory_ready_callback(CajaDirectory * directory,GList * files,gpointer callback_data)9829 metadata_for_files_in_directory_ready_callback (CajaDirectory *directory,
9830 GList *files,
9831 gpointer callback_data)
9832 {
9833 FMDirectoryView *view;
9834
9835 view = callback_data;
9836
9837 g_assert (FM_IS_DIRECTORY_VIEW (view));
9838 g_assert (view->details->model == directory);
9839 g_assert (view->details->metadata_for_files_in_directory_pending);
9840
9841 view->details->metadata_for_files_in_directory_pending = FALSE;
9842
9843 finish_loading_if_all_metadata_loaded (view);
9844 }
9845
9846 static void
finish_undoredo_callback(gpointer data)9847 finish_undoredo_callback (gpointer data)
9848 {
9849 }
9850
9851 char **
fm_directory_view_get_emblem_names_to_exclude(FMDirectoryView * view)9852 fm_directory_view_get_emblem_names_to_exclude (FMDirectoryView *view)
9853 {
9854 g_return_val_if_fail (FM_IS_DIRECTORY_VIEW (view), NULL);
9855
9856 return EEL_CALL_METHOD_WITH_RETURN_VALUE
9857 (FM_DIRECTORY_VIEW_CLASS, view,
9858 get_emblem_names_to_exclude, (view));
9859 }
9860
9861 static char **
real_get_emblem_names_to_exclude(FMDirectoryView * view)9862 real_get_emblem_names_to_exclude (FMDirectoryView *view)
9863 {
9864 char **excludes;
9865 int i;
9866
9867 g_assert (FM_IS_DIRECTORY_VIEW (view));
9868
9869 excludes = g_new (char *, 3);
9870
9871 i = 0;
9872 excludes[i++] = g_strdup (CAJA_FILE_EMBLEM_NAME_TRASH);
9873
9874 if (!caja_file_can_write (view->details->directory_as_file)) {
9875 excludes[i++] = g_strdup (CAJA_FILE_EMBLEM_NAME_CANT_WRITE);
9876 }
9877
9878 excludes[i++] = NULL;
9879
9880 return excludes;
9881 }
9882
9883 /**
9884 * fm_directory_view_merge_menus:
9885 *
9886 * Add this view's menus to the window's menu bar.
9887 * @view: FMDirectoryView in question.
9888 */
9889 static void
fm_directory_view_merge_menus(FMDirectoryView * view)9890 fm_directory_view_merge_menus (FMDirectoryView *view)
9891 {
9892 g_return_if_fail (FM_IS_DIRECTORY_VIEW (view));
9893
9894 EEL_CALL_METHOD
9895 (FM_DIRECTORY_VIEW_CLASS, view,
9896 merge_menus, (view));
9897 }
9898
9899 static void
fm_directory_view_unmerge_menus(FMDirectoryView * view)9900 fm_directory_view_unmerge_menus (FMDirectoryView *view)
9901 {
9902 g_return_if_fail (FM_IS_DIRECTORY_VIEW (view));
9903
9904 EEL_CALL_METHOD
9905 (FM_DIRECTORY_VIEW_CLASS, view,
9906 unmerge_menus, (view));
9907 }
9908
9909 static void
disconnect_handler(GObject * object,guint * id)9910 disconnect_handler (GObject *object, guint *id)
9911 {
9912 if (*id != 0) {
9913 g_signal_handler_disconnect (object, *id);
9914 *id = 0;
9915 }
9916 }
9917
9918 static void
disconnect_directory_handler(FMDirectoryView * view,guint * id)9919 disconnect_directory_handler (FMDirectoryView *view, guint *id)
9920 {
9921 disconnect_handler (G_OBJECT (view->details->model), id);
9922 }
9923
9924 static void
disconnect_directory_as_file_handler(FMDirectoryView * view,guint * id)9925 disconnect_directory_as_file_handler (FMDirectoryView *view, guint *id)
9926 {
9927 disconnect_handler (G_OBJECT (view->details->directory_as_file), id);
9928 }
9929
9930 static void
disconnect_model_handlers(FMDirectoryView * view)9931 disconnect_model_handlers (FMDirectoryView *view)
9932 {
9933 if (view->details->model == NULL) {
9934 return;
9935 }
9936 disconnect_directory_handler (view, &view->details->files_added_handler_id);
9937 disconnect_directory_handler (view, &view->details->files_changed_handler_id);
9938 disconnect_directory_handler (view, &view->details->done_loading_handler_id);
9939 disconnect_directory_handler (view, &view->details->load_error_handler_id);
9940 disconnect_directory_as_file_handler (view, &view->details->file_changed_handler_id);
9941 caja_file_cancel_call_when_ready (view->details->directory_as_file,
9942 metadata_for_directory_as_file_ready_callback,
9943 view);
9944 caja_directory_cancel_callback (view->details->model,
9945 metadata_for_files_in_directory_ready_callback,
9946 view);
9947 caja_directory_file_monitor_remove (view->details->model,
9948 &view->details->model);
9949 caja_file_monitor_remove (view->details->directory_as_file,
9950 &view->details->directory_as_file);
9951 }
9952
9953 /**
9954 * fm_directory_view_reset_to_defaults:
9955 *
9956 * set sorting order, zoom level, etc. to match defaults
9957 *
9958 **/
9959 void
fm_directory_view_reset_to_defaults(FMDirectoryView * view)9960 fm_directory_view_reset_to_defaults (FMDirectoryView *view)
9961 {
9962 CajaWindowShowHiddenFilesMode mode;
9963
9964 g_return_if_fail (FM_IS_DIRECTORY_VIEW (view));
9965
9966 EEL_CALL_METHOD
9967 (FM_DIRECTORY_VIEW_CLASS, view,
9968 reset_to_defaults, (view));
9969 mode = caja_window_info_get_hidden_files_mode (view->details->window);
9970 if (mode != CAJA_WINDOW_SHOW_HIDDEN_FILES_DEFAULT) {
9971 caja_window_info_set_hidden_files_mode (view->details->window,
9972 CAJA_WINDOW_SHOW_HIDDEN_FILES_DEFAULT);
9973 }
9974 }
9975
9976 /**
9977 * fm_directory_view_select_all:
9978 *
9979 * select all the items in the view
9980 *
9981 **/
9982 void
fm_directory_view_select_all(FMDirectoryView * view)9983 fm_directory_view_select_all (FMDirectoryView *view)
9984 {
9985 g_return_if_fail (FM_IS_DIRECTORY_VIEW (view));
9986
9987 EEL_CALL_METHOD
9988 (FM_DIRECTORY_VIEW_CLASS, view,
9989 select_all, (view));
9990 }
9991
9992 /**
9993 * fm_directory_view_set_selection:
9994 *
9995 * set the selection to the items identified in @selection. @selection
9996 * should be a list of CajaFiles
9997 *
9998 **/
9999 void
fm_directory_view_set_selection(FMDirectoryView * view,GList * selection)10000 fm_directory_view_set_selection (FMDirectoryView *view, GList *selection)
10001 {
10002 g_return_if_fail (FM_IS_DIRECTORY_VIEW (view));
10003
10004 EEL_CALL_METHOD
10005 (FM_DIRECTORY_VIEW_CLASS, view,
10006 set_selection, (view, selection));
10007 }
10008
10009 static void
fm_directory_view_select_file(FMDirectoryView * view,CajaFile * file)10010 fm_directory_view_select_file (FMDirectoryView *view, CajaFile *file)
10011 {
10012 GList file_list;
10013
10014 file_list.data = file;
10015 file_list.next = NULL;
10016 file_list.prev = NULL;
10017 fm_directory_view_set_selection (view, &file_list);
10018 }
10019
10020 /**
10021 * fm_directory_view_get_selected_icon_locations:
10022 *
10023 * return an array of locations of selected icons if available
10024 * Return value: GArray of GdkPoints
10025 *
10026 **/
10027 GArray *
fm_directory_view_get_selected_icon_locations(FMDirectoryView * view)10028 fm_directory_view_get_selected_icon_locations (FMDirectoryView *view)
10029 {
10030 g_return_val_if_fail (FM_IS_DIRECTORY_VIEW (view), NULL);
10031
10032 return EEL_CALL_METHOD_WITH_RETURN_VALUE
10033 (FM_DIRECTORY_VIEW_CLASS, view,
10034 get_selected_icon_locations, (view));
10035 }
10036
10037 /**
10038 * fm_directory_view_reveal_selection:
10039 *
10040 * Scroll as necessary to reveal the selected items.
10041 **/
10042 void
fm_directory_view_reveal_selection(FMDirectoryView * view)10043 fm_directory_view_reveal_selection (FMDirectoryView *view)
10044 {
10045 g_return_if_fail (FM_IS_DIRECTORY_VIEW (view));
10046
10047 EEL_CALL_METHOD
10048 (FM_DIRECTORY_VIEW_CLASS, view,
10049 reveal_selection, (view));
10050 }
10051
10052 /**
10053 * fm_directory_view_stop:
10054 *
10055 * Stop the current ongoing process, such as switching to a new uri.
10056 * @view: FMDirectoryView in question.
10057 *
10058 **/
10059 void
fm_directory_view_stop(FMDirectoryView * view)10060 fm_directory_view_stop (FMDirectoryView *view)
10061 {
10062 g_return_if_fail (FM_IS_DIRECTORY_VIEW (view));
10063
10064 unschedule_display_of_pending_files (view);
10065 reset_update_interval (view);
10066
10067 /* Free extra undisplayed files */
10068 file_and_directory_list_free (view->details->new_added_files);
10069 view->details->new_added_files = NULL;
10070 file_and_directory_list_free (view->details->new_changed_files);
10071 view->details->new_changed_files = NULL;
10072 g_hash_table_remove_all (view->details->non_ready_files);
10073 file_and_directory_list_free (view->details->old_added_files);
10074 view->details->old_added_files = NULL;
10075 file_and_directory_list_free (view->details->old_changed_files);
10076 view->details->old_changed_files = NULL;
10077 g_list_free_full (view->details->pending_locations_selected, g_object_unref);
10078 view->details->pending_locations_selected = NULL;
10079
10080 if (view->details->model != NULL) {
10081 caja_directory_file_monitor_remove (view->details->model, view);
10082 }
10083 done_loading (view, FALSE);
10084 }
10085
10086 gboolean
fm_directory_view_is_read_only(FMDirectoryView * view)10087 fm_directory_view_is_read_only (FMDirectoryView *view)
10088 {
10089 g_return_val_if_fail (FM_IS_DIRECTORY_VIEW (view), FALSE);
10090
10091 return EEL_CALL_METHOD_WITH_RETURN_VALUE
10092 (FM_DIRECTORY_VIEW_CLASS, view,
10093 is_read_only, (view));
10094 }
10095
10096 gboolean
fm_directory_view_is_empty(FMDirectoryView * view)10097 fm_directory_view_is_empty (FMDirectoryView *view)
10098 {
10099 g_return_val_if_fail (FM_IS_DIRECTORY_VIEW (view), FALSE);
10100
10101 return EEL_CALL_METHOD_WITH_RETURN_VALUE
10102 (FM_DIRECTORY_VIEW_CLASS, view,
10103 is_empty, (view));
10104 }
10105
10106 gboolean
fm_directory_view_is_editable(FMDirectoryView * view)10107 fm_directory_view_is_editable (FMDirectoryView *view)
10108 {
10109 CajaDirectory *directory;
10110
10111 directory = fm_directory_view_get_model (view);
10112
10113 if (directory != NULL) {
10114 return caja_directory_is_editable (directory);
10115 }
10116
10117 return TRUE;
10118 }
10119
10120 void
fm_directory_view_set_initiated_unmount(FMDirectoryView * view,gboolean initiated_unmount)10121 fm_directory_view_set_initiated_unmount (FMDirectoryView *view,
10122 gboolean initiated_unmount)
10123 {
10124 if (view->details->window != NULL) {
10125 caja_window_info_set_initiated_unmount(view->details->window,
10126 initiated_unmount);
10127 }
10128 }
10129
10130 static gboolean
real_is_read_only(FMDirectoryView * view)10131 real_is_read_only (FMDirectoryView *view)
10132 {
10133 CajaFile *file;
10134
10135 if (!fm_directory_view_is_editable (view)) {
10136 return TRUE;
10137 }
10138
10139 file = fm_directory_view_get_directory_as_file (view);
10140 if (file != NULL) {
10141 return !caja_file_can_write (file);
10142 }
10143 return FALSE;
10144 }
10145
10146 gboolean
fm_directory_view_supports_creating_files(FMDirectoryView * view)10147 fm_directory_view_supports_creating_files (FMDirectoryView *view)
10148 {
10149 g_return_val_if_fail (FM_IS_DIRECTORY_VIEW (view), FALSE);
10150
10151 return EEL_CALL_METHOD_WITH_RETURN_VALUE
10152 (FM_DIRECTORY_VIEW_CLASS, view,
10153 supports_creating_files, (view));
10154 }
10155
10156 gboolean
fm_directory_view_accepts_dragged_files(FMDirectoryView * view)10157 fm_directory_view_accepts_dragged_files (FMDirectoryView *view)
10158 {
10159 g_return_val_if_fail (FM_IS_DIRECTORY_VIEW (view), FALSE);
10160
10161 return EEL_CALL_METHOD_WITH_RETURN_VALUE
10162 (FM_DIRECTORY_VIEW_CLASS, view,
10163 accepts_dragged_files, (view));
10164 }
10165
10166 /**
10167 * fm_directory_view_should_show_file
10168 *
10169 * Returns whether or not this file should be displayed based on
10170 * current filtering options.
10171 */
10172 gboolean
fm_directory_view_should_show_file(FMDirectoryView * view,CajaFile * file)10173 fm_directory_view_should_show_file (FMDirectoryView *view, CajaFile *file)
10174 {
10175 return caja_file_should_show (file,
10176 view->details->show_hidden_files,
10177 view->details->show_foreign_files,
10178 view->details->show_backup_files);
10179 }
10180
10181 static gboolean
real_supports_creating_files(FMDirectoryView * view)10182 real_supports_creating_files (FMDirectoryView *view)
10183 {
10184 g_return_val_if_fail (FM_IS_DIRECTORY_VIEW (view), FALSE);
10185
10186 return !fm_directory_view_is_read_only (view) && !showing_trash_directory (view);
10187 }
10188
10189 static gboolean
real_accepts_dragged_files(FMDirectoryView * view)10190 real_accepts_dragged_files (FMDirectoryView *view)
10191 {
10192 g_return_val_if_fail (FM_IS_DIRECTORY_VIEW (view), FALSE);
10193
10194 return !fm_directory_view_is_read_only (view);
10195 }
10196
10197 gboolean
fm_directory_view_supports_properties(FMDirectoryView * view)10198 fm_directory_view_supports_properties (FMDirectoryView *view)
10199 {
10200 g_return_val_if_fail (FM_IS_DIRECTORY_VIEW (view), FALSE);
10201
10202 return EEL_CALL_METHOD_WITH_RETURN_VALUE
10203 (FM_DIRECTORY_VIEW_CLASS, view,
10204 supports_properties, (view));
10205 }
10206
10207 static gboolean
real_supports_properties(FMDirectoryView * view)10208 real_supports_properties (FMDirectoryView *view)
10209 {
10210 g_return_val_if_fail (FM_IS_DIRECTORY_VIEW (view), FALSE);
10211
10212 return TRUE;
10213 }
10214
10215 gboolean
fm_directory_view_supports_zooming(FMDirectoryView * view)10216 fm_directory_view_supports_zooming (FMDirectoryView *view)
10217 {
10218 g_return_val_if_fail (FM_IS_DIRECTORY_VIEW (view), FALSE);
10219
10220 return EEL_CALL_METHOD_WITH_RETURN_VALUE
10221 (FM_DIRECTORY_VIEW_CLASS, view,
10222 supports_zooming, (view));
10223 }
10224
10225 static gboolean
real_supports_zooming(FMDirectoryView * view)10226 real_supports_zooming (FMDirectoryView *view)
10227 {
10228 g_return_val_if_fail (FM_IS_DIRECTORY_VIEW (view), FALSE);
10229
10230 return TRUE;
10231 }
10232
10233 gboolean
fm_directory_view_using_manual_layout(FMDirectoryView * view)10234 fm_directory_view_using_manual_layout (FMDirectoryView *view)
10235 {
10236 g_return_val_if_fail (FM_IS_DIRECTORY_VIEW (view), FALSE);
10237
10238 return EEL_CALL_METHOD_WITH_RETURN_VALUE
10239 (FM_DIRECTORY_VIEW_CLASS, view,
10240 using_manual_layout, (view));
10241 }
10242
10243 static gboolean
real_using_manual_layout(FMDirectoryView * view)10244 real_using_manual_layout (FMDirectoryView *view)
10245 {
10246 g_return_val_if_fail (FM_IS_DIRECTORY_VIEW (view), FALSE);
10247
10248 return FALSE;
10249 }
10250
10251 /**
10252 * fm_directory_view_update_menus:
10253 *
10254 * Update the sensitivity and wording of dynamic menu items.
10255 * @view: FMDirectoryView in question.
10256 */
10257 void
fm_directory_view_update_menus(FMDirectoryView * view)10258 fm_directory_view_update_menus (FMDirectoryView *view)
10259 {
10260 g_return_if_fail (FM_IS_DIRECTORY_VIEW (view));
10261
10262 if (!view->details->active) {
10263 return;
10264 }
10265
10266
10267 EEL_CALL_METHOD
10268 (FM_DIRECTORY_VIEW_CLASS, view,
10269 update_menus, (view));
10270
10271 view->details->menu_states_untrustworthy = FALSE;
10272 }
10273
10274 static void
schedule_update_menus_callback(gpointer callback_data)10275 schedule_update_menus_callback (gpointer callback_data)
10276 {
10277 schedule_update_menus (FM_DIRECTORY_VIEW (callback_data));
10278 }
10279
10280 void
fm_directory_view_ignore_hidden_file_preferences(FMDirectoryView * view)10281 fm_directory_view_ignore_hidden_file_preferences (FMDirectoryView *view)
10282 {
10283 g_return_if_fail (view->details->model == NULL);
10284
10285 if (view->details->ignore_hidden_file_preferences) {
10286 return;
10287 }
10288
10289 view->details->show_hidden_files = FALSE;
10290 view->details->ignore_hidden_file_preferences = TRUE;
10291 }
10292
10293 void
fm_directory_view_set_show_foreign(FMDirectoryView * view,gboolean show_foreign)10294 fm_directory_view_set_show_foreign (FMDirectoryView *view,
10295 gboolean show_foreign)
10296 {
10297 view->details->show_foreign_files = show_foreign;
10298 }
10299
10300 char *
fm_directory_view_get_uri(FMDirectoryView * view)10301 fm_directory_view_get_uri (FMDirectoryView *view)
10302 {
10303 g_return_val_if_fail (FM_IS_DIRECTORY_VIEW (view), NULL);
10304 if (view->details->model == NULL) {
10305 return NULL;
10306 }
10307 return caja_directory_get_uri (view->details->model);
10308 }
10309
10310 /* Get the real directory where files will be stored and created */
10311 char *
fm_directory_view_get_backing_uri(FMDirectoryView * view)10312 fm_directory_view_get_backing_uri (FMDirectoryView *view)
10313 {
10314 CajaDirectory *directory;
10315 char *uri;
10316
10317 g_return_val_if_fail (FM_IS_DIRECTORY_VIEW (view), NULL);
10318
10319 if (view->details->model == NULL) {
10320 return NULL;
10321 }
10322
10323 directory = view->details->model;
10324
10325 if (CAJA_IS_DESKTOP_DIRECTORY (directory)) {
10326 directory = caja_desktop_directory_get_real_directory (CAJA_DESKTOP_DIRECTORY (directory));
10327 } else {
10328 caja_directory_ref (directory);
10329 }
10330
10331 uri = caja_directory_get_uri (directory);
10332
10333 caja_directory_unref (directory);
10334
10335 return uri;
10336 }
10337
10338 void
fm_directory_view_move_copy_items(const GList * item_uris,GArray * relative_item_points,const char * target_uri,int copy_action,int x,int y,FMDirectoryView * view)10339 fm_directory_view_move_copy_items (const GList *item_uris,
10340 GArray *relative_item_points,
10341 const char *target_uri,
10342 int copy_action,
10343 int x, int y,
10344 FMDirectoryView *view)
10345 {
10346 CajaFile *target_file;
10347
10348 g_assert (relative_item_points == NULL
10349 || relative_item_points->len == 0
10350 || g_list_length ((GList *)item_uris) == relative_item_points->len);
10351
10352 /* add the drop location to the icon offsets */
10353 offset_drop_points (relative_item_points, x, y);
10354
10355 target_file = caja_file_get_existing_by_uri (target_uri);
10356 /* special-case "command:" here instead of starting a move/copy */
10357 if (target_file != NULL && caja_file_is_launcher (target_file)) {
10358 caja_file_unref (target_file);
10359 caja_launch_desktop_file (
10360 gtk_widget_get_screen (GTK_WIDGET (view)),
10361 target_uri, item_uris,
10362 fm_directory_view_get_containing_window (view));
10363 return;
10364 } else if (copy_action == GDK_ACTION_COPY &&
10365 caja_is_engrampa_installed () &&
10366 target_file != NULL &&
10367 caja_file_is_archive (target_file)) {
10368 char *command, *quoted_uri, *tmp;
10369 const GList *l;
10370 GdkScreen *screen;
10371
10372 /* Handle dropping onto a engrampa archiver file, instead of starting a move/copy */
10373
10374 caja_file_unref (target_file);
10375
10376 quoted_uri = g_shell_quote (target_uri);
10377 command = g_strconcat ("engrampa -a ", quoted_uri, NULL);
10378 g_free (quoted_uri);
10379
10380 for (l = item_uris; l != NULL; l = l->next) {
10381 quoted_uri = g_shell_quote ((char *) l->data);
10382
10383 tmp = g_strconcat (command, " ", quoted_uri, NULL);
10384 g_free (command);
10385 command = tmp;
10386
10387 g_free (quoted_uri);
10388 }
10389
10390 screen = gtk_widget_get_screen (GTK_WIDGET (view));
10391 if (screen == NULL) {
10392 screen = gdk_screen_get_default ();
10393 }
10394
10395 mate_gdk_spawn_command_line_on_screen(screen, command, NULL);
10396 g_free (command);
10397
10398 return;
10399 }
10400 caja_file_unref (target_file);
10401
10402 caja_file_operations_copy_move
10403 (item_uris, relative_item_points,
10404 target_uri, copy_action, GTK_WIDGET (view),
10405 copy_move_done_callback, pre_copy_move (view));
10406 }
10407
10408 gboolean
fm_directory_view_can_accept_item(CajaFile * target_item,const char * item_uri,FMDirectoryView * view)10409 fm_directory_view_can_accept_item (CajaFile *target_item,
10410 const char *item_uri,
10411 FMDirectoryView *view)
10412 {
10413 g_return_val_if_fail (CAJA_IS_FILE (target_item), FALSE);
10414 g_return_val_if_fail (item_uri != NULL, FALSE);
10415 g_return_val_if_fail (FM_IS_DIRECTORY_VIEW (view), FALSE);
10416
10417 return caja_drag_can_accept_item (target_item, item_uri);
10418 }
10419
10420 static void
fm_directory_view_trash_state_changed_callback(CajaTrashMonitor * trash_monitor,gboolean state,gpointer callback_data)10421 fm_directory_view_trash_state_changed_callback (CajaTrashMonitor *trash_monitor,
10422 gboolean state, gpointer callback_data)
10423 {
10424 FMDirectoryView *view;
10425
10426 view = (FMDirectoryView *) callback_data;
10427 g_assert (FM_IS_DIRECTORY_VIEW (view));
10428
10429 schedule_update_menus (view);
10430 }
10431
10432 void
fm_directory_view_start_batching_selection_changes(FMDirectoryView * view)10433 fm_directory_view_start_batching_selection_changes (FMDirectoryView *view)
10434 {
10435 g_return_if_fail (FM_IS_DIRECTORY_VIEW (view));
10436
10437 ++view->details->batching_selection_level;
10438 view->details->selection_changed_while_batched = FALSE;
10439 }
10440
10441 void
fm_directory_view_stop_batching_selection_changes(FMDirectoryView * view)10442 fm_directory_view_stop_batching_selection_changes (FMDirectoryView *view)
10443 {
10444 g_return_if_fail (FM_IS_DIRECTORY_VIEW (view));
10445 g_return_if_fail (view->details->batching_selection_level > 0);
10446
10447 if (--view->details->batching_selection_level == 0) {
10448 if (view->details->selection_changed_while_batched) {
10449 fm_directory_view_notify_selection_changed (view);
10450 }
10451 }
10452 }
10453
10454 static void
revert_slashes(char * string)10455 revert_slashes (char *string)
10456 {
10457 while (*string != 0) {
10458 if (*string == '/') {
10459 *string = '\\';
10460 }
10461 string++;
10462 }
10463 }
10464
10465
10466 static GdkDragAction
ask_link_action(FMDirectoryView * view)10467 ask_link_action (FMDirectoryView *view)
10468 {
10469 int button_pressed;
10470 GdkDragAction result;
10471 GtkWindow *parent_window;
10472 GtkWidget *dialog;
10473
10474 parent_window = NULL;
10475
10476 /* Don't use desktop window as parent, since that means
10477 we show up an all desktops etc */
10478 if (! FM_IS_DESKTOP_ICON_VIEW (view)) {
10479 parent_window = GTK_WINDOW (fm_directory_view_get_containing_window (view));
10480 }
10481
10482 dialog = gtk_message_dialog_new (parent_window,
10483 GTK_DIALOG_DESTROY_WITH_PARENT,
10484 GTK_MESSAGE_QUESTION,
10485 GTK_BUTTONS_NONE,
10486 _("Download location?"));
10487
10488 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
10489 _("You can download it or make a link to it."));
10490
10491 gtk_dialog_add_button (GTK_DIALOG (dialog),
10492 _("Make a _Link"), 0);
10493
10494 eel_dialog_add_button (GTK_DIALOG (dialog),
10495 _("_Cancel"),
10496 "process-stop", 1);
10497
10498 gtk_dialog_add_button (GTK_DIALOG (dialog),
10499 _("_Download"), 2);
10500
10501 gtk_window_set_title (GTK_WINDOW (dialog), ""); /* as per HIG */
10502 gtk_window_set_focus_on_map (GTK_WINDOW (dialog), TRUE);
10503 gtk_dialog_set_default_response (GTK_DIALOG (dialog), 2);
10504
10505 gtk_window_present (GTK_WINDOW (dialog));
10506
10507 button_pressed = gtk_dialog_run (GTK_DIALOG (dialog));
10508
10509 gtk_widget_destroy (dialog);
10510
10511 switch (button_pressed) {
10512 case 0:
10513 result = GDK_ACTION_LINK;
10514 break;
10515 case 1:
10516 case GTK_RESPONSE_DELETE_EVENT:
10517 result = 0;
10518 break;
10519 case 2:
10520 result = GDK_ACTION_COPY;
10521 break;
10522 default:
10523 g_assert_not_reached ();
10524 result = 0;
10525 }
10526
10527 return result;
10528 }
10529
10530 typedef struct {
10531 FMDirectoryView *view;
10532 GCancellable *cancellable;
10533 char *encoded_url;
10534 char *target_uri;
10535 int x;
10536 int y;
10537 guint timeout;
10538 } NetscapeUrlDropAsk;
10539
10540 static void
handle_netscape_url_drop_ask_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)10541 handle_netscape_url_drop_ask_cb (GObject *source_object,
10542 GAsyncResult *res,
10543 gpointer user_data)
10544 {
10545 NetscapeUrlDropAsk *data;
10546 GdkDragAction action;
10547 GFileInfo *info;
10548 GFile *f;
10549 const char *mime_type;
10550
10551 data = user_data;
10552 f = G_FILE (source_object);
10553
10554 info = g_file_query_info_finish (f, res, NULL);
10555 mime_type = NULL;
10556
10557 if (info) {
10558 mime_type = g_file_info_get_content_type (info);
10559 }
10560
10561 if (mime_type != NULL &&
10562 (g_content_type_equals (mime_type, "text/html") ||
10563 g_content_type_equals (mime_type, "text/xml") ||
10564 g_content_type_equals (mime_type, "application/xhtml+xml"))) {
10565 action = GDK_ACTION_LINK;
10566 } else if (mime_type != NULL &&
10567 g_content_type_equals (mime_type, "text/plain")) {
10568 action = ask_link_action (data->view);
10569 } else {
10570 action = GDK_ACTION_COPY;
10571 }
10572 if (info) {
10573 g_object_unref (info);
10574 }
10575
10576 if (action != 0) {
10577 fm_directory_view_handle_netscape_url_drop (data->view,
10578 data->encoded_url,
10579 data->target_uri,
10580 action,
10581 data->x, data->y);
10582 }
10583
10584 g_object_unref (data->view);
10585 g_object_unref (data->cancellable);
10586 if (data->timeout != 0) {
10587 g_source_remove (data->timeout);
10588 }
10589 g_free (data->encoded_url);
10590 g_free (data->target_uri);
10591 g_free (data);
10592 }
10593
10594 static gboolean
handle_netscape_url_drop_timeout(gpointer user_data)10595 handle_netscape_url_drop_timeout (gpointer user_data)
10596 {
10597 NetscapeUrlDropAsk *data;
10598
10599 data = user_data;
10600
10601 g_cancellable_cancel (data->cancellable);
10602 data->timeout = 0;
10603
10604 return FALSE;
10605 }
10606
10607 static inline void
fm_directory_view_widget_to_file_operation_position(FMDirectoryView * view,GdkPoint * position)10608 fm_directory_view_widget_to_file_operation_position (FMDirectoryView *view,
10609 GdkPoint *position)
10610 {
10611 EEL_CALL_METHOD (FM_DIRECTORY_VIEW_CLASS, view,
10612 widget_to_file_operation_position,
10613 (view, position));
10614 }
10615
10616 static void
fm_directory_view_widget_to_file_operation_position_xy(FMDirectoryView * view,int * x,int * y)10617 fm_directory_view_widget_to_file_operation_position_xy (FMDirectoryView *view,
10618 int *x, int *y)
10619 {
10620 GdkPoint position;
10621
10622 position.x = *x;
10623 position.y = *y;
10624 fm_directory_view_widget_to_file_operation_position (view, &position);
10625 *x = position.x;
10626 *y = position.y;
10627 }
10628
10629 void
fm_directory_view_handle_netscape_url_drop(FMDirectoryView * view,const char * encoded_url,const char * target_uri,GdkDragAction action,int x,int y)10630 fm_directory_view_handle_netscape_url_drop (FMDirectoryView *view,
10631 const char *encoded_url,
10632 const char *target_uri,
10633 GdkDragAction action,
10634 int x,
10635 int y)
10636 {
10637 GdkPoint point;
10638 char *url, *title;
10639 char *container_uri;
10640 char **bits;
10641 GList *uri_list = NULL;
10642 GFile *f;
10643
10644 if (encoded_url == NULL) {
10645 return;
10646 }
10647
10648 container_uri = NULL;
10649 if (target_uri == NULL) {
10650 container_uri = fm_directory_view_get_backing_uri (view);
10651 g_assert (container_uri != NULL);
10652 }
10653
10654 f = g_file_new_for_uri (target_uri != NULL ? target_uri : container_uri);
10655 if (!g_file_is_native (f)) {
10656 eel_show_warning_dialog (_("Drag and drop is not supported."),
10657 _("Drag and drop is only supported on local file systems."),
10658 fm_directory_view_get_containing_window (view));
10659 g_object_unref (f);
10660 g_free (container_uri);
10661 return;
10662 }
10663 g_object_unref (f);
10664
10665 /* _NETSCAPE_URL_ works like this: $URL\n$TITLE */
10666 bits = g_strsplit (encoded_url, "\n", 0);
10667 switch (g_strv_length (bits)) {
10668 case 0:
10669 g_strfreev (bits);
10670 g_free (container_uri);
10671 return;
10672 case 1:
10673 url = bits[0];
10674 title = NULL;
10675 break;
10676 default:
10677 url = bits[0];
10678 title = bits[1];
10679 }
10680
10681 if (action == GDK_ACTION_ASK) {
10682 NetscapeUrlDropAsk *data;
10683
10684 f = g_file_new_for_uri (url);
10685 data = g_new0 (NetscapeUrlDropAsk, 1);
10686 data->view = g_object_ref (view);
10687 data->cancellable = g_cancellable_new ();
10688 data->encoded_url = g_strdup (encoded_url);
10689 data->target_uri = g_strdup (target_uri);
10690 data->x = x;
10691 data->y = y;
10692 /* Ensure we wait at most 1 second for mimetype */
10693 data->timeout = g_timeout_add (1000,
10694 handle_netscape_url_drop_timeout,
10695 data);
10696 g_file_query_info_async (f,
10697 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, 0,
10698 0, data->cancellable,
10699 handle_netscape_url_drop_ask_cb,
10700 data);
10701
10702 g_strfreev (bits);
10703 g_free (container_uri);
10704 return;
10705 }
10706
10707 fm_directory_view_widget_to_file_operation_position_xy (view, &x, &y);
10708
10709 /* We don't support GDK_ACTION_ASK or GDK_ACTION_PRIVATE
10710 * and we don't support combinations either. */
10711 if ((action != GDK_ACTION_DEFAULT) &&
10712 (action != GDK_ACTION_COPY) &&
10713 (action != GDK_ACTION_MOVE) &&
10714 (action != GDK_ACTION_LINK)) {
10715 eel_show_warning_dialog (_("Drag and drop is not supported."),
10716 _("An invalid drag type was used."),
10717 fm_directory_view_get_containing_window (view));
10718 g_strfreev (bits);
10719 g_free (container_uri);
10720 return;
10721 }
10722
10723 if (action == GDK_ACTION_LINK) {
10724 char *link_name;
10725
10726 if (eel_str_is_empty (title)) {
10727 GFile *f;
10728
10729 f = g_file_new_for_uri (url);
10730 link_name = g_file_get_basename (f);
10731 g_object_unref (f);
10732 } else {
10733 link_name = g_strdup (title);
10734 }
10735
10736 if (!eel_str_is_empty (link_name)) {
10737 GdkScreen *screen;
10738 int screen_num;
10739 char *link_display_name;
10740 GError *error = NULL;
10741 gboolean success;
10742
10743 link_display_name = g_strdup_printf (_("Link to %s"), link_name);
10744
10745 /* The filename can't contain slashes, strip em.
10746 (the basename of http://foo/ is http://foo/) */
10747 revert_slashes (link_name);
10748
10749 point.x = x;
10750 point.y = y;
10751
10752 screen = gtk_widget_get_screen (GTK_WIDGET (view));
10753 screen_num = gdk_x11_screen_get_screen_number (screen);
10754
10755 success = caja_link_local_create (target_uri != NULL ? target_uri : container_uri,
10756 link_name,
10757 link_display_name,
10758 "mate-fs-bookmark",
10759 url,
10760 &point,
10761 screen_num,
10762 TRUE,
10763 &error);
10764 if (!success) {
10765 if (error) {
10766 eel_show_error_dialog (_("Link Creation Failed"),
10767 error->message, NULL);
10768 g_error_free (error);
10769 } else {
10770 gchar *error_message = g_strdup_printf (_("Cannot create the link to %s"), url);
10771 eel_show_error_dialog (_("Link Creation Failed"),
10772 error_message, NULL);
10773 g_free (error_message);
10774 }
10775 }
10776
10777 g_free (link_display_name);
10778 }
10779 g_free (link_name);
10780 } else {
10781 GArray *points;
10782
10783 GdkPoint tmp_point = { 0, 0 };
10784
10785 /* pass in a 1-item array of icon positions, relative to x, y */
10786 points = g_array_new (FALSE, TRUE, sizeof (GdkPoint));
10787 g_array_append_val (points, tmp_point);
10788
10789 uri_list = g_list_append (uri_list, url);
10790
10791 fm_directory_view_move_copy_items (uri_list, points,
10792 target_uri != NULL ? target_uri : container_uri,
10793 action, x, y, view);
10794
10795 g_list_free (uri_list);
10796 g_array_free (points, TRUE);
10797 }
10798
10799 g_strfreev (bits);
10800 g_free (container_uri);
10801 }
10802
10803 void
fm_directory_view_handle_uri_list_drop(FMDirectoryView * view,const char * item_uris,const char * target_uri,GdkDragAction action,int x,int y)10804 fm_directory_view_handle_uri_list_drop (FMDirectoryView *view,
10805 const char *item_uris,
10806 const char *target_uri,
10807 GdkDragAction action,
10808 int x,
10809 int y)
10810 {
10811 gchar **uri_list;
10812 GList *real_uri_list = NULL;
10813 char *container_uri;
10814 int n_uris, i;
10815 GArray *points;
10816
10817 if (item_uris == NULL) {
10818 return;
10819 }
10820
10821 container_uri = NULL;
10822 if (target_uri == NULL) {
10823 container_uri = fm_directory_view_get_backing_uri (view);
10824 g_assert (container_uri != NULL);
10825 }
10826
10827 if (action == GDK_ACTION_ASK) {
10828 action = caja_drag_drop_action_ask
10829 (GTK_WIDGET (view),
10830 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK);
10831 if (action == 0) {
10832 g_free (container_uri);
10833 return;
10834 }
10835 }
10836
10837 /* We don't support GDK_ACTION_ASK or GDK_ACTION_PRIVATE
10838 * and we don't support combinations either. */
10839 if ((action != GDK_ACTION_DEFAULT) &&
10840 (action != GDK_ACTION_COPY) &&
10841 (action != GDK_ACTION_MOVE) &&
10842 (action != GDK_ACTION_LINK)) {
10843 eel_show_warning_dialog (_("Drag and drop is not supported."),
10844 _("An invalid drag type was used."),
10845 fm_directory_view_get_containing_window (view));
10846 g_free (container_uri);
10847 return;
10848 }
10849
10850 n_uris = 0;
10851 uri_list = g_uri_list_extract_uris (item_uris);
10852 for (i = 0; uri_list[i] != NULL; i++) {
10853 real_uri_list = g_list_append (real_uri_list, uri_list[i]);
10854 n_uris++;
10855 }
10856 g_free (uri_list);
10857
10858 /* do nothing if no real uris are left */
10859 if (n_uris == 0) {
10860 g_free (container_uri);
10861 return;
10862 }
10863
10864 if (n_uris == 1) {
10865 GdkPoint tmp_point = { 0, 0 };
10866
10867 /* pass in a 1-item array of icon positions, relative to x, y */
10868 points = g_array_new (FALSE, TRUE, sizeof (GdkPoint));
10869 g_array_append_val (points, tmp_point);
10870 } else {
10871 points = NULL;
10872 }
10873
10874 fm_directory_view_widget_to_file_operation_position_xy (view, &x, &y);
10875
10876 fm_directory_view_move_copy_items (real_uri_list, points,
10877 target_uri != NULL ? target_uri : container_uri,
10878 action, x, y, view);
10879
10880 g_list_free_full (real_uri_list, g_free);
10881
10882 if (points != NULL)
10883 g_array_free (points, TRUE);
10884
10885 g_free (container_uri);
10886 }
10887
10888 void
fm_directory_view_handle_text_drop(FMDirectoryView * view,const char * text,const char * target_uri,GdkDragAction action,int x,int y)10889 fm_directory_view_handle_text_drop (FMDirectoryView *view,
10890 const char *text,
10891 const char *target_uri,
10892 GdkDragAction action,
10893 int x,
10894 int y)
10895 {
10896 int length;
10897 char *container_uri;
10898 GdkPoint pos;
10899
10900 if (text == NULL) {
10901 return;
10902 }
10903
10904 g_return_if_fail (action == GDK_ACTION_COPY);
10905
10906 container_uri = NULL;
10907 if (target_uri == NULL) {
10908 container_uri = fm_directory_view_get_backing_uri (view);
10909 g_assert (container_uri != NULL);
10910 }
10911
10912 length = strlen (text);
10913
10914 pos.x = x;
10915 pos.y = y;
10916 fm_directory_view_widget_to_file_operation_position (view, &pos);
10917
10918 fm_directory_view_new_file_with_initial_contents (
10919 view, target_uri != NULL ? target_uri : container_uri,
10920 /* Translators: This is the filename used for when you dnd text to a directory */
10921 _("dropped text.txt"),
10922 text, length, &pos);
10923
10924 g_free (container_uri);
10925 }
10926
10927 void
fm_directory_view_handle_raw_drop(FMDirectoryView * view,const char * raw_data,int length,const char * target_uri,const char * direct_save_uri,GdkDragAction action,int x,int y)10928 fm_directory_view_handle_raw_drop (FMDirectoryView *view,
10929 const char *raw_data,
10930 int length,
10931 const char *target_uri,
10932 const char *direct_save_uri,
10933 GdkDragAction action,
10934 int x,
10935 int y)
10936 {
10937 char *container_uri, *filename;
10938 GdkPoint pos;
10939
10940 if (raw_data == NULL) {
10941 return;
10942 }
10943
10944 g_return_if_fail (action == GDK_ACTION_COPY);
10945
10946 container_uri = NULL;
10947 if (target_uri == NULL) {
10948 container_uri = fm_directory_view_get_backing_uri (view);
10949 g_assert (container_uri != NULL);
10950 }
10951
10952 pos.x = x;
10953 pos.y = y;
10954 fm_directory_view_widget_to_file_operation_position (view, &pos);
10955
10956 filename = NULL;
10957 if (direct_save_uri != NULL) {
10958 GFile *direct_save_full;
10959
10960 direct_save_full = g_file_new_for_uri (direct_save_uri);
10961 filename = g_file_get_basename (direct_save_full);
10962 }
10963 if (filename == NULL) {
10964 /* Translators: This is the filename used for when you dnd raw
10965 * data to a directory, if the source didn't supply a name.
10966 */
10967 filename = _("dropped data");
10968 }
10969
10970 fm_directory_view_new_file_with_initial_contents (
10971 view, target_uri != NULL ? target_uri : container_uri,
10972 filename, raw_data, length, &pos);
10973
10974 g_free (container_uri);
10975 }
10976
10977 gboolean
fm_directory_view_get_active(FMDirectoryView * view)10978 fm_directory_view_get_active (FMDirectoryView *view)
10979 {
10980 g_assert (FM_IS_DIRECTORY_VIEW (view));
10981 return view->details->active;
10982 }
10983
10984 static GArray *
real_get_selected_icon_locations(FMDirectoryView * view)10985 real_get_selected_icon_locations (FMDirectoryView *view)
10986 {
10987 /* By default, just return an empty list. */
10988 return g_array_new (FALSE, TRUE, sizeof (GdkPoint));
10989 }
10990
10991 static void
fm_directory_view_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)10992 fm_directory_view_set_property (GObject *object,
10993 guint prop_id,
10994 const GValue *value,
10995 GParamSpec *pspec)
10996 {
10997 FMDirectoryView *directory_view;
10998 CajaWindowSlotInfo *slot;
10999 CajaWindowInfo *window;
11000
11001 directory_view = FM_DIRECTORY_VIEW (object);
11002
11003 switch (prop_id) {
11004 case PROP_WINDOW_SLOT:
11005 g_assert (directory_view->details->slot == NULL);
11006
11007 slot = CAJA_WINDOW_SLOT_INFO (g_value_get_object (value));
11008 window = caja_window_slot_info_get_window (slot);
11009
11010 directory_view->details->slot = slot;
11011 directory_view->details->window = window;
11012
11013 g_signal_connect_object (directory_view->details->slot,
11014 "active", G_CALLBACK (slot_active),
11015 directory_view, 0);
11016 g_signal_connect_object (directory_view->details->slot,
11017 "inactive", G_CALLBACK (slot_inactive),
11018 directory_view, 0);
11019
11020 g_signal_connect_object (directory_view->details->window,
11021 "hidden-files-mode-changed", G_CALLBACK (hidden_files_mode_changed),
11022 directory_view, 0);
11023 fm_directory_view_init_show_hidden_files (directory_view);
11024
11025 g_signal_connect_object (directory_view->details->window,
11026 "backup-files-mode-changed", G_CALLBACK (backup_files_mode_changed),
11027 directory_view, 0);
11028 fm_directory_view_init_show_backup_files (directory_view);
11029
11030 break;
11031 default:
11032 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
11033 break;
11034 }
11035 }
11036
11037
11038 gboolean
fm_directory_view_handle_scroll_event(FMDirectoryView * directory_view,GdkEventScroll * event)11039 fm_directory_view_handle_scroll_event (FMDirectoryView *directory_view,
11040 GdkEventScroll *event)
11041 {
11042 static gdouble total_delta_y = 0;
11043 gdouble delta_x, delta_y;
11044
11045 if (event->state & GDK_CONTROL_MASK) {
11046 switch (event->direction) {
11047 case GDK_SCROLL_UP:
11048 /* Zoom In */
11049 fm_directory_view_bump_zoom_level (directory_view, 1);
11050 return TRUE;
11051
11052 case GDK_SCROLL_DOWN:
11053 /* Zoom Out */
11054 fm_directory_view_bump_zoom_level (directory_view, -1);
11055 return TRUE;
11056
11057 case GDK_SCROLL_SMOOTH:
11058 gdk_event_get_scroll_deltas ((const GdkEvent *) event,
11059 &delta_x, &delta_y);
11060
11061 /* try to emulate a normal scrolling event by summing deltas */
11062 total_delta_y += delta_y;
11063
11064 if (total_delta_y >= 1) {
11065 total_delta_y = 0;
11066 /* emulate scroll down */
11067 fm_directory_view_bump_zoom_level (directory_view, -1);
11068 return TRUE;
11069 } else if (total_delta_y <= - 1) {
11070 total_delta_y = 0;
11071 /* emulate scroll up */
11072 fm_directory_view_bump_zoom_level (directory_view, 1);
11073 return TRUE;
11074 } else {
11075 /* eat event */
11076 return TRUE;
11077 }
11078
11079 case GDK_SCROLL_LEFT:
11080 case GDK_SCROLL_RIGHT:
11081 break;
11082
11083 default:
11084 g_assert_not_reached ();
11085 }
11086 }
11087
11088 return FALSE;
11089 }
11090
11091 /* handle Shift+Scroll, which will cause a zoom-in/out */
11092 static gboolean
fm_directory_view_scroll_event(GtkWidget * widget,GdkEventScroll * event)11093 fm_directory_view_scroll_event (GtkWidget *widget,
11094 GdkEventScroll *event)
11095 {
11096 FMDirectoryView *directory_view;
11097
11098 directory_view = FM_DIRECTORY_VIEW (widget);
11099 if (fm_directory_view_handle_scroll_event (directory_view, event)) {
11100 return TRUE;
11101 }
11102
11103 return GTK_WIDGET_CLASS (parent_class)->scroll_event (widget, event);
11104 }
11105
11106
11107 static void
fm_directory_view_parent_set(GtkWidget * widget,GtkWidget * old_parent)11108 fm_directory_view_parent_set (GtkWidget *widget,
11109 GtkWidget *old_parent)
11110 {
11111 FMDirectoryView *view;
11112 GtkWidget *parent;
11113
11114 view = FM_DIRECTORY_VIEW (widget);
11115
11116 parent = gtk_widget_get_parent (widget);
11117 g_assert (parent == NULL || old_parent == NULL);
11118
11119 if (GTK_WIDGET_CLASS (parent_class)->parent_set != NULL) {
11120 GTK_WIDGET_CLASS (parent_class)->parent_set (widget, old_parent);
11121 }
11122
11123 if (parent != NULL) {
11124 g_assert (old_parent == NULL);
11125
11126 if (view->details->slot ==
11127 caja_window_info_get_active_slot (view->details->window)) {
11128 view->details->active = TRUE;
11129
11130 fm_directory_view_merge_menus (view);
11131 schedule_update_menus (view);
11132 }
11133 } else {
11134 fm_directory_view_unmerge_menus (view);
11135 remove_update_menus_timeout_callback (view);
11136 }
11137 }
11138
11139 static void
fm_directory_view_class_init(FMDirectoryViewClass * klass)11140 fm_directory_view_class_init (FMDirectoryViewClass *klass)
11141 {
11142 GtkWidgetClass *widget_class;
11143 GtkScrolledWindowClass *scrolled_window_class;
11144 GtkBindingSet *binding_set;
11145
11146 widget_class = GTK_WIDGET_CLASS (klass);
11147 scrolled_window_class = GTK_SCROLLED_WINDOW_CLASS (klass);
11148
11149 G_OBJECT_CLASS (klass)->set_property = fm_directory_view_set_property;
11150 G_OBJECT_CLASS (klass)->finalize = fm_directory_view_finalize;
11151
11152 widget_class->destroy = fm_directory_view_destroy;
11153
11154 widget_class->scroll_event = fm_directory_view_scroll_event;
11155 widget_class->parent_set = fm_directory_view_parent_set;
11156
11157 /* Get rid of the strange 3-pixel gap that GtkScrolledWindow
11158 * uses by default. It does us no good.
11159 */
11160 scrolled_window_class->scrollbar_spacing = 0;
11161
11162 signals[ADD_FILE] =
11163 g_signal_new ("add_file",
11164 G_TYPE_FROM_CLASS (klass),
11165 G_SIGNAL_RUN_LAST,
11166 G_STRUCT_OFFSET (FMDirectoryViewClass, add_file),
11167 NULL, NULL,
11168 fm_marshal_VOID__OBJECT_OBJECT,
11169 G_TYPE_NONE, 2, CAJA_TYPE_FILE, CAJA_TYPE_DIRECTORY);
11170 signals[BEGIN_FILE_CHANGES] =
11171 g_signal_new ("begin_file_changes",
11172 G_TYPE_FROM_CLASS (klass),
11173 G_SIGNAL_RUN_LAST,
11174 G_STRUCT_OFFSET (FMDirectoryViewClass, begin_file_changes),
11175 NULL, NULL,
11176 g_cclosure_marshal_VOID__VOID,
11177 G_TYPE_NONE, 0);
11178 signals[BEGIN_LOADING] =
11179 g_signal_new ("begin_loading",
11180 G_TYPE_FROM_CLASS (klass),
11181 G_SIGNAL_RUN_LAST,
11182 G_STRUCT_OFFSET (FMDirectoryViewClass, begin_loading),
11183 NULL, NULL,
11184 g_cclosure_marshal_VOID__VOID,
11185 G_TYPE_NONE, 0);
11186 signals[CLEAR] =
11187 g_signal_new ("clear",
11188 G_TYPE_FROM_CLASS (klass),
11189 G_SIGNAL_RUN_LAST,
11190 G_STRUCT_OFFSET (FMDirectoryViewClass, clear),
11191 NULL, NULL,
11192 g_cclosure_marshal_VOID__VOID,
11193 G_TYPE_NONE, 0);
11194 signals[END_FILE_CHANGES] =
11195 g_signal_new ("end_file_changes",
11196 G_TYPE_FROM_CLASS (klass),
11197 G_SIGNAL_RUN_LAST,
11198 G_STRUCT_OFFSET (FMDirectoryViewClass, end_file_changes),
11199 NULL, NULL,
11200 g_cclosure_marshal_VOID__VOID,
11201 G_TYPE_NONE, 0);
11202 signals[FLUSH_ADDED_FILES] =
11203 g_signal_new ("flush_added_files",
11204 G_TYPE_FROM_CLASS (klass),
11205 G_SIGNAL_RUN_LAST,
11206 G_STRUCT_OFFSET (FMDirectoryViewClass, flush_added_files),
11207 NULL, NULL,
11208 g_cclosure_marshal_VOID__VOID,
11209 G_TYPE_NONE, 0);
11210 signals[END_LOADING] =
11211 g_signal_new ("end_loading",
11212 G_TYPE_FROM_CLASS (klass),
11213 G_SIGNAL_RUN_LAST,
11214 G_STRUCT_OFFSET (FMDirectoryViewClass, end_loading),
11215 NULL, NULL,
11216 g_cclosure_marshal_VOID__BOOLEAN,
11217 G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
11218 signals[FILE_CHANGED] =
11219 g_signal_new ("file_changed",
11220 G_TYPE_FROM_CLASS (klass),
11221 G_SIGNAL_RUN_LAST,
11222 G_STRUCT_OFFSET (FMDirectoryViewClass, file_changed),
11223 NULL, NULL,
11224 fm_marshal_VOID__OBJECT_OBJECT,
11225 G_TYPE_NONE, 2, CAJA_TYPE_FILE, CAJA_TYPE_DIRECTORY);
11226 signals[LOAD_ERROR] =
11227 g_signal_new ("load_error",
11228 G_TYPE_FROM_CLASS (klass),
11229 G_SIGNAL_RUN_LAST,
11230 G_STRUCT_OFFSET (FMDirectoryViewClass, load_error),
11231 NULL, NULL,
11232 g_cclosure_marshal_VOID__POINTER,
11233 G_TYPE_NONE, 1, G_TYPE_POINTER);
11234 signals[REMOVE_FILE] =
11235 g_signal_new ("remove_file",
11236 G_TYPE_FROM_CLASS (klass),
11237 G_SIGNAL_RUN_LAST,
11238 G_STRUCT_OFFSET (FMDirectoryViewClass, remove_file),
11239 NULL, NULL,
11240 fm_marshal_VOID__OBJECT_OBJECT,
11241 G_TYPE_NONE, 2, CAJA_TYPE_FILE, CAJA_TYPE_DIRECTORY);
11242
11243 klass->accepts_dragged_files = real_accepts_dragged_files;
11244 klass->file_still_belongs = real_file_still_belongs;
11245 klass->get_emblem_names_to_exclude = real_get_emblem_names_to_exclude;
11246 klass->get_selected_icon_locations = real_get_selected_icon_locations;
11247 klass->is_read_only = real_is_read_only;
11248 klass->load_error = real_load_error;
11249 klass->can_rename_file = can_rename_file;
11250 klass->start_renaming_file = start_renaming_file;
11251 klass->supports_creating_files = real_supports_creating_files;
11252 klass->supports_properties = real_supports_properties;
11253 klass->supports_zooming = real_supports_zooming;
11254 klass->using_manual_layout = real_using_manual_layout;
11255 klass->merge_menus = real_merge_menus;
11256 klass->unmerge_menus = real_unmerge_menus;
11257 klass->update_menus = real_update_menus;
11258 klass->set_is_active = real_set_is_active;
11259 /* Function pointers that subclasses must override */
11260 EEL_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, add_file);
11261 EEL_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, bump_zoom_level);
11262 EEL_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, can_zoom_in);
11263 EEL_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, can_zoom_out);
11264 EEL_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, clear);
11265 EEL_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, file_changed);
11266 EEL_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, get_background_widget);
11267 EEL_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, get_selection);
11268 EEL_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, get_selection_for_file_transfer);
11269 EEL_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, get_item_count);
11270 EEL_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, is_empty);
11271 EEL_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, reset_to_defaults);
11272 EEL_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, restore_default_zoom_level);
11273 EEL_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, select_all);
11274 EEL_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, set_selection);
11275 EEL_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, invert_selection);
11276 EEL_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, zoom_to_level);
11277 EEL_ASSIGN_MUST_OVERRIDE_SIGNAL (klass, fm_directory_view, get_zoom_level);
11278
11279 copied_files_atom = gdk_atom_intern ("x-special/mate-copied-files", FALSE);
11280
11281 g_object_class_install_property (G_OBJECT_CLASS (klass),
11282 PROP_WINDOW_SLOT,
11283 g_param_spec_object ("window-slot",
11284 "Window Slot",
11285 "The parent window slot reference",
11286 CAJA_TYPE_WINDOW_SLOT_INFO,
11287 G_PARAM_WRITABLE |
11288 G_PARAM_CONSTRUCT_ONLY));
11289
11290 signals[TRASH] =
11291 g_signal_new ("trash",
11292 G_TYPE_FROM_CLASS (klass),
11293 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
11294 G_STRUCT_OFFSET (FMDirectoryViewClass, trash),
11295 g_signal_accumulator_true_handled, NULL,
11296 fm_marshal_BOOLEAN__VOID,
11297 G_TYPE_BOOLEAN, 0);
11298 signals[DELETE] =
11299 g_signal_new ("delete",
11300 G_TYPE_FROM_CLASS (klass),
11301 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
11302 G_STRUCT_OFFSET (FMDirectoryViewClass, delete),
11303 g_signal_accumulator_true_handled, NULL,
11304 fm_marshal_BOOLEAN__VOID,
11305 G_TYPE_BOOLEAN, 0);
11306
11307 binding_set = gtk_binding_set_by_class (klass);
11308 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, 0,
11309 "trash", 0);
11310 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Delete, 0,
11311 "trash", 0);
11312 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, GDK_SHIFT_MASK,
11313 "delete", 0);
11314 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Delete, GDK_SHIFT_MASK,
11315 "delete", 0);
11316
11317 klass->trash = real_trash;
11318 klass->delete = real_delete;
11319 }
11320
11321 static void
undo_redo_menu_update_callback(CajaUndoStackManager * manager,gpointer arg,gpointer data)11322 undo_redo_menu_update_callback (CajaUndoStackManager* manager, gpointer arg, gpointer data)
11323 {
11324 FMDirectoryView *view;
11325 view = FM_DIRECTORY_VIEW (data);
11326
11327 CajaUndoStackMenuData* menudata = (CajaUndoStackMenuData*) arg;
11328
11329 g_free(view->details->undo_action_label);
11330 g_free(view->details->undo_action_description);
11331 g_free(view->details->redo_action_label);
11332 g_free(view->details->redo_action_description);
11333
11334 view->details->undo_active = menudata->undo_label ? TRUE : FALSE;
11335 view->details->redo_active = menudata->redo_label ? TRUE : FALSE;
11336
11337 view->details->undo_action_label = g_strdup (menudata->undo_label);
11338 view->details->undo_action_description = g_strdup (menudata->undo_description);
11339 view->details->redo_action_label = g_strdup (menudata->redo_label);
11340 view->details->redo_action_description = g_strdup (menudata->redo_description);
11341
11342 schedule_update_menus (view);
11343 }
11344
11345 static void
undo_update_menu(FMDirectoryView * view)11346 undo_update_menu (FMDirectoryView *view)
11347 {
11348 GtkAction *action;
11349 gboolean available = FALSE;
11350 gchar* label;
11351 gchar* tooltip;
11352
11353 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
11354 /* Update undo entry */
11355 action = gtk_action_group_get_action (view->details->dir_action_group,
11356 FM_ACTION_UNDO);
11357 G_GNUC_END_IGNORE_DEPRECATIONS;
11358 available = view->details->undo_active;
11359 if (available) {
11360 label = view->details->undo_action_label;
11361 tooltip = view->details->undo_action_description;
11362 } else {
11363 /* Reset to default info */
11364 label = _("Undo");
11365 tooltip = _("Undo the last action");
11366 }
11367 g_object_set (action,
11368 "label", label,
11369 "tooltip", tooltip,
11370 NULL);
11371 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
11372 gtk_action_set_sensitive (action, available);
11373
11374 /* Update redo entry */
11375 action = gtk_action_group_get_action (view->details->dir_action_group,
11376 FM_ACTION_REDO);
11377 G_GNUC_END_IGNORE_DEPRECATIONS;
11378 available = view->details->redo_active;
11379 if (available) {
11380 label = view->details->redo_action_label;
11381 tooltip = view->details->redo_action_description;
11382 } else {
11383 /* Reset to default info */
11384 label = _("Redo");
11385 tooltip = _("Redo the last undone action");
11386 }
11387 g_object_set (action,
11388 "label", label,
11389 "tooltip", tooltip,
11390 NULL);
11391 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
11392 gtk_action_set_sensitive (action, available);
11393 G_GNUC_END_IGNORE_DEPRECATIONS;
11394 }
11395