1 /*
2  *  nautilus-window-slot.c: Nautilus window slot
3  *
4  *  Copyright (C) 2008 Free Software Foundation, Inc.
5  *
6  *  This program is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU General Public License as
8  *  published by the Free Software Foundation; either version 2 of the
9  *  License, or (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public
17  *  License along with this program; if not, see <http://www.gnu.org/licenses/>.
18  *
19  *  Author: Christian Neumair <cneumair@gnome.org>
20  */
21 
22 #include "config.h"
23 
24 #include "nautilus-window-slot.h"
25 
26 #include "nautilus-application.h"
27 #include "nautilus-bookmark.h"
28 #include "nautilus-bookmark-list.h"
29 #include "nautilus-mime-actions.h"
30 #include "nautilus-places-view.h"
31 #include "nautilus-query-editor.h"
32 #include "nautilus-special-location-bar.h"
33 #include "nautilus-toolbar.h"
34 #include "nautilus-trash-bar.h"
35 #include "nautilus-trash-monitor.h"
36 #include "nautilus-view.h"
37 #include "nautilus-window.h"
38 #include "nautilus-x-content-bar.h"
39 
40 #include <glib/gi18n.h>
41 
42 #include "nautilus-file.h"
43 #include "nautilus-file-utilities.h"
44 #include "nautilus-global-preferences.h"
45 #include "nautilus-module.h"
46 #include "nautilus-monitor.h"
47 #include "nautilus-profile.h"
48 #include <nautilus-extension.h>
49 #include "nautilus-ui-utilities.h"
50 #include <eel/eel-vfs-extensions.h>
51 
52 enum
53 {
54     PROP_ACTIVE = 1,
55     PROP_WINDOW,
56     PROP_ICON,
57     PROP_TOOLBAR_MENU_SECTIONS,
58     PROP_EXTENSIONS_BACKGROUND_MENU,
59     PROP_TEMPLATES_MENU,
60     PROP_LOADING,
61     PROP_SEARCHING,
62     PROP_SELECTION,
63     PROP_LOCATION,
64     PROP_TOOLTIP,
65     NUM_PROPERTIES
66 };
67 
68 struct _NautilusWindowSlot
69 {
70     GtkBox parent_instance;
71 
72     NautilusWindow *window;
73 
74     gboolean active : 1;
75     guint loading : 1;
76 
77     /* slot contains
78      *  1) an vbox containing extra_location_widgets
79      *  2) the view
80      */
81     GtkWidget *extra_location_widgets;
82 
83     /* Slot actions */
84     GActionGroup *slot_action_group;
85 
86     /* Current location. */
87     GFile *location;
88     gchar *title;
89 
90     /* Viewed file */
91     NautilusView *content_view;
92     NautilusView *new_content_view;
93     NautilusFile *viewed_file;
94     gboolean viewed_file_seen;
95     gboolean viewed_file_in_trash;
96 
97     /* Information about bookmarks and history list */
98     NautilusBookmark *current_location_bookmark;
99     NautilusBookmark *last_location_bookmark;
100     GList *back_list;
101     GList *forward_list;
102 
103     /* Query editor */
104     NautilusQueryEditor *query_editor;
105     NautilusQuery *pending_search_query;
106     gulong qe_changed_id;
107     gulong qe_cancel_id;
108     gulong qe_activated_id;
109     gulong qe_focus_view_id;
110 
111     GtkLabel *search_info_label;
112     GtkRevealer *search_info_label_revealer;
113 
114     /* Load state */
115     GCancellable *find_mount_cancellable;
116     /* It could be either the view is loading the files or the search didn't
117      * finish. Used for showing a spinner to provide feedback to the user. */
118     gboolean allow_stop;
119     gboolean needs_reload;
120 
121     /* New location. */
122     GFile *pending_location;
123     NautilusLocationChangeType location_change_type;
124     guint location_change_distance;
125     char *pending_scroll_to;
126     GList *pending_selection;
127     NautilusFile *pending_file_to_activate;
128     NautilusFile *determine_view_file;
129     GCancellable *mount_cancellable;
130     GError *mount_error;
131     gboolean tried_mount;
132     gint view_mode_before_search;
133     gint view_mode_before_places;
134 
135     /* Menus */
136     GMenuModel *extensions_background_menu;
137     GMenuModel *templates_menu;
138 
139     /* View bindings */
140     GBinding *searching_binding;
141     GBinding *selection_binding;
142     GBinding *extensions_background_menu_binding;
143     GBinding *templates_menu_binding;
144     gboolean searching;
145     GList *selection;
146 };
147 
148 G_DEFINE_TYPE (NautilusWindowSlot, nautilus_window_slot, GTK_TYPE_BOX);
149 
150 static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
151 
152 static void nautilus_window_slot_force_reload (NautilusWindowSlot *self);
153 static void change_view (NautilusWindowSlot *self);
154 static void hide_query_editor (NautilusWindowSlot *self);
155 static void nautilus_window_slot_sync_actions (NautilusWindowSlot *self);
156 static void nautilus_window_slot_connect_new_content_view (NautilusWindowSlot *self);
157 static void nautilus_window_slot_disconnect_content_view (NautilusWindowSlot *self);
158 static gboolean nautilus_window_slot_content_view_matches (NautilusWindowSlot *self,
159                                                            guint               id);
160 static NautilusView *nautilus_window_slot_get_view_for_location (NautilusWindowSlot *self,
161                                                                  GFile              *location);
162 static void nautilus_window_slot_set_content_view (NautilusWindowSlot *self,
163                                                    guint               id);
164 static void nautilus_window_slot_set_loading (NautilusWindowSlot *self,
165                                               gboolean            loading);
166 char *nautilus_window_slot_get_location_uri (NautilusWindowSlot *self);
167 static void nautilus_window_slot_set_search_visible (NautilusWindowSlot *self,
168                                                      gboolean            visible);
169 static gboolean nautilus_window_slot_get_search_visible (NautilusWindowSlot *self);
170 static void nautilus_window_slot_set_location (NautilusWindowSlot *self,
171                                                GFile              *location);
172 static void trash_state_changed_cb (NautilusTrashMonitor *monitor,
173                                     gboolean              is_empty,
174                                     gpointer              user_data);
175 static void update_search_information (NautilusWindowSlot *self);
176 static void real_set_extensions_background_menu (NautilusWindowSlot *self,
177                                                  GMenuModel         *menu);
178 static GMenuModel *real_get_extensions_background_menu (NautilusWindowSlot *self);
179 static void real_set_templates_menu (NautilusWindowSlot *self,
180                                      GMenuModel         *menu);
181 static GMenuModel *real_get_templates_menu (NautilusWindowSlot *self);
182 static void nautilus_window_slot_setup_extra_location_widgets (NautilusWindowSlot *self);
183 
184 void
free_navigation_state(gpointer data)185 free_navigation_state (gpointer data)
186 {
187     NautilusNavigationState *navigation_state = data;
188 
189     g_list_free_full (navigation_state->back_list, g_object_unref);
190     g_list_free_full (navigation_state->forward_list, g_object_unref);
191     nautilus_file_unref (navigation_state->file);
192     g_clear_object (&navigation_state->current_location_bookmark);
193 
194     g_free (navigation_state);
195 }
196 
197 void
nautilus_window_slot_restore_navigation_state(NautilusWindowSlot * self,NautilusNavigationState * data)198 nautilus_window_slot_restore_navigation_state (NautilusWindowSlot      *self,
199                                                NautilusNavigationState *data)
200 {
201     self->back_list = g_steal_pointer (&data->back_list);
202 
203     self->forward_list = g_steal_pointer (&data->forward_list);
204 
205     self->view_mode_before_search = data->view_before_search;
206 
207     g_set_object (&self->current_location_bookmark, data->current_location_bookmark);
208 
209     self->location_change_type = NAUTILUS_LOCATION_CHANGE_RELOAD;
210 }
211 
212 NautilusNavigationState *
nautilus_window_slot_get_navigation_state(NautilusWindowSlot * self)213 nautilus_window_slot_get_navigation_state (NautilusWindowSlot *self)
214 {
215     NautilusNavigationState *data;
216     GList *back_list;
217     GList *forward_list;
218 
219     if (self->location == NULL)
220     {
221         return NULL;
222     }
223 
224     back_list = g_list_copy_deep (self->back_list,
225                                   (GCopyFunc) g_object_ref,
226                                   NULL);
227     forward_list = g_list_copy_deep (self->forward_list,
228                                      (GCopyFunc) g_object_ref,
229                                      NULL);
230 
231     /* This data is used to restore a tab after it was closed.
232      * In order to do that we need to keep the history, what was
233      * the view mode before search and a reference to the file.
234      * A GFile isn't enough, as the NautilusFile also keeps a
235      * reference to the search directory */
236     data = g_new0 (NautilusNavigationState, 1);
237     data->back_list = back_list;
238     data->forward_list = forward_list;
239     data->file = nautilus_file_get (self->location);
240     data->view_before_search = self->view_mode_before_search;
241     g_set_object (&data->current_location_bookmark, self->current_location_bookmark);
242 
243     return data;
244 }
245 
246 static NautilusView *
nautilus_window_slot_get_view_for_location(NautilusWindowSlot * self,GFile * location)247 nautilus_window_slot_get_view_for_location (NautilusWindowSlot *self,
248                                             GFile              *location)
249 {
250     g_autoptr (NautilusFile) file = NULL;
251     NautilusView *view;
252     guint view_id;
253 
254     file = nautilus_file_get (location);
255     view = NULL;
256     view_id = NAUTILUS_VIEW_INVALID_ID;
257 
258     if (nautilus_file_is_other_locations (file))
259     {
260         view = NAUTILUS_VIEW (nautilus_places_view_new ());
261 
262         /* Save the current view, so we can go back after places view */
263         if (NAUTILUS_IS_FILES_VIEW (self->content_view))
264         {
265             self->view_mode_before_places = nautilus_view_get_view_id (self->content_view);
266         }
267 
268         return view;
269     }
270 
271     /* If we are in search, try to use by default list view. */
272     if (nautilus_file_is_in_search (file))
273     {
274         /* If it's already set, is because we already made the change to search mode,
275          * so the view mode of the current view will be the one search is using,
276          * which is not the one we are interested in */
277         if (self->view_mode_before_search == NAUTILUS_VIEW_INVALID_ID &&
278             NAUTILUS_IS_FILES_VIEW (self->content_view))
279         {
280             self->view_mode_before_search = nautilus_view_get_view_id (self->content_view);
281         }
282         view_id = g_settings_get_enum (nautilus_preferences, NAUTILUS_PREFERENCES_SEARCH_VIEW);
283     }
284     else if (self->content_view != NULL)
285     {
286         /* If there is already a view, just use the view mode that it's currently using, or
287          * if we were on search before, use what we were using before entering
288          * search mode */
289         if (self->view_mode_before_search != NAUTILUS_VIEW_INVALID_ID)
290         {
291             view_id = self->view_mode_before_search;
292             self->view_mode_before_search = NAUTILUS_VIEW_INVALID_ID;
293         }
294         else if (NAUTILUS_IS_PLACES_VIEW (self->content_view))
295         {
296             view_id = self->view_mode_before_places;
297             self->view_mode_before_places = NAUTILUS_VIEW_INVALID_ID;
298         }
299         else
300         {
301             view_id = nautilus_view_get_view_id (self->content_view);
302         }
303     }
304 
305     /* If there is not previous view in this slot, use the default view mode
306      * from preferences */
307     if (view_id == NAUTILUS_VIEW_INVALID_ID)
308     {
309         view_id = g_settings_get_enum (nautilus_preferences, NAUTILUS_PREFERENCES_DEFAULT_FOLDER_VIEWER);
310     }
311 
312     /* Try to reuse the current view */
313     if (nautilus_window_slot_content_view_matches (self, view_id))
314     {
315         view = self->content_view;
316     }
317     else
318     {
319         view = NAUTILUS_VIEW (nautilus_files_view_new (view_id, self));
320     }
321 
322     return view;
323 }
324 
325 static gboolean
nautilus_window_slot_content_view_matches(NautilusWindowSlot * self,guint id)326 nautilus_window_slot_content_view_matches (NautilusWindowSlot *self,
327                                            guint               id)
328 {
329     if (self->content_view == NULL)
330     {
331         return FALSE;
332     }
333 
334     if (id != NAUTILUS_VIEW_INVALID_ID)
335     {
336         return nautilus_view_get_view_id (self->content_view) == id;
337     }
338     else
339     {
340         return FALSE;
341     }
342 }
343 
344 static void
update_search_visible(NautilusWindowSlot * self)345 update_search_visible (NautilusWindowSlot *self)
346 {
347     NautilusQuery *query;
348     NautilusView *view;
349 
350     view = nautilus_window_slot_get_current_view (self);
351     /* If we changed location just to another search location, for example,
352      * when changing the query, just keep the search visible.
353      * Make sure the search is visible though, since we could be returning
354      * from a previous search location when using the history */
355     if (nautilus_view_is_searching (view))
356     {
357         nautilus_window_slot_set_search_visible (self, TRUE);
358         return;
359     }
360 
361     query = nautilus_query_editor_get_query (self->query_editor);
362     if (query)
363     {
364         /* If the view is not searching, but search is visible, and the
365          * query is empty, we don't hide it. Some users enable the search
366          * and then change locations, then they search. */
367         if (!nautilus_query_is_empty (query))
368         {
369             nautilus_window_slot_set_search_visible (self, FALSE);
370         }
371     }
372 
373     if (self->pending_search_query)
374     {
375         nautilus_window_slot_search (self, g_object_ref (self->pending_search_query));
376     }
377 }
378 
379 static void
nautilus_window_slot_sync_actions(NautilusWindowSlot * self)380 nautilus_window_slot_sync_actions (NautilusWindowSlot *self)
381 {
382     NautilusView *view;
383     GAction *action;
384     GVariant *variant;
385 
386     if (!nautilus_window_slot_get_active (self))
387     {
388         return;
389     }
390 
391     if (self->content_view == NULL || self->new_content_view != NULL)
392     {
393         return;
394     }
395 
396     /* Check if we need to close the search or show search after changing the location.
397      * Needs to be done after the change has been done, if not, a loop happens,
398      * because setting the search enabled or not actually opens a location */
399     update_search_visible (self);
400 
401     /* Files view mode */
402     view = nautilus_window_slot_get_current_view (self);
403     action = g_action_map_lookup_action (G_ACTION_MAP (self->slot_action_group), "files-view-mode");
404     g_simple_action_set_enabled (G_SIMPLE_ACTION (action), NAUTILUS_IS_FILES_VIEW (view));
405     if (g_action_get_enabled (action))
406     {
407         variant = g_variant_new_uint32 (nautilus_view_get_view_id (view));
408         g_action_change_state (action, variant);
409     }
410     action = g_action_map_lookup_action (G_ACTION_MAP (self->slot_action_group), "files-view-mode-toggle");
411     g_simple_action_set_enabled (G_SIMPLE_ACTION (action), NAUTILUS_IS_FILES_VIEW (view));
412 }
413 
414 static void
query_editor_cancel_callback(NautilusQueryEditor * editor,NautilusWindowSlot * self)415 query_editor_cancel_callback (NautilusQueryEditor *editor,
416                               NautilusWindowSlot  *self)
417 {
418     nautilus_window_slot_set_search_visible (self, FALSE);
419 }
420 
421 static void
query_editor_activated_callback(NautilusQueryEditor * editor,NautilusWindowSlot * self)422 query_editor_activated_callback (NautilusQueryEditor *editor,
423                                  NautilusWindowSlot  *self)
424 {
425     if (self->content_view != NULL)
426     {
427         if (NAUTILUS_IS_FILES_VIEW (self->content_view))
428         {
429             nautilus_files_view_activate_selection (NAUTILUS_FILES_VIEW (self->content_view));
430         }
431     }
432 }
433 
434 static void
query_editor_focus_view_callback(NautilusQueryEditor * editor,NautilusWindowSlot * self)435 query_editor_focus_view_callback (NautilusQueryEditor *editor,
436                                   NautilusWindowSlot  *self)
437 {
438     if (self->content_view != NULL)
439     {
440         gtk_widget_grab_focus (GTK_WIDGET (self->content_view));
441     }
442 }
443 
444 static void
query_editor_changed_callback(NautilusQueryEditor * editor,NautilusQuery * query,gboolean reload,NautilusWindowSlot * self)445 query_editor_changed_callback (NautilusQueryEditor *editor,
446                                NautilusQuery       *query,
447                                gboolean             reload,
448                                NautilusWindowSlot  *self)
449 {
450     NautilusView *view;
451 
452     view = nautilus_window_slot_get_current_view (self);
453 
454     nautilus_view_set_search_query (view, query);
455     nautilus_window_slot_open_location_full (self, nautilus_view_get_location (view), 0, NULL);
456 }
457 
458 static void
hide_query_editor(NautilusWindowSlot * self)459 hide_query_editor (NautilusWindowSlot *self)
460 {
461     NautilusView *view;
462 
463     view = nautilus_window_slot_get_current_view (self);
464 
465     g_clear_signal_handler (&self->qe_changed_id, self->query_editor);
466     g_clear_signal_handler (&self->qe_cancel_id, self->query_editor);
467     g_clear_signal_handler (&self->qe_activated_id, self->query_editor);
468     g_clear_signal_handler (&self->qe_focus_view_id, self->query_editor);
469 
470     nautilus_query_editor_set_query (self->query_editor, NULL);
471 
472     if (nautilus_view_is_searching (view))
473     {
474         g_autolist (NautilusFile) selection = NULL;
475 
476         selection = nautilus_view_get_selection (view);
477 
478         nautilus_view_set_search_query (view, NULL);
479         nautilus_window_slot_open_location_full (self,
480                                                  nautilus_view_get_location (view),
481                                                  0,
482                                                  selection);
483     }
484 
485     if (nautilus_window_slot_get_active (self))
486     {
487         gtk_widget_grab_focus (GTK_WIDGET (self->window));
488     }
489 }
490 
491 static GFile *
nautilus_window_slot_get_current_location(NautilusWindowSlot * self)492 nautilus_window_slot_get_current_location (NautilusWindowSlot *self)
493 {
494     if (self->pending_location != NULL)
495     {
496         return self->pending_location;
497     }
498 
499     if (self->location != NULL)
500     {
501         return self->location;
502     }
503 
504     return NULL;
505 }
506 
507 static void
show_query_editor(NautilusWindowSlot * self)508 show_query_editor (NautilusWindowSlot *self)
509 {
510     NautilusView *view;
511 
512     view = nautilus_window_slot_get_current_view (self);
513     if (view == NULL)
514     {
515         return;
516     }
517 
518     if (nautilus_view_is_searching (view))
519     {
520         NautilusQuery *query;
521 
522         query = nautilus_view_get_search_query (view);
523 
524         if (query != NULL)
525         {
526             nautilus_query_editor_set_query (self->query_editor, query);
527         }
528     }
529 
530     gtk_widget_grab_focus (GTK_WIDGET (self->query_editor));
531 
532     if (self->qe_changed_id == 0)
533     {
534         self->qe_changed_id =
535             g_signal_connect (self->query_editor, "changed",
536                               G_CALLBACK (query_editor_changed_callback), self);
537     }
538     if (self->qe_cancel_id == 0)
539     {
540         self->qe_cancel_id =
541             g_signal_connect (self->query_editor, "cancel",
542                               G_CALLBACK (query_editor_cancel_callback), self);
543     }
544     if (self->qe_activated_id == 0)
545     {
546         self->qe_activated_id =
547             g_signal_connect (self->query_editor, "activated",
548                               G_CALLBACK (query_editor_activated_callback), self);
549     }
550     if (self->qe_focus_view_id == 0)
551     {
552         self->qe_focus_view_id =
553             g_signal_connect (self->query_editor, "focus-view",
554                               G_CALLBACK (query_editor_focus_view_callback), self);
555     }
556 }
557 
558 static void
nautilus_window_slot_set_search_visible(NautilusWindowSlot * self,gboolean visible)559 nautilus_window_slot_set_search_visible (NautilusWindowSlot *self,
560                                          gboolean            visible)
561 {
562     GAction *action;
563 
564     action = g_action_map_lookup_action (G_ACTION_MAP (self->slot_action_group),
565                                          "search-visible");
566     g_action_change_state (action, g_variant_new_boolean (visible));
567 }
568 
569 static gboolean
nautilus_window_slot_get_search_visible(NautilusWindowSlot * self)570 nautilus_window_slot_get_search_visible (NautilusWindowSlot *self)
571 {
572     GAction *action;
573     GVariant *state;
574     gboolean searching;
575 
576     action = g_action_map_lookup_action (G_ACTION_MAP (self->slot_action_group),
577                                          "search-visible");
578     state = g_action_get_state (action);
579     searching = g_variant_get_boolean (state);
580 
581     g_variant_unref (state);
582 
583     return searching;
584 }
585 
586 void
nautilus_window_slot_search(NautilusWindowSlot * self,NautilusQuery * query)587 nautilus_window_slot_search (NautilusWindowSlot *self,
588                              NautilusQuery      *query)
589 {
590     NautilusView *view;
591 
592     g_clear_object (&self->pending_search_query);
593 
594     view = nautilus_window_slot_get_current_view (self);
595     /* We could call this when the location is still being checked in the
596      * window slot. For that, save the search we want to do for once we have
597      * a view set up */
598     if (view)
599     {
600         nautilus_window_slot_set_search_visible (self, TRUE);
601         nautilus_query_editor_set_query (self->query_editor, query);
602     }
603     else
604     {
605         self->pending_search_query = g_object_ref (query);
606     }
607 }
608 
609 gboolean
nautilus_window_slot_handle_event(NautilusWindowSlot * self,GdkEvent * event)610 nautilus_window_slot_handle_event (NautilusWindowSlot *self,
611                                    GdkEvent           *event)
612 {
613     gboolean retval;
614     GAction *action;
615     guint keyval;
616 
617     retval = FALSE;
618     action = g_action_map_lookup_action (G_ACTION_MAP (self->slot_action_group),
619                                          "search-visible");
620 
621     if (gdk_event_get_event_type (event) != GDK_KEY_PRESS)
622     {
623         return GDK_EVENT_PROPAGATE;
624     }
625 
626     if (G_UNLIKELY (!gdk_event_get_keyval (event, &keyval)))
627     {
628         g_return_val_if_reached (GDK_EVENT_PROPAGATE);
629     }
630 
631     if (keyval == GDK_KEY_Escape)
632     {
633         g_autoptr (GVariant) state = NULL;
634 
635         state = g_action_get_state (action);
636 
637         if (g_variant_get_boolean (state))
638         {
639             nautilus_window_slot_set_search_visible (self, FALSE);
640         }
641     }
642 
643     /* If the action is not enabled, don't try to handle search */
644     if (g_action_get_enabled (action))
645     {
646         retval = nautilus_query_editor_handle_event (self->query_editor, event);
647     }
648 
649     if (retval)
650     {
651         nautilus_window_slot_set_search_visible (self, TRUE);
652     }
653 
654     return retval;
655 }
656 
657 static void
remove_all_extra_location_widgets(GtkWidget * widget,gpointer data)658 remove_all_extra_location_widgets (GtkWidget *widget,
659                                    gpointer   data)
660 {
661     NautilusWindowSlot *self = data;
662     NautilusDirectory *directory;
663 
664     directory = nautilus_directory_get (self->location);
665     if (widget != GTK_WIDGET (self->query_editor))
666     {
667         gtk_container_remove (GTK_CONTAINER (self->extra_location_widgets), widget);
668     }
669 
670     nautilus_directory_unref (directory);
671 }
672 
673 static void
nautilus_window_slot_remove_extra_location_widgets(NautilusWindowSlot * self)674 nautilus_window_slot_remove_extra_location_widgets (NautilusWindowSlot *self)
675 {
676     gtk_container_foreach (GTK_CONTAINER (self->extra_location_widgets),
677                            remove_all_extra_location_widgets,
678                            self);
679 }
680 
681 static void
nautilus_window_slot_add_extra_location_widget(NautilusWindowSlot * self,GtkWidget * widget)682 nautilus_window_slot_add_extra_location_widget (NautilusWindowSlot *self,
683                                                 GtkWidget          *widget)
684 {
685     gtk_box_pack_start (GTK_BOX (self->extra_location_widgets),
686                         widget, FALSE, TRUE, 0);
687     gtk_widget_show (self->extra_location_widgets);
688 }
689 
690 static void
nautilus_window_slot_set_searching(NautilusWindowSlot * self,gboolean searching)691 nautilus_window_slot_set_searching (NautilusWindowSlot *self,
692                                     gboolean            searching)
693 {
694     self->searching = searching;
695     g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SEARCHING]);
696 }
697 
698 static void
nautilus_window_slot_set_selection(NautilusWindowSlot * self,GList * selection)699 nautilus_window_slot_set_selection (NautilusWindowSlot *self,
700                                     GList              *selection)
701 {
702     self->selection = selection;
703     g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECTION]);
704 }
705 
706 static void
real_set_extensions_background_menu(NautilusWindowSlot * self,GMenuModel * menu)707 real_set_extensions_background_menu (NautilusWindowSlot *self,
708                                      GMenuModel         *menu)
709 {
710     g_set_object (&self->extensions_background_menu, menu);
711 }
712 
713 static void
real_set_templates_menu(NautilusWindowSlot * self,GMenuModel * menu)714 real_set_templates_menu (NautilusWindowSlot *self,
715                          GMenuModel         *menu)
716 {
717     g_set_object (&self->templates_menu, menu);
718 }
719 
720 static void
nautilus_window_slot_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)721 nautilus_window_slot_set_property (GObject      *object,
722                                    guint         property_id,
723                                    const GValue *value,
724                                    GParamSpec   *pspec)
725 {
726     NautilusWindowSlot *self = NAUTILUS_WINDOW_SLOT (object);
727 
728     switch (property_id)
729     {
730         case PROP_ACTIVE:
731         {
732             nautilus_window_slot_set_active (self, g_value_get_boolean (value));
733         }
734         break;
735 
736         case PROP_WINDOW:
737         {
738             nautilus_window_slot_set_window (self, g_value_get_object (value));
739         }
740         break;
741 
742         case PROP_LOCATION:
743         {
744             nautilus_window_slot_set_location (self, g_value_get_object (value));
745         }
746         break;
747 
748         case PROP_SEARCHING:
749         {
750             nautilus_window_slot_set_searching (self, g_value_get_boolean (value));
751         }
752         break;
753 
754         case PROP_EXTENSIONS_BACKGROUND_MENU:
755         {
756             real_set_extensions_background_menu (self, g_value_get_object (value));
757         }
758         break;
759 
760         case PROP_TEMPLATES_MENU:
761         {
762             real_set_templates_menu (self, g_value_get_object (value));
763         }
764         break;
765 
766         case PROP_SELECTION:
767         {
768             nautilus_window_slot_set_selection (self, g_value_get_pointer (value));
769         }
770         break;
771 
772         default:
773         {
774             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
775         }
776         break;
777     }
778 }
779 
780 static GMenuModel *
real_get_extensions_background_menu(NautilusWindowSlot * self)781 real_get_extensions_background_menu (NautilusWindowSlot *self)
782 {
783     return self->extensions_background_menu;
784 }
785 
786 GMenuModel *
nautilus_window_slot_get_extensions_background_menu(NautilusWindowSlot * self)787 nautilus_window_slot_get_extensions_background_menu (NautilusWindowSlot *self)
788 {
789     GMenuModel *menu = NULL;
790 
791     g_object_get (self, "extensions-background-menu", &menu, NULL);
792 
793     return menu;
794 }
795 
796 static GMenuModel *
real_get_templates_menu(NautilusWindowSlot * self)797 real_get_templates_menu (NautilusWindowSlot *self)
798 {
799     return self->templates_menu;
800 }
801 
802 GMenuModel *
nautilus_window_slot_get_templates_menu(NautilusWindowSlot * self)803 nautilus_window_slot_get_templates_menu (NautilusWindowSlot *self)
804 {
805     GMenuModel *menu = NULL;
806 
807     g_object_get (self, "templates-menu", &menu, NULL);
808 
809     return menu;
810 }
811 
812 static void
nautilus_window_slot_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)813 nautilus_window_slot_get_property (GObject    *object,
814                                    guint       property_id,
815                                    GValue     *value,
816                                    GParamSpec *pspec)
817 {
818     NautilusWindowSlot *self = NAUTILUS_WINDOW_SLOT (object);
819     switch (property_id)
820     {
821         case PROP_ACTIVE:
822         {
823             g_value_set_boolean (value, nautilus_window_slot_get_active (self));
824         }
825         break;
826 
827         case PROP_WINDOW:
828         {
829             g_value_set_object (value, self->window);
830         }
831         break;
832 
833         case PROP_ICON:
834         {
835             g_value_take_object (value, nautilus_window_slot_get_icon (self));
836         }
837         break;
838 
839         case PROP_TOOLBAR_MENU_SECTIONS:
840         {
841             g_value_set_object (value, nautilus_window_slot_get_toolbar_menu_sections (self));
842         }
843         break;
844 
845         case PROP_EXTENSIONS_BACKGROUND_MENU:
846         {
847             g_value_set_object (value, real_get_extensions_background_menu (self));
848         }
849         break;
850 
851         case PROP_TEMPLATES_MENU:
852         {
853             g_value_set_object (value, real_get_templates_menu (self));
854         }
855         break;
856 
857         case PROP_LOADING:
858         {
859             g_value_set_boolean (value, nautilus_window_slot_get_loading (self));
860         }
861         break;
862 
863         case PROP_LOCATION:
864         {
865             g_value_set_object (value, nautilus_window_slot_get_current_location (self));
866         }
867         break;
868 
869         case PROP_SEARCHING:
870         {
871             g_value_set_boolean (value, nautilus_window_slot_get_searching (self));
872         }
873         break;
874 
875         case PROP_TOOLTIP:
876         {
877             g_value_set_static_string (value, nautilus_window_slot_get_tooltip (self));
878         }
879         break;
880 
881         default:
882         {
883             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
884         }
885         break;
886     }
887 }
888 
889 gboolean
nautilus_window_slot_get_searching(NautilusWindowSlot * self)890 nautilus_window_slot_get_searching (NautilusWindowSlot *self)
891 {
892     return self->searching;
893 }
894 
895 GList *
nautilus_window_slot_get_selection(NautilusWindowSlot * self)896 nautilus_window_slot_get_selection (NautilusWindowSlot *self)
897 {
898     return self->selection;
899 }
900 
901 static void
nautilus_window_slot_constructed(GObject * object)902 nautilus_window_slot_constructed (GObject *object)
903 {
904     NautilusWindowSlot *self = NAUTILUS_WINDOW_SLOT (object);
905     GtkWidget *extras_vbox;
906     GtkStyleContext *style_context;
907 
908     G_OBJECT_CLASS (nautilus_window_slot_parent_class)->constructed (object);
909 
910     gtk_orientable_set_orientation (GTK_ORIENTABLE (self),
911                                     GTK_ORIENTATION_VERTICAL);
912     gtk_widget_show (GTK_WIDGET (self));
913 
914     extras_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
915     self->extra_location_widgets = extras_vbox;
916     gtk_box_pack_start (GTK_BOX (self), extras_vbox, FALSE, FALSE, 0);
917     gtk_widget_show (extras_vbox);
918 
919     self->query_editor = NAUTILUS_QUERY_EDITOR (nautilus_query_editor_new ());
920     /* We want to keep alive the query editor betwen additions and removals on the
921      * UI, specifically when the toolbar adds or removes it */
922     g_object_ref_sink (self->query_editor);
923     gtk_widget_show (GTK_WIDGET (self->query_editor));
924 
925     self->search_info_label = GTK_LABEL (gtk_label_new (NULL));
926     self->search_info_label_revealer = GTK_REVEALER (gtk_revealer_new ());
927 
928     gtk_container_add (GTK_CONTAINER (self->search_info_label_revealer),
929                        GTK_WIDGET (self->search_info_label));
930     gtk_container_add (GTK_CONTAINER (self),
931                        GTK_WIDGET (self->search_info_label_revealer));
932 
933     gtk_widget_show (GTK_WIDGET (self->search_info_label));
934     gtk_widget_show (GTK_WIDGET (self->search_info_label_revealer));
935 
936     style_context = gtk_widget_get_style_context (GTK_WIDGET (self->search_info_label));
937     gtk_style_context_add_class (style_context, "search-information");
938 
939     g_object_bind_property (self, "location",
940                             self->query_editor, "location",
941                             G_BINDING_DEFAULT);
942 
943     self->title = g_strdup (_("Loading…"));
944 }
945 
946 static void
action_search_visible(GSimpleAction * action,GVariant * state,gpointer user_data)947 action_search_visible (GSimpleAction *action,
948                        GVariant      *state,
949                        gpointer       user_data)
950 {
951     NautilusWindowSlot *self;
952     GVariant *current_state;
953 
954     self = NAUTILUS_WINDOW_SLOT (user_data);
955     current_state = g_action_get_state (G_ACTION (action));
956     if (g_variant_get_boolean (current_state) != g_variant_get_boolean (state))
957     {
958         g_simple_action_set_state (action, state);
959 
960         if (g_variant_get_boolean (state))
961         {
962             show_query_editor (self);
963             nautilus_window_slot_set_searching (self, TRUE);
964         }
965         else
966         {
967             hide_query_editor (self);
968             nautilus_window_slot_set_searching (self, FALSE);
969         }
970 
971         update_search_information (self);
972     }
973 
974     g_variant_unref (current_state);
975 }
976 
977 static void
change_files_view_mode(NautilusWindowSlot * self,guint view_id)978 change_files_view_mode (NautilusWindowSlot *self,
979                         guint               view_id)
980 {
981     const gchar *preferences_key;
982 
983     if (!nautilus_window_slot_content_view_matches (self, view_id))
984     {
985         nautilus_window_slot_set_content_view (self, view_id);
986     }
987     preferences_key = nautilus_view_is_searching (nautilus_window_slot_get_current_view (self)) ?
988                       NAUTILUS_PREFERENCES_SEARCH_VIEW :
989                       NAUTILUS_PREFERENCES_DEFAULT_FOLDER_VIEWER;
990 
991     g_settings_set_enum (nautilus_preferences, preferences_key, view_id);
992 }
993 
994 static void
action_files_view_mode_toggle(GSimpleAction * action,GVariant * value,gpointer user_data)995 action_files_view_mode_toggle (GSimpleAction *action,
996                                GVariant      *value,
997                                gpointer       user_data)
998 {
999     NautilusWindowSlot *self;
1000     guint current_view_id;
1001 
1002     self = NAUTILUS_WINDOW_SLOT (user_data);
1003     if (!NAUTILUS_IS_FILES_VIEW (self->content_view))
1004     {
1005         return;
1006     }
1007 
1008     current_view_id = nautilus_view_get_view_id (self->content_view);
1009     if (current_view_id == NAUTILUS_VIEW_LIST_ID)
1010     {
1011         change_files_view_mode (self, NAUTILUS_VIEW_GRID_ID);
1012     }
1013     else
1014     {
1015         change_files_view_mode (self, NAUTILUS_VIEW_LIST_ID);
1016     }
1017 }
1018 
1019 static void
action_files_view_mode(GSimpleAction * action,GVariant * value,gpointer user_data)1020 action_files_view_mode (GSimpleAction *action,
1021                         GVariant      *value,
1022                         gpointer       user_data)
1023 {
1024     NautilusWindowSlot *self;
1025     guint view_id;
1026 
1027     view_id = g_variant_get_uint32 (value);
1028     self = NAUTILUS_WINDOW_SLOT (user_data);
1029 
1030     if (!NAUTILUS_IS_FILES_VIEW (nautilus_window_slot_get_current_view (self)))
1031     {
1032         return;
1033     }
1034 
1035     change_files_view_mode (self, view_id);
1036 
1037     g_simple_action_set_state (action, value);
1038 }
1039 
1040 const GActionEntry slot_entries[] =
1041 {
1042     { "files-view-mode", NULL, "u", "uint32 " G_STRINGIFY (NAUTILUS_VIEW_INVALID_ID), action_files_view_mode },
1043     { "files-view-mode-toggle", action_files_view_mode_toggle },
1044     { "search-visible", NULL, NULL, "false", action_search_visible },
1045 };
1046 
1047 static void
update_search_information(NautilusWindowSlot * self)1048 update_search_information (NautilusWindowSlot *self)
1049 {
1050     GFile *location;
1051 
1052     if (!nautilus_window_slot_get_searching (self))
1053     {
1054         gtk_revealer_set_reveal_child (self->search_info_label_revealer, FALSE);
1055 
1056         return;
1057     }
1058 
1059     location = nautilus_window_slot_get_current_location (self);
1060 
1061     if (location)
1062     {
1063         g_autoptr (NautilusFile) file = NULL;
1064         gchar *label;
1065         g_autofree gchar *uri = NULL;
1066 
1067         file = nautilus_file_get (location);
1068         label = NULL;
1069         uri = g_file_get_uri (location);
1070 
1071         if (nautilus_file_is_other_locations (file))
1072         {
1073             label = _("Searching locations only");
1074         }
1075         else if (g_str_has_prefix (uri, "network://"))
1076         {
1077             label = _("Searching network locations only");
1078         }
1079         else if (nautilus_file_is_remote (file) &&
1080                  location_settings_search_get_recursive_for_location (location) == NAUTILUS_QUERY_RECURSIVE_NEVER)
1081         {
1082             label = _("Remote location — only searching the current folder");
1083         }
1084         else if (location_settings_search_get_recursive_for_location (location) == NAUTILUS_QUERY_RECURSIVE_NEVER)
1085         {
1086             label = _("Only searching the current folder");
1087         }
1088 
1089         gtk_label_set_label (self->search_info_label, label);
1090         gtk_revealer_set_reveal_child (self->search_info_label_revealer,
1091                                        label != NULL);
1092     }
1093 }
1094 
1095 static void
recursive_search_preferences_changed(GSettings * settings,gchar * key,gpointer callback_data)1096 recursive_search_preferences_changed (GSettings *settings,
1097                                       gchar     *key,
1098                                       gpointer   callback_data)
1099 {
1100     NautilusWindowSlot *self;
1101 
1102     self = callback_data;
1103 
1104     update_search_information (self);
1105 }
1106 
1107 static void
use_experimental_views_changed_callback(GSettings * settings,gchar * key,gpointer callback_data)1108 use_experimental_views_changed_callback (GSettings *settings,
1109                                          gchar     *key,
1110                                          gpointer   callback_data)
1111 {
1112     NautilusWindowSlot *self;
1113 
1114     self = callback_data;
1115 
1116     if (nautilus_window_slot_content_view_matches (self, NAUTILUS_VIEW_GRID_ID))
1117     {
1118         /* Note that although this call does not change the view id,
1119          * it changes the canvas view between new and old.
1120          */
1121         nautilus_window_slot_set_content_view (self, NAUTILUS_VIEW_GRID_ID);
1122     }
1123 }
1124 
1125 static void
nautilus_window_slot_init(NautilusWindowSlot * self)1126 nautilus_window_slot_init (NautilusWindowSlot *self)
1127 {
1128     GApplication *app;
1129     app = g_application_get_default ();
1130 
1131     g_signal_connect (nautilus_trash_monitor_get (),
1132                       "trash-state-changed",
1133                       G_CALLBACK (trash_state_changed_cb), self);
1134     g_signal_connect_object (nautilus_preferences,
1135                              "changed::" NAUTILUS_PREFERENCES_USE_EXPERIMENTAL_VIEWS,
1136                              G_CALLBACK (use_experimental_views_changed_callback), self, 0);
1137 
1138     g_signal_connect_object (nautilus_preferences,
1139                              "changed::recursive-search",
1140                              G_CALLBACK (recursive_search_preferences_changed),
1141                              self, 0);
1142 
1143     self->slot_action_group = G_ACTION_GROUP (g_simple_action_group_new ());
1144     g_action_map_add_action_entries (G_ACTION_MAP (self->slot_action_group),
1145                                      slot_entries,
1146                                      G_N_ELEMENTS (slot_entries),
1147                                      self);
1148     gtk_widget_insert_action_group (GTK_WIDGET (self),
1149                                     "slot",
1150                                     G_ACTION_GROUP (self->slot_action_group));
1151 
1152     nautilus_application_set_accelerator (app,
1153                                           "slot.files-view-mode(uint32 " G_STRINGIFY (NAUTILUS_VIEW_LIST_ID) ")",
1154                                           "<control>1");
1155     nautilus_application_set_accelerator (app,
1156                                           "slot.files-view-mode(uint32 " G_STRINGIFY (NAUTILUS_VIEW_GRID_ID) ")",
1157                                           "<control>2");
1158     nautilus_application_set_accelerator (app, "slot.search-visible", "<control>f");
1159 
1160     self->view_mode_before_search = NAUTILUS_VIEW_INVALID_ID;
1161 }
1162 
1163 #define DEBUG_FLAG NAUTILUS_DEBUG_WINDOW
1164 #include "nautilus-debug.h"
1165 
1166 static void begin_location_change (NautilusWindowSlot        *slot,
1167                                    GFile                     *location,
1168                                    GFile                     *previous_location,
1169                                    GList                     *new_selection,
1170                                    NautilusLocationChangeType type,
1171                                    guint                      distance,
1172                                    const char                *scroll_pos);
1173 static void free_location_change (NautilusWindowSlot *self);
1174 static void end_location_change (NautilusWindowSlot *self);
1175 static void got_file_info_for_view_selection_callback (NautilusFile *file,
1176                                                        gpointer      callback_data);
1177 static gboolean setup_view (NautilusWindowSlot *self,
1178                             NautilusView       *view);
1179 static void load_new_location (NautilusWindowSlot *slot,
1180                                GFile              *location,
1181                                GList              *selection,
1182                                NautilusFile       *file_to_activate,
1183                                gboolean            tell_current_content_view,
1184                                gboolean            tell_new_content_view);
1185 
1186 void
nautilus_window_slot_open_location_full(NautilusWindowSlot * self,GFile * location,NautilusWindowOpenFlags flags,GList * new_selection)1187 nautilus_window_slot_open_location_full (NautilusWindowSlot      *self,
1188                                          GFile                   *location,
1189                                          NautilusWindowOpenFlags  flags,
1190                                          GList                   *new_selection)
1191 {
1192     GFile *old_location;
1193     g_autolist (NautilusFile) old_selection = NULL;
1194 
1195     old_selection = NULL;
1196     old_location = nautilus_window_slot_get_location (self);
1197 
1198     if (self->content_view)
1199     {
1200         old_selection = nautilus_view_get_selection (self->content_view);
1201     }
1202     if (old_location && g_file_equal (old_location, location) &&
1203         nautilus_file_selection_equal (old_selection, new_selection))
1204     {
1205         goto done;
1206     }
1207 
1208     begin_location_change (self, location, old_location, new_selection,
1209                            NAUTILUS_LOCATION_CHANGE_STANDARD, 0, NULL);
1210 
1211 done:
1212     nautilus_profile_end (NULL);
1213 }
1214 
1215 static GList *
check_select_old_location_containing_folder(GList * new_selection,GFile * location,GFile * previous_location)1216 check_select_old_location_containing_folder (GList *new_selection,
1217                                              GFile *location,
1218                                              GFile *previous_location)
1219 {
1220     GFile *from_folder, *parent;
1221 
1222     /* If there is no new selection and the new location is
1223      * a (grand)parent of the old location then we automatically
1224      * select the folder the previous location was in */
1225     if (new_selection == NULL && previous_location != NULL &&
1226         g_file_has_prefix (previous_location, location))
1227     {
1228         from_folder = g_object_ref (previous_location);
1229         parent = g_file_get_parent (from_folder);
1230         while (parent != NULL && !g_file_equal (parent, location))
1231         {
1232             g_object_unref (from_folder);
1233             from_folder = parent;
1234             parent = g_file_get_parent (from_folder);
1235         }
1236 
1237         if (parent != NULL)
1238         {
1239             new_selection = g_list_prepend (NULL, nautilus_file_get (from_folder));
1240             g_object_unref (parent);
1241         }
1242 
1243         g_object_unref (from_folder);
1244     }
1245 
1246     return new_selection;
1247 }
1248 
1249 static void
check_force_reload(GFile * location,NautilusLocationChangeType type)1250 check_force_reload (GFile                      *location,
1251                     NautilusLocationChangeType  type)
1252 {
1253     NautilusDirectory *directory;
1254     NautilusFile *file;
1255     gboolean force_reload;
1256 
1257     /* The code to force a reload is here because if we do it
1258      * after determining an initial view (in the components), then
1259      * we end up fetching things twice.
1260      */
1261     directory = nautilus_directory_get (location);
1262     file = nautilus_file_get (location);
1263 
1264     if (type == NAUTILUS_LOCATION_CHANGE_RELOAD)
1265     {
1266         force_reload = TRUE;
1267     }
1268     else
1269     {
1270         force_reload = !g_file_is_native (location);
1271     }
1272 
1273     /* We need to invalidate file attributes as well due to how mounting works
1274      * in the window slot and to avoid other caching issues.
1275      * Read handle_mount_if_needed for one example */
1276     if (force_reload)
1277     {
1278         nautilus_file_invalidate_all_attributes (file);
1279         nautilus_directory_force_reload (directory);
1280     }
1281 
1282     nautilus_directory_unref (directory);
1283     nautilus_file_unref (file);
1284 }
1285 
1286 static void
save_scroll_position_for_history(NautilusWindowSlot * self)1287 save_scroll_position_for_history (NautilusWindowSlot *self)
1288 {
1289     /* Set current_bookmark scroll pos */
1290     if (self->current_location_bookmark != NULL &&
1291         self->content_view != NULL &&
1292         NAUTILUS_IS_FILES_VIEW (self->content_view))
1293     {
1294         char *current_pos;
1295 
1296         current_pos = nautilus_files_view_get_first_visible_file (NAUTILUS_FILES_VIEW (self->content_view));
1297         nautilus_bookmark_set_scroll_pos (self->current_location_bookmark, current_pos);
1298         g_free (current_pos);
1299     }
1300 }
1301 
1302 /*
1303  * begin_location_change
1304  *
1305  * Change a window slot's location.
1306  * @window: The NautilusWindow whose location should be changed.
1307  * @location: A url specifying the location to load
1308  * @previous_location: The url that was previously shown in the window that initialized the change, if any
1309  * @new_selection: The initial selection to present after loading the location
1310  * @type: Which type of location change is this? Standard, back, forward, or reload?
1311  * @distance: If type is back or forward, the index into the back or forward chain. If
1312  * type is standard or reload, this is ignored, and must be 0.
1313  * @scroll_pos: The file to scroll to when the location is loaded.
1314  *
1315  * This is the core function for changing the location of a window. Every change to the
1316  * location begins here.
1317  */
1318 static void
begin_location_change(NautilusWindowSlot * self,GFile * location,GFile * previous_location,GList * new_selection,NautilusLocationChangeType type,guint distance,const char * scroll_pos)1319 begin_location_change (NautilusWindowSlot         *self,
1320                        GFile                      *location,
1321                        GFile                      *previous_location,
1322                        GList                      *new_selection,
1323                        NautilusLocationChangeType  type,
1324                        guint                       distance,
1325                        const char                 *scroll_pos)
1326 {
1327     g_assert (self != NULL);
1328     g_assert (location != NULL);
1329     g_assert (type == NAUTILUS_LOCATION_CHANGE_BACK
1330               || type == NAUTILUS_LOCATION_CHANGE_FORWARD
1331               || distance == 0);
1332 
1333     nautilus_profile_start (NULL);
1334 
1335     /* Avoid to update status from the current view in our async calls */
1336     nautilus_window_slot_disconnect_content_view (self);
1337     /* We are going to change the location, so make sure we stop any loading
1338      * or searching of the previous view, so we avoid to be slow */
1339     nautilus_window_slot_stop_loading (self);
1340 
1341     nautilus_window_slot_set_allow_stop (self, TRUE);
1342 
1343     new_selection = check_select_old_location_containing_folder (new_selection, location, previous_location);
1344 
1345     g_assert (self->pending_location == NULL);
1346 
1347     self->pending_location = g_object_ref (location);
1348     self->location_change_type = type;
1349     self->location_change_distance = distance;
1350     self->tried_mount = FALSE;
1351     self->pending_selection = nautilus_file_list_copy (new_selection);
1352 
1353     self->pending_scroll_to = g_strdup (scroll_pos);
1354 
1355     check_force_reload (location, type);
1356 
1357     save_scroll_position_for_history (self);
1358 
1359     /* Get the info needed to make decisions about how to open the new location */
1360     self->determine_view_file = nautilus_file_get (location);
1361     g_assert (self->determine_view_file != NULL);
1362 
1363     nautilus_file_call_when_ready (self->determine_view_file,
1364                                    NAUTILUS_FILE_ATTRIBUTE_INFO |
1365                                    NAUTILUS_FILE_ATTRIBUTE_MOUNT,
1366                                    got_file_info_for_view_selection_callback,
1367                                    self);
1368 
1369     nautilus_profile_end (NULL);
1370 }
1371 
1372 static void
nautilus_window_slot_set_location(NautilusWindowSlot * self,GFile * location)1373 nautilus_window_slot_set_location (NautilusWindowSlot *self,
1374                                    GFile              *location)
1375 {
1376     GFile *old_location;
1377 
1378     if (self->location &&
1379         g_file_equal (location, self->location))
1380     {
1381         /* The location name could be updated even if the location
1382          * wasn't changed. This is the case for a search.
1383          */
1384         nautilus_window_slot_update_title (self);
1385         return;
1386     }
1387 
1388     old_location = self->location;
1389     self->location = g_object_ref (location);
1390 
1391     if (nautilus_window_slot_get_active (self))
1392     {
1393         nautilus_window_sync_location_widgets (self->window);
1394     }
1395 
1396     nautilus_window_slot_update_title (self);
1397 
1398     if (old_location)
1399     {
1400         g_object_unref (old_location);
1401     }
1402 
1403     g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_LOCATION]);
1404 }
1405 
1406 static void
viewed_file_changed_callback(NautilusFile * file,NautilusWindowSlot * self)1407 viewed_file_changed_callback (NautilusFile       *file,
1408                               NautilusWindowSlot *self)
1409 {
1410     GFile *new_location;
1411     gboolean is_in_trash, was_in_trash;
1412 
1413     g_assert (NAUTILUS_IS_FILE (file));
1414     g_assert (NAUTILUS_IS_WINDOW_SLOT (self));
1415 
1416     g_assert (file == self->viewed_file);
1417 
1418     if (!nautilus_file_is_not_yet_confirmed (file))
1419     {
1420         self->viewed_file_seen = TRUE;
1421     }
1422 
1423     was_in_trash = self->viewed_file_in_trash;
1424 
1425     self->viewed_file_in_trash = is_in_trash = nautilus_file_is_in_trash (file);
1426 
1427     if (nautilus_file_is_gone (file) || (is_in_trash && !was_in_trash))
1428     {
1429         if (self->viewed_file_seen)
1430         {
1431             GFile *go_to_file;
1432             GFile *parent;
1433             GFile *location;
1434             GMount *mount;
1435 
1436             parent = NULL;
1437             location = nautilus_file_get_location (file);
1438 
1439             if (g_file_is_native (location))
1440             {
1441                 mount = nautilus_get_mounted_mount_for_root (location);
1442 
1443                 if (mount == NULL)
1444                 {
1445                     parent = g_file_get_parent (location);
1446                 }
1447 
1448                 g_clear_object (&mount);
1449             }
1450 
1451             if (parent != NULL)
1452             {
1453                 /* auto-show existing parent */
1454                 go_to_file = nautilus_find_existing_uri_in_hierarchy (parent);
1455             }
1456             else
1457             {
1458                 go_to_file = g_file_new_for_path (g_get_home_dir ());
1459             }
1460 
1461             nautilus_window_slot_open_location_full (self, go_to_file, 0, NULL);
1462 
1463             g_clear_object (&parent);
1464             g_object_unref (go_to_file);
1465             g_object_unref (location);
1466         }
1467     }
1468     else
1469     {
1470         new_location = nautilus_file_get_location (file);
1471         nautilus_window_slot_set_location (self, new_location);
1472         g_object_unref (new_location);
1473     }
1474 }
1475 
1476 static void
nautilus_window_slot_go_home(NautilusWindowSlot * self,NautilusWindowOpenFlags flags)1477 nautilus_window_slot_go_home (NautilusWindowSlot      *self,
1478                               NautilusWindowOpenFlags  flags)
1479 {
1480     GFile *home;
1481 
1482     g_return_if_fail (NAUTILUS_IS_WINDOW_SLOT (self));
1483 
1484     home = g_file_new_for_path (g_get_home_dir ());
1485     nautilus_window_slot_open_location_full (self, home, flags, NULL);
1486     g_object_unref (home);
1487 }
1488 
1489 static void
nautilus_window_slot_set_viewed_file(NautilusWindowSlot * self,NautilusFile * file)1490 nautilus_window_slot_set_viewed_file (NautilusWindowSlot *self,
1491                                       NautilusFile       *file)
1492 {
1493     NautilusFileAttributes attributes;
1494 
1495     if (self->viewed_file == file)
1496     {
1497         return;
1498     }
1499 
1500     nautilus_file_ref (file);
1501 
1502     if (self->viewed_file != NULL)
1503     {
1504         g_signal_handlers_disconnect_by_func (self->viewed_file,
1505                                               G_CALLBACK (viewed_file_changed_callback),
1506                                               self);
1507         nautilus_file_monitor_remove (self->viewed_file,
1508                                       self);
1509     }
1510 
1511     if (file != NULL)
1512     {
1513         attributes = NAUTILUS_FILE_ATTRIBUTE_INFO;
1514         nautilus_file_monitor_add (file, self, attributes);
1515 
1516         g_signal_connect_object (file, "changed",
1517                                  G_CALLBACK (viewed_file_changed_callback), self, 0);
1518     }
1519 
1520     nautilus_file_unref (self->viewed_file);
1521     self->viewed_file = file;
1522 }
1523 
1524 typedef struct
1525 {
1526     GCancellable *cancellable;
1527     NautilusWindowSlot *slot;
1528 } MountNotMountedData;
1529 
1530 static void
mount_not_mounted_callback(GObject * source_object,GAsyncResult * res,gpointer user_data)1531 mount_not_mounted_callback (GObject      *source_object,
1532                             GAsyncResult *res,
1533                             gpointer      user_data)
1534 {
1535     MountNotMountedData *data;
1536     NautilusWindowSlot *self;
1537     GError *error;
1538     GCancellable *cancellable;
1539 
1540     data = user_data;
1541     self = data->slot;
1542     cancellable = data->cancellable;
1543     g_free (data);
1544 
1545     if (g_cancellable_is_cancelled (cancellable))
1546     {
1547         /* Cancelled, don't call back */
1548         g_object_unref (cancellable);
1549         return;
1550     }
1551 
1552     self->mount_cancellable = NULL;
1553 
1554     self->determine_view_file = nautilus_file_get (self->pending_location);
1555 
1556     error = NULL;
1557     if (!g_file_mount_enclosing_volume_finish (G_FILE (source_object), res, &error))
1558     {
1559         self->mount_error = error;
1560         got_file_info_for_view_selection_callback (self->determine_view_file, self);
1561         self->mount_error = NULL;
1562         g_error_free (error);
1563     }
1564     else
1565     {
1566         nautilus_file_invalidate_all_attributes (self->determine_view_file);
1567         nautilus_file_call_when_ready (self->determine_view_file,
1568                                        NAUTILUS_FILE_ATTRIBUTE_INFO |
1569                                        NAUTILUS_FILE_ATTRIBUTE_MOUNT,
1570                                        got_file_info_for_view_selection_callback,
1571                                        self);
1572     }
1573 
1574     g_object_unref (cancellable);
1575 }
1576 
1577 static void
nautilus_window_slot_display_view_selection_failure(NautilusWindow * window,NautilusFile * file,GFile * location,GError * error)1578 nautilus_window_slot_display_view_selection_failure (NautilusWindow *window,
1579                                                      NautilusFile   *file,
1580                                                      GFile          *location,
1581                                                      GError         *error)
1582 {
1583     char *error_message;
1584     char *detail_message;
1585     char *scheme_string;
1586     char *file_path;
1587 
1588     /* Some sort of failure occurred. How 'bout we tell the user? */
1589 
1590     error_message = g_strdup (_("Oops! Something went wrong."));
1591     detail_message = NULL;
1592     if (error == NULL)
1593     {
1594         if (nautilus_file_is_directory (file))
1595         {
1596             detail_message = g_strdup (_("Unable to display the contents of this folder."));
1597         }
1598         else
1599         {
1600             detail_message = g_strdup (_("This location doesn’t appear to be a folder."));
1601         }
1602     }
1603     else if (error->domain == G_IO_ERROR)
1604     {
1605         switch (error->code)
1606         {
1607             case G_IO_ERROR_NOT_FOUND:
1608             {
1609                 file_path = g_file_get_path (location);
1610                 if (file_path != NULL)
1611                 {
1612                     detail_message = g_strdup_printf (_("Unable to find “%s”. Please check the spelling and try again."),
1613                                                       file_path);
1614                 }
1615                 else
1616                 {
1617                     detail_message = g_strdup (_("Unable to find the requested file. Please check the spelling and try again."));
1618                 }
1619                 g_free (file_path);
1620             }
1621             break;
1622 
1623             case G_IO_ERROR_NOT_SUPPORTED:
1624             {
1625                 scheme_string = g_file_get_uri_scheme (location);
1626                 if (scheme_string != NULL)
1627                 {
1628                     detail_message = g_strdup_printf (_("“%s” locations are not supported."),
1629                                                       scheme_string);
1630                 }
1631                 else
1632                 {
1633                     detail_message = g_strdup (_("Unable to handle this kind of location."));
1634                 }
1635                 g_free (scheme_string);
1636             }
1637             break;
1638 
1639             case G_IO_ERROR_NOT_MOUNTED:
1640             {
1641                 detail_message = g_strdup (_("Unable to access the requested location."));
1642             }
1643             break;
1644 
1645             case G_IO_ERROR_PERMISSION_DENIED:
1646             {
1647                 detail_message = g_strdup (_("Don’t have permission to access the requested location."));
1648             }
1649             break;
1650 
1651             case G_IO_ERROR_HOST_NOT_FOUND:
1652             {
1653                 /* This case can be hit for user-typed strings like "foo" due to
1654                  * the code that guesses web addresses when there's no initial "/".
1655                  * But this case is also hit for legitimate web addresses when
1656                  * the proxy is set up wrong.
1657                  */
1658                 detail_message = g_strdup (_("Unable to find the requested location. Please check the spelling or the network settings."));
1659             }
1660             break;
1661 
1662             case G_IO_ERROR_CONNECTION_REFUSED:
1663             {
1664                 /* This case can be hit when server application is not installed
1665                  * or is inactive in the system user is trying to connect to.
1666                  */
1667                 detail_message = g_strdup (_("The server has refused the connection. Typically this means that the firewall is blocking access or that the remote service is not running."));
1668             }
1669             break;
1670 
1671             case G_IO_ERROR_CANCELLED:
1672             case G_IO_ERROR_FAILED_HANDLED:
1673             {
1674                 goto done;
1675             }
1676 
1677             default:
1678             {
1679             }
1680             break;
1681         }
1682     }
1683 
1684     if (detail_message == NULL)
1685     {
1686         detail_message = g_strdup_printf (_("Unhandled error message: %s"), error->message);
1687     }
1688 
1689     show_dialog (error_message, detail_message, GTK_WINDOW (window), GTK_MESSAGE_ERROR);
1690 
1691 done:
1692     g_free (error_message);
1693     g_free (detail_message);
1694 }
1695 
1696 /* FIXME: This works in the folowwing way. begin_location_change tries to get the
1697  * information of the file directly.
1698  * If the nautilus file finds that there is an error trying to get its
1699  * information and the error match that the file is not mounted, it sets an
1700  * internal attribute with the error then we try to mount it here.
1701  *
1702  * However, files are cached, and if the file doesn't get finalized in a location
1703  * change, because needs to be in the navigation history or is a bookmark, and the
1704  * file is not the root of the mount point, which is tracked by a volume monitor,
1705  * and it gets unmounted aftwerwards, the file doesn't realize it's unmounted, and
1706  * therefore this trick to open an unmounted file will fail the next time the user
1707  * tries to open.
1708  * For that, we need to always invalidate the file attributes when a location is
1709  * changed, which is done in check_force_reload.
1710  * A better way would be to make sure any children of the mounted root gets
1711  * akwnoledge by it either by adding a reference to its parent volume monitor
1712  * or with another solution. */
1713 static gboolean
handle_mount_if_needed(NautilusWindowSlot * self,NautilusFile * file)1714 handle_mount_if_needed (NautilusWindowSlot *self,
1715                         NautilusFile       *file)
1716 {
1717     NautilusWindow *window;
1718     GMountOperation *mount_op;
1719     MountNotMountedData *data;
1720     GFile *location;
1721     GError *error = NULL;
1722     gboolean needs_mount_handling = FALSE;
1723 
1724     window = nautilus_window_slot_get_window (self);
1725     if (self->mount_error)
1726     {
1727         error = g_error_copy (self->mount_error);
1728     }
1729     else if (nautilus_file_get_file_info_error (file) != NULL)
1730     {
1731         error = g_error_copy (nautilus_file_get_file_info_error (file));
1732     }
1733 
1734     if (error && error->domain == G_IO_ERROR && error->code == G_IO_ERROR_NOT_MOUNTED &&
1735         !self->tried_mount)
1736     {
1737         self->tried_mount = TRUE;
1738 
1739         mount_op = gtk_mount_operation_new (GTK_WINDOW (window));
1740         g_mount_operation_set_password_save (mount_op, G_PASSWORD_SAVE_FOR_SESSION);
1741         location = nautilus_file_get_location (file);
1742         data = g_new0 (MountNotMountedData, 1);
1743         data->cancellable = g_cancellable_new ();
1744         data->slot = self;
1745         self->mount_cancellable = data->cancellable;
1746         g_file_mount_enclosing_volume (location, 0, mount_op, self->mount_cancellable,
1747                                        mount_not_mounted_callback, data);
1748         g_object_unref (location);
1749         g_object_unref (mount_op);
1750 
1751         needs_mount_handling = TRUE;
1752     }
1753 
1754     g_clear_error (&error);
1755 
1756     return needs_mount_handling;
1757 }
1758 
1759 static gboolean
handle_regular_file_if_needed(NautilusWindowSlot * self,NautilusFile * file)1760 handle_regular_file_if_needed (NautilusWindowSlot *self,
1761                                NautilusFile       *file)
1762 {
1763     NautilusFile *parent_file;
1764     gboolean needs_regular_file_handling = FALSE;
1765     parent_file = nautilus_file_get_parent (file);
1766     if ((parent_file != NULL) &&
1767         nautilus_file_get_file_type (file) == G_FILE_TYPE_REGULAR)
1768     {
1769         g_clear_pointer (&self->pending_selection, nautilus_file_list_free);
1770         g_clear_object (&self->pending_location);
1771         g_clear_object (&self->pending_file_to_activate);
1772         g_free (self->pending_scroll_to);
1773 
1774         self->pending_location = nautilus_file_get_parent_location (file);
1775         if (nautilus_file_is_archive (file))
1776         {
1777             self->pending_file_to_activate = nautilus_file_ref (file);
1778         }
1779         else
1780         {
1781             self->pending_selection = g_list_prepend (NULL, nautilus_file_ref (file));
1782         }
1783         self->determine_view_file = nautilus_file_ref (parent_file);
1784         self->pending_scroll_to = nautilus_file_get_uri (file);
1785 
1786         nautilus_file_invalidate_all_attributes (self->determine_view_file);
1787         nautilus_file_call_when_ready (self->determine_view_file,
1788                                        NAUTILUS_FILE_ATTRIBUTE_INFO |
1789                                        NAUTILUS_FILE_ATTRIBUTE_MOUNT,
1790                                        got_file_info_for_view_selection_callback,
1791                                        self);
1792 
1793         needs_regular_file_handling = TRUE;
1794     }
1795 
1796     nautilus_file_unref (parent_file);
1797 
1798     return needs_regular_file_handling;
1799 }
1800 
1801 static void
got_file_info_for_view_selection_callback(NautilusFile * file,gpointer callback_data)1802 got_file_info_for_view_selection_callback (NautilusFile *file,
1803                                            gpointer      callback_data)
1804 {
1805     GError *error = NULL;
1806     NautilusWindow *window;
1807     NautilusWindowSlot *self;
1808     NautilusFile *viewed_file;
1809     NautilusView *view;
1810     GFile *location;
1811     NautilusApplication *app;
1812 
1813     self = callback_data;
1814     window = nautilus_window_slot_get_window (self);
1815 
1816     g_assert (self->determine_view_file == file);
1817     self->determine_view_file = NULL;
1818 
1819     nautilus_profile_start (NULL);
1820 
1821     if (handle_mount_if_needed (self, file))
1822     {
1823         goto done;
1824     }
1825 
1826     if (handle_regular_file_if_needed (self, file))
1827     {
1828         goto done;
1829     }
1830 
1831     if (self->mount_error)
1832     {
1833         error = g_error_copy (self->mount_error);
1834     }
1835     else if (nautilus_file_get_file_info_error (file) != NULL)
1836     {
1837         error = g_error_copy (nautilus_file_get_file_info_error (file));
1838     }
1839 
1840     location = self->pending_location;
1841 
1842     /* desktop and other-locations GFile operations report G_IO_ERROR_NOT_SUPPORTED,
1843      * but it's not an actual error for Nautilus */
1844     if (!error || g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED))
1845     {
1846         view = nautilus_window_slot_get_view_for_location (self, location);
1847         setup_view (self, view);
1848     }
1849     else
1850     {
1851         if (error == NULL)
1852         {
1853             error = g_error_new (G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
1854                                  _("Unable to load location"));
1855         }
1856         nautilus_window_slot_display_view_selection_failure (window,
1857                                                              file,
1858                                                              location,
1859                                                              error);
1860 
1861         if (!gtk_widget_get_visible (GTK_WIDGET (window)))
1862         {
1863             /* Destroy never-had-a-chance-to-be-seen window. This case
1864              * happens when a new window cannot display its initial URI.
1865              */
1866             /* if this is the only window, we don't want to quit, so we redirect it to home */
1867 
1868             app = NAUTILUS_APPLICATION (g_application_get_default ());
1869 
1870             if (g_list_length (nautilus_application_get_windows (app)) == 1)
1871             {
1872                 /* the user could have typed in a home directory that doesn't exist,
1873                  *  in which case going home would cause an infinite loop, so we
1874                  *  better test for that */
1875 
1876                 if (!nautilus_is_root_directory (location))
1877                 {
1878                     if (!nautilus_is_home_directory (location))
1879                     {
1880                         nautilus_window_slot_go_home (self, FALSE);
1881                     }
1882                     else
1883                     {
1884                         GFile *root;
1885 
1886                         root = g_file_new_for_path ("/");
1887                         /* the last fallback is to go to a known place that can't be deleted! */
1888                         nautilus_window_slot_open_location_full (self, location, 0, NULL);
1889                         g_object_unref (root);
1890                     }
1891                 }
1892                 else
1893                 {
1894                     gtk_widget_destroy (GTK_WIDGET (window));
1895                 }
1896             }
1897             else
1898             {
1899                 /* Since this is a window, destroying it will also unref it. */
1900                 gtk_widget_destroy (GTK_WIDGET (window));
1901             }
1902         }
1903         else
1904         {
1905             GFile *slot_location;
1906 
1907             /* Clean up state of already-showing window */
1908             end_location_change (self);
1909             slot_location = nautilus_window_slot_get_location (self);
1910 
1911             /* XXX FIXME VOODOO TODO:
1912              * Context: https://gitlab.gnome.org/GNOME/nautilus/issues/562
1913              * (and the associated MR)
1914              *
1915              * This used to just close the slot, which, in combination with
1916              * the transient error dialog, caused Mutter to have a heart attack
1917              * and die when the slot happened to be the only one remaining.
1918              * The following condition can hold true in (at least) two cases:
1919              *
1920              * 1. We are inside the “Other Locations” view and are opening
1921              *    a broken bookmark, which causes the window slot to get replaced
1922              *    with one that handles the location, and is, understandably,
1923              *    empty.
1924              * 2. We open a broken bookmark in a new window, which works almost
1925              *    the same, in that it has no open location.
1926              *
1927              * Ernestas: I’m leaning towards having an in-view message about the
1928              *           failure, which avoids dialogs and magically disappearing
1929              *           slots/tabs/windows (also allowing to go back to the
1930              *           previous location), but a dialog is quicker to inform
1931              *           about the failure.
1932              * XXX
1933              */
1934             if (slot_location == NULL)
1935             {
1936                 nautilus_window_slot_go_home (self, 0);
1937             }
1938             else
1939             {
1940                 /* We disconnected this, so we need to re-connect it */
1941                 viewed_file = nautilus_file_get (slot_location);
1942                 nautilus_window_slot_set_viewed_file (self, viewed_file);
1943                 nautilus_file_unref (viewed_file);
1944 
1945                 /* Leave the location bar showing the bad location that the user
1946                  * typed (or maybe achieved by dragging or something). Many times
1947                  * the mistake will just be an easily-correctable typo. The user
1948                  * can choose "Refresh" to get the original URI back in the location bar.
1949                  */
1950             }
1951         }
1952     }
1953 
1954 done:
1955     g_clear_error (&error);
1956 
1957     nautilus_file_unref (file);
1958     nautilus_profile_end (NULL);
1959 }
1960 
1961 /* Load a view into the window, either reusing the old one or creating
1962  * a new one. This happens when you want to load a new location, or just
1963  * switch to a different view.
1964  * If pending_location is set we're loading a new location and
1965  * pending_location/selection will be used. If not, we're just switching
1966  * view, and the current location will be used.
1967  */
1968 static gboolean
setup_view(NautilusWindowSlot * self,NautilusView * view)1969 setup_view (NautilusWindowSlot *self,
1970             NautilusView       *view)
1971 {
1972     gboolean ret = TRUE;
1973     GFile *old_location;
1974     nautilus_profile_start (NULL);
1975 
1976     nautilus_window_slot_disconnect_content_view (self);
1977 
1978     self->new_content_view = view;
1979 
1980     nautilus_window_slot_connect_new_content_view (self);
1981 
1982     /* Forward search selection and state before loading the new model */
1983     old_location = self->content_view ? nautilus_view_get_location (self->content_view) : NULL;
1984 
1985     /* Actually load the pending location and selection: */
1986     if (self->pending_location != NULL)
1987     {
1988         load_new_location (self,
1989                            self->pending_location,
1990                            self->pending_selection,
1991                            self->pending_file_to_activate,
1992                            FALSE,
1993                            TRUE);
1994 
1995         nautilus_file_list_free (self->pending_selection);
1996         self->pending_selection = NULL;
1997     }
1998     else if (old_location != NULL)
1999     {
2000         g_autolist (NautilusFile) selection = NULL;
2001 
2002         selection = nautilus_view_get_selection (self->content_view);
2003 
2004         load_new_location (self,
2005                            old_location,
2006                            selection,
2007                            NULL,
2008                            FALSE,
2009                            TRUE);
2010     }
2011     else
2012     {
2013         ret = FALSE;
2014         goto out;
2015     }
2016 
2017     change_view (self);
2018     gtk_widget_show (GTK_WIDGET (self->window));
2019 
2020 out:
2021     nautilus_profile_end (NULL);
2022 
2023     return ret;
2024 }
2025 
2026 static void
load_new_location(NautilusWindowSlot * self,GFile * location,GList * selection,NautilusFile * file_to_activate,gboolean tell_current_content_view,gboolean tell_new_content_view)2027 load_new_location (NautilusWindowSlot *self,
2028                    GFile              *location,
2029                    GList              *selection,
2030                    NautilusFile       *file_to_activate,
2031                    gboolean            tell_current_content_view,
2032                    gboolean            tell_new_content_view)
2033 {
2034     NautilusView *view;
2035     g_assert (self != NULL);
2036     g_assert (location != NULL);
2037 
2038     view = NULL;
2039     nautilus_profile_start (NULL);
2040     /* Note, these may recurse into report_load_underway */
2041     if (self->content_view != NULL && tell_current_content_view)
2042     {
2043         view = self->content_view;
2044         nautilus_view_set_location (self->content_view, location);
2045     }
2046 
2047     if (self->new_content_view != NULL && tell_new_content_view &&
2048         (!tell_current_content_view ||
2049          self->new_content_view != self->content_view))
2050     {
2051         view = self->new_content_view;
2052         nautilus_view_set_location (self->new_content_view, location);
2053     }
2054     if (view)
2055     {
2056         nautilus_view_set_selection (view, selection);
2057         if (file_to_activate != NULL)
2058         {
2059             g_autoptr (GAppInfo) app_info = NULL;
2060             const gchar *app_id;
2061 
2062             g_return_if_fail (NAUTILUS_IS_FILES_VIEW (view));
2063             app_info = nautilus_mime_get_default_application_for_file (file_to_activate);
2064             app_id = g_app_info_get_id (app_info);
2065             if (g_strcmp0 (app_id, NAUTILUS_DESKTOP_ID) == 0)
2066             {
2067                 nautilus_files_view_activate_file (NAUTILUS_FILES_VIEW (view),
2068                                                    file_to_activate, 0);
2069             }
2070         }
2071     }
2072 
2073     nautilus_profile_end (NULL);
2074 }
2075 
2076 static void
end_location_change(NautilusWindowSlot * self)2077 end_location_change (NautilusWindowSlot *self)
2078 {
2079     char *uri;
2080     uri = nautilus_window_slot_get_location_uri (self);
2081     if (uri)
2082     {
2083         DEBUG ("Finished loading window for uri %s", uri);
2084         g_free (uri);
2085     }
2086 
2087     nautilus_window_slot_set_allow_stop (self, FALSE);
2088 
2089     /* Now we can free details->pending_scroll_to, since the load_complete
2090      * callback already has been emitted.
2091      */
2092     g_free (self->pending_scroll_to);
2093     self->pending_scroll_to = NULL;
2094 
2095     free_location_change (self);
2096 }
2097 
2098 static void
free_location_change(NautilusWindowSlot * self)2099 free_location_change (NautilusWindowSlot *self)
2100 {
2101     g_clear_object (&self->pending_location);
2102     g_clear_object (&self->pending_file_to_activate);
2103     nautilus_file_list_free (self->pending_selection);
2104     self->pending_selection = NULL;
2105 
2106     /* Don't free details->pending_scroll_to, since thats needed until
2107      * the load_complete callback.
2108      */
2109 
2110     if (self->mount_cancellable != NULL)
2111     {
2112         g_cancellable_cancel (self->mount_cancellable);
2113         self->mount_cancellable = NULL;
2114     }
2115 
2116     if (self->determine_view_file != NULL)
2117     {
2118         nautilus_file_cancel_call_when_ready
2119             (self->determine_view_file,
2120             got_file_info_for_view_selection_callback, self);
2121         self->determine_view_file = NULL;
2122     }
2123 }
2124 
2125 /* This sets up a new view, for the current location, with the provided id. Used
2126  * whenever the user changes the type of view to use.
2127  *
2128  * Note that the current view will be thrown away, even if it has the same id.
2129  * Callers may first check if !nautilus_window_slot_content_view_matches().
2130  */
2131 static void
nautilus_window_slot_set_content_view(NautilusWindowSlot * self,guint id)2132 nautilus_window_slot_set_content_view (NautilusWindowSlot *self,
2133                                        guint               id)
2134 {
2135     NautilusFilesView *view;
2136     g_autolist (NautilusFile) selection = NULL;
2137     char *uri;
2138     g_assert (self != NULL);
2139 
2140     uri = nautilus_window_slot_get_location_uri (self);
2141     DEBUG ("Change view of window %s to %d", uri, id);
2142     g_free (uri);
2143 
2144     selection = nautilus_view_get_selection (self->content_view);
2145     view = nautilus_files_view_new (id, self);
2146 
2147     nautilus_window_slot_stop_loading (self);
2148 
2149     nautilus_window_slot_set_allow_stop (self, TRUE);
2150 
2151     if (g_list_length (selection) == 0 && NAUTILUS_IS_FILES_VIEW (self->content_view))
2152     {
2153         /* If there is no selection, queue a scroll to the same icon that
2154          * is currently visible */
2155         self->pending_scroll_to = nautilus_files_view_get_first_visible_file (NAUTILUS_FILES_VIEW (self->content_view));
2156     }
2157 
2158     self->location_change_type = NAUTILUS_LOCATION_CHANGE_RELOAD;
2159 
2160     if (!setup_view (self, NAUTILUS_VIEW (view)))
2161     {
2162         /* Just load the homedir. */
2163         nautilus_window_slot_go_home (self, FALSE);
2164     }
2165 }
2166 
2167 void
nautilus_window_slot_back_or_forward(NautilusWindowSlot * self,gboolean back,guint distance)2168 nautilus_window_slot_back_or_forward (NautilusWindowSlot *self,
2169                                       gboolean            back,
2170                                       guint               distance)
2171 {
2172     GList *list;
2173     guint len;
2174     NautilusBookmark *bookmark;
2175     g_autoptr (GFile) location = NULL;
2176     GFile *old_location;
2177     g_autofree char *scroll_pos = NULL;
2178 
2179     list = back ? self->back_list : self->forward_list;
2180     len = g_list_length (list);
2181 
2182     /* If we can't move in the direction at all, just return. */
2183     if (list == NULL)
2184     {
2185         return;
2186     }
2187 
2188     /* If the distance to move is off the end of the list, go to the end
2189      *  of the list. */
2190     if (distance >= len)
2191     {
2192         distance = len - 1;
2193     }
2194 
2195     bookmark = g_list_nth_data (list, distance);
2196     location = nautilus_bookmark_get_location (bookmark);
2197     old_location = nautilus_window_slot_get_location (self);
2198     scroll_pos = nautilus_bookmark_get_scroll_pos (bookmark);
2199 
2200     begin_location_change (self,
2201                            location, old_location,
2202                            NULL,
2203                            back ? NAUTILUS_LOCATION_CHANGE_BACK : NAUTILUS_LOCATION_CHANGE_FORWARD,
2204                            distance,
2205                            scroll_pos);
2206 }
2207 
2208 /* reload the contents of the window */
2209 static void
nautilus_window_slot_force_reload(NautilusWindowSlot * self)2210 nautilus_window_slot_force_reload (NautilusWindowSlot *self)
2211 {
2212     GFile *location;
2213     char *current_pos;
2214     g_autolist (NautilusFile) selection = NULL;
2215 
2216     g_assert (NAUTILUS_IS_WINDOW_SLOT (self));
2217 
2218     location = nautilus_window_slot_get_location (self);
2219     if (location == NULL)
2220     {
2221         return;
2222     }
2223 
2224     /* peek_slot_field (window, location) can be free'd during the processing
2225      * of begin_location_change, so make a copy
2226      */
2227     g_object_ref (location);
2228     current_pos = NULL;
2229 
2230     if (self->new_content_view)
2231     {
2232         selection = nautilus_view_get_selection (self->content_view);
2233 
2234         if (NAUTILUS_IS_FILES_VIEW (self->new_content_view))
2235         {
2236             current_pos = nautilus_files_view_get_first_visible_file (NAUTILUS_FILES_VIEW (self->content_view));
2237         }
2238     }
2239     begin_location_change
2240         (self, location, location, selection,
2241         NAUTILUS_LOCATION_CHANGE_RELOAD, 0, current_pos);
2242     g_free (current_pos);
2243     g_object_unref (location);
2244 }
2245 
2246 void
nautilus_window_slot_queue_reload(NautilusWindowSlot * self)2247 nautilus_window_slot_queue_reload (NautilusWindowSlot *self)
2248 {
2249     g_assert (NAUTILUS_IS_WINDOW_SLOT (self));
2250 
2251     if (nautilus_window_slot_get_location (self) == NULL)
2252     {
2253         return;
2254     }
2255 
2256     if (self->pending_location != NULL
2257         || self->content_view == NULL
2258         || nautilus_view_is_loading (self->content_view))
2259     {
2260         /* there is a reload in flight */
2261         self->needs_reload = TRUE;
2262         return;
2263     }
2264 
2265     nautilus_window_slot_force_reload (self);
2266 }
2267 
2268 static void
nautilus_window_slot_clear_forward_list(NautilusWindowSlot * self)2269 nautilus_window_slot_clear_forward_list (NautilusWindowSlot *self)
2270 {
2271     g_assert (NAUTILUS_IS_WINDOW_SLOT (self));
2272 
2273     g_list_free_full (self->forward_list, g_object_unref);
2274     self->forward_list = NULL;
2275 }
2276 
2277 static void
nautilus_window_slot_clear_back_list(NautilusWindowSlot * self)2278 nautilus_window_slot_clear_back_list (NautilusWindowSlot *self)
2279 {
2280     g_assert (NAUTILUS_IS_WINDOW_SLOT (self));
2281 
2282     g_list_free_full (self->back_list, g_object_unref);
2283     self->back_list = NULL;
2284 }
2285 
2286 static void
nautilus_window_slot_update_bookmark(NautilusWindowSlot * self,NautilusFile * file)2287 nautilus_window_slot_update_bookmark (NautilusWindowSlot *self,
2288                                       NautilusFile       *file)
2289 {
2290     gboolean recreate;
2291     GFile *new_location;
2292     new_location = nautilus_file_get_location (file);
2293 
2294     if (self->current_location_bookmark == NULL)
2295     {
2296         recreate = TRUE;
2297     }
2298     else
2299     {
2300         GFile *bookmark_location;
2301         bookmark_location = nautilus_bookmark_get_location (self->current_location_bookmark);
2302         recreate = !g_file_equal (bookmark_location, new_location);
2303         g_object_unref (bookmark_location);
2304     }
2305 
2306     if (recreate)
2307     {
2308         char *display_name = NULL;
2309 
2310         /* We've changed locations, must recreate bookmark for current location. */
2311         g_clear_object (&self->last_location_bookmark);
2312         self->last_location_bookmark = self->current_location_bookmark;
2313 
2314         display_name = nautilus_file_get_display_name (file);
2315         self->current_location_bookmark = nautilus_bookmark_new (new_location, display_name);
2316         g_free (display_name);
2317     }
2318 
2319     g_object_unref (new_location);
2320 }
2321 
2322 static void
check_bookmark_location_matches(NautilusBookmark * bookmark,GFile * location)2323 check_bookmark_location_matches (NautilusBookmark *bookmark,
2324                                  GFile            *location)
2325 {
2326     GFile *bookmark_location;
2327     char *bookmark_uri, *uri;
2328 
2329     bookmark_location = nautilus_bookmark_get_location (bookmark);
2330     if (!g_file_equal (location, bookmark_location))
2331     {
2332         bookmark_uri = g_file_get_uri (bookmark_location);
2333         uri = g_file_get_uri (location);
2334         g_warning ("bookmark uri is %s, but expected %s", bookmark_uri, uri);
2335         g_free (uri);
2336         g_free (bookmark_uri);
2337     }
2338     g_object_unref (bookmark_location);
2339 }
2340 
2341 /* Debugging function used to verify that the last_location_bookmark
2342  * is in the state we expect when we're about to use it to update the
2343  * Back or Forward list.
2344  */
2345 static void
check_last_bookmark_location_matches_slot(NautilusWindowSlot * self)2346 check_last_bookmark_location_matches_slot (NautilusWindowSlot *self)
2347 {
2348     check_bookmark_location_matches (self->last_location_bookmark,
2349                                      nautilus_window_slot_get_location (self));
2350 }
2351 
2352 static void
handle_go_direction(NautilusWindowSlot * self,GFile * location,gboolean forward)2353 handle_go_direction (NautilusWindowSlot *self,
2354                      GFile              *location,
2355                      gboolean            forward)
2356 {
2357     GList **list_ptr, **other_list_ptr;
2358     GList *list, *other_list, *link;
2359     NautilusBookmark *bookmark;
2360     gint i;
2361     list_ptr = (forward) ? (&self->forward_list) : (&self->back_list);
2362     other_list_ptr = (forward) ? (&self->back_list) : (&self->forward_list);
2363     list = *list_ptr;
2364     other_list = *other_list_ptr;
2365 
2366     /* Move items from the list to the other list. */
2367     g_assert (g_list_length (list) > self->location_change_distance);
2368     check_bookmark_location_matches (g_list_nth_data (list, self->location_change_distance),
2369                                      location);
2370     g_assert (nautilus_window_slot_get_location (self) != NULL);
2371 
2372     /* Move current location to list */
2373     check_last_bookmark_location_matches_slot (self);
2374 
2375     /* Use the first bookmark in the history list rather than creating a new one. */
2376     other_list = g_list_prepend (other_list, self->last_location_bookmark);
2377     g_object_ref (other_list->data);
2378 
2379     /* Move extra links from the list to the other list */
2380     for (i = 0; i < self->location_change_distance; ++i)
2381     {
2382         bookmark = NAUTILUS_BOOKMARK (list->data);
2383         list = g_list_remove (list, bookmark);
2384         other_list = g_list_prepend (other_list, bookmark);
2385     }
2386 
2387     /* One bookmark falls out of back/forward lists and becomes viewed location */
2388     link = list;
2389     list = g_list_remove_link (list, link);
2390     g_object_unref (link->data);
2391     g_list_free_1 (link);
2392 
2393     *list_ptr = list;
2394     *other_list_ptr = other_list;
2395 }
2396 
2397 static void
handle_go_elsewhere(NautilusWindowSlot * self,GFile * location)2398 handle_go_elsewhere (NautilusWindowSlot *self,
2399                      GFile              *location)
2400 {
2401     GFile *slot_location;
2402     /* Clobber the entire forward list, and move displayed location to back list */
2403     nautilus_window_slot_clear_forward_list (self);
2404 
2405     slot_location = nautilus_window_slot_get_location (self);
2406 
2407     if (slot_location != NULL)
2408     {
2409         /* If we're returning to the same uri somehow, don't put this uri on back list.
2410          * This also avoids a problem where set_displayed_location
2411          * didn't update last_location_bookmark since the uri didn't change.
2412          */
2413         if (!g_file_equal (slot_location, location))
2414         {
2415             /* Store bookmark for current location in back list, unless there is no current location */
2416             check_last_bookmark_location_matches_slot (self);
2417             /* Use the first bookmark in the history list rather than creating a new one. */
2418             self->back_list = g_list_prepend (self->back_list,
2419                                               self->last_location_bookmark);
2420             g_object_ref (self->back_list->data);
2421         }
2422     }
2423 }
2424 
2425 static void
update_history(NautilusWindowSlot * self,NautilusLocationChangeType type,GFile * new_location)2426 update_history (NautilusWindowSlot         *self,
2427                 NautilusLocationChangeType  type,
2428                 GFile                      *new_location)
2429 {
2430     switch (type)
2431     {
2432         case NAUTILUS_LOCATION_CHANGE_STANDARD:
2433         {
2434             handle_go_elsewhere (self, new_location);
2435             return;
2436         }
2437 
2438         case NAUTILUS_LOCATION_CHANGE_RELOAD:
2439         {
2440             /* for reload there is no work to do */
2441             return;
2442         }
2443 
2444         case NAUTILUS_LOCATION_CHANGE_BACK:
2445         {
2446             handle_go_direction (self, new_location, FALSE);
2447             return;
2448         }
2449 
2450         case NAUTILUS_LOCATION_CHANGE_FORWARD:
2451         {
2452             handle_go_direction (self, new_location, TRUE);
2453             return;
2454         }
2455     }
2456     g_return_if_fail (FALSE);
2457 }
2458 
2459 typedef struct
2460 {
2461     NautilusWindowSlot *slot;
2462     GCancellable *cancellable;
2463     GMount *mount;
2464 } FindMountData;
2465 
2466 static void
nautilus_window_slot_show_x_content_bar(NautilusWindowSlot * self,GMount * mount,const char * const * x_content_types)2467 nautilus_window_slot_show_x_content_bar (NautilusWindowSlot *self,
2468                                          GMount             *mount,
2469                                          const char * const *x_content_types)
2470 {
2471     GtkWidget *bar;
2472 
2473     g_assert (NAUTILUS_IS_WINDOW_SLOT (self));
2474 
2475     if (!should_handle_content_types (x_content_types))
2476     {
2477         return;
2478     }
2479 
2480     bar = nautilus_x_content_bar_new (mount, x_content_types);
2481     gtk_widget_show (bar);
2482     nautilus_window_slot_add_extra_location_widget (self, bar);
2483 }
2484 
2485 static void
found_content_type_cb(const char ** x_content_types,gpointer user_data)2486 found_content_type_cb (const char **x_content_types,
2487                        gpointer     user_data)
2488 {
2489     NautilusWindowSlot *self;
2490     FindMountData *data = user_data;
2491     self = data->slot;
2492     if (g_cancellable_is_cancelled (data->cancellable))
2493     {
2494         goto out;
2495     }
2496 
2497 
2498     if (x_content_types != NULL && x_content_types[0] != NULL)
2499     {
2500         nautilus_window_slot_show_x_content_bar (self, data->mount, (const char * const *) x_content_types);
2501     }
2502 
2503     self->find_mount_cancellable = NULL;
2504 
2505 out:
2506     g_object_unref (data->mount);
2507     g_object_unref (data->cancellable);
2508     g_free (data);
2509 }
2510 
2511 static void
found_mount_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)2512 found_mount_cb (GObject      *source_object,
2513                 GAsyncResult *res,
2514                 gpointer      user_data)
2515 {
2516     FindMountData *data = user_data;
2517     NautilusWindowSlot *self;
2518     GMount *mount;
2519     self = NAUTILUS_WINDOW_SLOT (data->slot);
2520     if (g_cancellable_is_cancelled (data->cancellable))
2521     {
2522         goto out;
2523     }
2524 
2525     mount = g_file_find_enclosing_mount_finish (G_FILE (source_object),
2526                                                 res,
2527                                                 NULL);
2528     if (mount != NULL)
2529     {
2530         data->mount = mount;
2531         nautilus_get_x_content_types_for_mount_async (mount,
2532                                                       found_content_type_cb,
2533                                                       data->cancellable,
2534                                                       data);
2535         return;
2536     }
2537 
2538     self->find_mount_cancellable = NULL;
2539 
2540 out:
2541     g_object_unref (data->cancellable);
2542     g_free (data);
2543 }
2544 
2545 static void
trash_state_changed_cb(NautilusTrashMonitor * monitor,gboolean is_empty,gpointer user_data)2546 trash_state_changed_cb (NautilusTrashMonitor *monitor,
2547                         gboolean              is_empty,
2548                         gpointer              user_data)
2549 {
2550     GFile *location;
2551     NautilusDirectory *directory;
2552     NautilusView *view;
2553 
2554     location = nautilus_window_slot_get_current_location (user_data);
2555     view = nautilus_window_slot_get_current_view (user_data);
2556 
2557     /* The signal 'trash-state-changed' could be emitted by NautilusTrashMonitor
2558      * while a NautilusWindowSlot is still initializing the content view.
2559      */
2560     if (location == NULL || view == NULL)
2561     {
2562         return;
2563     }
2564 
2565     directory = nautilus_directory_get (location);
2566 
2567     if (nautilus_directory_is_in_trash (directory))
2568     {
2569         if (nautilus_trash_monitor_is_empty ())
2570         {
2571             nautilus_window_slot_remove_extra_location_widgets (user_data);
2572         }
2573         else
2574         {
2575             nautilus_window_slot_setup_extra_location_widgets (user_data);
2576         }
2577     }
2578 }
2579 
2580 static void
nautilus_window_slot_show_trash_bar(NautilusWindowSlot * self)2581 nautilus_window_slot_show_trash_bar (NautilusWindowSlot *self)
2582 {
2583     GtkWidget *bar;
2584     NautilusView *view;
2585 
2586     view = nautilus_window_slot_get_current_view (self);
2587     g_return_if_fail (NAUTILUS_IS_FILES_VIEW (view));
2588     bar = nautilus_trash_bar_new (NAUTILUS_FILES_VIEW (view));
2589     gtk_widget_show (bar);
2590 
2591     nautilus_window_slot_add_extra_location_widget (self, bar);
2592 }
2593 
2594 static void
nautilus_window_slot_show_special_location_bar(NautilusWindowSlot * self,NautilusSpecialLocation special_location)2595 nautilus_window_slot_show_special_location_bar (NautilusWindowSlot      *self,
2596                                                 NautilusSpecialLocation  special_location)
2597 {
2598     GtkWidget *bar;
2599 
2600     bar = nautilus_special_location_bar_new (special_location);
2601     gtk_widget_show (bar);
2602 
2603     nautilus_window_slot_add_extra_location_widget (self, bar);
2604 }
2605 
2606 static void
slot_add_extension_extra_widgets(NautilusWindowSlot * self)2607 slot_add_extension_extra_widgets (NautilusWindowSlot *self)
2608 {
2609     GList *providers, *l;
2610     GtkWidget *widget;
2611     char *uri;
2612     NautilusWindow *window;
2613 
2614     providers = nautilus_module_get_extensions_for_type (NAUTILUS_TYPE_LOCATION_WIDGET_PROVIDER);
2615     window = nautilus_window_slot_get_window (self);
2616 
2617     uri = nautilus_window_slot_get_location_uri (self);
2618     for (l = providers; l != NULL; l = l->next)
2619     {
2620         NautilusLocationWidgetProvider *provider;
2621 
2622         provider = NAUTILUS_LOCATION_WIDGET_PROVIDER (l->data);
2623         widget = nautilus_location_widget_provider_get_widget (provider, uri, GTK_WIDGET (window));
2624         if (widget != NULL)
2625         {
2626             nautilus_window_slot_add_extra_location_widget (self, widget);
2627         }
2628     }
2629     g_free (uri);
2630 
2631     nautilus_module_extension_list_free (providers);
2632 }
2633 
2634 static void
nautilus_window_slot_update_for_new_location(NautilusWindowSlot * self)2635 nautilus_window_slot_update_for_new_location (NautilusWindowSlot *self)
2636 {
2637     GFile *new_location;
2638     NautilusFile *file;
2639     new_location = self->pending_location;
2640     self->pending_location = NULL;
2641 
2642     file = nautilus_file_get (new_location);
2643     nautilus_window_slot_update_bookmark (self, file);
2644 
2645     update_history (self, self->location_change_type, new_location);
2646 
2647     /* Create a NautilusFile for this location, so we can catch it
2648      * if it goes away.
2649      */
2650     nautilus_window_slot_set_viewed_file (self, file);
2651     self->viewed_file_seen = !nautilus_file_is_not_yet_confirmed (file);
2652     self->viewed_file_in_trash = nautilus_file_is_in_trash (file);
2653     nautilus_file_unref (file);
2654 
2655     nautilus_window_slot_set_location (self, new_location);
2656 
2657     /* Sync the actions for this new location. */
2658     nautilus_window_slot_sync_actions (self);
2659 }
2660 
2661 static void
view_started_loading(NautilusWindowSlot * self,NautilusView * view)2662 view_started_loading (NautilusWindowSlot *self,
2663                       NautilusView       *view)
2664 {
2665     if (view == self->content_view)
2666     {
2667         nautilus_window_slot_set_allow_stop (self, TRUE);
2668     }
2669 
2670     /* Only grab focus if the menu isn't showing. Otherwise the menu disappears
2671      * e.g. when the user toggles Show Hidden Files
2672      */
2673     if (!nautilus_toolbar_is_menu_visible (NAUTILUS_TOOLBAR (nautilus_window_get_toolbar (self->window))))
2674     {
2675         gtk_widget_grab_focus (GTK_WIDGET (self->window));
2676     }
2677 
2678     gtk_widget_show (GTK_WIDGET (self->window));
2679 
2680     nautilus_window_slot_set_loading (self, TRUE);
2681 }
2682 
2683 static void
view_ended_loading(NautilusWindowSlot * self,NautilusView * view)2684 view_ended_loading (NautilusWindowSlot *self,
2685                     NautilusView       *view)
2686 {
2687     if (view == self->content_view)
2688     {
2689         if (NAUTILUS_IS_FILES_VIEW (view) && self->pending_scroll_to != NULL)
2690         {
2691             nautilus_files_view_scroll_to_file (NAUTILUS_FILES_VIEW (self->content_view), self->pending_scroll_to);
2692         }
2693 
2694         end_location_change (self);
2695     }
2696 
2697     if (self->needs_reload)
2698     {
2699         nautilus_window_slot_queue_reload (self);
2700         self->needs_reload = FALSE;
2701     }
2702 
2703     nautilus_window_slot_set_allow_stop (self, FALSE);
2704 
2705     nautilus_window_slot_set_loading (self, FALSE);
2706 }
2707 
2708 static void
view_is_loading_changed_cb(GObject * object,GParamSpec * pspec,NautilusWindowSlot * self)2709 view_is_loading_changed_cb (GObject            *object,
2710                             GParamSpec         *pspec,
2711                             NautilusWindowSlot *self)
2712 {
2713     NautilusView *view;
2714 
2715     view = NAUTILUS_VIEW (object);
2716 
2717     nautilus_profile_start (NULL);
2718 
2719     if (nautilus_view_is_loading (view))
2720     {
2721         view_started_loading (self, view);
2722     }
2723     else
2724     {
2725         view_ended_loading (self, view);
2726     }
2727 
2728     nautilus_profile_end (NULL);
2729 }
2730 
2731 static void
nautilus_window_slot_setup_extra_location_widgets(NautilusWindowSlot * self)2732 nautilus_window_slot_setup_extra_location_widgets (NautilusWindowSlot *self)
2733 {
2734     GFile *location;
2735     FindMountData *data;
2736     NautilusDirectory *directory;
2737     location = nautilus_window_slot_get_current_location (self);
2738 
2739     if (location == NULL)
2740     {
2741         return;
2742     }
2743 
2744     directory = nautilus_directory_get (location);
2745 
2746     if (nautilus_directory_is_in_trash (directory))
2747     {
2748         if (!nautilus_trash_monitor_is_empty ())
2749         {
2750             nautilus_window_slot_show_trash_bar (self);
2751         }
2752     }
2753     else
2754     {
2755         NautilusFile *file;
2756         GFile *scripts_file;
2757         char *scripts_path = nautilus_get_scripts_directory_path ();
2758 
2759         scripts_file = g_file_new_for_path (scripts_path);
2760         g_free (scripts_path);
2761 
2762         file = nautilus_file_get (location);
2763 
2764         if (nautilus_should_use_templates_directory () &&
2765             nautilus_file_is_user_special_directory (file, G_USER_DIRECTORY_TEMPLATES))
2766         {
2767             nautilus_window_slot_show_special_location_bar (self, NAUTILUS_SPECIAL_LOCATION_TEMPLATES);
2768         }
2769         else if (g_file_equal (location, scripts_file))
2770         {
2771             nautilus_window_slot_show_special_location_bar (self, NAUTILUS_SPECIAL_LOCATION_SCRIPTS);
2772         }
2773 
2774         g_object_unref (scripts_file);
2775         nautilus_file_unref (file);
2776     }
2777 
2778     /* need the mount to determine if we should put up the x-content cluebar */
2779     if (self->find_mount_cancellable != NULL)
2780     {
2781         g_cancellable_cancel (self->find_mount_cancellable);
2782         self->find_mount_cancellable = NULL;
2783     }
2784 
2785     data = g_new (FindMountData, 1);
2786     data->slot = self;
2787     data->cancellable = g_cancellable_new ();
2788     data->mount = NULL;
2789 
2790     self->find_mount_cancellable = data->cancellable;
2791     g_file_find_enclosing_mount_async (location,
2792                                        G_PRIORITY_DEFAULT,
2793                                        data->cancellable,
2794                                        found_mount_cb,
2795                                        data);
2796 
2797     nautilus_directory_unref (directory);
2798 
2799     slot_add_extension_extra_widgets (self);
2800 }
2801 
2802 static void
nautilus_window_slot_connect_new_content_view(NautilusWindowSlot * self)2803 nautilus_window_slot_connect_new_content_view (NautilusWindowSlot *self)
2804 {
2805     if (self->new_content_view)
2806     {
2807         g_signal_connect (self->new_content_view,
2808                           "notify::loading",
2809                           G_CALLBACK (view_is_loading_changed_cb),
2810                           self);
2811     }
2812 }
2813 
2814 static void
nautilus_window_slot_disconnect_content_view(NautilusWindowSlot * self)2815 nautilus_window_slot_disconnect_content_view (NautilusWindowSlot *self)
2816 {
2817     if (self->content_view)
2818     {
2819         /* disconnect old view */
2820         g_signal_handlers_disconnect_by_func (self->content_view,
2821                                               G_CALLBACK (view_is_loading_changed_cb),
2822                                               self);
2823     }
2824 }
2825 
2826 static void
nautilus_window_slot_switch_new_content_view(NautilusWindowSlot * self)2827 nautilus_window_slot_switch_new_content_view (NautilusWindowSlot *self)
2828 {
2829     GtkWidget *widget;
2830     gboolean reusing_view;
2831     reusing_view = self->new_content_view &&
2832                    gtk_widget_get_parent (GTK_WIDGET (self->new_content_view)) != NULL;
2833     /* We are either reusing the view, so new_content_view and content_view
2834      * are the same, or the new_content_view is invalid */
2835     if (self->new_content_view == NULL || reusing_view)
2836     {
2837         goto done;
2838     }
2839 
2840     if (self->content_view != NULL)
2841     {
2842         g_binding_unbind (self->searching_binding);
2843         g_binding_unbind (self->selection_binding);
2844         g_binding_unbind (self->extensions_background_menu_binding);
2845         g_binding_unbind (self->templates_menu_binding);
2846         widget = GTK_WIDGET (self->content_view);
2847         gtk_widget_destroy (widget);
2848         g_clear_object (&self->content_view);
2849     }
2850 
2851     if (self->new_content_view != NULL)
2852     {
2853         self->content_view = self->new_content_view;
2854         self->new_content_view = NULL;
2855 
2856         widget = GTK_WIDGET (self->content_view);
2857         gtk_container_add (GTK_CONTAINER (self), widget);
2858         gtk_widget_set_vexpand (widget, TRUE);
2859         gtk_widget_show (widget);
2860         self->searching_binding = g_object_bind_property (self->content_view, "searching",
2861                                                           self, "searching",
2862                                                           G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
2863         self->selection_binding = g_object_bind_property (self->content_view, "selection",
2864                                                           self, "selection",
2865                                                           G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
2866         self->extensions_background_menu_binding = g_object_bind_property (self->content_view, "extensions-background-menu",
2867                                                                            self, "extensions-background-menu",
2868                                                                            G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
2869         self->templates_menu_binding = g_object_bind_property (self->content_view, "templates-menu",
2870                                                                self, "templates-menu",
2871                                                                G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
2872         g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ICON]);
2873         g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TOOLBAR_MENU_SECTIONS]);
2874         g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_EXTENSIONS_BACKGROUND_MENU]);
2875         g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TEMPLATES_MENU]);
2876         g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TOOLTIP]);
2877     }
2878 
2879 done:
2880     /* Clean up, so we don't confuse having a new_content_view available or
2881      * just that we didn't care about it here */
2882     self->new_content_view = NULL;
2883 }
2884 
2885 /* This is called when we have decided we can actually change to the new view/location situation. */
2886 static void
change_view(NautilusWindowSlot * self)2887 change_view (NautilusWindowSlot *self)
2888 {
2889     /* Switch to the new content view.
2890      * Destroy the extra location widgets first, since they might hold
2891      * a pointer to the old view, which will possibly be destroyed inside
2892      * nautilus_window_slot_switch_new_content_view().
2893      */
2894     nautilus_window_slot_remove_extra_location_widgets (self);
2895     nautilus_window_slot_switch_new_content_view (self);
2896 
2897     if (self->pending_location != NULL)
2898     {
2899         /* Tell the window we are finished. */
2900         nautilus_window_slot_update_for_new_location (self);
2901     }
2902 
2903     /* Now that we finished switching to the new location,
2904      * add back the extra location widgets.
2905      */
2906     nautilus_window_slot_setup_extra_location_widgets (self);
2907 }
2908 
2909 static void
nautilus_window_slot_dispose(GObject * object)2910 nautilus_window_slot_dispose (GObject *object)
2911 {
2912     NautilusWindowSlot *self;
2913     self = NAUTILUS_WINDOW_SLOT (object);
2914     g_signal_handlers_disconnect_by_data (nautilus_trash_monitor_get (), self);
2915 
2916     g_signal_handlers_disconnect_by_data (nautilus_preferences, self);
2917 
2918     nautilus_window_slot_clear_forward_list (self);
2919     nautilus_window_slot_clear_back_list (self);
2920 
2921     nautilus_window_slot_remove_extra_location_widgets (self);
2922 
2923     g_clear_pointer (&self->searching_binding, g_binding_unbind);
2924     g_clear_pointer (&self->selection_binding, g_binding_unbind);
2925     g_clear_pointer (&self->extensions_background_menu_binding, g_binding_unbind);
2926     g_clear_pointer (&self->templates_menu_binding, g_binding_unbind);
2927 
2928     g_clear_object (&self->templates_menu);
2929     g_clear_object (&self->extensions_background_menu);
2930 
2931     if (self->content_view)
2932     {
2933         gtk_widget_destroy (GTK_WIDGET (self->content_view));
2934         g_clear_object (&self->content_view);
2935     }
2936 
2937     if (self->new_content_view)
2938     {
2939         gtk_widget_destroy (GTK_WIDGET (self->new_content_view));
2940         g_clear_object (&self->new_content_view);
2941     }
2942 
2943     nautilus_window_slot_set_viewed_file (self, NULL);
2944 
2945     g_clear_object (&self->location);
2946     g_clear_object (&self->pending_file_to_activate);
2947     g_clear_pointer (&self->pending_selection, nautilus_file_list_free);
2948 
2949     g_clear_object (&self->current_location_bookmark);
2950     g_clear_object (&self->last_location_bookmark);
2951     g_clear_object (&self->slot_action_group);
2952     g_clear_object (&self->pending_search_query);
2953 
2954     g_clear_pointer (&self->find_mount_cancellable, g_cancellable_cancel);
2955 
2956     if (self->query_editor)
2957     {
2958         gtk_widget_destroy (GTK_WIDGET (self->query_editor));
2959         g_clear_object (&self->query_editor);
2960     }
2961 
2962     free_location_change (self);
2963 
2964     G_OBJECT_CLASS (nautilus_window_slot_parent_class)->dispose (object);
2965 }
2966 
2967 static void
nautilus_window_slot_finalize(GObject * object)2968 nautilus_window_slot_finalize (GObject *object)
2969 {
2970     NautilusWindowSlot *self;
2971     self = NAUTILUS_WINDOW_SLOT (object);
2972     g_clear_pointer (&self->title, g_free);
2973 
2974     G_OBJECT_CLASS (nautilus_window_slot_parent_class)->finalize (object);
2975 }
2976 
2977 static void
nautilus_window_slot_grab_focus(GtkWidget * widget)2978 nautilus_window_slot_grab_focus (GtkWidget *widget)
2979 {
2980     NautilusWindowSlot *self;
2981     self = NAUTILUS_WINDOW_SLOT (widget);
2982     GTK_WIDGET_CLASS (nautilus_window_slot_parent_class)->grab_focus (widget);
2983 
2984     if (nautilus_window_slot_get_search_visible (self))
2985     {
2986         gtk_widget_grab_focus (GTK_WIDGET (self->query_editor));
2987     }
2988     else if (self->content_view)
2989     {
2990         gtk_widget_grab_focus (GTK_WIDGET (self->content_view));
2991     }
2992     else if (self->new_content_view)
2993     {
2994         gtk_widget_grab_focus (GTK_WIDGET (self->new_content_view));
2995     }
2996 }
2997 
2998 static void
nautilus_window_slot_class_init(NautilusWindowSlotClass * klass)2999 nautilus_window_slot_class_init (NautilusWindowSlotClass *klass)
3000 {
3001     GObjectClass *oclass = G_OBJECT_CLASS (klass);
3002     GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
3003 
3004     oclass->dispose = nautilus_window_slot_dispose;
3005     oclass->finalize = nautilus_window_slot_finalize;
3006     oclass->constructed = nautilus_window_slot_constructed;
3007     oclass->set_property = nautilus_window_slot_set_property;
3008     oclass->get_property = nautilus_window_slot_get_property;
3009 
3010     widget_class->grab_focus = nautilus_window_slot_grab_focus;
3011 
3012     properties[PROP_ACTIVE] =
3013         g_param_spec_boolean ("active",
3014                               "Whether the slot is active",
3015                               "Whether the slot is the active slot of the window",
3016                               FALSE,
3017                               G_PARAM_READWRITE);
3018 
3019     properties[PROP_LOADING] =
3020         g_param_spec_boolean ("loading",
3021                               "Whether the slot loading",
3022                               "Whether the slot is loading a new location",
3023                               FALSE,
3024                               G_PARAM_READABLE);
3025 
3026     properties[PROP_SEARCHING] =
3027         g_param_spec_boolean ("searching",
3028                               "Whether the current view of the slot is searching",
3029                               "Whether the current view of the slot is searching. Proxy property from the view",
3030                               FALSE,
3031                               G_PARAM_READWRITE);
3032 
3033     properties[PROP_SELECTION] =
3034         g_param_spec_pointer ("selection",
3035                               "Selection of the current view of the slot",
3036                               "The selection of the current view of the slot. Proxy property from the view",
3037                               G_PARAM_READWRITE);
3038 
3039     properties[PROP_WINDOW] =
3040         g_param_spec_object ("window",
3041                              "The NautilusWindow",
3042                              "The NautilusWindow this slot is part of",
3043                              NAUTILUS_TYPE_WINDOW,
3044                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
3045 
3046     properties[PROP_ICON] =
3047         g_param_spec_object ("icon",
3048                              "Icon that represents the slot",
3049                              "The icon that represents the slot",
3050                              G_TYPE_ICON,
3051                              G_PARAM_READABLE);
3052 
3053     properties[PROP_TOOLBAR_MENU_SECTIONS] =
3054         g_param_spec_pointer ("toolbar-menu-sections",
3055                               "Menu sections for the toolbar menu",
3056                               "The menu sections to add to the toolbar menu for this slot",
3057                               G_PARAM_READABLE);
3058 
3059     properties[PROP_EXTENSIONS_BACKGROUND_MENU] =
3060         g_param_spec_object ("extensions-background-menu",
3061                              "Background menu of extensions",
3062                              "Proxy property from the view for the background menu for extensions",
3063                              G_TYPE_MENU_MODEL,
3064                              G_PARAM_READWRITE);
3065 
3066     properties[PROP_TEMPLATES_MENU] =
3067         g_param_spec_object ("templates-menu",
3068                              "Templates menu",
3069                              "Proxy property from the view for the templates menu",
3070                              G_TYPE_MENU_MODEL,
3071                              G_PARAM_READWRITE);
3072 
3073     properties[PROP_LOCATION] =
3074         g_param_spec_object ("location",
3075                              "Current location visible on the slot",
3076                              "Either the location that is used currently, or the pending location. Clients will see the same value they set, and therefore it will be cosistent from clients point of view.",
3077                              G_TYPE_FILE,
3078                              G_PARAM_READWRITE);
3079 
3080     properties[PROP_TOOLTIP] =
3081         g_param_spec_string ("tooltip",
3082                              "Tooltip that represents the slot",
3083                              "The tooltip that represents the slot",
3084                              NULL,
3085                              G_PARAM_READWRITE);
3086 
3087     g_object_class_install_properties (oclass, NUM_PROPERTIES, properties);
3088 }
3089 
3090 GFile *
nautilus_window_slot_get_location(NautilusWindowSlot * self)3091 nautilus_window_slot_get_location (NautilusWindowSlot *self)
3092 {
3093     g_return_val_if_fail (NAUTILUS_IS_WINDOW_SLOT (self), NULL);
3094 
3095     return self->location;
3096 }
3097 
3098 GFile *
nautilus_window_slot_get_pending_location(NautilusWindowSlot * self)3099 nautilus_window_slot_get_pending_location (NautilusWindowSlot *self)
3100 {
3101     g_return_val_if_fail (NAUTILUS_IS_WINDOW_SLOT (self), NULL);
3102 
3103     return self->pending_location;
3104 }
3105 
3106 const gchar *
nautilus_window_slot_get_title(NautilusWindowSlot * self)3107 nautilus_window_slot_get_title (NautilusWindowSlot *self)
3108 {
3109     return self->title;
3110 }
3111 
3112 char *
nautilus_window_slot_get_location_uri(NautilusWindowSlot * self)3113 nautilus_window_slot_get_location_uri (NautilusWindowSlot *self)
3114 {
3115     g_assert (NAUTILUS_IS_WINDOW_SLOT (self));
3116 
3117     if (self->location)
3118     {
3119         return g_file_get_uri (self->location);
3120     }
3121     return NULL;
3122 }
3123 
3124 NautilusWindow *
nautilus_window_slot_get_window(NautilusWindowSlot * self)3125 nautilus_window_slot_get_window (NautilusWindowSlot *self)
3126 {
3127     g_assert (NAUTILUS_IS_WINDOW_SLOT (self));
3128 
3129     return self->window;
3130 }
3131 
3132 void
nautilus_window_slot_set_window(NautilusWindowSlot * self,NautilusWindow * window)3133 nautilus_window_slot_set_window (NautilusWindowSlot *self,
3134                                  NautilusWindow     *window)
3135 {
3136     g_assert (NAUTILUS_IS_WINDOW_SLOT (self));
3137     g_assert (NAUTILUS_IS_WINDOW (window));
3138 
3139     if (self->window != window)
3140     {
3141         self->window = window;
3142         g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_WINDOW]);
3143     }
3144 }
3145 
3146 /* nautilus_window_slot_update_title:
3147  *
3148  * Re-calculate the slot title.
3149  * Called when the location or view has changed.
3150  * @slot: The NautilusWindowSlot in question.
3151  *
3152  */
3153 void
nautilus_window_slot_update_title(NautilusWindowSlot * self)3154 nautilus_window_slot_update_title (NautilusWindowSlot *self)
3155 {
3156     NautilusWindow *window;
3157     char *title;
3158     gboolean do_sync = FALSE;
3159     title = nautilus_compute_title_for_location (self->location);
3160     window = nautilus_window_slot_get_window (self);
3161 
3162     if (g_strcmp0 (title, self->title) != 0)
3163     {
3164         do_sync = TRUE;
3165 
3166         g_free (self->title);
3167         self->title = title;
3168         title = NULL;
3169     }
3170 
3171     if (strlen (self->title) > 0)
3172     {
3173         do_sync = TRUE;
3174     }
3175 
3176     if (do_sync)
3177     {
3178         nautilus_window_sync_title (window, self);
3179     }
3180 
3181     if (title != NULL)
3182     {
3183         g_free (title);
3184     }
3185 }
3186 
3187 gboolean
nautilus_window_slot_get_allow_stop(NautilusWindowSlot * self)3188 nautilus_window_slot_get_allow_stop (NautilusWindowSlot *self)
3189 {
3190     return self->allow_stop;
3191 }
3192 
3193 void
nautilus_window_slot_set_allow_stop(NautilusWindowSlot * self,gboolean allow)3194 nautilus_window_slot_set_allow_stop (NautilusWindowSlot *self,
3195                                      gboolean            allow)
3196 {
3197     NautilusWindow *window;
3198     g_assert (NAUTILUS_IS_WINDOW_SLOT (self));
3199 
3200     self->allow_stop = allow;
3201 
3202     window = nautilus_window_slot_get_window (self);
3203     nautilus_window_sync_allow_stop (window, self);
3204 }
3205 
3206 void
nautilus_window_slot_stop_loading(NautilusWindowSlot * self)3207 nautilus_window_slot_stop_loading (NautilusWindowSlot *self)
3208 {
3209     GFile *location;
3210     NautilusDirectory *directory;
3211     location = nautilus_window_slot_get_location (self);
3212     directory = nautilus_directory_get (self->location);
3213 
3214     if (NAUTILUS_IS_FILES_VIEW (self->content_view))
3215     {
3216         nautilus_files_view_stop_loading (NAUTILUS_FILES_VIEW (self->content_view));
3217     }
3218 
3219     nautilus_directory_unref (directory);
3220 
3221     if (self->pending_location != NULL &&
3222         location != NULL &&
3223         self->content_view != NULL &&
3224         NAUTILUS_IS_FILES_VIEW (self->content_view))
3225     {
3226         /* No need to tell the new view - either it is the
3227          * same as the old view, in which case it will already
3228          * be told, or it is the very pending change we wish
3229          * to cancel.
3230          */
3231         g_autolist (NautilusFile) selection = NULL;
3232 
3233         selection = nautilus_view_get_selection (self->content_view);
3234         load_new_location (self,
3235                            location,
3236                            selection,
3237                            NULL,
3238                            TRUE,
3239                            FALSE);
3240     }
3241 
3242     end_location_change (self);
3243 
3244     if (self->new_content_view)
3245     {
3246         g_object_unref (self->new_content_view);
3247         self->new_content_view = NULL;
3248     }
3249 }
3250 
3251 NautilusView *
nautilus_window_slot_get_current_view(NautilusWindowSlot * self)3252 nautilus_window_slot_get_current_view (NautilusWindowSlot *self)
3253 {
3254     if (self->content_view != NULL)
3255     {
3256         return self->content_view;
3257     }
3258     else if (self->new_content_view)
3259     {
3260         return self->new_content_view;
3261     }
3262 
3263     return NULL;
3264 }
3265 
3266 NautilusBookmark *
nautilus_window_slot_get_bookmark(NautilusWindowSlot * self)3267 nautilus_window_slot_get_bookmark (NautilusWindowSlot *self)
3268 {
3269     return self->current_location_bookmark;
3270 }
3271 
3272 GList *
nautilus_window_slot_get_back_history(NautilusWindowSlot * self)3273 nautilus_window_slot_get_back_history (NautilusWindowSlot *self)
3274 {
3275     return self->back_list;
3276 }
3277 
3278 GList *
nautilus_window_slot_get_forward_history(NautilusWindowSlot * self)3279 nautilus_window_slot_get_forward_history (NautilusWindowSlot *self)
3280 {
3281     return self->forward_list;
3282 }
3283 
3284 NautilusWindowSlot *
nautilus_window_slot_new(NautilusWindow * window)3285 nautilus_window_slot_new (NautilusWindow *window)
3286 {
3287     return g_object_new (NAUTILUS_TYPE_WINDOW_SLOT,
3288                          "window", window,
3289                          NULL);
3290 }
3291 
3292 GIcon *
nautilus_window_slot_get_icon(NautilusWindowSlot * self)3293 nautilus_window_slot_get_icon (NautilusWindowSlot *self)
3294 {
3295     guint current_view_id;
3296     g_return_val_if_fail (NAUTILUS_IS_WINDOW_SLOT (self), NULL);
3297 
3298     if (self->content_view == NULL)
3299     {
3300         return NULL;
3301     }
3302 
3303     current_view_id = nautilus_view_get_view_id (NAUTILUS_VIEW (self->content_view));
3304     switch (current_view_id)
3305     {
3306         case NAUTILUS_VIEW_LIST_ID:
3307         {
3308             return nautilus_view_get_icon (NAUTILUS_VIEW_GRID_ID);
3309         }
3310         break;
3311 
3312         case NAUTILUS_VIEW_GRID_ID:
3313         {
3314             return nautilus_view_get_icon (NAUTILUS_VIEW_LIST_ID);
3315         }
3316         break;
3317 
3318         case NAUTILUS_VIEW_OTHER_LOCATIONS_ID:
3319         {
3320             return nautilus_view_get_icon (NAUTILUS_VIEW_OTHER_LOCATIONS_ID);
3321         }
3322         break;
3323 
3324         default:
3325         {
3326             return NULL;
3327         }
3328     }
3329 }
3330 
3331 const gchar *
nautilus_window_slot_get_tooltip(NautilusWindowSlot * self)3332 nautilus_window_slot_get_tooltip (NautilusWindowSlot *self)
3333 {
3334     guint current_view_id;
3335     g_return_val_if_fail (NAUTILUS_IS_WINDOW_SLOT (self), NULL);
3336 
3337     if (self->content_view == NULL)
3338     {
3339         return NULL;
3340     }
3341 
3342     current_view_id = nautilus_view_get_view_id (NAUTILUS_VIEW (self->content_view));
3343     switch (current_view_id)
3344     {
3345         case NAUTILUS_VIEW_LIST_ID:
3346         {
3347             return nautilus_view_get_tooltip (NAUTILUS_VIEW_GRID_ID);
3348         }
3349         break;
3350 
3351         case NAUTILUS_VIEW_GRID_ID:
3352         {
3353             return nautilus_view_get_tooltip (NAUTILUS_VIEW_LIST_ID);
3354         }
3355         break;
3356 
3357         case NAUTILUS_VIEW_OTHER_LOCATIONS_ID:
3358         {
3359             return nautilus_view_get_tooltip (NAUTILUS_VIEW_OTHER_LOCATIONS_ID);
3360         }
3361         break;
3362 
3363         default:
3364         {
3365             return NULL;
3366         }
3367     }
3368 }
3369 
3370 NautilusToolbarMenuSections *
nautilus_window_slot_get_toolbar_menu_sections(NautilusWindowSlot * self)3371 nautilus_window_slot_get_toolbar_menu_sections (NautilusWindowSlot *self)
3372 {
3373     NautilusView *view;
3374 
3375     g_return_val_if_fail (NAUTILUS_IS_WINDOW_SLOT (self), NULL);
3376 
3377     view = nautilus_window_slot_get_current_view (self);
3378 
3379     return view ? nautilus_view_get_toolbar_menu_sections (view) : NULL;
3380 }
3381 
3382 gboolean
nautilus_window_slot_get_active(NautilusWindowSlot * self)3383 nautilus_window_slot_get_active (NautilusWindowSlot *self)
3384 {
3385     g_return_val_if_fail (NAUTILUS_IS_WINDOW_SLOT (self), FALSE);
3386 
3387     return self->active;
3388 }
3389 
3390 void
nautilus_window_slot_set_active(NautilusWindowSlot * self,gboolean active)3391 nautilus_window_slot_set_active (NautilusWindowSlot *self,
3392                                  gboolean            active)
3393 {
3394     NautilusWindow *window;
3395 
3396     g_return_if_fail (NAUTILUS_IS_WINDOW_SLOT (self));
3397 
3398     if (self->active != active)
3399     {
3400         self->active = active;
3401 
3402         if (active)
3403         {
3404             int page_num;
3405 
3406             window = self->window;
3407             page_num = gtk_notebook_page_num (GTK_NOTEBOOK (nautilus_window_get_notebook (window)),
3408                                               GTK_WIDGET (self));
3409             g_assert (page_num >= 0);
3410 
3411             gtk_notebook_set_current_page (GTK_NOTEBOOK (nautilus_window_get_notebook (window)), page_num);
3412 
3413             /* sync window to new slot */
3414             nautilus_window_sync_allow_stop (window, self);
3415             nautilus_window_sync_title (window, self);
3416             nautilus_window_sync_location_widgets (window);
3417             nautilus_window_slot_sync_actions (self);
3418 
3419             gtk_widget_insert_action_group (GTK_WIDGET (window), "slot", self->slot_action_group);
3420         }
3421         else
3422         {
3423             window = nautilus_window_slot_get_window (self);
3424             g_assert (self == nautilus_window_get_active_slot (window));
3425 
3426             gtk_widget_insert_action_group (GTK_WIDGET (window), "slot", NULL);
3427         }
3428 
3429         g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ACTIVE]);
3430     }
3431 }
3432 
3433 static void
nautilus_window_slot_set_loading(NautilusWindowSlot * self,gboolean loading)3434 nautilus_window_slot_set_loading (NautilusWindowSlot *self,
3435                                   gboolean            loading)
3436 {
3437     g_return_if_fail (NAUTILUS_IS_WINDOW_SLOT (self));
3438 
3439     self->loading = loading;
3440 
3441     g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_LOADING]);
3442 }
3443 
3444 gboolean
nautilus_window_slot_get_loading(NautilusWindowSlot * self)3445 nautilus_window_slot_get_loading (NautilusWindowSlot *self)
3446 {
3447     g_return_val_if_fail (NAUTILUS_IS_WINDOW_SLOT (self), FALSE);
3448 
3449     return self->loading;
3450 }
3451 
3452 NautilusQueryEditor *
nautilus_window_slot_get_query_editor(NautilusWindowSlot * self)3453 nautilus_window_slot_get_query_editor (NautilusWindowSlot *self)
3454 {
3455     g_return_val_if_fail (NAUTILUS_IS_WINDOW_SLOT (self), NULL);
3456 
3457     return self->query_editor;
3458 }
3459