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