1 /* fm-canvas-view.c - implementation of canvas view of directory.
2 *
3 * Copyright (C) 2000, 2001 Eazel, Inc.
4 *
5 * The Gnome Library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
9 *
10 * The Gnome Library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with the Gnome Library; see the file COPYING.LIB. If not,
17 * see <http://www.gnu.org/licenses/>.
18 *
19 * Authors: John Sullivan <sullivan@eazel.com>
20 */
21
22 #include <config.h>
23
24 #include "nautilus-canvas-view.h"
25
26 #include "nautilus-canvas-view-container.h"
27 #include "nautilus-error-reporting.h"
28 #include "nautilus-files-view-dnd.h"
29 #include "nautilus-toolbar.h"
30 #include "nautilus-view.h"
31
32 #include <stdlib.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <gtk/gtk.h>
36 #include <glib/gi18n.h>
37 #include <gio/gio.h>
38 #include "nautilus-directory.h"
39 #include "nautilus-dnd.h"
40 #include "nautilus-file-utilities.h"
41 #include "nautilus-ui-utilities.h"
42 #include "nautilus-global-preferences.h"
43 #include "nautilus-canvas-container.h"
44 #include "nautilus-canvas-dnd.h"
45 #include "nautilus-metadata.h"
46 #include "nautilus-clipboard.h"
47
48 #define DEBUG_FLAG NAUTILUS_DEBUG_CANVAS_VIEW
49 #include "nautilus-debug.h"
50
51 #include <locale.h>
52 #include <signal.h>
53 #include <stdio.h>
54 #include <sys/types.h>
55 #include <sys/wait.h>
56 #include <unistd.h>
57
58 typedef gboolean (*SortCriterionMatchFunc) (NautilusFile *file);
59
60 typedef struct
61 {
62 const NautilusFileSortType sort_type;
63 const char *metadata_text;
64 const char *action_target_name;
65 const gboolean reverse_order;
66 SortCriterionMatchFunc match_func;
67 } SortCriterion;
68
69 typedef enum
70 {
71 MENU_ITEM_TYPE_STANDARD,
72 MENU_ITEM_TYPE_CHECK,
73 MENU_ITEM_TYPE_RADIO,
74 MENU_ITEM_TYPE_TREE
75 } MenuItemType;
76
77 struct _NautilusCanvasView
78 {
79 NautilusFilesView parent_instance;
80
81 GList *icons_not_positioned;
82
83 guint react_to_canvas_change_idle_id;
84
85 const SortCriterion *sort;
86
87 GtkWidget *canvas_container;
88
89 /* FIXME: Needed for async operations. Suposedly we would use cancellable and gtask,
90 * sadly gtkclipboard doesn't support that.
91 * We follow this pattern for checking validity of the object in the views.
92 * Ideally we would connect to a weak reference and do a cancellable.
93 */
94 gboolean destroyed;
95 };
96
97 /* Note that the first item in this list is the default sort,
98 * and that the items show up in the menu in the order they
99 * appear in this list.
100 */
101 static const SortCriterion sort_criteria[] =
102 {
103 {
104 NAUTILUS_FILE_SORT_BY_DISPLAY_NAME,
105 "name",
106 "name",
107 FALSE
108 },
109 {
110 NAUTILUS_FILE_SORT_BY_DISPLAY_NAME,
111 "name",
112 "name-desc",
113 TRUE
114 },
115 {
116 NAUTILUS_FILE_SORT_BY_SIZE,
117 "size",
118 "size",
119 TRUE
120 },
121 {
122 NAUTILUS_FILE_SORT_BY_TYPE,
123 "type",
124 "type",
125 FALSE
126 },
127 {
128 NAUTILUS_FILE_SORT_BY_MTIME,
129 "modification date",
130 "modification-date",
131 FALSE
132 },
133 {
134 NAUTILUS_FILE_SORT_BY_MTIME,
135 "modification date",
136 "modification-date-desc",
137 TRUE
138 },
139 {
140 NAUTILUS_FILE_SORT_BY_ATIME,
141 "access date",
142 "access-date",
143 FALSE
144 },
145 {
146 NAUTILUS_FILE_SORT_BY_ATIME,
147 "access date",
148 "access-date-desc",
149 TRUE
150 },
151 {
152 NAUTILUS_FILE_SORT_BY_BTIME,
153 "creation date",
154 "creation-date",
155 FALSE
156 },
157 {
158 NAUTILUS_FILE_SORT_BY_BTIME,
159 "creation date",
160 "creation-date-desc",
161 TRUE
162 },
163 {
164 NAUTILUS_FILE_SORT_BY_TRASHED_TIME,
165 "trashed",
166 "trash-time",
167 TRUE,
168 nautilus_file_is_in_trash
169 },
170 {
171 NAUTILUS_FILE_SORT_BY_SEARCH_RELEVANCE,
172 NULL,
173 "search-relevance",
174 TRUE,
175 nautilus_file_is_in_search
176 },
177 {
178 NAUTILUS_FILE_SORT_BY_RECENCY,
179 NULL,
180 "recency",
181 TRUE,
182 nautilus_file_is_in_recent
183 }
184 };
185
186 G_DEFINE_TYPE (NautilusCanvasView, nautilus_canvas_view, NAUTILUS_TYPE_FILES_VIEW);
187
188 static void nautilus_canvas_view_set_directory_sort_by (NautilusCanvasView *canvas_view,
189 NautilusFile *file,
190 const SortCriterion *sort);
191 static void nautilus_canvas_view_update_click_mode (NautilusCanvasView *canvas_view);
192 static void nautilus_canvas_view_reveal_selection (NautilusFilesView *view);
193 static const SortCriterion *get_sort_criterion_by_metadata_text (const char *metadata_text,
194 gboolean reversed);
195 static const SortCriterion *get_sort_criterion_by_sort_type (NautilusFileSortType sort_type,
196 gboolean reversed);
197 static const SortCriterion *get_default_sort_order (NautilusFile *file);
198 static void nautilus_canvas_view_clear (NautilusFilesView *view);
199 static void on_clipboard_owner_changed (GtkClipboard *clipboard,
200 GdkEvent *event,
201 gpointer user_data);
202
203 static void
nautilus_canvas_view_destroy(GtkWidget * object)204 nautilus_canvas_view_destroy (GtkWidget *object)
205 {
206 NautilusCanvasView *canvas_view;
207 GtkClipboard *clipboard;
208
209 canvas_view = NAUTILUS_CANVAS_VIEW (object);
210
211 nautilus_canvas_view_clear (NAUTILUS_FILES_VIEW (object));
212
213 if (canvas_view->react_to_canvas_change_idle_id != 0)
214 {
215 g_source_remove (canvas_view->react_to_canvas_change_idle_id);
216 canvas_view->react_to_canvas_change_idle_id = 0;
217 }
218
219 clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
220 g_signal_handlers_disconnect_by_func (clipboard,
221 on_clipboard_owner_changed,
222 canvas_view);
223
224 if (canvas_view->icons_not_positioned)
225 {
226 nautilus_file_list_free (canvas_view->icons_not_positioned);
227 canvas_view->icons_not_positioned = NULL;
228 }
229
230 GTK_WIDGET_CLASS (nautilus_canvas_view_parent_class)->destroy (object);
231 }
232
233 static NautilusCanvasContainer *
get_canvas_container(NautilusCanvasView * canvas_view)234 get_canvas_container (NautilusCanvasView *canvas_view)
235 {
236 return NAUTILUS_CANVAS_CONTAINER (canvas_view->canvas_container);
237 }
238
239 NautilusCanvasContainer *
nautilus_canvas_view_get_canvas_container(NautilusCanvasView * canvas_view)240 nautilus_canvas_view_get_canvas_container (NautilusCanvasView *canvas_view)
241 {
242 return get_canvas_container (canvas_view);
243 }
244
245 static void
update_sort_criterion(NautilusCanvasView * canvas_view,const SortCriterion * sort,gboolean set_metadata)246 update_sort_criterion (NautilusCanvasView *canvas_view,
247 const SortCriterion *sort,
248 gboolean set_metadata)
249 {
250 NautilusFile *file;
251 const SortCriterion *overrided_sort_criterion;
252
253 file = nautilus_files_view_get_directory_as_file (NAUTILUS_FILES_VIEW (canvas_view));
254
255 /* Make sure we use the default one and not one that the user used previously
256 * of the change to not allow sorting on search and recent, or the
257 * case that the user or some app modified directly the metadata */
258 if (nautilus_file_is_in_search (file) || nautilus_file_is_in_recent (file))
259 {
260 overrided_sort_criterion = get_default_sort_order (file);
261 }
262 else if (sort != NULL && canvas_view->sort != sort)
263 {
264 overrided_sort_criterion = sort;
265 if (set_metadata)
266 {
267 /* Store the new sort setting. */
268 nautilus_canvas_view_set_directory_sort_by (canvas_view,
269 file,
270 sort);
271 }
272 }
273 else
274 {
275 return;
276 }
277
278 canvas_view->sort = overrided_sort_criterion;
279 }
280
281 static void
list_covers(NautilusCanvasIconData * data,gpointer callback_data)282 list_covers (NautilusCanvasIconData *data,
283 gpointer callback_data)
284 {
285 GSList **file_list;
286
287 file_list = callback_data;
288
289 *file_list = g_slist_prepend (*file_list, data);
290 }
291
292 static void
unref_cover(NautilusCanvasIconData * data,gpointer callback_data)293 unref_cover (NautilusCanvasIconData *data,
294 gpointer callback_data)
295 {
296 nautilus_file_unref (NAUTILUS_FILE (data));
297 }
298
299 static void
nautilus_canvas_view_clear(NautilusFilesView * view)300 nautilus_canvas_view_clear (NautilusFilesView *view)
301 {
302 NautilusCanvasContainer *canvas_container;
303 GSList *file_list;
304
305 g_return_if_fail (NAUTILUS_IS_CANVAS_VIEW (view));
306
307 canvas_container = get_canvas_container (NAUTILUS_CANVAS_VIEW (view));
308 if (!canvas_container)
309 {
310 return;
311 }
312
313 /* Clear away the existing icons. */
314 file_list = NULL;
315 nautilus_canvas_container_for_each (canvas_container, list_covers, &file_list);
316 nautilus_canvas_container_clear (canvas_container);
317 g_slist_foreach (file_list, (GFunc) unref_cover, NULL);
318 g_slist_free (file_list);
319 }
320
321 static void
nautilus_canvas_view_remove_file(NautilusFilesView * view,NautilusFile * file,NautilusDirectory * directory)322 nautilus_canvas_view_remove_file (NautilusFilesView *view,
323 NautilusFile *file,
324 NautilusDirectory *directory)
325 {
326 NautilusCanvasView *canvas_view;
327
328 /* This used to assert that 'directory == nautilus_files_view_get_model (view)', but that
329 * resulted in a lot of crash reports (bug #352592). I don't see how that trace happens.
330 * It seems that somehow we get a files_changed event sent to the view from a directory
331 * that isn't the model, but the code disables the monitor and signal callback handlers when
332 * changing directories. Maybe we can get some more information when this happens.
333 * Further discussion in bug #368178.
334 */
335 if (directory != nautilus_files_view_get_model (view))
336 {
337 char *file_uri, *dir_uri, *model_uri;
338 file_uri = nautilus_file_get_uri (file);
339 dir_uri = nautilus_directory_get_uri (directory);
340 model_uri = nautilus_directory_get_uri (nautilus_files_view_get_model (view));
341 g_warning ("nautilus_canvas_view_remove_file() - directory not canvas view model, shouldn't happen.\n"
342 "file: %p:%s, dir: %p:%s, model: %p:%s, view loading: %d\n"
343 "If you see this, please add this info to http://bugzilla.gnome.org/show_bug.cgi?id=368178",
344 file, file_uri, directory, dir_uri, nautilus_files_view_get_model (view), model_uri, nautilus_files_view_get_loading (view));
345 g_free (file_uri);
346 g_free (dir_uri);
347 g_free (model_uri);
348 }
349
350 canvas_view = NAUTILUS_CANVAS_VIEW (view);
351
352 if (nautilus_canvas_container_remove (get_canvas_container (canvas_view),
353 NAUTILUS_CANVAS_ICON_DATA (file)))
354 {
355 nautilus_file_unref (file);
356 }
357 }
358
359 static void
nautilus_canvas_view_add_files(NautilusFilesView * view,GList * files)360 nautilus_canvas_view_add_files (NautilusFilesView *view,
361 GList *files)
362 {
363 NautilusCanvasView *canvas_view;
364 NautilusCanvasContainer *canvas_container;
365 GList *l;
366
367 canvas_view = NAUTILUS_CANVAS_VIEW (view);
368 canvas_container = get_canvas_container (canvas_view);
369
370 for (l = files; l != NULL; l = l->next)
371 {
372 if (nautilus_canvas_container_add (canvas_container,
373 NAUTILUS_CANVAS_ICON_DATA (l->data)))
374 {
375 nautilus_file_ref (NAUTILUS_FILE (l->data));
376 }
377 }
378 }
379
380 static void
nautilus_canvas_view_file_changed(NautilusFilesView * view,NautilusFile * file,NautilusDirectory * directory)381 nautilus_canvas_view_file_changed (NautilusFilesView *view,
382 NautilusFile *file,
383 NautilusDirectory *directory)
384 {
385 NautilusCanvasView *canvas_view;
386
387 g_assert (directory == nautilus_files_view_get_model (view));
388
389 g_return_if_fail (view != NULL);
390 canvas_view = NAUTILUS_CANVAS_VIEW (view);
391
392 nautilus_canvas_container_request_update
393 (get_canvas_container (canvas_view),
394 NAUTILUS_CANVAS_ICON_DATA (file));
395 }
396
397 static const SortCriterion *
nautilus_canvas_view_get_directory_sort_by(NautilusCanvasView * canvas_view,NautilusFile * file)398 nautilus_canvas_view_get_directory_sort_by (NautilusCanvasView *canvas_view,
399 NautilusFile *file)
400 {
401 const SortCriterion *default_sort;
402 g_autofree char *sort_by = NULL;
403 gboolean reversed;
404
405 default_sort = get_default_sort_order (file);
406 g_return_val_if_fail (default_sort != NULL, NULL);
407
408 sort_by = nautilus_file_get_metadata (file,
409 NAUTILUS_METADATA_KEY_ICON_VIEW_SORT_BY,
410 default_sort->metadata_text);
411
412 reversed = nautilus_file_get_boolean_metadata (file,
413 NAUTILUS_METADATA_KEY_ICON_VIEW_SORT_REVERSED,
414 default_sort->reverse_order);
415
416 return get_sort_criterion_by_metadata_text (sort_by, reversed);
417 }
418
419 static const SortCriterion *
get_default_sort_order(NautilusFile * file)420 get_default_sort_order (NautilusFile *file)
421 {
422 NautilusFileSortType sort_type;
423 gboolean reversed;
424
425 sort_type = nautilus_file_get_default_sort_type (file, &reversed);
426
427 return get_sort_criterion_by_sort_type (sort_type, reversed);
428 }
429
430 static void
nautilus_canvas_view_set_directory_sort_by(NautilusCanvasView * canvas_view,NautilusFile * file,const SortCriterion * sort)431 nautilus_canvas_view_set_directory_sort_by (NautilusCanvasView *canvas_view,
432 NautilusFile *file,
433 const SortCriterion *sort)
434 {
435 const SortCriterion *default_sort_criterion;
436
437 default_sort_criterion = get_default_sort_order (file);
438 g_return_if_fail (default_sort_criterion != NULL);
439
440 nautilus_file_set_metadata
441 (file, NAUTILUS_METADATA_KEY_ICON_VIEW_SORT_BY,
442 default_sort_criterion->metadata_text,
443 sort->metadata_text);
444 nautilus_file_set_boolean_metadata (file,
445 NAUTILUS_METADATA_KEY_ICON_VIEW_SORT_REVERSED,
446 default_sort_criterion->reverse_order,
447 sort->reverse_order);
448 }
449
450 static const SortCriterion *
get_sort_criterion_by_metadata_text(const char * metadata_text,gboolean reversed)451 get_sort_criterion_by_metadata_text (const char *metadata_text,
452 gboolean reversed)
453 {
454 guint i;
455
456 /* Figure out what the new sort setting should be. */
457 for (i = 0; i < G_N_ELEMENTS (sort_criteria); i++)
458 {
459 if (g_strcmp0 (sort_criteria[i].metadata_text, metadata_text) == 0
460 && reversed == sort_criteria[i].reverse_order)
461 {
462 return &sort_criteria[i];
463 }
464 }
465 return &sort_criteria[0];
466 }
467
468 static const SortCriterion *
get_sort_criterion_by_action_target_name(const char * action_target_name)469 get_sort_criterion_by_action_target_name (const char *action_target_name)
470 {
471 guint i;
472 /* Figure out what the new sort setting should be. */
473 for (i = 0; i < G_N_ELEMENTS (sort_criteria); i++)
474 {
475 if (g_strcmp0 (sort_criteria[i].action_target_name, action_target_name) == 0)
476 {
477 return &sort_criteria[i];
478 }
479 }
480 return NULL;
481 }
482
483 static const SortCriterion *
get_sort_criterion_by_sort_type(NautilusFileSortType sort_type,gboolean reversed)484 get_sort_criterion_by_sort_type (NautilusFileSortType sort_type,
485 gboolean reversed)
486 {
487 guint i;
488
489 /* Figure out what the new sort setting should be. */
490 for (i = 0; i < G_N_ELEMENTS (sort_criteria); i++)
491 {
492 if (sort_type == sort_criteria[i].sort_type
493 && reversed == sort_criteria[i].reverse_order)
494 {
495 return &sort_criteria[i];
496 }
497 }
498
499 return &sort_criteria[0];
500 }
501
502 static NautilusCanvasZoomLevel
get_default_zoom_level(NautilusCanvasView * canvas_view)503 get_default_zoom_level (NautilusCanvasView *canvas_view)
504 {
505 NautilusCanvasZoomLevel default_zoom_level;
506
507 default_zoom_level = g_settings_get_enum (nautilus_icon_view_preferences,
508 NAUTILUS_PREFERENCES_ICON_VIEW_DEFAULT_ZOOM_LEVEL);
509
510 return CLAMP (default_zoom_level, NAUTILUS_CANVAS_ZOOM_LEVEL_SMALL, NAUTILUS_CANVAS_ZOOM_LEVEL_LARGER);
511 }
512
513 static void
nautilus_canvas_view_begin_loading(NautilusFilesView * view)514 nautilus_canvas_view_begin_loading (NautilusFilesView *view)
515 {
516 NautilusCanvasView *canvas_view;
517 NautilusFile *file;
518 char *uri;
519 const SortCriterion *sort;
520
521 g_return_if_fail (NAUTILUS_IS_CANVAS_VIEW (view));
522
523 canvas_view = NAUTILUS_CANVAS_VIEW (view);
524 file = nautilus_files_view_get_directory_as_file (view);
525 uri = nautilus_file_get_uri (file);
526
527 g_free (uri);
528
529 /* Set the sort mode.
530 * It's OK not to resort the icons because the
531 * container doesn't have any icons at this point.
532 */
533 sort = nautilus_canvas_view_get_directory_sort_by (canvas_view, file);
534 update_sort_criterion (canvas_view, sort, FALSE);
535
536 /* We could have changed to the trash directory or to searching, and then
537 * we need to update the menus */
538 nautilus_files_view_update_context_menus (view);
539 nautilus_files_view_update_toolbar_menus (view);
540 }
541
542 static void
on_clipboard_contents_received(GtkClipboard * clipboard,GtkSelectionData * selection_data,gpointer user_data)543 on_clipboard_contents_received (GtkClipboard *clipboard,
544 GtkSelectionData *selection_data,
545 gpointer user_data)
546 {
547 NautilusCanvasView *canvas_view;
548
549 canvas_view = NAUTILUS_CANVAS_VIEW (user_data);
550
551 if (canvas_view->destroyed)
552 {
553 /* We've been destroyed since call */
554 g_object_unref (canvas_view);
555 return;
556 }
557
558 if (nautilus_clipboard_is_cut_from_selection_data (selection_data))
559 {
560 GList *uris;
561 GList *files;
562
563 uris = nautilus_clipboard_get_uri_list_from_selection_data (selection_data);
564 files = nautilus_file_list_from_uri_list (uris);
565 nautilus_canvas_container_set_highlighted_for_clipboard (get_canvas_container (canvas_view),
566 files);
567
568 nautilus_file_list_free (files);
569 g_list_free_full (uris, g_free);
570 }
571 else
572 {
573 nautilus_canvas_container_set_highlighted_for_clipboard (get_canvas_container (canvas_view),
574 NULL);
575 }
576
577 g_object_unref (canvas_view);
578 }
579
580 static void
update_clipboard_status(NautilusCanvasView * view)581 update_clipboard_status (NautilusCanvasView *view)
582 {
583 g_object_ref (view); /* Need to keep the object alive until we get the reply */
584 gtk_clipboard_request_contents (nautilus_clipboard_get (GTK_WIDGET (view)),
585 nautilus_clipboard_get_atom (),
586 on_clipboard_contents_received,
587 view);
588 }
589
590 static void
on_clipboard_owner_changed(GtkClipboard * clipboard,GdkEvent * event,gpointer user_data)591 on_clipboard_owner_changed (GtkClipboard *clipboard,
592 GdkEvent *event,
593 gpointer user_data)
594 {
595 update_clipboard_status (NAUTILUS_CANVAS_VIEW (user_data));
596 }
597
598 static void
nautilus_canvas_view_end_loading(NautilusFilesView * view,gboolean all_files_seen)599 nautilus_canvas_view_end_loading (NautilusFilesView *view,
600 gboolean all_files_seen)
601 {
602 NautilusCanvasView *canvas_view;
603
604 canvas_view = NAUTILUS_CANVAS_VIEW (view);
605 update_clipboard_status (canvas_view);
606 }
607
608 static NautilusCanvasZoomLevel
nautilus_canvas_view_get_zoom_level(NautilusFilesView * view)609 nautilus_canvas_view_get_zoom_level (NautilusFilesView *view)
610 {
611 g_return_val_if_fail (NAUTILUS_IS_CANVAS_VIEW (view), NAUTILUS_CANVAS_ZOOM_LEVEL_LARGE);
612
613 return nautilus_canvas_container_get_zoom_level (get_canvas_container (NAUTILUS_CANVAS_VIEW (view)));
614 }
615
616 static void
nautilus_canvas_view_zoom_to_level(NautilusFilesView * view,gint new_level)617 nautilus_canvas_view_zoom_to_level (NautilusFilesView *view,
618 gint new_level)
619 {
620 NautilusCanvasView *canvas_view;
621 NautilusCanvasContainer *canvas_container;
622
623 g_return_if_fail (NAUTILUS_IS_CANVAS_VIEW (view));
624 g_return_if_fail (new_level >= NAUTILUS_CANVAS_ZOOM_LEVEL_SMALL &&
625 new_level <= NAUTILUS_CANVAS_ZOOM_LEVEL_LARGER);
626
627 canvas_view = NAUTILUS_CANVAS_VIEW (view);
628 canvas_container = get_canvas_container (canvas_view);
629 if (nautilus_canvas_container_get_zoom_level (canvas_container) == new_level)
630 {
631 return;
632 }
633
634 nautilus_canvas_container_set_zoom_level (canvas_container, new_level);
635 g_action_group_change_action_state (nautilus_files_view_get_action_group (view),
636 "zoom-to-level", g_variant_new_int32 (new_level));
637
638 nautilus_files_view_update_toolbar_menus (view);
639 }
640
641 static void
nautilus_canvas_view_bump_zoom_level(NautilusFilesView * view,int zoom_increment)642 nautilus_canvas_view_bump_zoom_level (NautilusFilesView *view,
643 int zoom_increment)
644 {
645 NautilusCanvasZoomLevel new_level;
646
647 g_return_if_fail (NAUTILUS_IS_CANVAS_VIEW (view));
648 if (!nautilus_files_view_supports_zooming (view))
649 {
650 return;
651 }
652
653 new_level = nautilus_canvas_view_get_zoom_level (view) + zoom_increment;
654
655 if (new_level >= NAUTILUS_CANVAS_ZOOM_LEVEL_SMALL &&
656 new_level <= NAUTILUS_CANVAS_ZOOM_LEVEL_LARGER)
657 {
658 nautilus_canvas_view_zoom_to_level (view, new_level);
659 }
660 }
661
662 static void
nautilus_canvas_view_restore_standard_zoom_level(NautilusFilesView * view)663 nautilus_canvas_view_restore_standard_zoom_level (NautilusFilesView *view)
664 {
665 nautilus_canvas_view_zoom_to_level (view, NAUTILUS_CANVAS_ZOOM_LEVEL_LARGE);
666 }
667
668 static gboolean
nautilus_canvas_view_can_zoom_in(NautilusFilesView * view)669 nautilus_canvas_view_can_zoom_in (NautilusFilesView *view)
670 {
671 g_return_val_if_fail (NAUTILUS_IS_CANVAS_VIEW (view), FALSE);
672
673 return nautilus_canvas_view_get_zoom_level (view)
674 < NAUTILUS_CANVAS_ZOOM_LEVEL_LARGER;
675 }
676
677 static gboolean
nautilus_canvas_view_can_zoom_out(NautilusFilesView * view)678 nautilus_canvas_view_can_zoom_out (NautilusFilesView *view)
679 {
680 g_return_val_if_fail (NAUTILUS_IS_CANVAS_VIEW (view), FALSE);
681
682 return nautilus_canvas_view_get_zoom_level (view)
683 > NAUTILUS_CANVAS_ZOOM_LEVEL_SMALL;
684 }
685
686 static gfloat
nautilus_canvas_view_get_zoom_level_percentage(NautilusFilesView * view)687 nautilus_canvas_view_get_zoom_level_percentage (NautilusFilesView *view)
688 {
689 guint icon_size;
690 NautilusCanvasZoomLevel zoom_level;
691
692 zoom_level = nautilus_canvas_view_get_zoom_level (view);
693 icon_size = nautilus_canvas_container_get_icon_size_for_zoom_level (zoom_level);
694
695 return (gfloat) icon_size / NAUTILUS_CANVAS_ICON_SIZE_LARGE;
696 }
697
698 static gboolean
nautilus_canvas_view_is_zoom_level_default(NautilusFilesView * view)699 nautilus_canvas_view_is_zoom_level_default (NautilusFilesView *view)
700 {
701 guint icon_size;
702 NautilusCanvasZoomLevel zoom_level;
703
704 zoom_level = nautilus_canvas_view_get_zoom_level (view);
705 icon_size = nautilus_canvas_container_get_icon_size_for_zoom_level (zoom_level);
706
707 return icon_size == NAUTILUS_CANVAS_ICON_SIZE_LARGE;
708 }
709
710 static gboolean
nautilus_canvas_view_is_empty(NautilusFilesView * view)711 nautilus_canvas_view_is_empty (NautilusFilesView *view)
712 {
713 g_assert (NAUTILUS_IS_CANVAS_VIEW (view));
714
715 return nautilus_canvas_container_is_empty
716 (get_canvas_container (NAUTILUS_CANVAS_VIEW (view)));
717 }
718
719 static GList *
nautilus_canvas_view_get_selection(NautilusFilesView * view)720 nautilus_canvas_view_get_selection (NautilusFilesView *view)
721 {
722 GList *list;
723
724 g_return_val_if_fail (NAUTILUS_IS_CANVAS_VIEW (view), NULL);
725
726 list = nautilus_canvas_container_get_selection
727 (get_canvas_container (NAUTILUS_CANVAS_VIEW (view)));
728 nautilus_file_list_ref (list);
729 return list;
730 }
731
732 static void
action_sort_order_changed(GSimpleAction * action,GVariant * value,gpointer user_data)733 action_sort_order_changed (GSimpleAction *action,
734 GVariant *value,
735 gpointer user_data)
736 {
737 const gchar *target_name;
738 const SortCriterion *sort_criterion;
739
740 g_assert (NAUTILUS_IS_CANVAS_VIEW (user_data));
741
742 target_name = g_variant_get_string (value, NULL);
743 sort_criterion = get_sort_criterion_by_action_target_name (target_name);
744
745 g_assert (sort_criterion != NULL);
746
747 update_sort_criterion (user_data, sort_criterion, TRUE);
748
749 nautilus_canvas_container_sort (get_canvas_container (user_data));
750 nautilus_canvas_view_reveal_selection (NAUTILUS_FILES_VIEW (user_data));
751
752 g_simple_action_set_state (action, value);
753 }
754
755 static void
action_zoom_to_level(GSimpleAction * action,GVariant * state,gpointer user_data)756 action_zoom_to_level (GSimpleAction *action,
757 GVariant *state,
758 gpointer user_data)
759 {
760 NautilusFilesView *view;
761 NautilusCanvasZoomLevel zoom_level;
762
763 g_assert (NAUTILUS_IS_FILES_VIEW (user_data));
764
765 view = NAUTILUS_FILES_VIEW (user_data);
766 zoom_level = g_variant_get_int32 (state);
767 nautilus_canvas_view_zoom_to_level (view, zoom_level);
768
769 g_simple_action_set_state (G_SIMPLE_ACTION (action), state);
770 if (g_settings_get_enum (nautilus_icon_view_preferences,
771 NAUTILUS_PREFERENCES_ICON_VIEW_DEFAULT_ZOOM_LEVEL) != zoom_level)
772 {
773 g_settings_set_enum (nautilus_icon_view_preferences,
774 NAUTILUS_PREFERENCES_ICON_VIEW_DEFAULT_ZOOM_LEVEL,
775 zoom_level);
776 }
777 }
778
779 const GActionEntry canvas_view_entries[] =
780 {
781 { "sort", NULL, "s", "'name'", action_sort_order_changed },
782 { "zoom-to-level", NULL, NULL, "1", action_zoom_to_level }
783 };
784
785 static void
update_sort_action_state_hint(NautilusCanvasView * canvas_view)786 update_sort_action_state_hint (NautilusCanvasView *canvas_view)
787 {
788 NautilusFile *file;
789 GVariantBuilder builder;
790 GActionGroup *action_group;
791 GAction *action;
792 GVariant *state_hint;
793 gint idx;
794
795 file = nautilus_files_view_get_directory_as_file (NAUTILUS_FILES_VIEW (canvas_view));
796 g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
797
798 for (idx = 0; idx < G_N_ELEMENTS (sort_criteria); idx++)
799 {
800 if (sort_criteria[idx].match_func == NULL ||
801 (file != NULL && sort_criteria[idx].match_func (file)))
802 {
803 g_variant_builder_add (&builder, "s", sort_criteria[idx].action_target_name);
804 }
805 }
806
807 state_hint = g_variant_builder_end (&builder);
808
809 action_group = nautilus_files_view_get_action_group (NAUTILUS_FILES_VIEW (canvas_view));
810 action = g_action_map_lookup_action (G_ACTION_MAP (action_group), "sort");
811 g_simple_action_set_state_hint (G_SIMPLE_ACTION (action), state_hint);
812
813 g_variant_unref (state_hint);
814 }
815
816 static gboolean
showing_recent_directory(NautilusFilesView * view)817 showing_recent_directory (NautilusFilesView *view)
818 {
819 NautilusFile *file;
820
821 file = nautilus_files_view_get_directory_as_file (view);
822 if (file != NULL)
823 {
824 return nautilus_file_is_in_recent (file);
825 }
826 return FALSE;
827 }
828
829 static gboolean
showing_search_directory(NautilusFilesView * view)830 showing_search_directory (NautilusFilesView *view)
831 {
832 NautilusFile *file;
833
834 file = nautilus_files_view_get_directory_as_file (view);
835 if (file != NULL)
836 {
837 return nautilus_file_is_in_search (file);
838 }
839 return FALSE;
840 }
841
842 static void
nautilus_canvas_view_update_actions_state(NautilusFilesView * view)843 nautilus_canvas_view_update_actions_state (NautilusFilesView *view)
844 {
845 GActionGroup *view_action_group;
846 GVariant *sort_state;
847 GAction *action;
848 NautilusCanvasView *canvas_view;
849
850 canvas_view = NAUTILUS_CANVAS_VIEW (view);
851
852 NAUTILUS_FILES_VIEW_CLASS (nautilus_canvas_view_parent_class)->update_actions_state (view);
853
854 view_action_group = nautilus_files_view_get_action_group (view);
855
856 /* When we change the sort action state, even using the same value, it triggers
857 * the sort action changed handler, which reveals the selection, since we expect
858 * the selection to be visible when the user changes the sort order. But we may
859 * need to update the actions state for others reason than an actual sort change,
860 * so we need to prevent to trigger the sort action changed handler for those cases.
861 * To achieve this, check if the action state value actually changed before setting
862 * it
863 */
864 sort_state = g_action_group_get_action_state (view_action_group, "sort");
865
866 if (g_strcmp0 (g_variant_get_string (sort_state, NULL),
867 canvas_view->sort->action_target_name) != 0)
868 {
869 g_action_group_change_action_state (view_action_group,
870 "sort",
871 g_variant_new_string (canvas_view->sort->action_target_name));
872 }
873
874 action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group), "sort");
875 g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
876 !showing_recent_directory (view) &&
877 !showing_search_directory (view));
878
879 update_sort_action_state_hint (canvas_view);
880
881 g_variant_unref (sort_state);
882 }
883
884 static void
nautilus_canvas_view_select_all(NautilusFilesView * view)885 nautilus_canvas_view_select_all (NautilusFilesView *view)
886 {
887 NautilusCanvasContainer *canvas_container;
888
889 g_return_if_fail (NAUTILUS_IS_CANVAS_VIEW (view));
890
891 canvas_container = get_canvas_container (NAUTILUS_CANVAS_VIEW (view));
892 nautilus_canvas_container_select_all (canvas_container);
893 }
894
895 static void
nautilus_canvas_view_select_first(NautilusFilesView * view)896 nautilus_canvas_view_select_first (NautilusFilesView *view)
897 {
898 NautilusCanvasContainer *canvas_container;
899
900 g_return_if_fail (NAUTILUS_IS_CANVAS_VIEW (view));
901
902 canvas_container = get_canvas_container (NAUTILUS_CANVAS_VIEW (view));
903 nautilus_canvas_container_select_first (canvas_container);
904 }
905
906 static void
nautilus_canvas_view_reveal_selection(NautilusFilesView * view)907 nautilus_canvas_view_reveal_selection (NautilusFilesView *view)
908 {
909 g_autolist (NautilusFile) selection = NULL;
910
911 g_return_if_fail (NAUTILUS_IS_CANVAS_VIEW (view));
912
913 selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
914
915 /* Make sure at least one of the selected items is scrolled into view */
916 if (selection != NULL)
917 {
918 /* Update the icon ordering to reveal the rigth selection */
919 nautilus_canvas_container_layout_now (get_canvas_container (NAUTILUS_CANVAS_VIEW (view)));
920 nautilus_canvas_container_reveal
921 (get_canvas_container (NAUTILUS_CANVAS_VIEW (view)),
922 selection->data);
923 }
924 }
925
926 static GdkRectangle *
get_rectangle_for_data(NautilusFilesView * view,NautilusCanvasIconData * data)927 get_rectangle_for_data (NautilusFilesView *view,
928 NautilusCanvasIconData *data)
929 {
930 NautilusCanvasContainer *container;
931 GdkRectangle *rectangle;
932
933 container = get_canvas_container (NAUTILUS_CANVAS_VIEW (view));
934 rectangle = nautilus_canvas_container_get_icon_bounding_box (container, data);
935 if (rectangle != NULL)
936 {
937 GtkWidget *context_widget;
938 GtkAdjustment *vadjustment;
939 GtkAdjustment *hadjustment;
940
941 context_widget = nautilus_files_view_get_content_widget (view);
942 vadjustment = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (context_widget));
943 hadjustment = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (context_widget));
944
945 rectangle->x -= gtk_adjustment_get_value (hadjustment);
946 rectangle->y -= gtk_adjustment_get_value (vadjustment);
947 }
948 return rectangle;
949 }
950
951 static GdkRectangle *
nautilus_canvas_view_compute_rename_popover_pointing_to(NautilusFilesView * view)952 nautilus_canvas_view_compute_rename_popover_pointing_to (NautilusFilesView *view)
953 {
954 g_autolist (NautilusFile) selection = NULL;
955 NautilusCanvasIconData *data;
956
957 g_return_val_if_fail (NAUTILUS_IS_CANVAS_VIEW (view), NULL);
958
959 selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
960 g_return_val_if_fail (selection != NULL, NULL);
961
962 /* We only allow renaming one item at once */
963 data = NAUTILUS_CANVAS_ICON_DATA (selection->data);
964
965 return get_rectangle_for_data (view, data);
966 }
967
968 static GdkRectangle *
nautilus_canvas_view_reveal_for_selection_context_menu(NautilusFilesView * view)969 nautilus_canvas_view_reveal_for_selection_context_menu (NautilusFilesView *view)
970 {
971 g_autolist (NautilusFile) selection = NULL;
972 NautilusCanvasContainer *container;
973 NautilusCanvasIconData *data;
974
975 g_return_val_if_fail (NAUTILUS_IS_CANVAS_VIEW (view), NULL);
976
977 selection = nautilus_view_get_selection (NAUTILUS_VIEW (view));
978 g_return_val_if_fail (selection != NULL, NULL);
979
980 container = get_canvas_container (NAUTILUS_CANVAS_VIEW (view));
981
982 /* Update the icon ordering to reveal the rigth selection */
983 nautilus_canvas_container_layout_now (container);
984
985 /* Get the data of the focused item, if selected. Otherwise, get the
986 * data of the last selected item.*/
987 data = nautilus_canvas_container_get_focused_icon (container);
988 if (data == NULL || g_list_find (selection, NAUTILUS_FILE (data)) == NULL)
989 {
990 selection = g_list_last (selection);
991 data = NAUTILUS_CANVAS_ICON_DATA (selection->data);
992 }
993
994 nautilus_canvas_container_reveal (container, data);
995
996 return get_rectangle_for_data (view, data);
997 }
998
999 static void
nautilus_canvas_view_set_selection(NautilusFilesView * view,GList * selection)1000 nautilus_canvas_view_set_selection (NautilusFilesView *view,
1001 GList *selection)
1002 {
1003 g_return_if_fail (NAUTILUS_IS_CANVAS_VIEW (view));
1004
1005 nautilus_canvas_container_set_selection
1006 (get_canvas_container (NAUTILUS_CANVAS_VIEW (view)), selection);
1007 }
1008
1009 static void
nautilus_canvas_view_invert_selection(NautilusFilesView * view)1010 nautilus_canvas_view_invert_selection (NautilusFilesView *view)
1011 {
1012 g_return_if_fail (NAUTILUS_IS_CANVAS_VIEW (view));
1013
1014 nautilus_canvas_container_invert_selection
1015 (get_canvas_container (NAUTILUS_CANVAS_VIEW (view)));
1016 }
1017
1018 static void
nautilus_canvas_view_widget_to_file_operation_position(NautilusFilesView * view,GdkPoint * position)1019 nautilus_canvas_view_widget_to_file_operation_position (NautilusFilesView *view,
1020 GdkPoint *position)
1021 {
1022 g_assert (NAUTILUS_IS_CANVAS_VIEW (view));
1023
1024 nautilus_canvas_container_widget_to_file_operation_position
1025 (get_canvas_container (NAUTILUS_CANVAS_VIEW (view)), position);
1026 }
1027
1028 static void
canvas_container_activate_callback(NautilusCanvasContainer * container,GList * file_list,NautilusCanvasView * canvas_view)1029 canvas_container_activate_callback (NautilusCanvasContainer *container,
1030 GList *file_list,
1031 NautilusCanvasView *canvas_view)
1032 {
1033 g_assert (NAUTILUS_IS_CANVAS_VIEW (canvas_view));
1034 g_assert (container == get_canvas_container (canvas_view));
1035
1036 nautilus_files_view_activate_files (NAUTILUS_FILES_VIEW (canvas_view),
1037 file_list,
1038 0, TRUE);
1039 }
1040
1041 static void
canvas_container_activate_previewer_callback(NautilusCanvasContainer * container,GList * file_list,GArray * locations,NautilusCanvasView * canvas_view)1042 canvas_container_activate_previewer_callback (NautilusCanvasContainer *container,
1043 GList *file_list,
1044 GArray *locations,
1045 NautilusCanvasView *canvas_view)
1046 {
1047 g_assert (NAUTILUS_IS_CANVAS_VIEW (canvas_view));
1048 g_assert (container == get_canvas_container (canvas_view));
1049
1050 nautilus_files_view_preview_files (NAUTILUS_FILES_VIEW (canvas_view),
1051 file_list, locations);
1052 }
1053
1054 /* this is called in one of these cases:
1055 * - we activate with enter holding shift
1056 * - we activate with space holding shift
1057 * - we double click an canvas holding shift
1058 * - we middle click an canvas
1059 *
1060 * If we don't open in new windows by default, the behavior should be
1061 * - middle click, shift + activate -> open in new tab
1062 * - shift + double click -> open in new window
1063 *
1064 * If we open in new windows by default, the behaviour should be
1065 * - middle click, or shift + activate, or shift + double-click -> close parent
1066 */
1067 static void
canvas_container_activate_alternate_callback(NautilusCanvasContainer * container,GList * file_list,NautilusCanvasView * canvas_view)1068 canvas_container_activate_alternate_callback (NautilusCanvasContainer *container,
1069 GList *file_list,
1070 NautilusCanvasView *canvas_view)
1071 {
1072 GdkEvent *event;
1073 GdkEventButton *button_event;
1074 GdkEventKey *key_event;
1075 gboolean open_in_tab, open_in_window;
1076 NautilusWindowOpenFlags flags;
1077
1078 g_assert (NAUTILUS_IS_CANVAS_VIEW (canvas_view));
1079 g_assert (container == get_canvas_container (canvas_view));
1080
1081 flags = 0;
1082 event = gtk_get_current_event ();
1083 open_in_tab = FALSE;
1084 open_in_window = FALSE;
1085
1086 if (event->type == GDK_BUTTON_PRESS ||
1087 event->type == GDK_BUTTON_RELEASE ||
1088 event->type == GDK_2BUTTON_PRESS ||
1089 event->type == GDK_3BUTTON_PRESS)
1090 {
1091 button_event = (GdkEventButton *) event;
1092 open_in_window = ((button_event->state & GDK_SHIFT_MASK) != 0);
1093 open_in_tab = !open_in_window;
1094 }
1095 else if (event->type == GDK_KEY_PRESS ||
1096 event->type == GDK_KEY_RELEASE)
1097 {
1098 key_event = (GdkEventKey *) event;
1099 open_in_tab = ((key_event->state & GDK_SHIFT_MASK) != 0);
1100 }
1101
1102 if (open_in_tab)
1103 {
1104 flags |= NAUTILUS_WINDOW_OPEN_FLAG_NEW_TAB;
1105 flags |= NAUTILUS_WINDOW_OPEN_FLAG_DONT_MAKE_ACTIVE;
1106 }
1107
1108 if (open_in_window)
1109 {
1110 flags |= NAUTILUS_WINDOW_OPEN_FLAG_NEW_WINDOW;
1111 }
1112
1113 DEBUG ("Activate alternate, open in tab %d, new window %d\n",
1114 open_in_tab, open_in_window);
1115
1116 nautilus_files_view_activate_files (NAUTILUS_FILES_VIEW (canvas_view),
1117 file_list,
1118 flags,
1119 TRUE);
1120 }
1121
1122 static void
band_select_started_callback(NautilusCanvasContainer * container,NautilusCanvasView * canvas_view)1123 band_select_started_callback (NautilusCanvasContainer *container,
1124 NautilusCanvasView *canvas_view)
1125 {
1126 g_assert (NAUTILUS_IS_CANVAS_VIEW (canvas_view));
1127 g_assert (container == get_canvas_container (canvas_view));
1128
1129 nautilus_files_view_start_batching_selection_changes (NAUTILUS_FILES_VIEW (canvas_view));
1130 }
1131
1132 static void
band_select_ended_callback(NautilusCanvasContainer * container,NautilusCanvasView * canvas_view)1133 band_select_ended_callback (NautilusCanvasContainer *container,
1134 NautilusCanvasView *canvas_view)
1135 {
1136 g_assert (NAUTILUS_IS_CANVAS_VIEW (canvas_view));
1137 g_assert (container == get_canvas_container (canvas_view));
1138
1139 nautilus_files_view_stop_batching_selection_changes (NAUTILUS_FILES_VIEW (canvas_view));
1140 }
1141
1142 int
nautilus_canvas_view_compare_files(NautilusCanvasView * canvas_view,NautilusFile * a,NautilusFile * b)1143 nautilus_canvas_view_compare_files (NautilusCanvasView *canvas_view,
1144 NautilusFile *a,
1145 NautilusFile *b)
1146 {
1147 return nautilus_file_compare_for_sort
1148 (a, b, canvas_view->sort->sort_type,
1149 /* Use type-unsafe cast for performance */
1150 nautilus_files_view_should_sort_directories_first ((NautilusFilesView *) canvas_view),
1151 canvas_view->sort->reverse_order);
1152 }
1153
1154 static int
compare_files(NautilusFilesView * canvas_view,NautilusFile * a,NautilusFile * b)1155 compare_files (NautilusFilesView *canvas_view,
1156 NautilusFile *a,
1157 NautilusFile *b)
1158 {
1159 return nautilus_canvas_view_compare_files ((NautilusCanvasView *) canvas_view, a, b);
1160 }
1161
1162 static void
selection_changed_callback(NautilusCanvasContainer * container,NautilusCanvasView * canvas_view)1163 selection_changed_callback (NautilusCanvasContainer *container,
1164 NautilusCanvasView *canvas_view)
1165 {
1166 g_assert (NAUTILUS_IS_CANVAS_VIEW (canvas_view));
1167 g_assert (container == get_canvas_container (canvas_view));
1168
1169 nautilus_files_view_notify_selection_changed (NAUTILUS_FILES_VIEW (canvas_view));
1170 }
1171
1172 static void
canvas_container_context_click_selection_callback(NautilusCanvasContainer * container,const GdkEvent * event,NautilusCanvasView * canvas_view)1173 canvas_container_context_click_selection_callback (NautilusCanvasContainer *container,
1174 const GdkEvent *event,
1175 NautilusCanvasView *canvas_view)
1176 {
1177 g_assert (NAUTILUS_IS_CANVAS_CONTAINER (container));
1178 g_assert (NAUTILUS_IS_CANVAS_VIEW (canvas_view));
1179
1180 nautilus_files_view_pop_up_selection_context_menu (NAUTILUS_FILES_VIEW (canvas_view),
1181 event);
1182 }
1183
1184 static void
canvas_container_context_click_background_callback(NautilusCanvasContainer * container,const GdkEvent * event,NautilusCanvasView * canvas_view)1185 canvas_container_context_click_background_callback (NautilusCanvasContainer *container,
1186 const GdkEvent *event,
1187 NautilusCanvasView *canvas_view)
1188 {
1189 g_assert (NAUTILUS_IS_CANVAS_CONTAINER (container));
1190 g_assert (NAUTILUS_IS_CANVAS_VIEW (canvas_view));
1191
1192 nautilus_files_view_pop_up_background_context_menu (NAUTILUS_FILES_VIEW (canvas_view),
1193 event);
1194 }
1195
1196 static char *
get_icon_uri_callback(NautilusCanvasContainer * container,NautilusFile * file,NautilusCanvasView * canvas_view)1197 get_icon_uri_callback (NautilusCanvasContainer *container,
1198 NautilusFile *file,
1199 NautilusCanvasView *canvas_view)
1200 {
1201 g_assert (NAUTILUS_IS_CANVAS_CONTAINER (container));
1202 g_assert (NAUTILUS_IS_FILE (file));
1203 g_assert (NAUTILUS_IS_CANVAS_VIEW (canvas_view));
1204
1205 return nautilus_file_get_uri (file);
1206 }
1207
1208 static char *
get_icon_activation_uri_callback(NautilusCanvasContainer * container,NautilusFile * file,NautilusCanvasView * canvas_view)1209 get_icon_activation_uri_callback (NautilusCanvasContainer *container,
1210 NautilusFile *file,
1211 NautilusCanvasView *canvas_view)
1212 {
1213 g_assert (NAUTILUS_IS_CANVAS_CONTAINER (container));
1214 g_assert (NAUTILUS_IS_FILE (file));
1215 g_assert (NAUTILUS_IS_CANVAS_VIEW (canvas_view));
1216
1217 return nautilus_file_get_activation_uri (file);
1218 }
1219
1220 static char *
get_icon_drop_target_uri_callback(NautilusCanvasContainer * container,NautilusFile * file,NautilusCanvasView * canvas_view)1221 get_icon_drop_target_uri_callback (NautilusCanvasContainer *container,
1222 NautilusFile *file,
1223 NautilusCanvasView *canvas_view)
1224 {
1225 g_return_val_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (container), NULL);
1226 g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
1227 g_return_val_if_fail (NAUTILUS_IS_CANVAS_VIEW (canvas_view), NULL);
1228
1229 return nautilus_file_get_uri (file);
1230 }
1231
1232 /* Preferences changed callbacks */
1233 static void
nautilus_canvas_view_click_policy_changed(NautilusFilesView * directory_view)1234 nautilus_canvas_view_click_policy_changed (NautilusFilesView *directory_view)
1235 {
1236 g_assert (NAUTILUS_IS_CANVAS_VIEW (directory_view));
1237
1238 nautilus_canvas_view_update_click_mode (NAUTILUS_CANVAS_VIEW (directory_view));
1239 }
1240
1241 static void
image_display_policy_changed_callback(gpointer callback_data)1242 image_display_policy_changed_callback (gpointer callback_data)
1243 {
1244 NautilusCanvasView *canvas_view;
1245
1246 canvas_view = NAUTILUS_CANVAS_VIEW (callback_data);
1247
1248 nautilus_canvas_container_request_update_all (get_canvas_container (canvas_view));
1249 }
1250
1251 static void
text_attribute_names_changed_callback(gpointer callback_data)1252 text_attribute_names_changed_callback (gpointer callback_data)
1253 {
1254 NautilusCanvasView *canvas_view;
1255
1256 canvas_view = NAUTILUS_CANVAS_VIEW (callback_data);
1257
1258 nautilus_canvas_container_request_update_all (get_canvas_container (canvas_view));
1259 }
1260
1261 static void
default_sort_order_changed_callback(gpointer callback_data)1262 default_sort_order_changed_callback (gpointer callback_data)
1263 {
1264 NautilusCanvasView *canvas_view;
1265 NautilusFile *file;
1266 const SortCriterion *sort;
1267 NautilusCanvasContainer *canvas_container;
1268
1269 g_return_if_fail (NAUTILUS_IS_CANVAS_VIEW (callback_data));
1270
1271 canvas_view = NAUTILUS_CANVAS_VIEW (callback_data);
1272
1273 file = nautilus_files_view_get_directory_as_file (NAUTILUS_FILES_VIEW (canvas_view));
1274 sort = nautilus_canvas_view_get_directory_sort_by (canvas_view, file);
1275 update_sort_criterion (canvas_view, sort, FALSE);
1276
1277 canvas_container = get_canvas_container (canvas_view);
1278 g_return_if_fail (NAUTILUS_IS_CANVAS_CONTAINER (canvas_container));
1279
1280 nautilus_canvas_container_request_update_all (canvas_container);
1281 }
1282
1283 static void
nautilus_canvas_view_sort_directories_first_changed(NautilusFilesView * directory_view)1284 nautilus_canvas_view_sort_directories_first_changed (NautilusFilesView *directory_view)
1285 {
1286 NautilusCanvasView *canvas_view;
1287
1288 canvas_view = NAUTILUS_CANVAS_VIEW (directory_view);
1289
1290 nautilus_canvas_container_sort (get_canvas_container (canvas_view));
1291 }
1292
1293 static void
nautilus_canvas_view_preview_selection_event(NautilusFilesView * directory_view,GtkDirectionType direction)1294 nautilus_canvas_view_preview_selection_event (NautilusFilesView *directory_view,
1295 GtkDirectionType direction)
1296 {
1297 NautilusCanvasView *canvas_view;
1298
1299 canvas_view = NAUTILUS_CANVAS_VIEW (directory_view);
1300
1301 nautilus_canvas_container_preview_selection_event (get_canvas_container (canvas_view),
1302 direction);
1303 }
1304
1305 static char *
canvas_view_get_container_uri(NautilusCanvasContainer * container,NautilusFilesView * view)1306 canvas_view_get_container_uri (NautilusCanvasContainer *container,
1307 NautilusFilesView *view)
1308 {
1309 return nautilus_files_view_get_uri (view);
1310 }
1311
1312 static void
canvas_view_move_copy_items(NautilusCanvasContainer * container,const GList * item_uris,const char * target_dir,int copy_action,NautilusFilesView * view)1313 canvas_view_move_copy_items (NautilusCanvasContainer *container,
1314 const GList *item_uris,
1315 const char *target_dir,
1316 int copy_action,
1317 NautilusFilesView *view)
1318 {
1319 nautilus_clipboard_clear_if_colliding_uris (GTK_WIDGET (view),
1320 item_uris);
1321 nautilus_files_view_move_copy_items (view, item_uris, target_dir,
1322 copy_action);
1323 }
1324
1325 static void
nautilus_canvas_view_update_click_mode(NautilusCanvasView * canvas_view)1326 nautilus_canvas_view_update_click_mode (NautilusCanvasView *canvas_view)
1327 {
1328 NautilusCanvasContainer *canvas_container;
1329 int click_mode;
1330
1331 canvas_container = get_canvas_container (canvas_view);
1332 g_assert (canvas_container != NULL);
1333
1334 click_mode = g_settings_get_enum (nautilus_preferences, NAUTILUS_PREFERENCES_CLICK_POLICY);
1335
1336 nautilus_canvas_container_set_single_click_mode (canvas_container,
1337 click_mode == NAUTILUS_CLICK_POLICY_SINGLE);
1338 }
1339
1340 static void
canvas_container_longpress_gesture_pressed_callback(GtkGestureLongPress * gesture,gdouble x,gdouble y,gpointer user_data)1341 canvas_container_longpress_gesture_pressed_callback (GtkGestureLongPress *gesture,
1342 gdouble x,
1343 gdouble y,
1344 gpointer user_data)
1345 {
1346 GdkEventSequence *event_sequence;
1347 const GdkEvent *event;
1348 NautilusCanvasView *view = NAUTILUS_CANVAS_VIEW (user_data);
1349
1350 event_sequence = gtk_gesture_get_last_updated_sequence (GTK_GESTURE (gesture));
1351 event = gtk_gesture_get_last_event (GTK_GESTURE (gesture), event_sequence);
1352
1353 if (nautilus_view_get_selection (NAUTILUS_VIEW (view)))
1354 {
1355 nautilus_files_view_pop_up_selection_context_menu (NAUTILUS_FILES_VIEW (view),
1356 event);
1357 }
1358 else
1359 {
1360 nautilus_files_view_pop_up_background_context_menu (NAUTILUS_FILES_VIEW (view),
1361 event);
1362 }
1363 }
1364
1365 static void
initialize_canvas_container(NautilusCanvasView * canvas_view,NautilusCanvasContainer * canvas_container)1366 initialize_canvas_container (NautilusCanvasView *canvas_view,
1367 NautilusCanvasContainer *canvas_container)
1368 {
1369 GtkWidget *content_widget;
1370 GtkGesture *longpress_gesture;
1371
1372 content_widget = nautilus_files_view_get_content_widget (NAUTILUS_FILES_VIEW (canvas_view));
1373 canvas_view->canvas_container = GTK_WIDGET (canvas_container);
1374 g_object_add_weak_pointer (G_OBJECT (canvas_container),
1375 (gpointer *) &canvas_view->canvas_container);
1376
1377 longpress_gesture = gtk_gesture_long_press_new (GTK_WIDGET (content_widget));
1378 gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (longpress_gesture),
1379 GTK_PHASE_CAPTURE);
1380 gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (longpress_gesture),
1381 TRUE);
1382 g_signal_connect (longpress_gesture, "pressed",
1383 (GCallback) canvas_container_longpress_gesture_pressed_callback,
1384 canvas_view);
1385
1386 gtk_widget_set_can_focus (GTK_WIDGET (canvas_container), TRUE);
1387
1388 g_signal_connect_object (canvas_container, "activate",
1389 G_CALLBACK (canvas_container_activate_callback), canvas_view, 0);
1390 g_signal_connect_object (canvas_container, "activate-alternate",
1391 G_CALLBACK (canvas_container_activate_alternate_callback), canvas_view, 0);
1392 g_signal_connect_object (canvas_container, "activate-previewer",
1393 G_CALLBACK (canvas_container_activate_previewer_callback), canvas_view, 0);
1394 g_signal_connect_object (canvas_container, "band-select-started",
1395 G_CALLBACK (band_select_started_callback), canvas_view, 0);
1396 g_signal_connect_object (canvas_container, "band-select-ended",
1397 G_CALLBACK (band_select_ended_callback), canvas_view, 0);
1398 g_signal_connect_object (canvas_container, "context-click-selection",
1399 G_CALLBACK (canvas_container_context_click_selection_callback), canvas_view, 0);
1400 g_signal_connect_object (canvas_container, "context-click-background",
1401 G_CALLBACK (canvas_container_context_click_background_callback), canvas_view, 0);
1402 g_signal_connect_object (canvas_container, "selection-changed",
1403 G_CALLBACK (selection_changed_callback), canvas_view, 0);
1404 /* FIXME: many of these should move into fm-canvas-container as virtual methods */
1405 g_signal_connect_object (canvas_container, "get-icon-uri",
1406 G_CALLBACK (get_icon_uri_callback), canvas_view, 0);
1407 g_signal_connect_object (canvas_container, "get-icon-activation-uri",
1408 G_CALLBACK (get_icon_activation_uri_callback), canvas_view, 0);
1409 g_signal_connect_object (canvas_container, "get-icon-drop-target-uri",
1410 G_CALLBACK (get_icon_drop_target_uri_callback), canvas_view, 0);
1411 g_signal_connect_object (canvas_container, "move-copy-items",
1412 G_CALLBACK (canvas_view_move_copy_items), canvas_view, 0);
1413 g_signal_connect_object (canvas_container, "get-container-uri",
1414 G_CALLBACK (canvas_view_get_container_uri), canvas_view, 0);
1415
1416 gtk_container_add (GTK_CONTAINER (content_widget),
1417 GTK_WIDGET (canvas_container));
1418
1419 nautilus_canvas_view_update_click_mode (canvas_view);
1420 nautilus_canvas_container_set_zoom_level (canvas_container,
1421 get_default_zoom_level (canvas_view));
1422
1423 gtk_widget_show (GTK_WIDGET (canvas_container));
1424 }
1425
1426 static void
canvas_view_handle_uri_list(NautilusCanvasContainer * container,const char * item_uris,const char * target_uri,GdkDragAction action,NautilusCanvasView * view)1427 canvas_view_handle_uri_list (NautilusCanvasContainer *container,
1428 const char *item_uris,
1429 const char *target_uri,
1430 GdkDragAction action,
1431 NautilusCanvasView *view)
1432 {
1433 nautilus_files_view_handle_uri_list_drop (NAUTILUS_FILES_VIEW (view),
1434 item_uris, target_uri, action);
1435 }
1436
1437 /* Handles an URL received from Mozilla */
1438 static void
canvas_view_handle_netscape_url(NautilusCanvasContainer * container,const char * encoded_url,const char * target_uri,GdkDragAction action,NautilusCanvasView * view)1439 canvas_view_handle_netscape_url (NautilusCanvasContainer *container,
1440 const char *encoded_url,
1441 const char *target_uri,
1442 GdkDragAction action,
1443 NautilusCanvasView *view)
1444 {
1445 nautilus_files_view_handle_netscape_url_drop (NAUTILUS_FILES_VIEW (view),
1446 encoded_url, target_uri, action);
1447 }
1448
1449 static void
canvas_view_handle_text(NautilusCanvasContainer * container,const char * text,const char * target_uri,GdkDragAction action,NautilusCanvasView * view)1450 canvas_view_handle_text (NautilusCanvasContainer *container,
1451 const char *text,
1452 const char *target_uri,
1453 GdkDragAction action,
1454 NautilusCanvasView *view)
1455 {
1456 nautilus_files_view_handle_text_drop (NAUTILUS_FILES_VIEW (view),
1457 text, target_uri, action);
1458 }
1459
1460 static void
canvas_view_handle_raw(NautilusCanvasContainer * container,const char * raw_data,int length,const char * target_uri,const char * direct_save_uri,GdkDragAction action,NautilusCanvasView * view)1461 canvas_view_handle_raw (NautilusCanvasContainer *container,
1462 const char *raw_data,
1463 int length,
1464 const char *target_uri,
1465 const char *direct_save_uri,
1466 GdkDragAction action,
1467 NautilusCanvasView *view)
1468 {
1469 nautilus_files_view_handle_raw_drop (NAUTILUS_FILES_VIEW (view),
1470 raw_data, length, target_uri, direct_save_uri, action);
1471 }
1472
1473 static void
canvas_view_handle_hover(NautilusCanvasContainer * container,const char * target_uri,NautilusCanvasView * view)1474 canvas_view_handle_hover (NautilusCanvasContainer *container,
1475 const char *target_uri,
1476 NautilusCanvasView *view)
1477 {
1478 nautilus_files_view_handle_hover (NAUTILUS_FILES_VIEW (view), target_uri);
1479 }
1480
1481 static char *
canvas_view_get_first_visible_file(NautilusFilesView * view)1482 canvas_view_get_first_visible_file (NautilusFilesView *view)
1483 {
1484 NautilusFile *file;
1485 NautilusCanvasView *canvas_view;
1486
1487 canvas_view = NAUTILUS_CANVAS_VIEW (view);
1488
1489 file = NAUTILUS_FILE (nautilus_canvas_container_get_first_visible_icon (get_canvas_container (canvas_view)));
1490
1491 if (file)
1492 {
1493 return nautilus_file_get_uri (file);
1494 }
1495
1496 return NULL;
1497 }
1498
1499 static void
canvas_view_scroll_to_file(NautilusFilesView * view,const char * uri)1500 canvas_view_scroll_to_file (NautilusFilesView *view,
1501 const char *uri)
1502 {
1503 NautilusFile *file;
1504 NautilusCanvasView *canvas_view;
1505
1506 canvas_view = NAUTILUS_CANVAS_VIEW (view);
1507
1508 if (uri != NULL)
1509 {
1510 /* Only if existing, since we don't want to add the file to
1511 * the directory if it has been removed since then */
1512 file = nautilus_file_get_existing_by_uri (uri);
1513 if (file != NULL)
1514 {
1515 nautilus_canvas_container_scroll_to_canvas (get_canvas_container (canvas_view),
1516 NAUTILUS_CANVAS_ICON_DATA (file));
1517 nautilus_file_unref (file);
1518 }
1519 }
1520 }
1521
1522 static guint
nautilus_canvas_view_get_id(NautilusFilesView * view)1523 nautilus_canvas_view_get_id (NautilusFilesView *view)
1524 {
1525 return NAUTILUS_VIEW_GRID_ID;
1526 }
1527
1528 static void
nautilus_canvas_view_dispose(GObject * object)1529 nautilus_canvas_view_dispose (GObject *object)
1530 {
1531 NautilusCanvasView *canvas_view;
1532
1533 canvas_view = NAUTILUS_CANVAS_VIEW (object);
1534 canvas_view->destroyed = TRUE;
1535
1536 g_signal_handlers_disconnect_by_func (nautilus_preferences,
1537 default_sort_order_changed_callback,
1538 canvas_view);
1539 g_signal_handlers_disconnect_by_func (nautilus_preferences,
1540 image_display_policy_changed_callback,
1541 canvas_view);
1542
1543 g_signal_handlers_disconnect_by_func (nautilus_icon_view_preferences,
1544 text_attribute_names_changed_callback,
1545 canvas_view);
1546
1547
1548 G_OBJECT_CLASS (nautilus_canvas_view_parent_class)->dispose (object);
1549 }
1550
1551 static void
nautilus_canvas_view_class_init(NautilusCanvasViewClass * klass)1552 nautilus_canvas_view_class_init (NautilusCanvasViewClass *klass)
1553 {
1554 NautilusFilesViewClass *nautilus_files_view_class;
1555 GObjectClass *oclass;
1556
1557 nautilus_files_view_class = NAUTILUS_FILES_VIEW_CLASS (klass);
1558 oclass = G_OBJECT_CLASS (klass);
1559
1560 oclass->dispose = nautilus_canvas_view_dispose;
1561
1562 GTK_WIDGET_CLASS (klass)->destroy = nautilus_canvas_view_destroy;
1563
1564 nautilus_files_view_class->add_files = nautilus_canvas_view_add_files;
1565 nautilus_files_view_class->begin_loading = nautilus_canvas_view_begin_loading;
1566 nautilus_files_view_class->bump_zoom_level = nautilus_canvas_view_bump_zoom_level;
1567 nautilus_files_view_class->can_zoom_in = nautilus_canvas_view_can_zoom_in;
1568 nautilus_files_view_class->can_zoom_out = nautilus_canvas_view_can_zoom_out;
1569 nautilus_files_view_class->get_zoom_level_percentage = nautilus_canvas_view_get_zoom_level_percentage;
1570 nautilus_files_view_class->is_zoom_level_default = nautilus_canvas_view_is_zoom_level_default;
1571 nautilus_files_view_class->clear = nautilus_canvas_view_clear;
1572 nautilus_files_view_class->end_loading = nautilus_canvas_view_end_loading;
1573 nautilus_files_view_class->file_changed = nautilus_canvas_view_file_changed;
1574 nautilus_files_view_class->compute_rename_popover_pointing_to = nautilus_canvas_view_compute_rename_popover_pointing_to;
1575 nautilus_files_view_class->get_selection = nautilus_canvas_view_get_selection;
1576 nautilus_files_view_class->get_selection_for_file_transfer = nautilus_canvas_view_get_selection;
1577 nautilus_files_view_class->is_empty = nautilus_canvas_view_is_empty;
1578 nautilus_files_view_class->remove_file = nautilus_canvas_view_remove_file;
1579 nautilus_files_view_class->restore_standard_zoom_level = nautilus_canvas_view_restore_standard_zoom_level;
1580 nautilus_files_view_class->reveal_selection = nautilus_canvas_view_reveal_selection;
1581 nautilus_files_view_class->select_all = nautilus_canvas_view_select_all;
1582 nautilus_files_view_class->select_first = nautilus_canvas_view_select_first;
1583 nautilus_files_view_class->set_selection = nautilus_canvas_view_set_selection;
1584 nautilus_files_view_class->invert_selection = nautilus_canvas_view_invert_selection;
1585 nautilus_files_view_class->compare_files = compare_files;
1586 nautilus_files_view_class->click_policy_changed = nautilus_canvas_view_click_policy_changed;
1587 nautilus_files_view_class->update_actions_state = nautilus_canvas_view_update_actions_state;
1588 nautilus_files_view_class->sort_directories_first_changed = nautilus_canvas_view_sort_directories_first_changed;
1589 nautilus_files_view_class->widget_to_file_operation_position = nautilus_canvas_view_widget_to_file_operation_position;
1590 nautilus_files_view_class->get_view_id = nautilus_canvas_view_get_id;
1591 nautilus_files_view_class->get_first_visible_file = canvas_view_get_first_visible_file;
1592 nautilus_files_view_class->scroll_to_file = canvas_view_scroll_to_file;
1593 nautilus_files_view_class->reveal_for_selection_context_menu = nautilus_canvas_view_reveal_for_selection_context_menu;
1594 nautilus_files_view_class->preview_selection_event = nautilus_canvas_view_preview_selection_event;
1595 }
1596
1597 static void
nautilus_canvas_view_init(NautilusCanvasView * canvas_view)1598 nautilus_canvas_view_init (NautilusCanvasView *canvas_view)
1599 {
1600 NautilusCanvasContainer *canvas_container;
1601 GActionGroup *view_action_group;
1602 GtkClipboard *clipboard;
1603
1604 canvas_view->sort = &sort_criteria[0];
1605 canvas_view->destroyed = FALSE;
1606
1607 canvas_container = nautilus_canvas_view_container_new (canvas_view);
1608 initialize_canvas_container (canvas_view, canvas_container);
1609
1610 g_signal_connect_swapped (nautilus_preferences,
1611 "changed::" NAUTILUS_PREFERENCES_DEFAULT_SORT_ORDER,
1612 G_CALLBACK (default_sort_order_changed_callback),
1613 canvas_view);
1614 g_signal_connect_swapped (nautilus_preferences,
1615 "changed::" NAUTILUS_PREFERENCES_DEFAULT_SORT_IN_REVERSE_ORDER,
1616 G_CALLBACK (default_sort_order_changed_callback),
1617 canvas_view);
1618 g_signal_connect_swapped (nautilus_preferences,
1619 "changed::" NAUTILUS_PREFERENCES_SHOW_FILE_THUMBNAILS,
1620 G_CALLBACK (image_display_policy_changed_callback),
1621 canvas_view);
1622
1623 g_signal_connect_swapped (nautilus_icon_view_preferences,
1624 "changed::" NAUTILUS_PREFERENCES_ICON_VIEW_CAPTIONS,
1625 G_CALLBACK (text_attribute_names_changed_callback),
1626 canvas_view);
1627
1628 g_signal_connect_object (canvas_container, "handle-uri-list",
1629 G_CALLBACK (canvas_view_handle_uri_list), canvas_view, 0);
1630 g_signal_connect_object (canvas_container, "handle-netscape-url",
1631 G_CALLBACK (canvas_view_handle_netscape_url), canvas_view, 0);
1632 g_signal_connect_object (canvas_container, "handle-text",
1633 G_CALLBACK (canvas_view_handle_text), canvas_view, 0);
1634 g_signal_connect_object (canvas_container, "handle-raw",
1635 G_CALLBACK (canvas_view_handle_raw), canvas_view, 0);
1636 g_signal_connect_object (canvas_container, "handle-hover",
1637 G_CALLBACK (canvas_view_handle_hover), canvas_view, 0);
1638
1639 /* React to clipboard changes */
1640 clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
1641 g_signal_connect (clipboard, "owner-change",
1642 G_CALLBACK (on_clipboard_owner_changed), canvas_view);
1643
1644 view_action_group = nautilus_files_view_get_action_group (NAUTILUS_FILES_VIEW (canvas_view));
1645 g_action_map_add_action_entries (G_ACTION_MAP (view_action_group),
1646 canvas_view_entries,
1647 G_N_ELEMENTS (canvas_view_entries),
1648 canvas_view);
1649 /* Keep the action synced with the actual value, so the toolbar can poll it */
1650 g_action_group_change_action_state (nautilus_files_view_get_action_group (NAUTILUS_FILES_VIEW (canvas_view)),
1651 "zoom-to-level", g_variant_new_int32 (get_default_zoom_level (canvas_view)));
1652 }
1653
1654 NautilusFilesView *
nautilus_canvas_view_new(NautilusWindowSlot * slot)1655 nautilus_canvas_view_new (NautilusWindowSlot *slot)
1656 {
1657 return g_object_new (NAUTILUS_TYPE_CANVAS_VIEW,
1658 "window-slot", slot,
1659 NULL);
1660 }
1661