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