1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 
3 /* fm-icon-view.c - implementation of icon view of directory.
4 
5    Copyright (C) 2000, 2001 Eazel, Inc.
6 
7    The Mate Library is free software; you can redistribute it and/or
8    modify it under the terms of the GNU Library General Public License as
9    published by the Free Software Foundation; either version 2 of the
10    License, or (at your option) any later version.
11 
12    The Mate Library is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    Library General Public License for more details.
16 
17    You should have received a copy of the GNU Library General Public
18    License along with the Mate Library; see the file COPYING.LIB.  If not,
19    write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20    Boston, MA 02110-1301, USA.
21 
22    Authors: John Sullivan <sullivan@eazel.com>
23 */
24 
25 #include <config.h>
26 #include <stdlib.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <locale.h>
30 #include <signal.h>
31 #include <stdio.h>
32 #include <unistd.h>
33 
34 #include <gtk/gtk.h>
35 #include <glib/gi18n.h>
36 #include <gio/gio.h>
37 #include <sys/types.h>
38 #include <sys/wait.h>
39 
40 #include <eel/eel-background.h>
41 #include <eel/eel-glib-extensions.h>
42 #include <eel/eel-gtk-extensions.h>
43 #include <eel/eel-gtk-macros.h>
44 #include <eel/eel-stock-dialogs.h>
45 #include <eel/eel-string.h>
46 #include <eel/eel-vfs-extensions.h>
47 
48 #include <libcaja-private/caja-clipboard-monitor.h>
49 #include <libcaja-private/caja-directory-background.h>
50 #include <libcaja-private/caja-directory.h>
51 #include <libcaja-private/caja-dnd.h>
52 #include <libcaja-private/caja-file-utilities.h>
53 #include <libcaja-private/caja-ui-utilities.h>
54 #include <libcaja-private/caja-global-preferences.h>
55 #include <libcaja-private/caja-icon-container.h>
56 #include <libcaja-private/caja-icon-dnd.h>
57 #include <libcaja-private/caja-link.h>
58 #include <libcaja-private/caja-metadata.h>
59 #include <libcaja-private/caja-view-factory.h>
60 #include <libcaja-private/caja-clipboard.h>
61 #include <libcaja-private/caja-desktop-icon-file.h>
62 
63 #include "fm-icon-view.h"
64 #include "fm-actions.h"
65 #include "fm-icon-container.h"
66 #include "fm-desktop-icon-view.h"
67 #include "fm-error-reporting.h"
68 #include "caja-audio-mime-types.h"
69 
70 #define POPUP_PATH_ICON_APPEARANCE		"/selection/Icon Appearance Items"
71 
72 enum
73 {
74     PROP_0,
75     PROP_COMPACT
76 };
77 
78 typedef struct
79 {
80     const CajaFileSortType sort_type;
81     const char *metadata_text;
82     const char *action;
83     const char *menu_label;
84     const char *menu_hint;
85 } SortCriterion;
86 
87 typedef enum
88 {
89     MENU_ITEM_TYPE_STANDARD,
90     MENU_ITEM_TYPE_CHECK,
91     MENU_ITEM_TYPE_RADIO,
92     MENU_ITEM_TYPE_TREE
93 } MenuItemType;
94 
95 struct FMIconViewDetails
96 {
97     GList *icons_not_positioned;
98 
99     guint react_to_icon_change_idle_id;
100 
101     const SortCriterion *sort;
102     gboolean sort_reversed;
103 
104     GtkActionGroup *icon_action_group;
105     guint icon_merge_id;
106 
107     int audio_preview_timeout;
108     CajaFile *audio_preview_file;
109     int audio_preview_child_watch;
110     GPid audio_preview_child_pid;
111 
112     gboolean filter_by_screen;
113 
114     gboolean compact;
115 
116     gulong clipboard_handler_id;
117 };
118 
119 
120 /* Note that the first item in this list is the default sort,
121  * and that the items show up in the menu in the order they
122  * appear in this list.
123  */
124 static const SortCriterion sort_criteria[] =
125 {
126     {
127         CAJA_FILE_SORT_BY_DISPLAY_NAME,
128         "name",
129         "Sort by Name",
130         N_("by _Name"),
131         N_("Keep icons sorted by name in rows")
132     },
133     {
134         CAJA_FILE_SORT_BY_SIZE,
135         "size",
136         "Sort by Size",
137         N_("by _Size"),
138         N_("Keep icons sorted by size in rows")
139     },
140     {
141         CAJA_FILE_SORT_BY_SIZE_ON_DISK,
142         "size_on_disk",
143         "Sort by Size on Disk",
144         N_("by S_ize on Disk"),
145         N_("Keep icons sorted by disk usage in rows")
146     },
147     {
148         CAJA_FILE_SORT_BY_TYPE,
149         "type",
150         "Sort by Type",
151         N_("by _Type"),
152         N_("Keep icons sorted by type in rows")
153     },
154     {
155         CAJA_FILE_SORT_BY_MTIME,
156         "modification date",
157         "Sort by Modification Date",
158         N_("by Modification _Date"),
159         N_("Keep icons sorted by modification date in rows")
160     },
161     {
162         CAJA_FILE_SORT_BY_BTIME,
163         "creation date",
164         "Sort by Creation Date",
165         N_("by _Creation Date"),
166         N_("Keep icons sorted by creation date in rows")
167     },
168     {
169         CAJA_FILE_SORT_BY_EMBLEMS,
170         "emblems",
171         "Sort by Emblems",
172         N_("by _Emblems"),
173         N_("Keep icons sorted by emblems in rows")
174     },
175     {
176         CAJA_FILE_SORT_BY_TRASHED_TIME,
177         "trashed",
178         "Sort by Trash Time",
179         N_("by T_rash Time"),
180         N_("Keep icons sorted by trash time in rows")
181     },
182     {
183         CAJA_FILE_SORT_BY_EXTENSION,
184         "extension",
185         "Sort by Extension",
186         N_("by E_xtension"),
187         N_("Keep icons sorted by reversed extension segments in rows")
188     }
189 };
190 
191 static gboolean default_sort_in_reverse_order = FALSE;
192 static int preview_sound_auto_value;
193 
194 static void                 fm_icon_view_set_directory_sort_by        (FMIconView           *icon_view,
195         CajaFile         *file,
196         const char           *sort_by);
197 static void                 fm_icon_view_set_zoom_level               (FMIconView           *view,
198         CajaZoomLevel     new_level,
199         gboolean              always_emit);
200 static void                 fm_icon_view_update_click_mode            (FMIconView           *icon_view);
201 static void                 fm_icon_view_set_directory_tighter_layout (FMIconView           *icon_view,
202         CajaFile         *file,
203         gboolean              tighter_layout);
204 static gboolean             fm_icon_view_supports_manual_layout       (FMIconView           *icon_view);
205 static gboolean             fm_icon_view_supports_scaling	      (FMIconView           *icon_view);
206 static void                 fm_icon_view_reveal_selection             (FMDirectoryView      *view);
207 static const SortCriterion *get_sort_criterion_by_sort_type           (CajaFileSortType  sort_type);
208 static void                 set_sort_criterion_by_sort_type           (FMIconView           *icon_view,
209         CajaFileSortType  sort_type);
210 static gboolean             set_sort_reversed                         (FMIconView           *icon_view,
211         gboolean              new_value);
212 static void                 switch_to_manual_layout                   (FMIconView           *view);
213 static void                 preview_audio                             (FMIconView           *icon_view,
214         CajaFile         *file,
215         gboolean              start_flag);
216 static void                 update_layout_menus                       (FMIconView           *view);
217 static CajaFileSortType get_default_sort_order                    (CajaFile         *file,
218         gboolean             *reversed);
219 
220 static void default_sort_order_changed_callback            (gpointer callback_data);
221 static void default_sort_in_reverse_order_changed_callback (gpointer callback_data);
222 static void default_use_tighter_layout_changed_callback    (gpointer callback_data);
223 static void default_zoom_level_changed_callback            (gpointer callback_data);
224 static void labels_beside_icons_changed_callback           (gpointer callback_data);
225 static void all_columns_same_width_changed_callback        (gpointer callback_data);
226 
227 static void fm_icon_view_iface_init (CajaViewIface *iface);
228 
229 G_DEFINE_TYPE_WITH_CODE (FMIconView, fm_icon_view, FM_TYPE_DIRECTORY_VIEW,
230                          G_IMPLEMENT_INTERFACE (CAJA_TYPE_VIEW,
231                                  fm_icon_view_iface_init));
232 
233 static void
fm_icon_view_destroy(GtkWidget * object)234 fm_icon_view_destroy (GtkWidget *object)
235 {
236     FMIconView *icon_view;
237 
238     icon_view = FM_ICON_VIEW (object);
239 
240     if (icon_view->details->react_to_icon_change_idle_id != 0)
241     {
242         g_source_remove (icon_view->details->react_to_icon_change_idle_id);
243         icon_view->details->react_to_icon_change_idle_id = 0;
244     }
245 
246     if (icon_view->details->clipboard_handler_id != 0)
247     {
248         g_signal_handler_disconnect (caja_clipboard_monitor_get (),
249                                      icon_view->details->clipboard_handler_id);
250         icon_view->details->clipboard_handler_id = 0;
251     }
252 
253     /* kill any sound preview process that is ongoing */
254     preview_audio (icon_view, NULL, FALSE);
255 
256     if (icon_view->details->icons_not_positioned)
257     {
258         caja_file_list_free (icon_view->details->icons_not_positioned);
259         icon_view->details->icons_not_positioned = NULL;
260     }
261 
262     GTK_WIDGET_CLASS (fm_icon_view_parent_class)->destroy (object);
263 }
264 
265 static void
fm_icon_view_finalize(GObject * object)266 fm_icon_view_finalize (GObject *object)
267 {
268     FMIconView *icon_view;
269 
270     icon_view = FM_ICON_VIEW (object);
271 
272     g_free (icon_view->details);
273 
274     g_signal_handlers_disconnect_by_func (caja_preferences,
275                                           default_sort_order_changed_callback,
276                                           icon_view);
277     g_signal_handlers_disconnect_by_func (caja_preferences,
278                                           default_sort_in_reverse_order_changed_callback,
279                                           icon_view);
280     g_signal_handlers_disconnect_by_func (caja_icon_view_preferences,
281                                           default_use_tighter_layout_changed_callback,
282                                           icon_view);
283     g_signal_handlers_disconnect_by_func (caja_icon_view_preferences,
284                                           default_zoom_level_changed_callback,
285                                           icon_view);
286     g_signal_handlers_disconnect_by_func (caja_icon_view_preferences,
287                                           labels_beside_icons_changed_callback,
288                                           icon_view);
289     g_signal_handlers_disconnect_by_func (caja_compact_view_preferences,
290                                           default_zoom_level_changed_callback,
291                                           icon_view);
292     g_signal_handlers_disconnect_by_func (caja_compact_view_preferences,
293                                           all_columns_same_width_changed_callback,
294                                           icon_view);
295 
296     G_OBJECT_CLASS (fm_icon_view_parent_class)->finalize (object);
297 }
298 
299 static CajaIconContainer *
get_icon_container(FMIconView * icon_view)300 get_icon_container (FMIconView *icon_view)
301 {
302     return CAJA_ICON_CONTAINER (gtk_bin_get_child (GTK_BIN (icon_view)));
303 }
304 
305 static gboolean
get_stored_icon_position_callback(CajaIconContainer * container,CajaFile * file,CajaIconPosition * position,FMIconView * icon_view)306 get_stored_icon_position_callback (CajaIconContainer *container,
307                                    CajaFile *file,
308                                    CajaIconPosition *position,
309                                    FMIconView *icon_view)
310 {
311     char *position_string;
312     gboolean position_good;
313     char c;
314 
315     g_assert (CAJA_IS_ICON_CONTAINER (container));
316     g_assert (CAJA_IS_FILE (file));
317     g_assert (position != NULL);
318     g_assert (FM_IS_ICON_VIEW (icon_view));
319 
320     if (!fm_icon_view_supports_manual_layout (icon_view))
321     {
322         return FALSE;
323     }
324 
325     /* Get the current position of this icon from the metadata. */
326     position_string = caja_file_get_metadata
327                       (file, CAJA_METADATA_KEY_ICON_POSITION, "");
328     position_good = sscanf
329                     (position_string, " %d , %d %c",
330                      &position->x, &position->y, &c) == 2;
331     g_free (position_string);
332 
333     /* If it is the desktop directory, maybe the mate-libs metadata has information about it */
334 
335     /* Disable scaling if not on the desktop */
336     if (fm_icon_view_supports_scaling (icon_view))
337     {
338         char *scale_string;
339 
340         /* Get the scale of the icon from the metadata. */
341         scale_string = caja_file_get_metadata
342                        (file, CAJA_METADATA_KEY_ICON_SCALE, "1");
343         position->scale = g_ascii_strtod (scale_string, NULL);
344 
345         if (errno != 0)
346         {
347             position->scale = 1.0;
348         }
349 
350         g_free (scale_string);
351     }
352     else
353     {
354         position->scale = 1.0;
355     }
356 
357     return position_good;
358 }
359 
360 static void
real_set_sort_criterion(FMIconView * icon_view,const SortCriterion * sort,gboolean clear)361 real_set_sort_criterion (FMIconView *icon_view,
362                          const SortCriterion *sort,
363                          gboolean clear)
364 {
365     CajaFile *file;
366 
367     file = fm_directory_view_get_directory_as_file (FM_DIRECTORY_VIEW (icon_view));
368 
369     if (clear)
370     {
371         caja_file_set_metadata (file,
372                                 CAJA_METADATA_KEY_ICON_VIEW_SORT_BY, NULL, NULL);
373         caja_file_set_metadata (file,
374                                 CAJA_METADATA_KEY_ICON_VIEW_SORT_REVERSED, NULL, NULL);
375         icon_view->details->sort =
376             get_sort_criterion_by_sort_type	(get_default_sort_order
377                                              (file, &icon_view->details->sort_reversed));
378     }
379     else
380     {
381         /* Store the new sort setting. */
382         fm_icon_view_set_directory_sort_by (icon_view,
383                                             file,
384                                             sort->metadata_text);
385     }
386 
387     /* Update the layout menus to match the new sort setting. */
388     update_layout_menus (icon_view);
389 }
390 
391 static void
set_sort_criterion(FMIconView * icon_view,const SortCriterion * sort)392 set_sort_criterion (FMIconView *icon_view, const SortCriterion *sort)
393 {
394     if (sort == NULL ||
395             icon_view->details->sort == sort)
396     {
397         return;
398     }
399 
400     icon_view->details->sort = sort;
401 
402     real_set_sort_criterion (icon_view, sort, FALSE);
403 }
404 
405 static void
clear_sort_criterion(FMIconView * icon_view)406 clear_sort_criterion (FMIconView *icon_view)
407 {
408     real_set_sort_criterion (icon_view, NULL, TRUE);
409 }
410 
411 static void
action_stretch_callback(GtkAction * action,gpointer callback_data)412 action_stretch_callback (GtkAction *action,
413                          gpointer callback_data)
414 {
415     g_assert (FM_IS_ICON_VIEW (callback_data));
416 
417     caja_icon_container_show_stretch_handles
418     (get_icon_container (FM_ICON_VIEW (callback_data)));
419 }
420 
421 static void
action_unstretch_callback(GtkAction * action,gpointer callback_data)422 action_unstretch_callback (GtkAction *action,
423                            gpointer callback_data)
424 {
425     g_assert (FM_IS_ICON_VIEW (callback_data));
426 
427     caja_icon_container_unstretch
428     (get_icon_container (FM_ICON_VIEW (callback_data)));
429 }
430 
431 static void
fm_icon_view_clean_up(FMIconView * icon_view)432 fm_icon_view_clean_up (FMIconView *icon_view)
433 {
434     EEL_CALL_METHOD (FM_ICON_VIEW_CLASS, icon_view, clean_up, (icon_view));
435 }
436 
437 static void
fm_icon_view_real_clean_up(FMIconView * icon_view)438 fm_icon_view_real_clean_up (FMIconView *icon_view)
439 {
440     CajaIconContainer *icon_container;
441     gboolean saved_sort_reversed;
442 
443     icon_container = get_icon_container (icon_view);
444 
445     /* Hardwire Clean Up to always be by name, in forward order */
446     saved_sort_reversed = icon_view->details->sort_reversed;
447 
448     set_sort_reversed (icon_view, FALSE);
449     set_sort_criterion (icon_view, &sort_criteria[0]);
450 
451     caja_icon_container_sort (icon_container);
452     caja_icon_container_freeze_icon_positions (icon_container);
453 
454     set_sort_reversed (icon_view, saved_sort_reversed);
455 }
456 
457 static void
action_clean_up_callback(GtkAction * action,gpointer callback_data)458 action_clean_up_callback (GtkAction *action, gpointer callback_data)
459 {
460     fm_icon_view_clean_up (FM_ICON_VIEW (callback_data));
461 }
462 
463 static void
set_tighter_layout(FMIconView * icon_view,gboolean new_value)464 set_tighter_layout (FMIconView *icon_view, gboolean new_value)
465 {
466     fm_icon_view_set_directory_tighter_layout (icon_view,
467             fm_directory_view_get_directory_as_file
468             (FM_DIRECTORY_VIEW (icon_view)),
469             new_value);
470     caja_icon_container_set_tighter_layout (get_icon_container (icon_view),
471                                             new_value);
472 }
473 
474 static void
action_tighter_layout_callback(GtkAction * action,gpointer user_data)475 action_tighter_layout_callback (GtkAction *action,
476                                 gpointer user_data)
477 {
478     g_assert (FM_IS_ICON_VIEW (user_data));
479 
480     G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
481     set_tighter_layout (FM_ICON_VIEW (user_data),
482                         gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)));
483     G_GNUC_END_IGNORE_DEPRECATIONS;
484 }
485 
486 
487 static gboolean
fm_icon_view_using_auto_layout(FMIconView * icon_view)488 fm_icon_view_using_auto_layout (FMIconView *icon_view)
489 {
490     return caja_icon_container_is_auto_layout
491            (get_icon_container (icon_view));
492 }
493 
494 static gboolean
fm_icon_view_using_tighter_layout(FMIconView * icon_view)495 fm_icon_view_using_tighter_layout (FMIconView *icon_view)
496 {
497     return caja_icon_container_is_tighter_layout
498            (get_icon_container (icon_view));
499 }
500 
501 static void
action_sort_radio_callback(GtkAction * action,GtkRadioAction * current,FMIconView * view)502 action_sort_radio_callback (GtkAction *action,
503                             GtkRadioAction *current,
504                             FMIconView *view)
505 {
506     CajaFileSortType sort_type;
507 
508     G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
509     sort_type = gtk_radio_action_get_current_value (current);
510     G_GNUC_END_IGNORE_DEPRECATIONS;
511 
512     /* Note that id might be a toggle item.
513      * Ignore non-sort ids so that they don't cause sorting.
514      */
515     if (sort_type == CAJA_FILE_SORT_NONE)
516     {
517         switch_to_manual_layout (view);
518     }
519     else
520     {
521         set_sort_criterion_by_sort_type (view, sort_type);
522     }
523 }
524 
525 static void
list_covers(CajaIconData * data,gpointer callback_data)526 list_covers (CajaIconData *data, gpointer callback_data)
527 {
528     GSList **file_list;
529 
530     file_list = callback_data;
531 
532     *file_list = g_slist_prepend (*file_list, data);
533 }
534 
535 static void
unref_cover(CajaIconData * data,gpointer callback_data)536 unref_cover (CajaIconData *data, gpointer callback_data)
537 {
538     caja_file_unref (CAJA_FILE (data));
539 }
540 
541 static void
fm_icon_view_clear(FMDirectoryView * view)542 fm_icon_view_clear (FMDirectoryView *view)
543 {
544     CajaIconContainer *icon_container;
545     GSList *file_list;
546 
547     g_return_if_fail (FM_IS_ICON_VIEW (view));
548 
549     icon_container = get_icon_container (FM_ICON_VIEW (view));
550     if (!icon_container)
551         return;
552 
553     /* Clear away the existing icons. */
554     file_list = NULL;
555     caja_icon_container_for_each (icon_container, list_covers, &file_list);
556     caja_icon_container_clear (icon_container);
557     g_slist_foreach (file_list, (GFunc)unref_cover, NULL);
558     g_slist_free (file_list);
559 }
560 
561 
562 static gboolean
should_show_file_on_screen(FMDirectoryView * view,CajaFile * file)563 should_show_file_on_screen (FMDirectoryView *view, CajaFile *file)
564 {
565     if (!fm_directory_view_should_show_file (view, file))
566     {
567         return FALSE;
568     }
569 
570     return TRUE;
571 }
572 
573 static void
fm_icon_view_remove_file(FMDirectoryView * view,CajaFile * file,CajaDirectory * directory)574 fm_icon_view_remove_file (FMDirectoryView *view, CajaFile *file, CajaDirectory *directory)
575 {
576     FMIconView *icon_view;
577 
578     /* This used to assert that 'directory == fm_directory_view_get_model (view)', but that
579      * resulted in a lot of crash reports (bug #352592). I don't see how that trace happens.
580      * It seems that somehow we get a files_changed event sent to the view from a directory
581      * that isn't the model, but the code disables the monitor and signal callback handlers when
582      * changing directories. Maybe we can get some more information when this happens.
583      * Further discussion in bug #368178.
584      */
585     if (directory != fm_directory_view_get_model (view))
586     {
587         char *file_uri, *dir_uri, *model_uri;
588         file_uri = caja_file_get_uri (file);
589         dir_uri = caja_directory_get_uri (directory);
590         model_uri = caja_directory_get_uri (fm_directory_view_get_model (view));
591         g_warning ("fm_icon_view_remove_file() - directory not icon view model, shouldn't happen.\n"
592                    "file: %p:%s, dir: %p:%s, model: %p:%s, view loading: %d\n"
593                    "If you see this, please add this info to https://bugzilla.gnome.org/show_bug.cgi?id=368178",
594                    file, file_uri, directory, dir_uri, fm_directory_view_get_model (view), model_uri, fm_directory_view_get_loading (view));
595         g_free (file_uri);
596         g_free (dir_uri);
597         g_free (model_uri);
598     }
599 
600     icon_view = FM_ICON_VIEW (view);
601 
602     if (caja_icon_container_remove (get_icon_container (icon_view),
603                                     CAJA_ICON_CONTAINER_ICON_DATA (file)))
604     {
605         if (file == icon_view->details->audio_preview_file)
606         {
607             preview_audio (icon_view, NULL, FALSE);
608         }
609 
610         caja_file_unref (file);
611     }
612 }
613 
614 static void
fm_icon_view_add_file(FMDirectoryView * view,CajaFile * file,CajaDirectory * directory)615 fm_icon_view_add_file (FMDirectoryView *view, CajaFile *file, CajaDirectory *directory)
616 {
617     FMIconView *icon_view;
618     CajaIconContainer *icon_container;
619 
620     g_assert (directory == fm_directory_view_get_model (view));
621 
622     icon_view = FM_ICON_VIEW (view);
623     icon_container = get_icon_container (icon_view);
624 
625     if (icon_view->details->filter_by_screen &&
626             !should_show_file_on_screen (view, file))
627     {
628         return;
629     }
630 
631     /* Reset scroll region for the first icon added when loading a directory. */
632     if (fm_directory_view_get_loading (view) && caja_icon_container_is_empty (icon_container))
633     {
634         caja_icon_container_reset_scroll_region (icon_container);
635     }
636 
637     if (caja_icon_container_add (icon_container,
638                                  CAJA_ICON_CONTAINER_ICON_DATA (file)))
639     {
640         caja_file_ref (file);
641     }
642 }
643 
644 static void
fm_icon_view_flush_added_files(FMDirectoryView * view)645 fm_icon_view_flush_added_files (FMDirectoryView *view)
646 {
647     caja_icon_container_layout_now (get_icon_container (FM_ICON_VIEW (view)));
648 }
649 
650 static void
fm_icon_view_file_changed(FMDirectoryView * view,CajaFile * file,CajaDirectory * directory)651 fm_icon_view_file_changed (FMDirectoryView *view, CajaFile *file, CajaDirectory *directory)
652 {
653     FMIconView *icon_view;
654 
655     g_assert (directory == fm_directory_view_get_model (view));
656 
657     g_return_if_fail (view != NULL);
658     icon_view = FM_ICON_VIEW (view);
659 
660     if (!icon_view->details->filter_by_screen)
661     {
662         caja_icon_container_request_update
663         (get_icon_container (icon_view),
664          CAJA_ICON_CONTAINER_ICON_DATA (file));
665         return;
666     }
667 
668     if (!should_show_file_on_screen (view, file))
669     {
670         fm_icon_view_remove_file (view, file, directory);
671     }
672     else
673     {
674 
675         caja_icon_container_request_update
676         (get_icon_container (icon_view),
677          CAJA_ICON_CONTAINER_ICON_DATA (file));
678     }
679 }
680 
681 static gboolean
fm_icon_view_supports_auto_layout(FMIconView * view)682 fm_icon_view_supports_auto_layout (FMIconView *view)
683 {
684     g_return_val_if_fail (FM_IS_ICON_VIEW (view), FALSE);
685 
686     return EEL_CALL_METHOD_WITH_RETURN_VALUE
687            (FM_ICON_VIEW_CLASS, view,
688             supports_auto_layout, (view));
689 }
690 
691 static gboolean
fm_icon_view_supports_scaling(FMIconView * view)692 fm_icon_view_supports_scaling (FMIconView *view)
693 {
694     g_return_val_if_fail (FM_IS_ICON_VIEW (view), FALSE);
695 
696     return EEL_CALL_METHOD_WITH_RETURN_VALUE
697            (FM_ICON_VIEW_CLASS, view,
698             supports_scaling, (view));
699 }
700 
701 static gboolean
fm_icon_view_supports_manual_layout(FMIconView * view)702 fm_icon_view_supports_manual_layout (FMIconView *view)
703 {
704     g_return_val_if_fail (FM_IS_ICON_VIEW (view), FALSE);
705 
706     return EEL_CALL_METHOD_WITH_RETURN_VALUE
707            (FM_ICON_VIEW_CLASS, view,
708             supports_manual_layout, (view));
709 }
710 
711 static gboolean
fm_icon_view_supports_keep_aligned(FMIconView * view)712 fm_icon_view_supports_keep_aligned (FMIconView *view)
713 {
714     g_return_val_if_fail (FM_IS_ICON_VIEW (view), FALSE);
715 
716     return EEL_CALL_METHOD_WITH_RETURN_VALUE
717            (FM_ICON_VIEW_CLASS, view,
718             supports_keep_aligned, (view));
719 }
720 
721 static gboolean
fm_icon_view_supports_labels_beside_icons(FMIconView * view)722 fm_icon_view_supports_labels_beside_icons (FMIconView *view)
723 {
724     g_return_val_if_fail (FM_IS_ICON_VIEW (view), FALSE);
725 
726     return EEL_CALL_METHOD_WITH_RETURN_VALUE
727            (FM_ICON_VIEW_CLASS, view,
728             supports_labels_beside_icons, (view));
729 }
730 
731 static gboolean
fm_icon_view_supports_tighter_layout(FMIconView * view)732 fm_icon_view_supports_tighter_layout (FMIconView *view)
733 {
734     return !fm_icon_view_is_compact (view);
735 }
736 
737 static void
update_layout_menus(FMIconView * view)738 update_layout_menus (FMIconView *view)
739 {
740     gboolean is_auto_layout;
741     GtkAction *action;
742     CajaFile *file;
743 
744     if (view->details->icon_action_group == NULL)
745     {
746         return;
747     }
748 
749     is_auto_layout = fm_icon_view_using_auto_layout (view);
750     file = fm_directory_view_get_directory_as_file (FM_DIRECTORY_VIEW (view));
751 
752     G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
753     if (fm_icon_view_supports_auto_layout (view))
754     {
755         const char *action_name;
756 
757         /* Mark sort criterion. */
758         action_name = is_auto_layout ? view->details->sort->action : FM_ACTION_MANUAL_LAYOUT;
759         action = gtk_action_group_get_action (view->details->icon_action_group,
760                                               action_name);
761         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
762 
763         action = gtk_action_group_get_action (view->details->icon_action_group,
764                                               FM_ACTION_TIGHTER_LAYOUT);
765         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
766                                       fm_icon_view_using_tighter_layout (view));
767         gtk_action_set_sensitive (action, fm_icon_view_supports_tighter_layout (view));
768         gtk_action_set_visible (action, fm_icon_view_supports_tighter_layout (view));
769 
770         action = gtk_action_group_get_action (view->details->icon_action_group,
771                                               FM_ACTION_REVERSED_ORDER);
772         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
773                                       view->details->sort_reversed);
774         gtk_action_set_sensitive (action, is_auto_layout);
775 
776         action = gtk_action_group_get_action (view->details->icon_action_group,
777                                               FM_ACTION_SORT_TRASH_TIME);
778 
779         if (file != NULL && caja_file_is_in_trash (file))
780         {
781             gtk_action_set_visible (action, TRUE);
782         }
783         else
784         {
785             gtk_action_set_visible (action, FALSE);
786         }
787     }
788 
789     action = gtk_action_group_get_action (view->details->icon_action_group,
790                                           FM_ACTION_MANUAL_LAYOUT);
791     gtk_action_set_visible (action,
792                             fm_icon_view_supports_manual_layout (view));
793 
794     /* Clean Up is only relevant for manual layout */
795     action = gtk_action_group_get_action (view->details->icon_action_group,
796                                           FM_ACTION_CLEAN_UP);
797     gtk_action_set_sensitive (action, !is_auto_layout);
798 
799     if (FM_IS_DESKTOP_ICON_VIEW (view))
800     {
801         gtk_action_set_label (action, _("_Organize Desktop by Name"));
802     }
803 
804     action = gtk_action_group_get_action (view->details->icon_action_group,
805                                           FM_ACTION_KEEP_ALIGNED);
806     gtk_action_set_visible (action,
807                             fm_icon_view_supports_keep_aligned (view));
808     gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
809                                   caja_icon_container_is_keep_aligned (get_icon_container (view)));
810     gtk_action_set_sensitive (action, !is_auto_layout);
811 
812     action = gtk_action_group_get_action (view->details->icon_action_group,
813                                           FM_ACTION_LOCK_ICON_POSITION);
814     gtk_action_set_visible (action, !is_auto_layout);
815     gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
816                                   caja_icon_container_is_lock_icons_position (get_icon_container (view)));
817     G_GNUC_END_IGNORE_DEPRECATIONS;
818 }
819 
820 
821 static char *
fm_icon_view_get_directory_sort_by(FMIconView * icon_view,CajaFile * file)822 fm_icon_view_get_directory_sort_by (FMIconView *icon_view,
823                                     CajaFile *file)
824 {
825     if (!fm_icon_view_supports_auto_layout (icon_view))
826     {
827         return g_strdup ("name");
828     }
829 
830     return EEL_CALL_METHOD_WITH_RETURN_VALUE
831            (FM_ICON_VIEW_CLASS, icon_view,
832             get_directory_sort_by, (icon_view, file));
833 }
834 
835 static CajaFileSortType default_sort_order = CAJA_FILE_SORT_BY_DISPLAY_NAME;
836 
837 static CajaFileSortType
get_default_sort_order(CajaFile * file,gboolean * reversed)838 get_default_sort_order (CajaFile *file, gboolean *reversed)
839 {
840     static gboolean auto_storaged_added = FALSE;
841     CajaFileSortType retval;
842 
843     if (auto_storaged_added == FALSE)
844     {
845         auto_storaged_added = TRUE;
846         eel_g_settings_add_auto_enum (caja_preferences,
847                                       CAJA_PREFERENCES_DEFAULT_SORT_ORDER,
848                                       (int *) &default_sort_order);
849         eel_g_settings_add_auto_boolean (caja_preferences,
850                                          CAJA_PREFERENCES_DEFAULT_SORT_IN_REVERSE_ORDER,
851                                          &default_sort_in_reverse_order);
852     }
853 
854     retval = caja_file_get_default_sort_type (file, reversed);
855 
856     if (retval == CAJA_FILE_SORT_NONE)
857     {
858 
859         if (reversed != NULL)
860         {
861             *reversed = default_sort_in_reverse_order;
862         }
863 
864         retval = CLAMP (default_sort_order, CAJA_FILE_SORT_BY_DISPLAY_NAME,
865                         CAJA_FILE_SORT_BY_EMBLEMS);
866     }
867 
868     return retval;
869 }
870 
871 static char *
fm_icon_view_real_get_directory_sort_by(FMIconView * icon_view,CajaFile * file)872 fm_icon_view_real_get_directory_sort_by (FMIconView *icon_view,
873         CajaFile *file)
874 {
875     const SortCriterion *default_sort_criterion;
876     default_sort_criterion = get_sort_criterion_by_sort_type (get_default_sort_order (file, NULL));
877     g_return_val_if_fail (default_sort_criterion != NULL, NULL);
878 
879     return caja_file_get_metadata
880            (file, CAJA_METADATA_KEY_ICON_VIEW_SORT_BY,
881             default_sort_criterion->metadata_text);
882 }
883 
884 static void
fm_icon_view_set_directory_sort_by(FMIconView * icon_view,CajaFile * file,const char * sort_by)885 fm_icon_view_set_directory_sort_by (FMIconView *icon_view,
886                                     CajaFile *file,
887                                     const char *sort_by)
888 {
889     if (!fm_icon_view_supports_auto_layout (icon_view))
890     {
891         return;
892     }
893 
894     EEL_CALL_METHOD (FM_ICON_VIEW_CLASS, icon_view,
895                      set_directory_sort_by, (icon_view, file, sort_by));
896 }
897 
898 static void
fm_icon_view_real_set_directory_sort_by(FMIconView * icon_view,CajaFile * file,const char * sort_by)899 fm_icon_view_real_set_directory_sort_by (FMIconView *icon_view,
900         CajaFile *file,
901         const char *sort_by)
902 {
903     const SortCriterion *default_sort_criterion;
904     default_sort_criterion = get_sort_criterion_by_sort_type (get_default_sort_order (file, NULL));
905     g_return_if_fail (default_sort_criterion != NULL);
906 
907     caja_file_set_metadata
908     (file, CAJA_METADATA_KEY_ICON_VIEW_SORT_BY,
909      default_sort_criterion->metadata_text,
910      sort_by);
911 }
912 
913 static gboolean
fm_icon_view_get_directory_sort_reversed(FMIconView * icon_view,CajaFile * file)914 fm_icon_view_get_directory_sort_reversed (FMIconView *icon_view,
915         CajaFile *file)
916 {
917     if (!fm_icon_view_supports_auto_layout (icon_view))
918     {
919         return FALSE;
920     }
921 
922     return EEL_CALL_METHOD_WITH_RETURN_VALUE
923            (FM_ICON_VIEW_CLASS, icon_view,
924             get_directory_sort_reversed, (icon_view, file));
925 }
926 
927 static gboolean
fm_icon_view_real_get_directory_sort_reversed(FMIconView * icon_view,CajaFile * file)928 fm_icon_view_real_get_directory_sort_reversed (FMIconView *icon_view,
929         CajaFile *file)
930 {
931     gboolean reversed;
932 
933     get_default_sort_order (file, &reversed);
934     return caja_file_get_boolean_metadata
935            (file,
936             CAJA_METADATA_KEY_ICON_VIEW_SORT_REVERSED,
937             reversed);
938 }
939 
940 static void
fm_icon_view_set_directory_sort_reversed(FMIconView * icon_view,CajaFile * file,gboolean sort_reversed)941 fm_icon_view_set_directory_sort_reversed (FMIconView *icon_view,
942         CajaFile *file,
943         gboolean sort_reversed)
944 {
945     if (!fm_icon_view_supports_auto_layout (icon_view))
946     {
947         return;
948     }
949 
950     EEL_CALL_METHOD (FM_ICON_VIEW_CLASS, icon_view,
951                      set_directory_sort_reversed,
952                      (icon_view, file, sort_reversed));
953 }
954 
955 static void
fm_icon_view_real_set_directory_sort_reversed(FMIconView * icon_view,CajaFile * file,gboolean sort_reversed)956 fm_icon_view_real_set_directory_sort_reversed (FMIconView *icon_view,
957         CajaFile *file,
958         gboolean sort_reversed)
959 {
960     gboolean reversed;
961 
962     get_default_sort_order (file, &reversed);
963     caja_file_set_boolean_metadata
964     (file,
965      CAJA_METADATA_KEY_ICON_VIEW_SORT_REVERSED,
966      reversed, sort_reversed);
967 }
968 
969 static gboolean
get_default_directory_keep_aligned(void)970 get_default_directory_keep_aligned (void)
971 {
972     return TRUE;
973 }
974 
975 static gboolean
fm_icon_view_get_directory_keep_aligned(FMIconView * icon_view,CajaFile * file)976 fm_icon_view_get_directory_keep_aligned (FMIconView *icon_view,
977         CajaFile *file)
978 {
979     if (!fm_icon_view_supports_keep_aligned (icon_view))
980     {
981         return FALSE;
982     }
983 
984     return  caja_file_get_boolean_metadata
985             (file,
986              CAJA_METADATA_KEY_ICON_VIEW_KEEP_ALIGNED,
987              get_default_directory_keep_aligned ());
988 }
989 
990 static void
fm_icon_view_set_directory_keep_aligned(FMIconView * icon_view,CajaFile * file,gboolean keep_aligned)991 fm_icon_view_set_directory_keep_aligned (FMIconView *icon_view,
992         CajaFile *file,
993         gboolean keep_aligned)
994 {
995     if (!fm_icon_view_supports_keep_aligned (icon_view))
996     {
997         return;
998     }
999 
1000     caja_file_set_boolean_metadata
1001     (file, CAJA_METADATA_KEY_ICON_VIEW_KEEP_ALIGNED,
1002      get_default_directory_keep_aligned (),
1003      keep_aligned);
1004 }
1005 
1006 static gboolean
get_default_directory_lock_icons_position(void)1007 get_default_directory_lock_icons_position (void)
1008 {
1009     return FALSE;
1010 }
1011 
1012 static gboolean
fm_icon_view_get_directory_lock_icons_position(FMIconView * icon_view,CajaFile * file)1013 fm_icon_view_get_directory_lock_icons_position (FMIconView *icon_view,
1014         CajaFile *file)
1015 {
1016     if (!fm_icon_view_supports_manual_layout (icon_view))
1017     {
1018         return FALSE;
1019     }
1020 
1021     return caja_file_get_boolean_metadata
1022             (file,
1023              CAJA_METADATA_KEY_ICON_VIEW_LOCK_ICONS_POSITION,
1024              get_default_directory_lock_icons_position ());
1025 }
1026 
1027 static void
fm_icon_view_set_directory_lock_icons_position(FMIconView * icon_view,CajaFile * file,gboolean lock_icons_position)1028 fm_icon_view_set_directory_lock_icons_position (FMIconView *icon_view,
1029         CajaFile *file,
1030         gboolean lock_icons_position)
1031 {
1032     if (!fm_icon_view_supports_manual_layout (icon_view))
1033     {
1034         return;
1035     }
1036 
1037     caja_file_set_boolean_metadata
1038     (file, CAJA_METADATA_KEY_ICON_VIEW_LOCK_ICONS_POSITION,
1039      get_default_directory_lock_icons_position (),
1040      lock_icons_position);
1041 }
1042 
1043 static gboolean
fm_icon_view_get_directory_auto_layout(FMIconView * icon_view,CajaFile * file)1044 fm_icon_view_get_directory_auto_layout (FMIconView *icon_view,
1045                                         CajaFile *file)
1046 {
1047     if (!fm_icon_view_supports_auto_layout (icon_view))
1048     {
1049         return FALSE;
1050     }
1051 
1052     if (!fm_icon_view_supports_manual_layout (icon_view))
1053     {
1054         return TRUE;
1055     }
1056 
1057     return EEL_CALL_METHOD_WITH_RETURN_VALUE
1058            (FM_ICON_VIEW_CLASS, icon_view,
1059             get_directory_auto_layout, (icon_view, file));
1060 }
1061 
1062 static gboolean
fm_icon_view_real_get_directory_auto_layout(FMIconView * icon_view,CajaFile * file)1063 fm_icon_view_real_get_directory_auto_layout (FMIconView *icon_view,
1064         CajaFile *file)
1065 {
1066 
1067 
1068     return caja_file_get_boolean_metadata
1069            (file, CAJA_METADATA_KEY_ICON_VIEW_AUTO_LAYOUT, TRUE);
1070 }
1071 
1072 static void
fm_icon_view_set_directory_auto_layout(FMIconView * icon_view,CajaFile * file,gboolean auto_layout)1073 fm_icon_view_set_directory_auto_layout (FMIconView *icon_view,
1074                                         CajaFile *file,
1075                                         gboolean auto_layout)
1076 {
1077     if (!fm_icon_view_supports_auto_layout (icon_view) ||
1078             !fm_icon_view_supports_manual_layout (icon_view))
1079     {
1080         return;
1081     }
1082 
1083     EEL_CALL_METHOD (FM_ICON_VIEW_CLASS, icon_view,
1084                      set_directory_auto_layout, (icon_view, file, auto_layout));
1085 }
1086 
1087 static void
fm_icon_view_real_set_directory_auto_layout(FMIconView * icon_view,CajaFile * file,gboolean auto_layout)1088 fm_icon_view_real_set_directory_auto_layout (FMIconView *icon_view,
1089         CajaFile *file,
1090         gboolean auto_layout)
1091 {
1092     if (!fm_icon_view_supports_manual_layout (icon_view))
1093     {
1094         return;
1095     }
1096 
1097     caja_file_set_boolean_metadata
1098     (file, CAJA_METADATA_KEY_ICON_VIEW_AUTO_LAYOUT,
1099      TRUE,
1100      auto_layout);
1101 }
1102 /* maintainence of tighter layout boolean */
1103 
1104 static gboolean
fm_icon_view_get_directory_tighter_layout(FMIconView * icon_view,CajaFile * file)1105 fm_icon_view_get_directory_tighter_layout (FMIconView *icon_view,
1106         CajaFile *file)
1107 {
1108     return EEL_CALL_METHOD_WITH_RETURN_VALUE
1109            (FM_ICON_VIEW_CLASS, icon_view,
1110             get_directory_tighter_layout, (icon_view, file));
1111 }
1112 
1113 static gboolean default_directory_tighter_layout = FALSE;
1114 
1115 static gboolean
get_default_directory_tighter_layout(void)1116 get_default_directory_tighter_layout (void)
1117 {
1118     static gboolean auto_storaged_added = FALSE;
1119 
1120     if (auto_storaged_added == FALSE)
1121     {
1122         auto_storaged_added = TRUE;
1123         eel_g_settings_add_auto_boolean (caja_icon_view_preferences,
1124                                          CAJA_PREFERENCES_ICON_VIEW_DEFAULT_USE_TIGHTER_LAYOUT,
1125                                          &default_directory_tighter_layout);
1126     }
1127 
1128     return default_directory_tighter_layout;
1129 }
1130 
1131 static gboolean
fm_icon_view_real_get_directory_tighter_layout(FMIconView * icon_view,CajaFile * file)1132 fm_icon_view_real_get_directory_tighter_layout (FMIconView *icon_view,
1133         CajaFile *file)
1134 {
1135     if (!fm_icon_view_supports_tighter_layout (icon_view))
1136     {
1137         return FALSE;
1138     }
1139 
1140     return caja_file_get_boolean_metadata
1141            (file,
1142             CAJA_METADATA_KEY_ICON_VIEW_TIGHTER_LAYOUT,
1143             get_default_directory_tighter_layout ());
1144 }
1145 
1146 static void
fm_icon_view_set_directory_tighter_layout(FMIconView * icon_view,CajaFile * file,gboolean tighter_layout)1147 fm_icon_view_set_directory_tighter_layout (FMIconView *icon_view,
1148         CajaFile *file,
1149         gboolean tighter_layout)
1150 {
1151     EEL_CALL_METHOD (FM_ICON_VIEW_CLASS, icon_view,
1152                      set_directory_tighter_layout, (icon_view, file, tighter_layout));
1153 }
1154 
1155 static void
fm_icon_view_real_set_directory_tighter_layout(FMIconView * icon_view,CajaFile * file,gboolean tighter_layout)1156 fm_icon_view_real_set_directory_tighter_layout (FMIconView *icon_view,
1157         CajaFile *file,
1158         gboolean tighter_layout)
1159 {
1160     if (!fm_icon_view_supports_tighter_layout (icon_view))
1161     {
1162         return;
1163     }
1164 
1165     caja_file_set_boolean_metadata
1166     (file, CAJA_METADATA_KEY_ICON_VIEW_TIGHTER_LAYOUT,
1167      get_default_directory_tighter_layout (),
1168      tighter_layout);
1169 }
1170 
1171 static gboolean
real_supports_auto_layout(FMIconView * view)1172 real_supports_auto_layout (FMIconView *view)
1173 {
1174     g_return_val_if_fail (FM_IS_ICON_VIEW (view), FALSE);
1175 
1176     return TRUE;
1177 }
1178 
1179 static gboolean
real_supports_scaling(FMIconView * view)1180 real_supports_scaling (FMIconView *view)
1181 {
1182     g_return_val_if_fail (FM_IS_ICON_VIEW (view), FALSE);
1183 
1184     return FALSE;
1185 }
1186 
1187 static gboolean
real_supports_manual_layout(FMIconView * view)1188 real_supports_manual_layout (FMIconView *view)
1189 {
1190     g_return_val_if_fail (FM_IS_ICON_VIEW (view), FALSE);
1191 
1192     return !fm_icon_view_is_compact (view);
1193 }
1194 
1195 static gboolean
real_supports_keep_aligned(FMIconView * view)1196 real_supports_keep_aligned (FMIconView *view)
1197 {
1198     g_return_val_if_fail (FM_IS_ICON_VIEW (view), FALSE);
1199 
1200     return FALSE;
1201 }
1202 
1203 static gboolean
real_supports_labels_beside_icons(FMIconView * view)1204 real_supports_labels_beside_icons (FMIconView *view)
1205 {
1206     g_return_val_if_fail (FM_IS_ICON_VIEW (view), TRUE);
1207 
1208     return TRUE;
1209 }
1210 
1211 static gboolean
set_sort_reversed(FMIconView * icon_view,gboolean new_value)1212 set_sort_reversed (FMIconView *icon_view, gboolean new_value)
1213 {
1214     if (icon_view->details->sort_reversed == new_value)
1215     {
1216         return FALSE;
1217     }
1218     icon_view->details->sort_reversed = new_value;
1219 
1220     /* Store the new sort setting. */
1221     fm_icon_view_set_directory_sort_reversed (icon_view, fm_directory_view_get_directory_as_file (FM_DIRECTORY_VIEW (icon_view)), new_value);
1222 
1223     /* Update the layout menus to match the new sort-order setting. */
1224     update_layout_menus (icon_view);
1225 
1226     return TRUE;
1227 }
1228 
1229 static const SortCriterion *
get_sort_criterion_by_metadata_text(const char * metadata_text)1230 get_sort_criterion_by_metadata_text (const char *metadata_text)
1231 {
1232     guint i;
1233 
1234     /* Figure out what the new sort setting should be. */
1235     for (i = 0; i < G_N_ELEMENTS (sort_criteria); i++)
1236     {
1237         if (g_strcmp0 (sort_criteria[i].metadata_text, metadata_text) == 0)
1238         {
1239             return &sort_criteria[i];
1240         }
1241     }
1242     return NULL;
1243 }
1244 
1245 static const SortCriterion *
get_sort_criterion_by_sort_type(CajaFileSortType sort_type)1246 get_sort_criterion_by_sort_type (CajaFileSortType sort_type)
1247 {
1248     guint i;
1249 
1250     /* Figure out what the new sort setting should be. */
1251     for (i = 0; i < G_N_ELEMENTS (sort_criteria); i++)
1252     {
1253         if (sort_type == sort_criteria[i].sort_type)
1254         {
1255             return &sort_criteria[i];
1256         }
1257     }
1258 
1259     return NULL;
1260 }
1261 
1262 static CajaZoomLevel default_zoom_level = CAJA_ZOOM_LEVEL_STANDARD;
1263 static CajaZoomLevel default_compact_zoom_level = CAJA_ZOOM_LEVEL_STANDARD;
1264 #define DEFAULT_ZOOM_LEVEL(icon_view) icon_view->details->compact ? default_compact_zoom_level : default_zoom_level
1265 
1266 static CajaZoomLevel
get_default_zoom_level(FMIconView * icon_view)1267 get_default_zoom_level (FMIconView *icon_view)
1268 {
1269     static gboolean auto_storage_added = FALSE;
1270 
1271     if (!auto_storage_added)
1272     {
1273         auto_storage_added = TRUE;
1274         eel_g_settings_add_auto_enum (caja_icon_view_preferences,
1275                                       CAJA_PREFERENCES_ICON_VIEW_DEFAULT_ZOOM_LEVEL,
1276                                       (int *) &default_zoom_level);
1277         eel_g_settings_add_auto_enum (caja_compact_view_preferences,
1278                                       CAJA_PREFERENCES_COMPACT_VIEW_DEFAULT_ZOOM_LEVEL,
1279                                       (int *) &default_compact_zoom_level);
1280     }
1281 
1282     return MIN (DEFAULT_ZOOM_LEVEL(icon_view), CAJA_ZOOM_LEVEL_LARGEST);
1283 }
1284 
1285 static void
set_labels_beside_icons(FMIconView * icon_view)1286 set_labels_beside_icons (FMIconView *icon_view)
1287 {
1288     gboolean labels_beside;
1289 
1290     if (fm_icon_view_supports_labels_beside_icons (icon_view))
1291     {
1292         labels_beside = fm_icon_view_is_compact (icon_view) ||
1293                         g_settings_get_boolean (caja_icon_view_preferences, CAJA_PREFERENCES_ICON_VIEW_LABELS_BESIDE_ICONS);
1294 
1295         if (labels_beside)
1296         {
1297             caja_icon_container_set_label_position
1298             (get_icon_container (icon_view),
1299              CAJA_ICON_LABEL_POSITION_BESIDE);
1300         }
1301         else
1302         {
1303             caja_icon_container_set_label_position
1304             (get_icon_container (icon_view),
1305              CAJA_ICON_LABEL_POSITION_UNDER);
1306         }
1307     }
1308 }
1309 
1310 static void
set_columns_same_width(FMIconView * icon_view)1311 set_columns_same_width (FMIconView *icon_view)
1312 {
1313     gboolean all_columns_same_width;
1314 
1315     if (fm_icon_view_is_compact (icon_view))
1316     {
1317         all_columns_same_width = g_settings_get_boolean (caja_compact_view_preferences, CAJA_PREFERENCES_COMPACT_VIEW_ALL_COLUMNS_SAME_WIDTH);
1318         caja_icon_container_set_all_columns_same_width (get_icon_container (icon_view), all_columns_same_width);
1319     }
1320 }
1321 
1322 static void
fm_icon_view_begin_loading(FMDirectoryView * view)1323 fm_icon_view_begin_loading (FMDirectoryView *view)
1324 {
1325     FMIconView *icon_view;
1326     GtkWidget *icon_container;
1327     CajaFile *file;
1328     char *sort_name;
1329 
1330     g_return_if_fail (FM_IS_ICON_VIEW (view));
1331 
1332     icon_view = FM_ICON_VIEW (view);
1333     file = fm_directory_view_get_directory_as_file (view);
1334     icon_container = GTK_WIDGET (get_icon_container (icon_view));
1335 
1336     caja_icon_container_begin_loading (CAJA_ICON_CONTAINER (icon_container));
1337 
1338     caja_icon_container_set_allow_moves (CAJA_ICON_CONTAINER (icon_container),
1339                                          fm_directory_view_get_allow_moves (view));
1340 
1341     /* kill any sound preview process that is ongoing */
1342     preview_audio (icon_view, NULL, FALSE);
1343     /* FIXME bugzilla.gnome.org 45060: Should use methods instead
1344      * of hardcoding desktop knowledge in here.
1345      */
1346     if (FM_IS_DESKTOP_ICON_VIEW (view))
1347     {
1348         caja_connect_desktop_background_to_settings (CAJA_ICON_CONTAINER (icon_container));
1349     }
1350     else
1351     {
1352         GdkDragAction default_action;
1353 
1354         if (caja_window_info_get_window_type (fm_directory_view_get_caja_window (view)) == CAJA_WINDOW_NAVIGATION)
1355         {
1356             default_action = CAJA_DND_ACTION_SET_AS_GLOBAL_BACKGROUND;
1357         }
1358         else
1359         {
1360             default_action = CAJA_DND_ACTION_SET_AS_FOLDER_BACKGROUND;
1361         }
1362 
1363         caja_connect_background_to_file_metadata (icon_container, file, default_action);
1364     }
1365 
1366     /* Set up the zoom level from the metadata. */
1367     if (fm_directory_view_supports_zooming (FM_DIRECTORY_VIEW (icon_view)))
1368     {
1369         int level;
1370 
1371         if (icon_view->details->compact)
1372         {
1373             level = caja_file_get_integer_metadata
1374                     (file,
1375                      CAJA_METADATA_KEY_COMPACT_VIEW_ZOOM_LEVEL,
1376                      get_default_zoom_level (icon_view));
1377         }
1378         else
1379         {
1380             level = caja_file_get_integer_metadata
1381                     (file,
1382                      CAJA_METADATA_KEY_ICON_VIEW_ZOOM_LEVEL,
1383                      get_default_zoom_level (icon_view));
1384         }
1385 
1386         fm_icon_view_set_zoom_level (icon_view, level, TRUE);
1387     }
1388 
1389     /* Set the sort mode.
1390      * It's OK not to resort the icons because the
1391      * container doesn't have any icons at this point.
1392      */
1393     sort_name = fm_icon_view_get_directory_sort_by (icon_view, file);
1394     set_sort_criterion (icon_view, get_sort_criterion_by_metadata_text (sort_name));
1395     g_free (sort_name);
1396 
1397     /* Set the sort direction from the metadata. */
1398     set_sort_reversed (icon_view, fm_icon_view_get_directory_sort_reversed (icon_view, file));
1399 
1400     caja_icon_container_set_keep_aligned
1401     (get_icon_container (icon_view),
1402      fm_icon_view_get_directory_keep_aligned (icon_view, file));
1403     caja_icon_container_set_lock_icons_position
1404     (get_icon_container (icon_view),
1405      fm_icon_view_get_directory_lock_icons_position (icon_view, file));
1406     caja_icon_container_set_tighter_layout
1407     (get_icon_container (icon_view),
1408      fm_icon_view_get_directory_tighter_layout (icon_view, file));
1409 
1410     set_labels_beside_icons (icon_view);
1411     set_columns_same_width (icon_view);
1412 
1413     /* We must set auto-layout last, because it invokes the layout_changed
1414      * callback, which works incorrectly if the other layout criteria are
1415      * not already set up properly (see bug 6500, e.g.)
1416      */
1417     caja_icon_container_set_auto_layout
1418     (get_icon_container (icon_view),
1419      fm_icon_view_get_directory_auto_layout (icon_view, file));
1420 
1421     /* e.g. keep aligned may have changed */
1422     update_layout_menus (icon_view);
1423 }
1424 
1425 static void
icon_view_notify_clipboard_info(CajaClipboardMonitor * monitor,CajaClipboardInfo * info,FMIconView * icon_view)1426 icon_view_notify_clipboard_info (CajaClipboardMonitor *monitor,
1427                                  CajaClipboardInfo *info,
1428                                  FMIconView *icon_view)
1429 {
1430     GList *icon_data;
1431 
1432     icon_data = NULL;
1433     if (info && info->cut)
1434     {
1435         icon_data = info->files;
1436     }
1437 
1438     caja_icon_container_set_highlighted_for_clipboard (
1439         get_icon_container (icon_view), icon_data);
1440 }
1441 
1442 static void
fm_icon_view_end_loading(FMDirectoryView * view,gboolean all_files_seen)1443 fm_icon_view_end_loading (FMDirectoryView *view,
1444                           gboolean all_files_seen)
1445 {
1446     FMIconView *icon_view;
1447     GtkWidget *icon_container;
1448     CajaClipboardMonitor *monitor;
1449     CajaClipboardInfo *info;
1450 
1451     icon_view = FM_ICON_VIEW (view);
1452 
1453     icon_container = GTK_WIDGET (get_icon_container (icon_view));
1454     caja_icon_container_end_loading (CAJA_ICON_CONTAINER (icon_container), all_files_seen);
1455 
1456     monitor = caja_clipboard_monitor_get ();
1457     info = caja_clipboard_monitor_get_clipboard_info (monitor);
1458 
1459     icon_view_notify_clipboard_info (monitor, info, icon_view);
1460 }
1461 
1462 static CajaZoomLevel
fm_icon_view_get_zoom_level(FMDirectoryView * view)1463 fm_icon_view_get_zoom_level (FMDirectoryView *view)
1464 {
1465     g_return_val_if_fail (FM_IS_ICON_VIEW (view), CAJA_ZOOM_LEVEL_STANDARD);
1466 
1467     return caja_icon_container_get_zoom_level (get_icon_container (FM_ICON_VIEW (view)));
1468 }
1469 
1470 static void
fm_icon_view_set_zoom_level(FMIconView * view,CajaZoomLevel new_level,gboolean always_emit)1471 fm_icon_view_set_zoom_level (FMIconView *view,
1472                              CajaZoomLevel new_level,
1473                              gboolean always_emit)
1474 {
1475     CajaIconContainer *icon_container;
1476 
1477     g_return_if_fail (FM_IS_ICON_VIEW (view));
1478     g_return_if_fail (new_level >= CAJA_ZOOM_LEVEL_SMALLEST &&
1479                       new_level <= CAJA_ZOOM_LEVEL_LARGEST);
1480 
1481     icon_container = get_icon_container (view);
1482     if (caja_icon_container_get_zoom_level (icon_container) == new_level)
1483     {
1484         if (always_emit)
1485         {
1486             g_signal_emit_by_name (view, "zoom_level_changed");
1487         }
1488         return;
1489     }
1490 
1491     if (view->details->compact)
1492     {
1493         caja_file_set_integer_metadata
1494         (fm_directory_view_get_directory_as_file (FM_DIRECTORY_VIEW (view)),
1495          CAJA_METADATA_KEY_COMPACT_VIEW_ZOOM_LEVEL,
1496          get_default_zoom_level (view),
1497          new_level);
1498     }
1499     else
1500     {
1501         caja_file_set_integer_metadata
1502         (fm_directory_view_get_directory_as_file (FM_DIRECTORY_VIEW (view)),
1503          CAJA_METADATA_KEY_ICON_VIEW_ZOOM_LEVEL,
1504          get_default_zoom_level (view),
1505          new_level);
1506     }
1507 
1508     caja_icon_container_set_zoom_level (icon_container, new_level);
1509 
1510     g_signal_emit_by_name (view, "zoom_level_changed");
1511 
1512     if (fm_directory_view_get_active (FM_DIRECTORY_VIEW (view)))
1513     {
1514         fm_directory_view_update_menus (FM_DIRECTORY_VIEW (view));
1515     }
1516 }
1517 
1518 static void
fm_icon_view_bump_zoom_level(FMDirectoryView * view,int zoom_increment)1519 fm_icon_view_bump_zoom_level (FMDirectoryView *view, int zoom_increment)
1520 {
1521     CajaZoomLevel new_level;
1522 
1523     g_return_if_fail (FM_IS_ICON_VIEW (view));
1524 
1525     new_level = fm_icon_view_get_zoom_level (view) + zoom_increment;
1526 
1527     if (new_level >= CAJA_ZOOM_LEVEL_SMALLEST &&
1528             new_level <= CAJA_ZOOM_LEVEL_LARGEST)
1529     {
1530         fm_directory_view_zoom_to_level (view, new_level);
1531     }
1532 }
1533 
1534 static void
fm_icon_view_zoom_to_level(FMDirectoryView * view,CajaZoomLevel zoom_level)1535 fm_icon_view_zoom_to_level (FMDirectoryView *view,
1536                             CajaZoomLevel zoom_level)
1537 {
1538     FMIconView *icon_view;
1539 
1540     g_assert (FM_IS_ICON_VIEW (view));
1541 
1542     icon_view = FM_ICON_VIEW (view);
1543     fm_icon_view_set_zoom_level (icon_view, zoom_level, FALSE);
1544 }
1545 
1546 static void
fm_icon_view_restore_default_zoom_level(FMDirectoryView * view)1547 fm_icon_view_restore_default_zoom_level (FMDirectoryView *view)
1548 {
1549     FMIconView *icon_view;
1550 
1551     g_return_if_fail (FM_IS_ICON_VIEW (view));
1552 
1553     icon_view = FM_ICON_VIEW (view);
1554     fm_directory_view_zoom_to_level
1555     (view, get_default_zoom_level (icon_view));
1556 }
1557 
1558 static gboolean
fm_icon_view_can_zoom_in(FMDirectoryView * view)1559 fm_icon_view_can_zoom_in (FMDirectoryView *view)
1560 {
1561     g_return_val_if_fail (FM_IS_ICON_VIEW (view), FALSE);
1562 
1563     return fm_icon_view_get_zoom_level (view)
1564            < CAJA_ZOOM_LEVEL_LARGEST;
1565 }
1566 
1567 static gboolean
fm_icon_view_can_zoom_out(FMDirectoryView * view)1568 fm_icon_view_can_zoom_out (FMDirectoryView *view)
1569 {
1570     g_return_val_if_fail (FM_IS_ICON_VIEW (view), FALSE);
1571 
1572     return fm_icon_view_get_zoom_level (view)
1573            > CAJA_ZOOM_LEVEL_SMALLEST;
1574 }
1575 
1576 static GtkWidget *
fm_icon_view_get_background_widget(FMDirectoryView * view)1577 fm_icon_view_get_background_widget (FMDirectoryView *view)
1578 {
1579     g_return_val_if_fail (FM_IS_ICON_VIEW (view), NULL);
1580 
1581     return GTK_WIDGET (get_icon_container (FM_ICON_VIEW (view)));
1582 }
1583 
1584 static gboolean
fm_icon_view_is_empty(FMDirectoryView * view)1585 fm_icon_view_is_empty (FMDirectoryView *view)
1586 {
1587     g_assert (FM_IS_ICON_VIEW (view));
1588 
1589     return caja_icon_container_is_empty
1590            (get_icon_container (FM_ICON_VIEW (view)));
1591 }
1592 
1593 static GList *
fm_icon_view_get_selection(FMDirectoryView * view)1594 fm_icon_view_get_selection (FMDirectoryView *view)
1595 {
1596     GList *list;
1597 
1598     g_return_val_if_fail (FM_IS_ICON_VIEW (view), NULL);
1599 
1600     list = caja_icon_container_get_selection
1601            (get_icon_container (FM_ICON_VIEW (view)));
1602     caja_file_list_ref (list);
1603     return list;
1604 }
1605 
1606 static void
count_item(CajaIconData * icon_data,gpointer callback_data)1607 count_item (CajaIconData *icon_data,
1608             gpointer callback_data)
1609 {
1610     guint *count;
1611 
1612     count = callback_data;
1613     (*count)++;
1614 }
1615 
1616 static guint
fm_icon_view_get_item_count(FMDirectoryView * view)1617 fm_icon_view_get_item_count (FMDirectoryView *view)
1618 {
1619     guint count;
1620 
1621     g_return_val_if_fail (FM_IS_ICON_VIEW (view), 0);
1622 
1623     count = 0;
1624 
1625     caja_icon_container_for_each
1626     (get_icon_container (FM_ICON_VIEW (view)),
1627      count_item, &count);
1628 
1629     return count;
1630 }
1631 
1632 static void
set_sort_criterion_by_sort_type(FMIconView * icon_view,CajaFileSortType sort_type)1633 set_sort_criterion_by_sort_type (FMIconView *icon_view,
1634                                  CajaFileSortType  sort_type)
1635 {
1636     const SortCriterion *sort;
1637 
1638     g_assert (FM_IS_ICON_VIEW (icon_view));
1639 
1640     sort = get_sort_criterion_by_sort_type (sort_type);
1641     g_return_if_fail (sort != NULL);
1642 
1643     if (sort == icon_view->details->sort
1644             && fm_icon_view_using_auto_layout (icon_view))
1645     {
1646         return;
1647     }
1648 
1649     set_sort_criterion (icon_view, sort);
1650     caja_icon_container_sort (get_icon_container (icon_view));
1651     fm_icon_view_reveal_selection (FM_DIRECTORY_VIEW (icon_view));
1652 }
1653 
1654 
1655 static void
action_reversed_order_callback(GtkAction * action,gpointer user_data)1656 action_reversed_order_callback (GtkAction *action,
1657                                 gpointer user_data)
1658 {
1659     FMIconView *icon_view;
1660 
1661     icon_view = FM_ICON_VIEW (user_data);
1662 
1663     G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1664     if (set_sort_reversed (icon_view,
1665                            gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))))
1666     {
1667         caja_icon_container_sort (get_icon_container (icon_view));
1668         fm_icon_view_reveal_selection (FM_DIRECTORY_VIEW (icon_view));
1669     }
1670     G_GNUC_END_IGNORE_DEPRECATIONS;
1671 }
1672 
1673 static void
action_keep_aligned_callback(GtkAction * action,gpointer user_data)1674 action_keep_aligned_callback (GtkAction *action,
1675                               gpointer user_data)
1676 {
1677     FMIconView *icon_view;
1678     CajaFile *file;
1679     gboolean keep_aligned;
1680 
1681     icon_view = FM_ICON_VIEW (user_data);
1682 
1683     G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1684     keep_aligned = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
1685     G_GNUC_END_IGNORE_DEPRECATIONS;
1686 
1687     file = fm_directory_view_get_directory_as_file (FM_DIRECTORY_VIEW (icon_view));
1688     fm_icon_view_set_directory_keep_aligned (icon_view,
1689             file,
1690             keep_aligned);
1691 
1692     caja_icon_container_set_keep_aligned (get_icon_container (icon_view),
1693                                           keep_aligned);
1694 }
1695 
1696 static void
action_lock_icons_position_callback(GtkAction * action,gpointer user_data)1697 action_lock_icons_position_callback (GtkAction *action,
1698                                      gpointer user_data)
1699 {
1700     FMIconView *icon_view;
1701     CajaFile *file;
1702     gboolean lock_icons_position;
1703 
1704     icon_view = FM_ICON_VIEW (user_data);
1705 
1706     lock_icons_position = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
1707 
1708     file = fm_directory_view_get_directory_as_file (FM_DIRECTORY_VIEW (icon_view));
1709     fm_icon_view_set_directory_lock_icons_position (icon_view,
1710             file,
1711             lock_icons_position);
1712 
1713     caja_icon_container_set_lock_icons_position (get_icon_container (icon_view),
1714                                                  lock_icons_position);
1715 }
1716 
1717 static void
switch_to_manual_layout(FMIconView * icon_view)1718 switch_to_manual_layout (FMIconView *icon_view)
1719 {
1720     if (!fm_icon_view_using_auto_layout (icon_view))
1721     {
1722         return;
1723     }
1724 
1725     icon_view->details->sort = &sort_criteria[0];
1726 
1727     caja_icon_container_set_auto_layout
1728     (get_icon_container (icon_view), FALSE);
1729 }
1730 
1731 static void
layout_changed_callback(CajaIconContainer * container,FMIconView * icon_view)1732 layout_changed_callback (CajaIconContainer *container,
1733                          FMIconView *icon_view)
1734 {
1735     CajaFile *file;
1736 
1737     g_assert (FM_IS_ICON_VIEW (icon_view));
1738     g_assert (container == get_icon_container (icon_view));
1739 
1740     file = fm_directory_view_get_directory_as_file (FM_DIRECTORY_VIEW (icon_view));
1741 
1742     if (file != NULL)
1743     {
1744         fm_icon_view_set_directory_auto_layout
1745         (icon_view,
1746          file,
1747          fm_icon_view_using_auto_layout (icon_view));
1748         fm_icon_view_set_directory_tighter_layout
1749         (icon_view,
1750          file,
1751          fm_icon_view_using_tighter_layout (icon_view));
1752     }
1753 
1754     update_layout_menus (icon_view);
1755 }
1756 
1757 static gboolean
fm_icon_view_can_rename_file(FMDirectoryView * view,CajaFile * file)1758 fm_icon_view_can_rename_file (FMDirectoryView *view, CajaFile *file)
1759 {
1760     if (!(fm_icon_view_get_zoom_level (view) > CAJA_ZOOM_LEVEL_SMALLEST))
1761     {
1762         return FALSE;
1763     }
1764 
1765     return FM_DIRECTORY_VIEW_CLASS(fm_icon_view_parent_class)->can_rename_file (view, file);
1766 }
1767 
1768 static void
fm_icon_view_start_renaming_file(FMDirectoryView * view,CajaFile * file,gboolean select_all)1769 fm_icon_view_start_renaming_file (FMDirectoryView *view,
1770                                   CajaFile *file,
1771                                   gboolean select_all)
1772 {
1773     /* call parent class to make sure the right icon is selected */
1774     FM_DIRECTORY_VIEW_CLASS(fm_icon_view_parent_class)->start_renaming_file (view, file, select_all);
1775 
1776     /* start renaming */
1777     caja_icon_container_start_renaming_selected_item
1778     (get_icon_container (FM_ICON_VIEW (view)), select_all);
1779 }
1780 
1781 static const GtkActionEntry icon_view_entries[] =
1782 {
1783     /* name, stock id, label */  { "Arrange Items", NULL, N_("Arran_ge Items"),
1784                                    NULL, NULL, NULL },
1785     /* name, stock id */         { "Stretch", NULL,
1786     /* label, accelerator */       N_("Resize Icon..."), NULL,
1787     /* tooltip */                  N_("Make the selected icon resizable"),
1788                                    G_CALLBACK (action_stretch_callback) },
1789     /* name, stock id */         { "Unstretch", NULL,
1790     /* label, accelerator */       N_("Restore Icons' Original Si_zes"), NULL,
1791     /* tooltip */                  N_("Restore each selected icon to its original size"),
1792                                    G_CALLBACK (action_unstretch_callback) },
1793     /* name, stock id */         { "Clean Up", NULL,
1794     /* label, accelerator */       N_("_Organize by Name"), NULL,
1795     /* tooltip */                  N_("Reposition icons to better fit in the window and avoid overlapping"),
1796                                    G_CALLBACK (action_clean_up_callback) },
1797 };
1798 
1799 static const GtkToggleActionEntry icon_view_toggle_entries[] =
1800 {
1801     /* name, stock id */      { "Tighter Layout", NULL,
1802         /* label, accelerator */    N_("Compact _Layout"), NULL,
1803         /* tooltip */               N_("Toggle using a tighter layout scheme"),
1804         G_CALLBACK (action_tighter_layout_callback),
1805         0
1806     },
1807     /* name, stock id */      { "Reversed Order", NULL,
1808         /* label, accelerator */    N_("Re_versed Order"), NULL,
1809         /* tooltip */               N_("Display icons in the opposite order"),
1810         G_CALLBACK (action_reversed_order_callback),
1811         0
1812     },
1813     /* name, stock id */      { "Keep Aligned", NULL,
1814         /* label, accelerator */    N_("_Keep Aligned"), NULL,
1815         /* tooltip */               N_("Keep icons lined up on a grid"),
1816         G_CALLBACK (action_keep_aligned_callback),
1817         0
1818     },
1819     /* name, stock id */      { "Lock Icons Position", NULL,
1820         /* label, accelerator */    N_("_Lock Icons Position"), NULL,
1821         /* tooltip */               N_("Prevent repositioning icons"),
1822         G_CALLBACK (action_lock_icons_position_callback),
1823         0
1824     },
1825 };
1826 
1827 static const GtkRadioActionEntry arrange_radio_entries[] =
1828 {
1829     {
1830         "Manual Layout", NULL,
1831         N_("_Manually"), NULL,
1832         N_("Leave icons wherever they are dropped"),
1833         CAJA_FILE_SORT_NONE
1834     },
1835     {
1836         "Sort by Name", NULL,
1837         N_("By _Name"), NULL,
1838         N_("Keep icons sorted by name in rows"),
1839         CAJA_FILE_SORT_BY_DISPLAY_NAME
1840     },
1841     {
1842         "Sort by Size", NULL,
1843         N_("By _Size"), NULL,
1844         N_("Keep icons sorted by size in rows"),
1845         CAJA_FILE_SORT_BY_SIZE
1846     },
1847     {
1848         "Sort by Size on Disk", NULL,
1849         N_("By S_ize on Disk"), NULL,
1850         N_("Keep icons sorted by disk usage in rows"),
1851         CAJA_FILE_SORT_BY_SIZE_ON_DISK
1852     },
1853     {
1854         "Sort by Type", NULL,
1855         N_("By _Type"), NULL,
1856         N_("Keep icons sorted by type in rows"),
1857         CAJA_FILE_SORT_BY_TYPE
1858     },
1859     {
1860         "Sort by Modification Date", NULL,
1861         N_("By Modification _Date"), NULL,
1862         N_("Keep icons sorted by modification date in rows"),
1863         CAJA_FILE_SORT_BY_MTIME
1864     },
1865     {
1866         "Sort by Creation Date", NULL,
1867         N_("By _Creation Date"), NULL,
1868         N_("Keep icons sorted by creation date in rows"),
1869         CAJA_FILE_SORT_BY_BTIME
1870     },
1871     {
1872         "Sort by Emblems", NULL,
1873         N_("By _Emblems"), NULL,
1874         N_("Keep icons sorted by emblems in rows"),
1875         CAJA_FILE_SORT_BY_EMBLEMS
1876     },
1877     {
1878         "Sort by Trash Time", NULL,
1879         N_("By T_rash Time"), NULL,
1880         N_("Keep icons sorted by trash time in rows"),
1881         CAJA_FILE_SORT_BY_TRASHED_TIME
1882     },
1883     {
1884         "Sort by Extension", NULL,
1885         N_("By E_xtension"), NULL,
1886         N_("Keep icons sorted by reverse extension segments in rows"),
1887         CAJA_FILE_SORT_BY_EXTENSION
1888     },
1889 };
1890 
1891 static void
fm_icon_view_merge_menus(FMDirectoryView * view)1892 fm_icon_view_merge_menus (FMDirectoryView *view)
1893 {
1894     FMIconView *icon_view;
1895     GtkUIManager *ui_manager;
1896     GtkActionGroup *action_group;
1897     const char *ui;
1898 
1899     g_assert (FM_IS_ICON_VIEW (view));
1900 
1901     FM_DIRECTORY_VIEW_CLASS (fm_icon_view_parent_class)->merge_menus (view);
1902 
1903     icon_view = FM_ICON_VIEW (view);
1904 
1905     ui_manager = fm_directory_view_get_ui_manager (FM_DIRECTORY_VIEW (icon_view));
1906 
1907     G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1908     action_group = gtk_action_group_new ("IconViewActions");
1909 #ifdef ENABLE_NLS
1910     gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1911 #endif /* ENABLE_NLS */
1912     icon_view->details->icon_action_group = action_group;
1913     gtk_action_group_add_actions (action_group,
1914                                   icon_view_entries, G_N_ELEMENTS (icon_view_entries),
1915                                   icon_view);
1916     gtk_action_group_add_toggle_actions (action_group,
1917                                          icon_view_toggle_entries, G_N_ELEMENTS (icon_view_toggle_entries),
1918                                          icon_view);
1919     gtk_action_group_add_radio_actions (action_group,
1920                                         arrange_radio_entries,
1921                                         G_N_ELEMENTS (arrange_radio_entries),
1922                                         -1,
1923                                         G_CALLBACK (action_sort_radio_callback),
1924                                         icon_view);
1925     G_GNUC_END_IGNORE_DEPRECATIONS;
1926 
1927     gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
1928     g_object_unref (action_group); /* owned by ui manager */
1929 
1930     ui = caja_ui_string_get ("caja-icon-view-ui.xml");
1931     icon_view->details->icon_merge_id =
1932         gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, NULL);
1933 
1934     /* Do one-time state-setting here; context-dependent state-setting
1935      * is done in update_menus.
1936      */
1937     if (!fm_icon_view_supports_auto_layout (icon_view))
1938     {
1939         GtkAction *action;
1940 
1941         G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1942         action = gtk_action_group_get_action (action_group,
1943                                               FM_ACTION_ARRANGE_ITEMS);
1944         gtk_action_set_visible (action, FALSE);
1945         G_GNUC_END_IGNORE_DEPRECATIONS;
1946     }
1947 
1948     if (fm_icon_view_supports_scaling (icon_view))
1949     {
1950         gtk_ui_manager_add_ui (ui_manager,
1951                                icon_view->details->icon_merge_id,
1952                                POPUP_PATH_ICON_APPEARANCE,
1953                                FM_ACTION_STRETCH,
1954                                FM_ACTION_STRETCH,
1955                                GTK_UI_MANAGER_MENUITEM,
1956                                FALSE);
1957         gtk_ui_manager_add_ui (ui_manager,
1958                                icon_view->details->icon_merge_id,
1959                                POPUP_PATH_ICON_APPEARANCE,
1960                                FM_ACTION_UNSTRETCH,
1961                                FM_ACTION_UNSTRETCH,
1962                                GTK_UI_MANAGER_MENUITEM,
1963                                FALSE);
1964     }
1965 
1966     update_layout_menus (icon_view);
1967 }
1968 
1969 static void
fm_icon_view_unmerge_menus(FMDirectoryView * view)1970 fm_icon_view_unmerge_menus (FMDirectoryView *view)
1971 {
1972     FMIconView *icon_view;
1973     GtkUIManager *ui_manager;
1974 
1975     icon_view = FM_ICON_VIEW (view);
1976 
1977     FM_DIRECTORY_VIEW_CLASS (fm_icon_view_parent_class)->unmerge_menus (view);
1978 
1979     ui_manager = fm_directory_view_get_ui_manager (view);
1980     if (ui_manager != NULL)
1981     {
1982         caja_ui_unmerge_ui (ui_manager,
1983                             &icon_view->details->icon_merge_id,
1984                             &icon_view->details->icon_action_group);
1985     }
1986 }
1987 
1988 static void
fm_icon_view_update_menus(FMDirectoryView * view)1989 fm_icon_view_update_menus (FMDirectoryView *view)
1990 {
1991     FMIconView *icon_view;
1992     GList *selection;
1993     int selection_count;
1994     GtkAction *action;
1995     CajaIconContainer *icon_container;
1996     gboolean editable;
1997 
1998     icon_view = FM_ICON_VIEW (view);
1999 
2000     FM_DIRECTORY_VIEW_CLASS (fm_icon_view_parent_class)->update_menus(view);
2001 
2002     selection = fm_directory_view_get_selection (view);
2003     selection_count = g_list_length (selection);
2004     icon_container = get_icon_container (icon_view);
2005 
2006     G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
2007     action = gtk_action_group_get_action (icon_view->details->icon_action_group,
2008                                           FM_ACTION_STRETCH);
2009     gtk_action_set_sensitive (action,
2010                               selection_count == 1
2011                               && icon_container != NULL
2012                               && !caja_icon_container_has_stretch_handles (icon_container));
2013 
2014     gtk_action_set_visible (action,
2015                             fm_icon_view_supports_scaling (icon_view));
2016 
2017     action = gtk_action_group_get_action (icon_view->details->icon_action_group,
2018                                           FM_ACTION_UNSTRETCH);
2019     g_object_set (action, "label",
2020                   eel_g_list_more_than_one_item (selection)
2021                   ? _("Restore Icons' Original Si_zes")
2022                   : _("Restore Icon's Original Si_ze"),
2023                   NULL);
2024     gtk_action_set_sensitive (action,
2025                               icon_container != NULL
2026                               && caja_icon_container_is_stretched (icon_container));
2027 
2028     gtk_action_set_visible (action,
2029                             fm_icon_view_supports_scaling (icon_view));
2030 
2031     caja_file_list_free (selection);
2032 
2033     editable = fm_directory_view_is_editable (view);
2034     action = gtk_action_group_get_action (icon_view->details->icon_action_group,
2035                                           FM_ACTION_MANUAL_LAYOUT);
2036     gtk_action_set_sensitive (action, editable);
2037     G_GNUC_END_IGNORE_DEPRECATIONS;
2038 }
2039 
2040 static void
fm_icon_view_reset_to_defaults(FMDirectoryView * view)2041 fm_icon_view_reset_to_defaults (FMDirectoryView *view)
2042 {
2043     CajaIconContainer *icon_container;
2044     FMIconView *icon_view;
2045 
2046     icon_view = FM_ICON_VIEW (view);
2047     icon_container = get_icon_container (icon_view);
2048 
2049     clear_sort_criterion (icon_view);
2050     caja_icon_container_set_keep_aligned
2051     (icon_container, get_default_directory_keep_aligned ());
2052     caja_icon_container_set_lock_icons_position
2053     (icon_container, get_default_directory_lock_icons_position ());
2054     caja_icon_container_set_tighter_layout
2055     (icon_container, get_default_directory_tighter_layout ());
2056 
2057     caja_icon_container_sort (icon_container);
2058 
2059     update_layout_menus (icon_view);
2060 
2061     fm_icon_view_restore_default_zoom_level (view);
2062 }
2063 
2064 static void
fm_icon_view_select_all(FMDirectoryView * view)2065 fm_icon_view_select_all (FMDirectoryView *view)
2066 {
2067     CajaIconContainer *icon_container;
2068 
2069     g_return_if_fail (FM_IS_ICON_VIEW (view));
2070 
2071     icon_container = get_icon_container (FM_ICON_VIEW (view));
2072     caja_icon_container_select_all (icon_container);
2073 }
2074 
2075 static void
fm_icon_view_reveal_selection(FMDirectoryView * view)2076 fm_icon_view_reveal_selection (FMDirectoryView *view)
2077 {
2078     GList *selection;
2079 
2080     g_return_if_fail (FM_IS_ICON_VIEW (view));
2081 
2082     selection = fm_directory_view_get_selection (view);
2083 
2084     /* Make sure at least one of the selected items is scrolled into view */
2085     if (selection != NULL)
2086     {
2087         caja_icon_container_reveal
2088         (get_icon_container (FM_ICON_VIEW (view)),
2089          selection->data);
2090     }
2091 
2092     caja_file_list_free (selection);
2093 }
2094 
2095 static GArray *
fm_icon_view_get_selected_icon_locations(FMDirectoryView * view)2096 fm_icon_view_get_selected_icon_locations (FMDirectoryView *view)
2097 {
2098     g_return_val_if_fail (FM_IS_ICON_VIEW (view), NULL);
2099 
2100     return caja_icon_container_get_selected_icon_locations
2101            (get_icon_container (FM_ICON_VIEW (view)));
2102 }
2103 
2104 
2105 static void
fm_icon_view_set_selection(FMDirectoryView * view,GList * selection)2106 fm_icon_view_set_selection (FMDirectoryView *view, GList *selection)
2107 {
2108     g_return_if_fail (FM_IS_ICON_VIEW (view));
2109 
2110     caja_icon_container_set_selection
2111     (get_icon_container (FM_ICON_VIEW (view)), selection);
2112 }
2113 
2114 static void
fm_icon_view_invert_selection(FMDirectoryView * view)2115 fm_icon_view_invert_selection (FMDirectoryView *view)
2116 {
2117     g_return_if_fail (FM_IS_ICON_VIEW (view));
2118 
2119     caja_icon_container_invert_selection
2120     (get_icon_container (FM_ICON_VIEW (view)));
2121 }
2122 
2123 static gboolean
fm_icon_view_using_manual_layout(FMDirectoryView * view)2124 fm_icon_view_using_manual_layout (FMDirectoryView *view)
2125 {
2126     g_return_val_if_fail (FM_IS_ICON_VIEW (view), FALSE);
2127 
2128     return !fm_icon_view_using_auto_layout (FM_ICON_VIEW (view));
2129 }
2130 
2131 static void
fm_icon_view_widget_to_file_operation_position(FMDirectoryView * view,GdkPoint * position)2132 fm_icon_view_widget_to_file_operation_position (FMDirectoryView *view,
2133         GdkPoint *position)
2134 {
2135     g_assert (FM_IS_ICON_VIEW (view));
2136 
2137     caja_icon_container_widget_to_file_operation_position
2138     (get_icon_container (FM_ICON_VIEW (view)), position);
2139 }
2140 
2141 static void
icon_container_activate_callback(CajaIconContainer * container,GList * file_list,FMIconView * icon_view)2142 icon_container_activate_callback (CajaIconContainer *container,
2143                                   GList *file_list,
2144                                   FMIconView *icon_view)
2145 {
2146     g_assert (FM_IS_ICON_VIEW (icon_view));
2147     g_assert (container == get_icon_container (icon_view));
2148 
2149     fm_directory_view_activate_files (FM_DIRECTORY_VIEW (icon_view),
2150                                       file_list,
2151                                       CAJA_WINDOW_OPEN_ACCORDING_TO_MODE, 0,
2152                                       TRUE);
2153 }
2154 
2155 static void
icon_container_activate_alternate_callback(CajaIconContainer * container,GList * file_list,FMIconView * icon_view)2156 icon_container_activate_alternate_callback (CajaIconContainer *container,
2157         GList *file_list,
2158         FMIconView *icon_view)
2159 {
2160     gboolean open_in_tab;
2161     CajaWindowInfo *window_info;
2162     CajaWindowOpenFlags flags;
2163 
2164     g_assert (FM_IS_ICON_VIEW (icon_view));
2165     g_assert (container == get_icon_container (icon_view));
2166 
2167     open_in_tab = TRUE;
2168 
2169     window_info = fm_directory_view_get_caja_window (FM_DIRECTORY_VIEW (icon_view));
2170 
2171     if (caja_window_info_get_window_type (window_info) == CAJA_WINDOW_NAVIGATION)
2172     {
2173         GdkEvent *event;
2174 
2175         event = gtk_get_current_event ();
2176 
2177         if (event->type == GDK_BUTTON_PRESS ||
2178                 event->type == GDK_BUTTON_RELEASE ||
2179                 event->type == GDK_2BUTTON_PRESS ||
2180                 event->type == GDK_3BUTTON_PRESS)
2181         {
2182             GdkEventButton *button_event;
2183 
2184             button_event = (GdkEventButton *) event;
2185             open_in_tab = (button_event->state & GDK_SHIFT_MASK) == 0;
2186         }
2187         else if (event->type == GDK_KEY_PRESS ||
2188                  event->type == GDK_KEY_RELEASE)
2189         {
2190             GdkEventKey *key_event;
2191 
2192             key_event = (GdkEventKey *) event;
2193             open_in_tab = !((key_event->state & GDK_SHIFT_MASK) != 0 &&
2194                             (key_event->state & GDK_CONTROL_MASK) != 0);
2195         }
2196         else
2197         {
2198             open_in_tab = TRUE;
2199         }
2200     }
2201 
2202     flags = CAJA_WINDOW_OPEN_FLAG_CLOSE_BEHIND;
2203     if (open_in_tab)
2204     {
2205         flags |= CAJA_WINDOW_OPEN_FLAG_NEW_TAB;
2206     }
2207     else
2208     {
2209         flags |= CAJA_WINDOW_OPEN_FLAG_NEW_WINDOW;
2210     }
2211 
2212     fm_directory_view_activate_files (FM_DIRECTORY_VIEW (icon_view),
2213                                       file_list,
2214                                       CAJA_WINDOW_OPEN_ACCORDING_TO_MODE,
2215                                       flags,
2216                                       TRUE);
2217 }
2218 
2219 static void
band_select_started_callback(CajaIconContainer * container,FMIconView * icon_view)2220 band_select_started_callback (CajaIconContainer *container,
2221                               FMIconView *icon_view)
2222 {
2223     g_assert (FM_IS_ICON_VIEW (icon_view));
2224     g_assert (container == get_icon_container (icon_view));
2225 
2226     fm_directory_view_start_batching_selection_changes (FM_DIRECTORY_VIEW (icon_view));
2227 }
2228 
2229 static void
band_select_ended_callback(CajaIconContainer * container,FMIconView * icon_view)2230 band_select_ended_callback (CajaIconContainer *container,
2231                             FMIconView *icon_view)
2232 {
2233     g_assert (FM_IS_ICON_VIEW (icon_view));
2234     g_assert (container == get_icon_container (icon_view));
2235 
2236     fm_directory_view_stop_batching_selection_changes (FM_DIRECTORY_VIEW (icon_view));
2237 }
2238 
2239 /* handle the preview signal by inspecting the mime type.  For now, we only preview local sound files. */
2240 
2241 static char **
get_preview_argv(char * uri)2242 get_preview_argv (char *uri)
2243 {
2244     char *command;
2245 
2246     command = g_find_program_in_path ("gst-launch-1.0");
2247 
2248     if (!command)
2249     {
2250         command = g_find_program_in_path ("gst-launch-0.10");
2251     }
2252 
2253     if (command)
2254     {
2255         char **argv;
2256         int i;
2257 
2258         argv = g_new (char *, 5);
2259         i = 0;
2260         argv[i++] = command;
2261         argv[i++] = g_strdup ("playbin");
2262         argv[i++] = g_strconcat ("uri=", uri, NULL);
2263         /* do not display videos */
2264         argv[i++] = g_strdup ("video-sink=fakesink");
2265         argv[i++] = NULL;
2266         return argv;
2267     }
2268 
2269     return NULL;
2270 }
2271 
2272 static void
audio_child_died(GPid pid,gint status,gpointer data)2273 audio_child_died (GPid     pid,
2274                   gint     status,
2275                   gpointer data)
2276 {
2277     FMIconView *icon_view;
2278 
2279     g_return_if_fail (FM_IS_ICON_VIEW (data));
2280 
2281     icon_view = FM_ICON_VIEW (data);
2282 
2283     icon_view->details->audio_preview_child_watch = 0;
2284     icon_view->details->audio_preview_child_pid = 0;
2285 }
2286 
2287 /* here's the timer task that actually plays the file using mpg123, ogg123 or play. */
2288 /* FIXME bugzilla.gnome.org 41258: we should get the application from our mime-type stuff */
2289 static gboolean
play_file(gpointer callback_data)2290 play_file (gpointer callback_data)
2291 {
2292     CajaFile *file;
2293     FMIconView *icon_view;
2294     GPid child_pid;
2295     char **argv;
2296     GError *error;
2297     char *uri;
2298     GFile *gfile;
2299     char *path;
2300 
2301     icon_view = FM_ICON_VIEW (callback_data);
2302 
2303     /* Stop timeout */
2304     icon_view->details->audio_preview_timeout = 0;
2305 
2306     file = icon_view->details->audio_preview_file;
2307     gfile = caja_file_get_location (file);
2308     path = g_file_get_path (gfile);
2309 
2310     /* if we have a local path, use that instead of the native URI.
2311      * this can be useful for special GVfs mounts, such as cdda://
2312      */
2313     if (path) {
2314         uri = g_filename_to_uri (path, NULL, NULL);
2315     } else {
2316         uri = caja_file_get_uri (file);
2317     }
2318 
2319     g_object_unref (gfile);
2320     g_free (path);
2321 
2322     argv = get_preview_argv (uri);
2323     g_free (uri);
2324     if (argv == NULL)
2325     {
2326         return FALSE;
2327     }
2328 
2329     error = NULL;
2330     if (!g_spawn_async_with_pipes (NULL,
2331                                    argv,
2332                                    NULL,
2333                                    G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL,
2334                                    NULL,
2335                                    NULL /* user_data */,
2336                                    &child_pid,
2337                                    NULL, NULL, NULL,
2338                                    &error))
2339     {
2340         g_strfreev (argv);
2341         g_warning ("Error spawning sound preview: %s\n", error->message);
2342         g_error_free (error);
2343         return FALSE;
2344     }
2345     g_strfreev (argv);
2346 
2347     icon_view->details->audio_preview_child_watch =
2348         g_child_watch_add (child_pid,
2349                            audio_child_died, NULL);
2350     icon_view->details->audio_preview_child_pid = child_pid;
2351 
2352     return FALSE;
2353 }
2354 
2355 /* FIXME bugzilla.gnome.org 42530: Hardcoding this here sucks. We should be using components
2356  * for open ended things like this.
2357  */
2358 
2359 /* this routine is invoked from the preview signal handler to preview a sound file.  We
2360    want to wait a suitable delay until we actually do it, so set up a timer task to actually
2361    start playing.  If we move out before the task files, we remove it. */
2362 
2363 static void
preview_audio(FMIconView * icon_view,CajaFile * file,gboolean start_flag)2364 preview_audio (FMIconView *icon_view, CajaFile *file, gboolean start_flag)
2365 {
2366     /* Stop current audio playback */
2367     if (icon_view->details->audio_preview_child_pid != 0)
2368     {
2369         kill (icon_view->details->audio_preview_child_pid, SIGTERM);
2370         g_source_remove (icon_view->details->audio_preview_child_watch);
2371         waitpid (icon_view->details->audio_preview_child_pid, NULL, 0);
2372         icon_view->details->audio_preview_child_pid = 0;
2373     }
2374 
2375     if (icon_view->details->audio_preview_timeout != 0)
2376     {
2377         g_source_remove (icon_view->details->audio_preview_timeout);
2378         icon_view->details->audio_preview_timeout = 0;
2379     }
2380 
2381     if (start_flag)
2382     {
2383         icon_view->details->audio_preview_file = file;
2384         icon_view->details->audio_preview_timeout = g_timeout_add_seconds (1, play_file, icon_view);
2385     }
2386 }
2387 
2388 static gboolean
sound_preview_type_supported(CajaFile * file)2389 sound_preview_type_supported (CajaFile *file)
2390 {
2391     char *mime_type;
2392     guint i;
2393 
2394     mime_type = caja_file_get_mime_type (file);
2395     if (mime_type == NULL)
2396     {
2397         return FALSE;
2398     }
2399     for (i = 0; i < G_N_ELEMENTS (audio_mime_types); i++)
2400     {
2401         if (g_content_type_is_a (mime_type, audio_mime_types[i]))
2402         {
2403             g_free (mime_type);
2404             return TRUE;
2405         }
2406     }
2407 
2408     g_free (mime_type);
2409     return FALSE;
2410 }
2411 
2412 
2413 static gboolean
should_preview_sound(CajaFile * file)2414 should_preview_sound (CajaFile *file)
2415 {
2416     GFile *location;
2417     GFilesystemPreviewType use_preview;
2418 
2419     use_preview = caja_file_get_filesystem_use_preview (file);
2420 
2421     location = caja_file_get_location (file);
2422     if (g_file_has_uri_scheme (location, "burn"))
2423     {
2424         g_object_unref (location);
2425         return FALSE;
2426     }
2427     g_object_unref (location);
2428 
2429     /* Check user performance preference */
2430     if (preview_sound_auto_value == CAJA_SPEED_TRADEOFF_NEVER)
2431     {
2432         return FALSE;
2433     }
2434 
2435     if (preview_sound_auto_value == CAJA_SPEED_TRADEOFF_ALWAYS)
2436     {
2437         if (use_preview == G_FILESYSTEM_PREVIEW_TYPE_NEVER)
2438         {
2439             return FALSE;
2440         }
2441         else
2442         {
2443             return TRUE;
2444         }
2445     }
2446 
2447     if (use_preview == G_FILESYSTEM_PREVIEW_TYPE_NEVER)
2448     {
2449         /* file system says to never preview anything */
2450         return FALSE;
2451     }
2452     else if (use_preview == G_FILESYSTEM_PREVIEW_TYPE_IF_LOCAL)
2453     {
2454         /* file system says we should treat file as if it's local */
2455         return TRUE;
2456     }
2457     else
2458     {
2459         /* only local files */
2460         return caja_file_is_local (file);
2461     }
2462 }
2463 
2464 static int
icon_container_preview_callback(CajaIconContainer * container,CajaFile * file,gboolean start_flag,FMIconView * icon_view)2465 icon_container_preview_callback (CajaIconContainer *container,
2466                                  CajaFile *file,
2467                                  gboolean start_flag,
2468                                  FMIconView *icon_view)
2469 {
2470     int result;
2471 
2472     result = 0;
2473 
2474     /* preview files based on the mime_type. */
2475     /* at first, we just handle sounds */
2476     if (should_preview_sound (file))
2477     {
2478         if (sound_preview_type_supported (file))
2479         {
2480             result = 1;
2481             preview_audio (icon_view, file, start_flag);
2482         }
2483     }
2484 
2485     /* Display file name in status area at low zoom levels, since
2486      * the name is not displayed or hard to read in the icon view.
2487      */
2488     if (fm_icon_view_get_zoom_level (FM_DIRECTORY_VIEW (icon_view)) <= CAJA_ZOOM_LEVEL_SMALLER)
2489     {
2490         if (start_flag)
2491         {
2492             char *file_name, *message;
2493 
2494             file_name = caja_file_get_display_name (file);
2495             message = g_strdup_printf (_("pointing at \"%s\""), file_name);
2496             g_free (file_name);
2497             caja_window_slot_info_set_status
2498             (fm_directory_view_get_caja_window_slot (FM_DIRECTORY_VIEW (icon_view)),
2499              message);
2500             g_free (message);
2501         }
2502         else
2503         {
2504             fm_directory_view_display_selection_info (FM_DIRECTORY_VIEW(icon_view));
2505         }
2506     }
2507 
2508     return result;
2509 }
2510 
2511 static void
renaming_icon_callback(CajaIconContainer * container,GtkWidget * widget,gpointer callback_data)2512 renaming_icon_callback (CajaIconContainer *container,
2513                         GtkWidget *widget,
2514                         gpointer callback_data)
2515 {
2516     FMDirectoryView *directory_view;
2517 
2518     directory_view = FM_DIRECTORY_VIEW (callback_data);
2519     caja_clipboard_set_up_editable
2520     (GTK_EDITABLE (widget),
2521      fm_directory_view_get_ui_manager (directory_view),
2522      FALSE);
2523 }
2524 
2525 int
fm_icon_view_compare_files(FMIconView * icon_view,CajaFile * a,CajaFile * b)2526 fm_icon_view_compare_files (FMIconView   *icon_view,
2527                             CajaFile *a,
2528                             CajaFile *b)
2529 {
2530     return caja_file_compare_for_sort
2531            (a, b, icon_view->details->sort->sort_type,
2532             /* Use type-unsafe cast for performance */
2533             fm_directory_view_should_sort_directories_first ((FMDirectoryView *)icon_view),
2534             icon_view->details->sort_reversed);
2535 }
2536 
2537 static int
compare_files(FMDirectoryView * icon_view,CajaFile * a,CajaFile * b)2538 compare_files (FMDirectoryView   *icon_view,
2539                CajaFile *a,
2540                CajaFile *b)
2541 {
2542     return fm_icon_view_compare_files ((FMIconView *)icon_view, a, b);
2543 }
2544 
2545 
2546 void
fm_icon_view_filter_by_screen(FMIconView * icon_view,gboolean filter)2547 fm_icon_view_filter_by_screen (FMIconView *icon_view,
2548                                gboolean filter)
2549 {
2550     icon_view->details->filter_by_screen = filter;
2551 }
2552 
2553 static void
fm_icon_view_screen_changed(GtkWidget * widget,GdkScreen * previous_screen)2554 fm_icon_view_screen_changed (GtkWidget *widget,
2555                              GdkScreen *previous_screen)
2556 {
2557     FMDirectoryView *view;
2558     GList *files, *l;
2559 
2560     if (GTK_WIDGET_CLASS (fm_icon_view_parent_class)->screen_changed)
2561     {
2562         GTK_WIDGET_CLASS (fm_icon_view_parent_class)->screen_changed (widget, previous_screen);
2563     }
2564 
2565     view = FM_DIRECTORY_VIEW (widget);
2566     if (FM_ICON_VIEW (view)->details->filter_by_screen)
2567     {
2568         CajaDirectory *directory;
2569         CajaIconContainer *icon_container;
2570         CajaFile *file = NULL;
2571 
2572         icon_container = get_icon_container (FM_ICON_VIEW (view));
2573 
2574         directory = fm_directory_view_get_model (view);
2575         files = caja_directory_get_file_list (directory);
2576 
2577         for (l = files; l != NULL; l = l->next)
2578         {
2579             file = l->data;
2580 
2581             if (!should_show_file_on_screen (view, file))
2582             {
2583                 fm_icon_view_remove_file (view, file, directory);
2584             }
2585             else
2586             {
2587                 if (caja_icon_container_add (icon_container,
2588                                              CAJA_ICON_CONTAINER_ICON_DATA (file)))
2589                 {
2590                     caja_file_ref (file);
2591                 }
2592             }
2593         }
2594 
2595         caja_file_list_unref (files);
2596         g_list_free (files);
2597     }
2598 }
2599 
2600 static gboolean
fm_icon_view_scroll_event(GtkWidget * widget,GdkEventScroll * scroll_event)2601 fm_icon_view_scroll_event (GtkWidget *widget,
2602                            GdkEventScroll *scroll_event)
2603 {
2604     FMIconView *icon_view;
2605     gboolean ret;
2606 
2607     icon_view = FM_ICON_VIEW (widget);
2608 
2609     if(icon_view->details->compact)
2610     {
2611         if((ret = fm_directory_view_handle_scroll_event(FM_DIRECTORY_VIEW(icon_view), scroll_event)))
2612             return ret;
2613 
2614         if(scroll_event->direction == GDK_SCROLL_UP)
2615             scroll_event->direction = GDK_SCROLL_LEFT;
2616         else if(scroll_event->direction == GDK_SCROLL_DOWN)
2617             scroll_event->direction = GDK_SCROLL_RIGHT;
2618         else if(scroll_event->direction == GDK_SCROLL_SMOOTH)
2619         {
2620             /* no x value implies only vertical scrolling enabled */
2621             if(scroll_event->delta_x == 0.0)
2622             {
2623                 /* convert vertical to horizontal */
2624                 scroll_event->delta_x = scroll_event->delta_y;
2625                 scroll_event->delta_y = 0.0;
2626             }
2627         }
2628     }
2629 
2630     return GTK_WIDGET_CLASS (fm_icon_view_parent_class)->scroll_event (widget, scroll_event);
2631 }
2632 
2633 static void
selection_changed_callback(CajaIconContainer * container,FMIconView * icon_view)2634 selection_changed_callback (CajaIconContainer *container,
2635                             FMIconView *icon_view)
2636 {
2637     g_assert (FM_IS_ICON_VIEW (icon_view));
2638     g_assert (container == get_icon_container (icon_view));
2639 
2640     fm_directory_view_notify_selection_changed (FM_DIRECTORY_VIEW (icon_view));
2641 }
2642 
2643 static void
icon_container_context_click_selection_callback(CajaIconContainer * container,GdkEventButton * event,FMIconView * icon_view)2644 icon_container_context_click_selection_callback (CajaIconContainer *container,
2645         GdkEventButton *event,
2646         FMIconView *icon_view)
2647 {
2648     g_assert (CAJA_IS_ICON_CONTAINER (container));
2649     g_assert (FM_IS_ICON_VIEW (icon_view));
2650 
2651     fm_directory_view_pop_up_selection_context_menu
2652     (FM_DIRECTORY_VIEW (icon_view), event);
2653 }
2654 
2655 static void
icon_container_context_click_background_callback(CajaIconContainer * container,GdkEventButton * event,FMIconView * icon_view)2656 icon_container_context_click_background_callback (CajaIconContainer *container,
2657         GdkEventButton *event,
2658         FMIconView *icon_view)
2659 {
2660     g_assert (CAJA_IS_ICON_CONTAINER (container));
2661     g_assert (FM_IS_ICON_VIEW (icon_view));
2662 
2663     /* FIXME: passing event from here won't work
2664      * for gtk_menu_popup_at_pointer (in eel_pop_up_context_menu() )
2665      * if the menu is being triggered from here by the menu key
2666      */
2667     fm_directory_view_pop_up_background_context_menu
2668     (FM_DIRECTORY_VIEW (icon_view), NULL);
2669 }
2670 
2671 static gboolean
fm_icon_view_react_to_icon_change_idle_callback(gpointer data)2672 fm_icon_view_react_to_icon_change_idle_callback (gpointer data)
2673 {
2674     FMIconView *icon_view;
2675 
2676     g_assert (FM_IS_ICON_VIEW (data));
2677 
2678     icon_view = FM_ICON_VIEW (data);
2679     icon_view->details->react_to_icon_change_idle_id = 0;
2680 
2681     /* Rebuild the menus since some of them (e.g. Restore Stretched Icons)
2682      * may be different now.
2683      */
2684     fm_directory_view_update_menus (FM_DIRECTORY_VIEW (icon_view));
2685 
2686     /* Don't call this again (unless rescheduled) */
2687     return FALSE;
2688 }
2689 
2690 static void
icon_position_changed_callback(CajaIconContainer * container,CajaFile * file,const CajaIconPosition * position,FMIconView * icon_view)2691 icon_position_changed_callback (CajaIconContainer *container,
2692                                 CajaFile *file,
2693                                 const CajaIconPosition *position,
2694                                 FMIconView *icon_view)
2695 {
2696     char scale_string[G_ASCII_DTOSTR_BUF_SIZE];
2697 
2698     g_assert (FM_IS_ICON_VIEW (icon_view));
2699     g_assert (container == get_icon_container (icon_view));
2700     g_assert (CAJA_IS_FILE (file));
2701 
2702     /* Schedule updating menus for the next idle. Doing it directly here
2703      * noticeably slows down icon stretching.  The other work here to
2704      * store the icon position and scale does not seem to noticeably
2705      * slow down icon stretching. It would be trickier to move to an
2706      * idle call, because we'd have to keep track of potentially multiple
2707      * sets of file/geometry info.
2708      */
2709     if (fm_directory_view_get_active (FM_DIRECTORY_VIEW (icon_view)) &&
2710             icon_view->details->react_to_icon_change_idle_id == 0)
2711     {
2712         icon_view->details->react_to_icon_change_idle_id
2713             = g_idle_add (fm_icon_view_react_to_icon_change_idle_callback,
2714                           icon_view);
2715     }
2716 
2717     /* Store the new position of the icon in the metadata. */
2718     if (!fm_icon_view_using_auto_layout (icon_view))
2719     {
2720         char *position_string;
2721 
2722         position_string = g_strdup_printf
2723                           ("%d,%d", position->x, position->y);
2724         caja_file_set_metadata
2725         (file, CAJA_METADATA_KEY_ICON_POSITION,
2726          NULL, position_string);
2727         g_free (position_string);
2728     }
2729 
2730 
2731     g_ascii_dtostr (scale_string, sizeof (scale_string), position->scale);
2732     caja_file_set_metadata
2733     (file, CAJA_METADATA_KEY_ICON_SCALE,
2734      "1.0", scale_string);
2735 }
2736 
2737 /* Attempt to change the filename to the new text.  Notify user if operation fails. */
2738 static void
fm_icon_view_icon_text_changed_callback(CajaIconContainer * container,CajaFile * file,char * new_name,FMIconView * icon_view)2739 fm_icon_view_icon_text_changed_callback (CajaIconContainer *container,
2740         CajaFile *file,
2741         char *new_name,
2742         FMIconView *icon_view)
2743 {
2744     g_assert (CAJA_IS_FILE (file));
2745 
2746     /* Don't allow a rename with an empty string. Revert to original
2747      * without notifying the user.
2748      */
2749     if ((new_name == NULL) || (new_name[0] == '\0'))
2750     {
2751         return;
2752     }
2753     fm_rename_file (file, new_name, NULL, NULL);
2754 }
2755 
2756 static char *
get_icon_uri_callback(CajaIconContainer * container,CajaFile * file,FMIconView * icon_view)2757 get_icon_uri_callback (CajaIconContainer *container,
2758                        CajaFile *file,
2759                        FMIconView *icon_view)
2760 {
2761     g_assert (CAJA_IS_ICON_CONTAINER (container));
2762     g_assert (CAJA_IS_FILE (file));
2763     g_assert (FM_IS_ICON_VIEW (icon_view));
2764 
2765     return caja_file_get_uri (file);
2766 }
2767 
2768 static char *
get_icon_drop_target_uri_callback(CajaIconContainer * container,CajaFile * file,FMIconView * icon_view)2769 get_icon_drop_target_uri_callback (CajaIconContainer *container,
2770                                    CajaFile *file,
2771                                    FMIconView *icon_view)
2772 {
2773     g_return_val_if_fail (CAJA_IS_ICON_CONTAINER (container), NULL);
2774     g_return_val_if_fail (CAJA_IS_FILE (file), NULL);
2775     g_return_val_if_fail (FM_IS_ICON_VIEW (icon_view), NULL);
2776 
2777     return caja_file_get_drop_target_uri (file);
2778 }
2779 
2780 /* Preferences changed callbacks */
2781 static void
fm_icon_view_text_attribute_names_changed(FMDirectoryView * directory_view)2782 fm_icon_view_text_attribute_names_changed (FMDirectoryView *directory_view)
2783 {
2784     g_assert (FM_IS_ICON_VIEW (directory_view));
2785 
2786     caja_icon_container_request_update_all (get_icon_container (FM_ICON_VIEW (directory_view)));
2787 }
2788 
2789 static void
fm_icon_view_embedded_text_policy_changed(FMDirectoryView * directory_view)2790 fm_icon_view_embedded_text_policy_changed (FMDirectoryView *directory_view)
2791 {
2792     g_assert (FM_IS_ICON_VIEW (directory_view));
2793 
2794     caja_icon_container_request_update_all (get_icon_container (FM_ICON_VIEW (directory_view)));
2795 }
2796 
2797 static void
fm_icon_view_image_display_policy_changed(FMDirectoryView * directory_view)2798 fm_icon_view_image_display_policy_changed (FMDirectoryView *directory_view)
2799 {
2800     g_assert (FM_IS_ICON_VIEW (directory_view));
2801 
2802     caja_icon_container_request_update_all (get_icon_container (FM_ICON_VIEW (directory_view)));
2803 }
2804 
2805 static void
fm_icon_view_click_policy_changed(FMDirectoryView * directory_view)2806 fm_icon_view_click_policy_changed (FMDirectoryView *directory_view)
2807 {
2808     g_assert (FM_IS_ICON_VIEW (directory_view));
2809 
2810     fm_icon_view_update_click_mode (FM_ICON_VIEW (directory_view));
2811 }
2812 
2813 static void
fm_icon_view_emblems_changed(FMDirectoryView * directory_view)2814 fm_icon_view_emblems_changed (FMDirectoryView *directory_view)
2815 {
2816     g_assert (FM_IS_ICON_VIEW (directory_view));
2817 
2818     caja_icon_container_request_update_all (get_icon_container (FM_ICON_VIEW (directory_view)));
2819 }
2820 
2821 static void
default_sort_order_changed_callback(gpointer callback_data)2822 default_sort_order_changed_callback (gpointer callback_data)
2823 {
2824     FMIconView *icon_view;
2825     CajaFile *file;
2826     char *sort_name;
2827     CajaIconContainer *icon_container;
2828 
2829     g_return_if_fail (FM_IS_ICON_VIEW (callback_data));
2830 
2831     icon_view = FM_ICON_VIEW (callback_data);
2832 
2833     file = fm_directory_view_get_directory_as_file (FM_DIRECTORY_VIEW (icon_view));
2834     sort_name = fm_icon_view_get_directory_sort_by (icon_view, file);
2835     set_sort_criterion (icon_view, get_sort_criterion_by_metadata_text (sort_name));
2836     g_free (sort_name);
2837 
2838     icon_container = get_icon_container (icon_view);
2839     g_return_if_fail (CAJA_IS_ICON_CONTAINER (icon_container));
2840 
2841     caja_icon_container_request_update_all (icon_container);
2842 }
2843 
2844 static void
default_sort_in_reverse_order_changed_callback(gpointer callback_data)2845 default_sort_in_reverse_order_changed_callback (gpointer callback_data)
2846 {
2847     FMIconView *icon_view;
2848     CajaFile *file;
2849     CajaIconContainer *icon_container;
2850 
2851     g_return_if_fail (FM_IS_ICON_VIEW (callback_data));
2852 
2853     icon_view = FM_ICON_VIEW (callback_data);
2854 
2855     file = fm_directory_view_get_directory_as_file (FM_DIRECTORY_VIEW (icon_view));
2856     set_sort_reversed (icon_view, fm_icon_view_get_directory_sort_reversed (icon_view, file));
2857     icon_container = get_icon_container (icon_view);
2858     g_return_if_fail (CAJA_IS_ICON_CONTAINER (icon_container));
2859 
2860     caja_icon_container_request_update_all (icon_container);
2861 }
2862 
2863 static void
default_use_tighter_layout_changed_callback(gpointer callback_data)2864 default_use_tighter_layout_changed_callback (gpointer callback_data)
2865 {
2866     FMIconView *icon_view;
2867     CajaFile *file;
2868     CajaIconContainer *icon_container;
2869 
2870     g_return_if_fail (FM_IS_ICON_VIEW (callback_data));
2871 
2872     icon_view = FM_ICON_VIEW (callback_data);
2873 
2874     file = fm_directory_view_get_directory_as_file (FM_DIRECTORY_VIEW (icon_view));
2875     icon_container = get_icon_container (icon_view);
2876     g_return_if_fail (CAJA_IS_ICON_CONTAINER (icon_container));
2877 
2878     caja_icon_container_set_tighter_layout (
2879         icon_container,
2880         fm_icon_view_get_directory_tighter_layout (icon_view, file));
2881 
2882     caja_icon_container_request_update_all (icon_container);
2883 }
2884 
2885 static void
default_zoom_level_changed_callback(gpointer callback_data)2886 default_zoom_level_changed_callback (gpointer callback_data)
2887 {
2888     FMIconView *icon_view;
2889 
2890     g_return_if_fail (FM_IS_ICON_VIEW (callback_data));
2891 
2892     icon_view = FM_ICON_VIEW (callback_data);
2893 
2894     if (fm_directory_view_supports_zooming (FM_DIRECTORY_VIEW (icon_view)))
2895     {
2896         CajaFile *file;
2897         int level;
2898 
2899         file = fm_directory_view_get_directory_as_file (FM_DIRECTORY_VIEW (icon_view));
2900 
2901         if (fm_icon_view_is_compact (icon_view))
2902         {
2903             level = caja_file_get_integer_metadata (file,
2904                                                     CAJA_METADATA_KEY_COMPACT_VIEW_ZOOM_LEVEL,
2905                                                     get_default_zoom_level (icon_view));
2906         }
2907         else
2908         {
2909             level = caja_file_get_integer_metadata (file,
2910                                                     CAJA_METADATA_KEY_ICON_VIEW_ZOOM_LEVEL,
2911                                                     get_default_zoom_level (icon_view));
2912         }
2913         fm_directory_view_zoom_to_level (FM_DIRECTORY_VIEW (icon_view), level);
2914     }
2915 }
2916 
2917 static void
labels_beside_icons_changed_callback(gpointer callback_data)2918 labels_beside_icons_changed_callback (gpointer callback_data)
2919 {
2920     FMIconView *icon_view;
2921 
2922     g_return_if_fail (FM_IS_ICON_VIEW (callback_data));
2923 
2924     icon_view = FM_ICON_VIEW (callback_data);
2925 
2926     set_labels_beside_icons (icon_view);
2927 }
2928 
2929 static void
all_columns_same_width_changed_callback(gpointer callback_data)2930 all_columns_same_width_changed_callback (gpointer callback_data)
2931 {
2932     FMIconView *icon_view;
2933 
2934     g_assert (FM_IS_ICON_VIEW (callback_data));
2935 
2936     icon_view = FM_ICON_VIEW (callback_data);
2937 
2938     set_columns_same_width (icon_view);
2939 }
2940 
2941 
2942 static void
fm_icon_view_sort_directories_first_changed(FMDirectoryView * directory_view)2943 fm_icon_view_sort_directories_first_changed (FMDirectoryView *directory_view)
2944 {
2945     FMIconView *icon_view;
2946 
2947     icon_view = FM_ICON_VIEW (directory_view);
2948 
2949     if (fm_icon_view_using_auto_layout (icon_view))
2950     {
2951         caja_icon_container_sort
2952         (get_icon_container (icon_view));
2953     }
2954 }
2955 
2956 static gboolean
icon_view_can_accept_item(CajaIconContainer * container,CajaFile * target_item,const char * item_uri,FMDirectoryView * view)2957 icon_view_can_accept_item (CajaIconContainer *container,
2958                            CajaFile *target_item,
2959                            const char *item_uri,
2960                            FMDirectoryView *view)
2961 {
2962     return fm_directory_view_can_accept_item (target_item, item_uri, view);
2963 }
2964 
2965 static char *
icon_view_get_container_uri(CajaIconContainer * container,FMDirectoryView * view)2966 icon_view_get_container_uri (CajaIconContainer *container,
2967                              FMDirectoryView *view)
2968 {
2969     return fm_directory_view_get_uri (view);
2970 }
2971 
2972 static void
icon_view_move_copy_items(CajaIconContainer * container,const GList * item_uris,GArray * relative_item_points,const char * target_dir,int copy_action,int x,int y,FMDirectoryView * view)2973 icon_view_move_copy_items (CajaIconContainer *container,
2974                            const GList *item_uris,
2975                            GArray *relative_item_points,
2976                            const char *target_dir,
2977                            int copy_action,
2978                            int x, int y,
2979                            FMDirectoryView *view)
2980 {
2981     caja_clipboard_clear_if_colliding_uris (GTK_WIDGET (view),
2982                                             item_uris,
2983                                             fm_directory_view_get_copied_files_atom (view));
2984     fm_directory_view_move_copy_items (item_uris, relative_item_points, target_dir,
2985                                        copy_action, x, y, view);
2986 }
2987 
2988 static void
fm_icon_view_update_click_mode(FMIconView * icon_view)2989 fm_icon_view_update_click_mode (FMIconView *icon_view)
2990 {
2991     CajaIconContainer	*icon_container;
2992     int			click_mode;
2993 
2994     icon_container = get_icon_container (icon_view);
2995     g_assert (icon_container != NULL);
2996 
2997     click_mode = g_settings_get_enum (caja_preferences, CAJA_PREFERENCES_CLICK_POLICY);
2998 
2999     caja_icon_container_set_single_click_mode (icon_container,
3000             click_mode == CAJA_CLICK_POLICY_SINGLE);
3001 }
3002 
3003 static gboolean
get_stored_layout_timestamp(CajaIconContainer * container,CajaIconData * icon_data,time_t * timestamp,FMIconView * view)3004 get_stored_layout_timestamp (CajaIconContainer *container,
3005                              CajaIconData *icon_data,
3006                              time_t *timestamp,
3007                              FMIconView *view)
3008 {
3009     if (icon_data == NULL)
3010     {
3011         CajaFile *file;
3012         CajaDirectory *directory;
3013 
3014         directory = fm_directory_view_get_model (FM_DIRECTORY_VIEW (view));
3015 
3016         if (directory == NULL)
3017         {
3018             return FALSE;
3019         }
3020 
3021         file = caja_directory_get_corresponding_file (directory);
3022         *timestamp = caja_file_get_time_metadata (file,
3023                      CAJA_METADATA_KEY_ICON_VIEW_LAYOUT_TIMESTAMP);
3024         caja_file_unref (file);
3025     }
3026     else
3027     {
3028         *timestamp = caja_file_get_time_metadata (CAJA_FILE (icon_data),
3029                      CAJA_METADATA_KEY_ICON_POSITION_TIMESTAMP);
3030     }
3031 
3032     return TRUE;
3033 }
3034 
3035 static gboolean
store_layout_timestamp(CajaIconContainer * container,CajaIconData * icon_data,const time_t * timestamp,FMIconView * view)3036 store_layout_timestamp (CajaIconContainer *container,
3037                         CajaIconData *icon_data,
3038                         const time_t *timestamp,
3039                         FMIconView *view)
3040 {
3041     if (icon_data == NULL)
3042     {
3043         CajaFile *file;
3044         CajaDirectory *directory;
3045 
3046         directory = fm_directory_view_get_model (FM_DIRECTORY_VIEW (view));
3047 
3048         if (directory == NULL)
3049         {
3050             return FALSE;
3051         }
3052 
3053         file = caja_directory_get_corresponding_file (directory);
3054         caja_file_set_time_metadata (file,
3055                                      CAJA_METADATA_KEY_ICON_VIEW_LAYOUT_TIMESTAMP,
3056                                      (time_t) *timestamp);
3057         caja_file_unref (file);
3058     }
3059     else
3060     {
3061         caja_file_set_time_metadata (CAJA_FILE (icon_data),
3062                                      CAJA_METADATA_KEY_ICON_POSITION_TIMESTAMP,
3063                                      (time_t) *timestamp);
3064     }
3065 
3066     return TRUE;
3067 }
3068 
3069 static gboolean
focus_in_event_callback(GtkWidget * widget,GdkEventFocus * event,gpointer user_data)3070 focus_in_event_callback (GtkWidget *widget, GdkEventFocus *event, gpointer user_data)
3071 {
3072     CajaWindowSlotInfo *slot_info;
3073     FMIconView *icon_view = FM_ICON_VIEW (user_data);
3074 
3075     /* make the corresponding slot (and the pane that contains it) active */
3076     slot_info = fm_directory_view_get_caja_window_slot (FM_DIRECTORY_VIEW (icon_view));
3077     caja_window_slot_info_make_hosting_pane_active (slot_info);
3078 
3079     return FALSE;
3080 }
3081 
3082 static CajaIconContainer *
create_icon_container(FMIconView * icon_view)3083 create_icon_container (FMIconView *icon_view)
3084 {
3085     CajaIconContainer *icon_container;
3086 
3087     icon_container = fm_icon_container_new (icon_view);
3088 
3089     gtk_widget_set_can_focus (GTK_WIDGET (icon_container), TRUE);
3090 
3091     g_signal_connect_object (icon_container, "focus_in_event",
3092                              G_CALLBACK (focus_in_event_callback), icon_view, 0);
3093     g_signal_connect_object (icon_container, "activate",
3094                              G_CALLBACK (icon_container_activate_callback), icon_view, 0);
3095     g_signal_connect_object (icon_container, "activate_alternate",
3096                              G_CALLBACK (icon_container_activate_alternate_callback), icon_view, 0);
3097     g_signal_connect_object (icon_container, "band_select_started",
3098                              G_CALLBACK (band_select_started_callback), icon_view, 0);
3099     g_signal_connect_object (icon_container, "band_select_ended",
3100                              G_CALLBACK (band_select_ended_callback), icon_view, 0);
3101     g_signal_connect_object (icon_container, "context_click_selection",
3102                              G_CALLBACK (icon_container_context_click_selection_callback), icon_view, 0);
3103     g_signal_connect_object (icon_container, "context_click_background",
3104                              G_CALLBACK (icon_container_context_click_background_callback), icon_view, 0);
3105     g_signal_connect_object (icon_container, "icon_position_changed",
3106                              G_CALLBACK (icon_position_changed_callback), icon_view, 0);
3107     g_signal_connect_object (icon_container, "icon_text_changed",
3108                              G_CALLBACK (fm_icon_view_icon_text_changed_callback), icon_view, 0);
3109     g_signal_connect_object (icon_container, "selection_changed",
3110                              G_CALLBACK (selection_changed_callback), icon_view, 0);
3111     /* FIXME: many of these should move into fm-icon-container as virtual methods */
3112     g_signal_connect_object (icon_container, "get_icon_uri",
3113                              G_CALLBACK (get_icon_uri_callback), icon_view, 0);
3114     g_signal_connect_object (icon_container, "get_icon_drop_target_uri",
3115                              G_CALLBACK (get_icon_drop_target_uri_callback), icon_view, 0);
3116     g_signal_connect_object (icon_container, "move_copy_items",
3117                              G_CALLBACK (icon_view_move_copy_items), icon_view, 0);
3118     g_signal_connect_object (icon_container, "get_container_uri",
3119                              G_CALLBACK (icon_view_get_container_uri), icon_view, 0);
3120     g_signal_connect_object (icon_container, "can_accept_item",
3121                              G_CALLBACK (icon_view_can_accept_item), icon_view, 0);
3122     g_signal_connect_object (icon_container, "get_stored_icon_position",
3123                              G_CALLBACK (get_stored_icon_position_callback), icon_view, 0);
3124     g_signal_connect_object (icon_container, "layout_changed",
3125                              G_CALLBACK (layout_changed_callback), icon_view, 0);
3126     g_signal_connect_object (icon_container, "preview",
3127                              G_CALLBACK (icon_container_preview_callback), icon_view, 0);
3128     g_signal_connect_object (icon_container, "renaming_icon",
3129                              G_CALLBACK (renaming_icon_callback), icon_view, 0);
3130     g_signal_connect_object (icon_container, "icon_stretch_started",
3131                              G_CALLBACK (fm_directory_view_update_menus), icon_view,
3132                              G_CONNECT_SWAPPED);
3133     g_signal_connect_object (icon_container, "icon_stretch_ended",
3134                              G_CALLBACK (fm_directory_view_update_menus), icon_view,
3135                              G_CONNECT_SWAPPED);
3136 
3137     g_signal_connect_object (icon_container, "get_stored_layout_timestamp",
3138                              G_CALLBACK (get_stored_layout_timestamp), icon_view, 0);
3139     g_signal_connect_object (icon_container, "store_layout_timestamp",
3140                              G_CALLBACK (store_layout_timestamp), icon_view, 0);
3141 
3142     gtk_container_add (GTK_CONTAINER (icon_view),
3143                        GTK_WIDGET (icon_container));
3144 
3145     fm_icon_view_update_click_mode (icon_view);
3146 
3147     gtk_widget_show (GTK_WIDGET (icon_container));
3148 
3149     return icon_container;
3150 }
3151 
3152 /* Handles an URL received from Mozilla */
3153 static void
icon_view_handle_netscape_url(CajaIconContainer * container,const char * encoded_url,const char * target_uri,GdkDragAction action,int x,int y,FMIconView * view)3154 icon_view_handle_netscape_url (CajaIconContainer *container, const char *encoded_url,
3155                                const char *target_uri,
3156                                GdkDragAction action, int x, int y, FMIconView *view)
3157 {
3158     fm_directory_view_handle_netscape_url_drop (FM_DIRECTORY_VIEW (view),
3159             encoded_url, target_uri, action, x, y);
3160 }
3161 
3162 static void
icon_view_handle_uri_list(CajaIconContainer * container,const char * item_uris,const char * target_uri,GdkDragAction action,int x,int y,FMIconView * view)3163 icon_view_handle_uri_list (CajaIconContainer *container, const char *item_uris,
3164                            const char *target_uri,
3165                            GdkDragAction action, int x, int y, FMIconView *view)
3166 {
3167     fm_directory_view_handle_uri_list_drop (FM_DIRECTORY_VIEW (view),
3168                                             item_uris, target_uri, action, x, y);
3169 }
3170 
3171 static void
icon_view_handle_text(CajaIconContainer * container,const char * text,const char * target_uri,GdkDragAction action,int x,int y,FMIconView * view)3172 icon_view_handle_text (CajaIconContainer *container, const char *text,
3173                        const char *target_uri,
3174                        GdkDragAction action, int x, int y, FMIconView *view)
3175 {
3176     fm_directory_view_handle_text_drop (FM_DIRECTORY_VIEW (view),
3177                                         text, target_uri, action, x, y);
3178 }
3179 
3180 static void
icon_view_handle_raw(CajaIconContainer * container,const char * raw_data,int length,const char * target_uri,const char * direct_save_uri,GdkDragAction action,int x,int y,FMIconView * view)3181 icon_view_handle_raw (CajaIconContainer *container, const char *raw_data,
3182                       int length, const char *target_uri, const char *direct_save_uri,
3183                       GdkDragAction action, int x, int y, FMIconView *view)
3184 {
3185     fm_directory_view_handle_raw_drop (FM_DIRECTORY_VIEW (view),
3186                                        raw_data, length, target_uri, direct_save_uri, action, x, y);
3187 }
3188 
3189 static char *
icon_view_get_first_visible_file(CajaView * view)3190 icon_view_get_first_visible_file (CajaView *view)
3191 {
3192     CajaFile *file;
3193     FMIconView *icon_view;
3194 
3195     icon_view = FM_ICON_VIEW (view);
3196 
3197     file = CAJA_FILE (caja_icon_container_get_first_visible_icon (get_icon_container (icon_view)));
3198 
3199     if (file)
3200     {
3201         return caja_file_get_uri (file);
3202     }
3203 
3204     return NULL;
3205 }
3206 
3207 static void
icon_view_scroll_to_file(CajaView * view,const char * uri)3208 icon_view_scroll_to_file (CajaView *view,
3209                           const char *uri)
3210 {
3211     FMIconView *icon_view;
3212 
3213     icon_view = FM_ICON_VIEW (view);
3214 
3215     if (uri != NULL)
3216     {
3217         CajaFile *file;
3218 
3219         /* Only if existing, since we don't want to add the file to
3220            the directory if it has been removed since then */
3221         file = caja_file_get_existing_by_uri (uri);
3222         if (file != NULL)
3223         {
3224             caja_icon_container_scroll_to_icon (get_icon_container (icon_view),
3225                                                 CAJA_ICON_CONTAINER_ICON_DATA (file));
3226             caja_file_unref (file);
3227         }
3228     }
3229 }
3230 
3231 static void
fm_icon_view_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)3232 fm_icon_view_set_property (GObject         *object,
3233                            guint            prop_id,
3234                            const GValue    *value,
3235                            GParamSpec      *pspec)
3236 {
3237     FMIconView *icon_view;
3238 
3239     icon_view = FM_ICON_VIEW (object);
3240 
3241     switch (prop_id)
3242     {
3243     case PROP_COMPACT:
3244         icon_view->details->compact = g_value_get_boolean (value);
3245         if (icon_view->details->compact)
3246         {
3247             caja_icon_container_set_layout_mode (get_icon_container (icon_view),
3248                                                  gtk_widget_get_direction (GTK_WIDGET(icon_view)) == GTK_TEXT_DIR_RTL ?
3249                                                  CAJA_ICON_LAYOUT_T_B_R_L :
3250                                                  CAJA_ICON_LAYOUT_T_B_L_R);
3251             caja_icon_container_set_forced_icon_size (get_icon_container (icon_view),
3252                     CAJA_ICON_SIZE_SMALLEST);
3253         }
3254         break;
3255 
3256     default:
3257         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
3258         break;
3259     }
3260 }
3261 
3262 
3263 
3264 static void
fm_icon_view_class_init(FMIconViewClass * klass)3265 fm_icon_view_class_init (FMIconViewClass *klass)
3266 {
3267     FMDirectoryViewClass *fm_directory_view_class;
3268 
3269     fm_directory_view_class = FM_DIRECTORY_VIEW_CLASS (klass);
3270 
3271     G_OBJECT_CLASS (klass)->set_property = fm_icon_view_set_property;
3272     G_OBJECT_CLASS (klass)->finalize = fm_icon_view_finalize;
3273 
3274     GTK_WIDGET_CLASS (klass)->destroy = fm_icon_view_destroy;
3275     GTK_WIDGET_CLASS (klass)->screen_changed = fm_icon_view_screen_changed;
3276     GTK_WIDGET_CLASS (klass)->scroll_event = fm_icon_view_scroll_event;
3277 
3278     fm_directory_view_class->add_file = fm_icon_view_add_file;
3279     fm_directory_view_class->flush_added_files = fm_icon_view_flush_added_files;
3280     fm_directory_view_class->begin_loading = fm_icon_view_begin_loading;
3281     fm_directory_view_class->bump_zoom_level = fm_icon_view_bump_zoom_level;
3282     fm_directory_view_class->can_rename_file = fm_icon_view_can_rename_file;
3283     fm_directory_view_class->can_zoom_in = fm_icon_view_can_zoom_in;
3284     fm_directory_view_class->can_zoom_out = fm_icon_view_can_zoom_out;
3285     fm_directory_view_class->clear = fm_icon_view_clear;
3286     fm_directory_view_class->end_loading = fm_icon_view_end_loading;
3287     fm_directory_view_class->file_changed = fm_icon_view_file_changed;
3288     fm_directory_view_class->get_background_widget = fm_icon_view_get_background_widget;
3289     fm_directory_view_class->get_selected_icon_locations = fm_icon_view_get_selected_icon_locations;
3290     fm_directory_view_class->get_selection = fm_icon_view_get_selection;
3291     fm_directory_view_class->get_selection_for_file_transfer = fm_icon_view_get_selection;
3292     fm_directory_view_class->get_item_count = fm_icon_view_get_item_count;
3293     fm_directory_view_class->is_empty = fm_icon_view_is_empty;
3294     fm_directory_view_class->remove_file = fm_icon_view_remove_file;
3295     fm_directory_view_class->reset_to_defaults = fm_icon_view_reset_to_defaults;
3296     fm_directory_view_class->restore_default_zoom_level = fm_icon_view_restore_default_zoom_level;
3297     fm_directory_view_class->reveal_selection = fm_icon_view_reveal_selection;
3298     fm_directory_view_class->select_all = fm_icon_view_select_all;
3299     fm_directory_view_class->set_selection = fm_icon_view_set_selection;
3300     fm_directory_view_class->invert_selection = fm_icon_view_invert_selection;
3301     fm_directory_view_class->compare_files = compare_files;
3302     fm_directory_view_class->zoom_to_level = fm_icon_view_zoom_to_level;
3303     fm_directory_view_class->get_zoom_level = fm_icon_view_get_zoom_level;
3304     fm_directory_view_class->click_policy_changed = fm_icon_view_click_policy_changed;
3305     fm_directory_view_class->embedded_text_policy_changed = fm_icon_view_embedded_text_policy_changed;
3306     fm_directory_view_class->emblems_changed = fm_icon_view_emblems_changed;
3307     fm_directory_view_class->image_display_policy_changed = fm_icon_view_image_display_policy_changed;
3308     fm_directory_view_class->merge_menus = fm_icon_view_merge_menus;
3309     fm_directory_view_class->unmerge_menus = fm_icon_view_unmerge_menus;
3310     fm_directory_view_class->sort_directories_first_changed = fm_icon_view_sort_directories_first_changed;
3311     fm_directory_view_class->start_renaming_file = fm_icon_view_start_renaming_file;
3312     fm_directory_view_class->text_attribute_names_changed = fm_icon_view_text_attribute_names_changed;
3313     fm_directory_view_class->update_menus = fm_icon_view_update_menus;
3314     fm_directory_view_class->using_manual_layout = fm_icon_view_using_manual_layout;
3315     fm_directory_view_class->widget_to_file_operation_position = fm_icon_view_widget_to_file_operation_position;
3316 
3317     klass->clean_up = fm_icon_view_real_clean_up;
3318     klass->supports_auto_layout = real_supports_auto_layout;
3319     klass->supports_scaling = real_supports_scaling;
3320     klass->supports_manual_layout = real_supports_manual_layout;
3321     klass->supports_keep_aligned = real_supports_keep_aligned;
3322     klass->supports_labels_beside_icons = real_supports_labels_beside_icons;
3323     klass->get_directory_auto_layout = fm_icon_view_real_get_directory_auto_layout;
3324     klass->get_directory_sort_by = fm_icon_view_real_get_directory_sort_by;
3325     klass->get_directory_sort_reversed = fm_icon_view_real_get_directory_sort_reversed;
3326     klass->get_directory_tighter_layout = fm_icon_view_real_get_directory_tighter_layout;
3327     klass->set_directory_auto_layout = fm_icon_view_real_set_directory_auto_layout;
3328     klass->set_directory_sort_by = fm_icon_view_real_set_directory_sort_by;
3329     klass->set_directory_sort_reversed = fm_icon_view_real_set_directory_sort_reversed;
3330     klass->set_directory_tighter_layout = fm_icon_view_real_set_directory_tighter_layout;
3331 
3332     g_object_class_install_property (G_OBJECT_CLASS (klass),
3333                                      PROP_COMPACT,
3334                                      g_param_spec_boolean ("compact",
3335                                              "Compact",
3336                                              "Whether this view provides a compact listing",
3337                                              FALSE,
3338                                              G_PARAM_WRITABLE |
3339                                              G_PARAM_CONSTRUCT_ONLY));
3340 
3341 }
3342 
3343 static const char *
fm_icon_view_get_id(CajaView * view)3344 fm_icon_view_get_id (CajaView *view)
3345 {
3346     if (FM_IS_DESKTOP_ICON_VIEW (view))
3347     {
3348         return FM_DESKTOP_ICON_VIEW_ID;
3349     }
3350 
3351     if (fm_icon_view_is_compact (FM_ICON_VIEW (view)))
3352     {
3353         return FM_COMPACT_VIEW_ID;
3354     }
3355 
3356     return FM_ICON_VIEW_ID;
3357 }
3358 
3359 static void
fm_icon_view_iface_init(CajaViewIface * iface)3360 fm_icon_view_iface_init (CajaViewIface *iface)
3361 {
3362     fm_directory_view_init_view_iface (iface);
3363 
3364     iface->get_view_id = fm_icon_view_get_id;
3365     iface->get_first_visible_file = icon_view_get_first_visible_file;
3366     iface->scroll_to_file = icon_view_scroll_to_file;
3367     iface->get_title = NULL;
3368 }
3369 
3370 static void
fm_icon_view_init(FMIconView * icon_view)3371 fm_icon_view_init (FMIconView *icon_view)
3372 {
3373     static gboolean setup_sound_preview = FALSE;
3374     CajaIconContainer *icon_container;
3375 
3376     g_return_if_fail (gtk_bin_get_child (GTK_BIN (icon_view)) == NULL);
3377 
3378     icon_view->details = g_new0 (FMIconViewDetails, 1);
3379     icon_view->details->sort = &sort_criteria[0];
3380     icon_view->details->filter_by_screen = FALSE;
3381 
3382     icon_container = create_icon_container (icon_view);
3383 
3384     /* Set our default layout mode */
3385     caja_icon_container_set_layout_mode (icon_container,
3386                                          gtk_widget_get_direction (GTK_WIDGET(icon_container)) == GTK_TEXT_DIR_RTL ?
3387                                          CAJA_ICON_LAYOUT_R_L_T_B :
3388                                          CAJA_ICON_LAYOUT_L_R_T_B);
3389 
3390     if (!setup_sound_preview)
3391     {
3392         eel_g_settings_add_auto_enum (caja_preferences,
3393                                       CAJA_PREFERENCES_PREVIEW_SOUND,
3394                                       &preview_sound_auto_value);
3395 
3396         setup_sound_preview = TRUE;
3397     }
3398 
3399     g_signal_connect_swapped (caja_preferences,
3400                               "changed::" CAJA_PREFERENCES_DEFAULT_SORT_ORDER,
3401                               G_CALLBACK (default_sort_order_changed_callback),
3402                               icon_view);
3403     g_signal_connect_swapped (caja_preferences,
3404                               "changed::" CAJA_PREFERENCES_DEFAULT_SORT_IN_REVERSE_ORDER,
3405                               G_CALLBACK (default_sort_in_reverse_order_changed_callback),
3406                               icon_view);
3407     g_signal_connect_swapped (caja_icon_view_preferences,
3408                               "changed::" CAJA_PREFERENCES_ICON_VIEW_DEFAULT_USE_TIGHTER_LAYOUT,
3409                               G_CALLBACK (default_use_tighter_layout_changed_callback),
3410                               icon_view);
3411     g_signal_connect_swapped (caja_icon_view_preferences,
3412                               "changed::" CAJA_PREFERENCES_ICON_VIEW_DEFAULT_ZOOM_LEVEL,
3413                               G_CALLBACK (default_zoom_level_changed_callback),
3414                               icon_view);
3415     g_signal_connect_swapped (caja_icon_view_preferences,
3416                               "changed::" CAJA_PREFERENCES_ICON_VIEW_LABELS_BESIDE_ICONS,
3417                               G_CALLBACK (labels_beside_icons_changed_callback),
3418                               icon_view);
3419 
3420     g_signal_connect_swapped (caja_compact_view_preferences,
3421                               "changed::" CAJA_PREFERENCES_COMPACT_VIEW_DEFAULT_ZOOM_LEVEL,
3422                               G_CALLBACK (default_zoom_level_changed_callback),
3423                               icon_view);
3424     g_signal_connect_swapped (caja_compact_view_preferences,
3425                               "changed::" CAJA_PREFERENCES_COMPACT_VIEW_ALL_COLUMNS_SAME_WIDTH,
3426                               G_CALLBACK (all_columns_same_width_changed_callback),
3427                               icon_view);
3428 
3429     g_signal_connect_object (get_icon_container (icon_view), "handle_netscape_url",
3430                              G_CALLBACK (icon_view_handle_netscape_url), icon_view, 0);
3431     g_signal_connect_object (get_icon_container (icon_view), "handle_uri_list",
3432                              G_CALLBACK (icon_view_handle_uri_list), icon_view, 0);
3433     g_signal_connect_object (get_icon_container (icon_view), "handle_text",
3434                              G_CALLBACK (icon_view_handle_text), icon_view, 0);
3435     g_signal_connect_object (get_icon_container (icon_view), "handle_raw",
3436                              G_CALLBACK (icon_view_handle_raw), icon_view, 0);
3437 
3438     icon_view->details->clipboard_handler_id =
3439         g_signal_connect (caja_clipboard_monitor_get (),
3440                           "clipboard_info",
3441                           G_CALLBACK (icon_view_notify_clipboard_info), icon_view);
3442 }
3443 
3444 static CajaView *
fm_icon_view_create(CajaWindowSlotInfo * slot)3445 fm_icon_view_create (CajaWindowSlotInfo *slot)
3446 {
3447     FMIconView *view;
3448 
3449     view = g_object_new (FM_TYPE_ICON_VIEW,
3450                          "window-slot", slot,
3451                          "compact", FALSE,
3452                          NULL);
3453 
3454     gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (view)), GTK_STYLE_CLASS_VIEW);
3455 
3456     return CAJA_VIEW (view);
3457 }
3458 
3459 static CajaView *
fm_compact_view_create(CajaWindowSlotInfo * slot)3460 fm_compact_view_create (CajaWindowSlotInfo *slot)
3461 {
3462     FMIconView *view;
3463 
3464     view = g_object_new (FM_TYPE_ICON_VIEW,
3465                          "window-slot", slot,
3466                          "compact", TRUE,
3467                          NULL);
3468 
3469     gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (view)), GTK_STYLE_CLASS_VIEW);
3470 
3471     return CAJA_VIEW (view);
3472 }
3473 
3474 static gboolean
fm_icon_view_supports_uri(const char * uri,GFileType file_type,const char * mime_type)3475 fm_icon_view_supports_uri (const char *uri,
3476                            GFileType file_type,
3477                            const char *mime_type)
3478 {
3479     if (file_type == G_FILE_TYPE_DIRECTORY)
3480     {
3481         return TRUE;
3482     }
3483     if (strcmp (mime_type, CAJA_SAVED_SEARCH_MIMETYPE) == 0)
3484     {
3485         return TRUE;
3486     }
3487     if (g_str_has_prefix (uri, "trash:"))
3488     {
3489         return TRUE;
3490     }
3491     if (g_str_has_prefix (uri, EEL_SEARCH_URI))
3492     {
3493         return TRUE;
3494     }
3495 
3496     return FALSE;
3497 }
3498 
3499 #define TRANSLATE_VIEW_INFO(view_info) \
3500 	view_info.view_combo_label = _(view_info.view_combo_label); \
3501 	view_info.view_menu_label_with_mnemonic = _(view_info.view_menu_label_with_mnemonic); \
3502 	view_info.error_label = _(view_info.error_label); \
3503 	view_info.startup_error_label = _(view_info.startup_error_label); \
3504 	view_info.display_location_label = _(view_info.display_location_label); \
3505 
3506 
3507 static CajaViewInfo fm_icon_view =
3508 {
3509     .id = FM_ICON_VIEW_ID,
3510     /* Translators: this is used in the view selection dropdown
3511      * of navigation windows and in the preferences dialog */
3512     .view_combo_label = N_("Icon View"),
3513     /* Translators: this is used in the view menu */
3514     .view_menu_label_with_mnemonic = N_("_Icons"),
3515     .error_label = N_("The icon view encountered an error."),
3516     .startup_error_label = N_("The icon view encountered an error while starting up."),
3517     .display_location_label = N_("Display this location with the icon view."),
3518     .create = fm_icon_view_create,
3519     .supports_uri = fm_icon_view_supports_uri
3520 };
3521 
3522 static CajaViewInfo fm_compact_view =
3523 {
3524     .id = FM_COMPACT_VIEW_ID,
3525     /* Translators: this is used in the view selection dropdown
3526      * of navigation windows and in the preferences dialog */
3527     .view_combo_label = N_("Compact View"),
3528     /* Translators: this is used in the view menu */
3529     .view_menu_label_with_mnemonic = N_("_Compact"),
3530     .error_label = N_("The compact view encountered an error."),
3531     .startup_error_label = N_("The compact view encountered an error while starting up."),
3532     .display_location_label = N_("Display this location with the compact view."),
3533     .create = fm_compact_view_create,
3534     .supports_uri = fm_icon_view_supports_uri
3535 };
3536 
3537 gboolean
fm_icon_view_is_compact(FMIconView * view)3538 fm_icon_view_is_compact (FMIconView *view)
3539 {
3540     return view->details->compact;
3541 }
3542 
3543 void
fm_icon_view_register(void)3544 fm_icon_view_register (void)
3545 {
3546     TRANSLATE_VIEW_INFO (fm_icon_view)
3547     caja_view_factory_register (&fm_icon_view);
3548 }
3549 
3550 void
fm_compact_view_register(void)3551 fm_compact_view_register (void)
3552 {
3553     TRANSLATE_VIEW_INFO (fm_compact_view)
3554     caja_view_factory_register (&fm_compact_view);
3555 }
3556