2008-04-30 A. Walton <awalton@gnome.org>
[nautilus.git] / src / nautilus-window-manage-views.c
blobeffc7dff6030168de3c5134d3b1fa172f0facea9
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 /*
4 * Nautilus
6 * Copyright (C) 1999, 2000 Red Hat, Inc.
7 * Copyright (C) 1999, 2000, 2001 Eazel, Inc.
9 * Nautilus is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * Nautilus is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
19 * You should have received a copy of the GNU General Public
20 * License along with this program; if not, write to the Free
21 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 * Authors: Elliot Lee <sopwith@redhat.com>
24 * John Sullivan <sullivan@eazel.com>
25 * Darin Adler <darin@bentspoon.com>
28 #include <config.h>
29 #include "nautilus-window-manage-views.h"
31 #include "nautilus-actions.h"
32 #include "nautilus-application.h"
33 #include "nautilus-location-bar.h"
34 #include "nautilus-search-bar.h"
35 #include "nautilus-pathbar.h"
36 #include "nautilus-main.h"
37 #include "nautilus-window-private.h"
38 #include "nautilus-trash-bar.h"
39 #include "nautilus-x-content-bar.h"
40 #include "nautilus-zoom-control.h"
41 #include <eel/eel-accessibility.h>
42 #include <eel/eel-debug.h>
43 #include <eel/eel-gdk-extensions.h>
44 #include <eel/eel-glib-extensions.h>
45 #include <eel/eel-gtk-extensions.h>
46 #include <eel/eel-stock-dialogs.h>
47 #include <eel/eel-string.h>
48 #include <eel/eel-mount-operation.h>
49 #include <gtk/gtkmain.h>
50 #include <gtk/gtksignal.h>
51 #include <gdk/gdkx.h>
52 #include <glib/gi18n.h>
53 #include <libgnomeui/gnome-icon-theme.h>
54 #include <libnautilus-extension/nautilus-location-widget-provider.h>
55 #include <libnautilus-private/nautilus-debug-log.h>
56 #include <libnautilus-private/nautilus-file-attributes.h>
57 #include <libnautilus-private/nautilus-file-utilities.h>
58 #include <libnautilus-private/nautilus-file.h>
59 #include <libnautilus-private/nautilus-global-preferences.h>
60 #include <libnautilus-private/nautilus-metadata.h>
61 #include <libnautilus-private/nautilus-mime-actions.h>
62 #include <libnautilus-private/nautilus-module.h>
63 #include <libnautilus-private/nautilus-monitor.h>
64 #include <libnautilus-private/nautilus-search-directory.h>
65 #include <libnautilus-private/nautilus-view-factory.h>
66 #include <libnautilus-private/nautilus-window-info.h>
67 #include <libnautilus-private/nautilus-autorun.h>
69 /* FIXME bugzilla.gnome.org 41243:
70 * We should use inheritance instead of these special cases
71 * for the desktop window.
73 #include "nautilus-desktop-window.h"
75 /* This number controls a maximum character count for a URL that is
76 * displayed as part of a dialog. It's fairly arbitrary -- big enough
77 * to allow most "normal" URIs to display in full, but small enough to
78 * prevent the dialog from getting insanely wide.
80 #define MAX_URI_IN_DIALOG_LENGTH 60
82 static void connect_view (NautilusWindow *window,
83 NautilusView *view);
84 static void disconnect_view (NautilusWindow *window,
85 NautilusView *view);
86 static void begin_location_change (NautilusWindow *window,
87 GFile *location,
88 GList *new_selection,
89 NautilusLocationChangeType type,
90 guint distance,
91 const char *scroll_pos);
92 static void free_location_change (NautilusWindow *window);
93 static void end_location_change (NautilusWindow *window);
94 static void cancel_location_change (NautilusWindow *window);
95 static void got_file_info_for_view_selection_callback (NautilusFile *file,
96 gpointer callback_data);
97 static void create_content_view (NautilusWindow *window,
98 const char *view_id);
99 static void display_view_selection_failure (NautilusWindow *window,
100 NautilusFile *file,
101 GFile *location,
102 GError *error);
103 static void load_new_location (NautilusWindow *window,
104 GFile *location,
105 GList *selection,
106 gboolean tell_current_content_view,
107 gboolean tell_new_content_view);
108 static void location_has_really_changed (NautilusWindow *window);
109 static void update_for_new_location (NautilusWindow *window);
110 static void zoom_parameters_changed_callback (NautilusView *view,
111 NautilusWindow *window);
112 static void update_extra_location_widgets_visibility (NautilusWindow *window);
113 static void remove_extra_location_widgets (NautilusWindow *window);
115 void
116 nautilus_window_report_selection_changed (NautilusWindowInfo *window)
118 g_signal_emit_by_name (window, "selection_changed");
121 /* set_displayed_location:
123 static void
124 set_displayed_location (NautilusWindow *window, GFile *location)
126 GFile *bookmark_location;
127 gboolean recreate;
128 char *name;
130 if (window->current_location_bookmark == NULL || location == NULL) {
131 recreate = TRUE;
132 } else {
133 bookmark_location = nautilus_bookmark_get_location (window->current_location_bookmark);
134 recreate = !g_file_equal (bookmark_location, location);
135 g_object_unref (bookmark_location);
138 if (recreate) {
139 /* We've changed locations, must recreate bookmark for current location. */
140 if (window->last_location_bookmark != NULL) {
141 g_object_unref (window->last_location_bookmark);
143 window->last_location_bookmark = window->current_location_bookmark;
144 name = g_file_get_uri (location);
145 window->current_location_bookmark = (location == NULL) ? NULL
146 : nautilus_bookmark_new (location, name);
147 g_free (name);
149 nautilus_window_update_title (window);
150 nautilus_window_update_icon (window);
153 static void
154 check_bookmark_location_matches (NautilusBookmark *bookmark, GFile *location)
156 GFile *bookmark_location;
157 char *bookmark_uri, *uri;
159 bookmark_location = nautilus_bookmark_get_location (bookmark);
160 if (!g_file_equal (location, bookmark_location)) {
161 bookmark_uri = g_file_get_uri (bookmark_location);
162 uri = g_file_get_uri (location);
163 g_warning ("bookmark uri is %s, but expected %s", bookmark_uri, uri);
164 g_free (uri);
165 g_free (bookmark_uri);
167 g_object_unref (bookmark_location);
170 /* Debugging function used to verify that the last_location_bookmark
171 * is in the state we expect when we're about to use it to update the
172 * Back or Forward list.
174 static void
175 check_last_bookmark_location_matches_window (NautilusWindow *window)
177 check_bookmark_location_matches (window->last_location_bookmark,
178 window->details->location);
181 static void
182 handle_go_back (NautilusNavigationWindow *window, GFile *location)
184 guint i;
185 GList *link;
186 NautilusBookmark *bookmark;
188 g_assert (NAUTILUS_IS_NAVIGATION_WINDOW (window));
190 /* Going back. Move items from the back list to the forward list. */
191 g_assert (g_list_length (window->back_list) > NAUTILUS_WINDOW (window)->details->location_change_distance);
192 check_bookmark_location_matches (NAUTILUS_BOOKMARK (g_list_nth_data (window->back_list,
193 NAUTILUS_WINDOW (window)->details->location_change_distance)),
194 location);
195 g_assert (NAUTILUS_WINDOW (window)->details->location != NULL);
197 /* Move current location to Forward list */
199 check_last_bookmark_location_matches_window (NAUTILUS_WINDOW (window));
201 /* Use the first bookmark in the history list rather than creating a new one. */
202 window->forward_list = g_list_prepend (window->forward_list,
203 NAUTILUS_WINDOW (window)->last_location_bookmark);
204 g_object_ref (window->forward_list->data);
206 /* Move extra links from Back to Forward list */
207 for (i = 0; i < NAUTILUS_WINDOW (window)->details->location_change_distance; ++i) {
208 bookmark = NAUTILUS_BOOKMARK (window->back_list->data);
209 window->back_list = g_list_remove (window->back_list, bookmark);
210 window->forward_list = g_list_prepend (window->forward_list, bookmark);
213 /* One bookmark falls out of back/forward lists and becomes viewed location */
214 link = window->back_list;
215 window->back_list = g_list_remove_link (window->back_list, link);
216 g_object_unref (link->data);
217 g_list_free_1 (link);
220 static void
221 handle_go_forward (NautilusNavigationWindow *window, GFile *location)
223 guint i;
224 GList *link;
225 NautilusBookmark *bookmark;
227 g_assert (NAUTILUS_IS_NAVIGATION_WINDOW (window));
229 /* Going forward. Move items from the forward list to the back list. */
230 g_assert (g_list_length (window->forward_list) > NAUTILUS_WINDOW (window)->details->location_change_distance);
231 check_bookmark_location_matches (NAUTILUS_BOOKMARK (g_list_nth_data (window->forward_list,
232 NAUTILUS_WINDOW (window)->details->location_change_distance)),
233 location);
234 g_assert (NAUTILUS_WINDOW (window)->details->location != NULL);
236 /* Move current location to Back list */
238 check_last_bookmark_location_matches_window (NAUTILUS_WINDOW (window));
240 /* Use the first bookmark in the history list rather than creating a new one. */
241 window->back_list = g_list_prepend (window->back_list,
242 NAUTILUS_WINDOW (window)->last_location_bookmark);
243 g_object_ref (window->back_list->data);
245 /* Move extra links from Forward to Back list */
246 for (i = 0; i < NAUTILUS_WINDOW (window)->details->location_change_distance; ++i) {
247 bookmark = NAUTILUS_BOOKMARK (window->forward_list->data);
248 window->forward_list = g_list_remove (window->forward_list, bookmark);
249 window->back_list = g_list_prepend (window->back_list, bookmark);
252 /* One bookmark falls out of back/forward lists and becomes viewed location */
253 link = window->forward_list;
254 window->forward_list = g_list_remove_link (window->forward_list, link);
255 g_object_unref (link->data);
256 g_list_free_1 (link);
259 static void
260 handle_go_elsewhere (NautilusWindow *window, GFile *location)
262 #if !NEW_UI_COMPLETE
263 if (NAUTILUS_IS_NAVIGATION_WINDOW (window)) {
264 /* Clobber the entire forward list, and move displayed location to back list */
265 nautilus_navigation_window_clear_forward_list (NAUTILUS_NAVIGATION_WINDOW (window));
267 if (window->details->location != NULL) {
268 /* If we're returning to the same uri somehow, don't put this uri on back list.
269 * This also avoids a problem where set_displayed_location
270 * didn't update last_location_bookmark since the uri didn't change.
272 if (!g_file_equal (window->details->location, location)) {
273 /* Store bookmark for current location in back list, unless there is no current location */
274 check_last_bookmark_location_matches_window (window);
275 /* Use the first bookmark in the history list rather than creating a new one. */
276 NAUTILUS_NAVIGATION_WINDOW (window)->back_list = g_list_prepend (NAUTILUS_NAVIGATION_WINDOW (window)->back_list,
277 window->last_location_bookmark);
278 g_object_ref (NAUTILUS_NAVIGATION_WINDOW (window)->back_list->data);
282 #endif
285 static void
286 update_up_button (NautilusWindow *window)
288 gboolean allowed;
289 GFile *parent;
291 allowed = FALSE;
292 if (window->details->location != NULL) {
293 parent = g_file_get_parent (window->details->location);
294 allowed = parent != NULL;
295 if (parent != NULL) {
296 g_object_unref (parent);
300 nautilus_window_allow_up (window, allowed);
303 static void
304 viewed_file_changed_callback (NautilusFile *file,
305 NautilusWindow *window)
307 GFile *new_location;
308 gboolean is_in_trash, was_in_trash;
309 char *uri;
311 g_assert (NAUTILUS_IS_FILE (file));
312 g_assert (NAUTILUS_IS_WINDOW (window));
313 g_assert (window->details->viewed_file == file);
315 if (!nautilus_file_is_not_yet_confirmed (file)) {
316 window->details->viewed_file_seen = TRUE;
319 was_in_trash = window->details->viewed_file_in_trash;
321 window->details->viewed_file_in_trash = is_in_trash = nautilus_file_is_in_trash (file);
323 /* Close window if the file it's viewing has been deleted or moved to trash. */
324 if (nautilus_file_is_gone (file) || (is_in_trash && !was_in_trash)) {
325 /* Don't close the window in the case where the
326 * file was never seen in the first place.
328 if (window->details->viewed_file_seen) {
329 /* Detecting a file is gone may happen in the
330 * middle of a pending location change, we
331 * need to cancel it before closing the window
332 * or things break.
334 /* FIXME: It makes no sense that this call is
335 * needed. When the window is destroyed, it
336 * calls nautilus_window_manage_views_destroy,
337 * which calls free_location_change, which
338 * should be sufficient. Also, if this was
339 * really needed, wouldn't it be needed for
340 * all other nautilus_window_close callers?
342 end_location_change (window);
344 if (NAUTILUS_IS_NAVIGATION_WINDOW (window)) {
345 /* auto-show existing parent. */
346 GFile *go_to_file, *parent, *location;
348 go_to_file = NULL;
349 location = nautilus_file_get_location (file);
350 parent = g_file_get_parent (location);
351 g_object_unref (location);
352 if (parent) {
353 go_to_file = nautilus_find_existing_uri_in_hierarchy (parent);
354 g_object_unref (parent);
357 if (go_to_file != NULL) {
358 /* the path bar URI will be set to go_to_uri immediately
359 * in begin_location_change, but we don't want the
360 * inexistant children to show up anymore */
361 nautilus_path_bar_clear_buttons (NAUTILUS_PATH_BAR (NAUTILUS_NAVIGATION_WINDOW (window)->path_bar));
362 nautilus_window_go_to (NAUTILUS_WINDOW (window), go_to_file);
363 g_object_unref (go_to_file);
364 } else {
365 nautilus_window_go_home (NAUTILUS_WINDOW (window));
367 } else {
368 nautilus_window_close (window);
371 } else {
372 new_location = nautilus_file_get_location (file);
374 /* If the file was renamed, update location and/or
375 * title. */
376 if (!g_file_equal (new_location,
377 window->details->location)) {
378 g_object_unref (window->details->location);
379 window->details->location = new_location;
381 /* Check if we can go up. */
382 update_up_button (window);
383 #if !NEW_UI_COMPLETE
384 uri = g_file_get_uri (window->details->location);
385 if (NAUTILUS_IS_NAVIGATION_WINDOW (window)) {
386 /* Change the location bar and path bar to match the current location. */
387 nautilus_navigation_bar_set_location
388 (NAUTILUS_NAVIGATION_BAR (NAUTILUS_NAVIGATION_WINDOW (window)->navigation_bar),
389 uri);
390 nautilus_path_bar_set_path (NAUTILUS_PATH_BAR (NAUTILUS_NAVIGATION_WINDOW (window)->path_bar),
391 window->details->location);
393 if (NAUTILUS_IS_SPATIAL_WINDOW (window)) {
394 /* Change the location button to match the current location. */
395 nautilus_spatial_window_set_location_button
396 (NAUTILUS_SPATIAL_WINDOW (window),
397 window->details->location);
399 g_free (uri);
400 #endif
402 } else {
403 g_object_unref (new_location);
406 nautilus_window_update_title (window);
407 nautilus_window_update_icon (window);
411 static void
412 update_history (NautilusWindow *window,
413 NautilusLocationChangeType type,
414 GFile *new_location)
416 switch (type) {
417 case NAUTILUS_LOCATION_CHANGE_STANDARD:
418 case NAUTILUS_LOCATION_CHANGE_FALLBACK:
419 nautilus_window_add_current_location_to_history_list (window);
420 handle_go_elsewhere (window, new_location);
421 return;
422 case NAUTILUS_LOCATION_CHANGE_RELOAD:
423 /* for reload there is no work to do */
424 return;
425 case NAUTILUS_LOCATION_CHANGE_BACK:
426 nautilus_window_add_current_location_to_history_list (window);
427 handle_go_back (NAUTILUS_NAVIGATION_WINDOW (window),
428 new_location);
429 return;
430 case NAUTILUS_LOCATION_CHANGE_FORWARD:
431 nautilus_window_add_current_location_to_history_list (window);
432 handle_go_forward (NAUTILUS_NAVIGATION_WINDOW (window),
433 new_location);
434 return;
435 case NAUTILUS_LOCATION_CHANGE_REDIRECT:
436 /* for the redirect case, the caller can do the updating */
437 return;
439 g_return_if_fail (FALSE);
442 static void
443 cancel_viewed_file_changed_callback (NautilusWindow *window)
445 NautilusFile *file;
447 file = window->details->viewed_file;
448 if (file != NULL) {
449 g_signal_handlers_disconnect_by_func (G_OBJECT (file),
450 G_CALLBACK (viewed_file_changed_callback),
451 window);
452 nautilus_file_monitor_remove (file, &window->details->viewed_file);
456 static void
457 new_window_show_callback (GtkWidget *widget,
458 gpointer user_data)
460 NautilusWindow *window;
462 window = NAUTILUS_WINDOW (user_data);
464 nautilus_window_close (window);
466 g_signal_handlers_disconnect_by_func (widget,
467 G_CALLBACK (new_window_show_callback),
468 user_data);
472 void
473 nautilus_window_open_location_full (NautilusWindow *window,
474 GFile *location,
475 NautilusWindowOpenMode mode,
476 NautilusWindowOpenFlags flags,
477 GList *new_selection)
479 NautilusWindow *target_window;
480 gboolean do_load_location = TRUE;
481 GFile *old_location;
482 char *old_uri, *new_uri;
484 target_window = NULL;
486 old_uri = nautilus_window_get_location_uri (window);
487 if (old_uri == NULL) {
488 old_uri = g_strdup ("(none)");
490 new_uri = g_file_get_uri (location);
491 nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_USER,
492 "window %p open location: old=\"%s\", new=\"%s\"",
493 window,
494 old_uri,
495 new_uri);
496 g_free (old_uri);
497 g_free (new_uri);
500 old_location = nautilus_window_get_location (window);
501 switch (mode) {
502 case NAUTILUS_WINDOW_OPEN_ACCORDING_TO_MODE :
503 if (eel_preferences_get_boolean (NAUTILUS_PREFERENCES_ALWAYS_USE_BROWSER)) {
504 target_window = window;
505 if (NAUTILUS_IS_SPATIAL_WINDOW (window)) {
506 if (!NAUTILUS_SPATIAL_WINDOW (window)->affect_spatial_window_on_next_location_change) {
507 target_window = nautilus_application_create_navigation_window
508 (window->application,
509 NULL,
510 gtk_window_get_screen (GTK_WINDOW (window)));
511 } else {
512 NAUTILUS_SPATIAL_WINDOW (window)->affect_spatial_window_on_next_location_change = FALSE;
514 } else if ((flags & NAUTILUS_WINDOW_OPEN_FLAG_NEW_WINDOW) != 0) {
515 target_window = nautilus_application_create_navigation_window
516 (window->application,
517 NULL,
518 gtk_window_get_screen (GTK_WINDOW (window)));
520 } else if (NAUTILUS_IS_SPATIAL_WINDOW (window)) {
521 if (!NAUTILUS_SPATIAL_WINDOW (window)->affect_spatial_window_on_next_location_change) {
522 target_window = nautilus_application_present_spatial_window_with_selection (
523 window->application,
524 window,
525 NULL,
526 location,
527 new_selection,
528 gtk_window_get_screen (GTK_WINDOW (window)));
529 do_load_location = FALSE;
530 } else {
531 NAUTILUS_SPATIAL_WINDOW (window)->affect_spatial_window_on_next_location_change = FALSE;
532 target_window = window;
534 } else if (flags & NAUTILUS_WINDOW_OPEN_FLAG_NEW_WINDOW) {
535 target_window = nautilus_application_create_navigation_window
536 (window->application,
537 NULL,
538 gtk_window_get_screen (GTK_WINDOW (window)));
539 } else {
540 target_window = window;
542 break;
543 case NAUTILUS_WINDOW_OPEN_IN_SPATIAL :
544 target_window = nautilus_application_present_spatial_window (
545 window->application,
546 window,
547 NULL,
548 location,
549 gtk_window_get_screen (GTK_WINDOW (window)));
550 break;
551 case NAUTILUS_WINDOW_OPEN_IN_NAVIGATION :
552 target_window = nautilus_application_create_navigation_window
553 (window->application,
554 NULL,
555 gtk_window_get_screen (GTK_WINDOW (window)));
556 break;
557 default :
558 g_warning ("Unknown open location mode");
559 g_object_unref (old_location);
560 return;
563 g_assert (target_window != NULL);
565 if ((flags & NAUTILUS_WINDOW_OPEN_FLAG_CLOSE_BEHIND) != 0) {
566 if (NAUTILUS_IS_SPATIAL_WINDOW (window) && !NAUTILUS_IS_DESKTOP_WINDOW (window)) {
567 if (GTK_WIDGET_VISIBLE (target_window)) {
568 nautilus_window_close (window);
569 } else {
570 g_signal_connect_object (target_window,
571 "show",
572 G_CALLBACK (new_window_show_callback),
573 window,
574 G_CONNECT_AFTER);
579 if ((!do_load_location) ||
580 (target_window == window &&
581 old_location && g_file_equal (old_location, location))) {
582 g_object_unref (old_location);
583 return;
586 if (old_location) {
587 g_object_unref (old_location);
590 begin_location_change (target_window, location, new_selection,
591 NAUTILUS_LOCATION_CHANGE_STANDARD, 0, NULL);
594 void
595 nautilus_window_open_location (NautilusWindow *window,
596 GFile *location,
597 gboolean close_behind)
599 NautilusWindowOpenFlags flags;
601 flags = 0;
602 if (close_behind) {
603 flags = NAUTILUS_WINDOW_OPEN_FLAG_CLOSE_BEHIND;
606 nautilus_window_open_location_full (window, location,
607 NAUTILUS_WINDOW_OPEN_ACCORDING_TO_MODE,
608 flags, NULL);
611 void
612 nautilus_window_open_location_with_selection (NautilusWindow *window,
613 GFile *location,
614 GList *selection,
615 gboolean close_behind)
617 NautilusWindowOpenFlags flags;
619 flags = 0;
620 if (close_behind) {
621 flags = NAUTILUS_WINDOW_OPEN_FLAG_CLOSE_BEHIND;
623 nautilus_window_open_location_full (window, location,
624 NAUTILUS_WINDOW_OPEN_ACCORDING_TO_MODE,
625 flags, selection);
628 char *
629 nautilus_window_get_view_error_label (NautilusWindow *window)
631 const NautilusViewInfo *info;
633 info = nautilus_view_factory_lookup (nautilus_window_get_content_view_id (window));
635 return g_strdup (info->error_label);
638 char *
639 nautilus_window_get_view_startup_error_label (NautilusWindow *window)
641 const NautilusViewInfo *info;
643 info = nautilus_view_factory_lookup (nautilus_window_get_content_view_id (window));
645 return g_strdup (info->startup_error_label);
648 static void
649 report_current_content_view_failure_to_user (NautilusWindow *window,
650 NautilusView *view)
652 char *message;
654 message = nautilus_window_get_view_startup_error_label (window);
655 eel_show_error_dialog (message,
656 _("You can choose another view or go to a different location."),
657 GTK_WINDOW (window));
658 g_free (message);
661 static void
662 report_nascent_content_view_failure_to_user (NautilusWindow *window,
663 NautilusView *view)
665 char *message;
667 message = nautilus_window_get_view_error_label (window);
668 eel_show_error_dialog (message,
669 _("The location cannot be displayed with this viewer."),
670 GTK_WINDOW (window));
671 g_free (message);
675 const char *
676 nautilus_window_get_content_view_id (NautilusWindow *window)
678 if (window->content_view == NULL) {
679 return NULL;
681 return nautilus_view_get_view_id (window->content_view);
684 gboolean
685 nautilus_window_content_view_matches_iid (NautilusWindow *window,
686 const char *iid)
688 if (window->content_view == NULL) {
689 return FALSE;
691 return eel_strcmp (nautilus_view_get_view_id (window->content_view),
692 iid) == 0;
697 * begin_location_change
699 * Change a window's location.
700 * @window: The NautilusWindow whose location should be changed.
701 * @location: A url specifying the location to load
702 * @new_selection: The initial selection to present after loading the location
703 * @type: Which type of location change is this? Standard, back, forward, or reload?
704 * @distance: If type is back or forward, the index into the back or forward chain. If
705 * type is standard or reload, this is ignored, and must be 0.
706 * @scroll_pos: The file to scroll to when the location is loaded.
708 * This is the core function for changing the location of a window. Every change to the
709 * location begins here.
711 static void
712 begin_location_change (NautilusWindow *window,
713 GFile *location,
714 GList *new_selection,
715 NautilusLocationChangeType type,
716 guint distance,
717 const char *scroll_pos)
719 NautilusDirectory *directory;
720 NautilusFile *file;
721 gboolean force_reload;
722 char *current_pos;
724 g_assert (NAUTILUS_IS_WINDOW (window));
725 g_assert (location != NULL);
726 g_assert (type == NAUTILUS_LOCATION_CHANGE_BACK
727 || type == NAUTILUS_LOCATION_CHANGE_FORWARD
728 || distance == 0);
730 g_object_ref (window);
732 end_location_change (window);
734 nautilus_window_allow_stop (window, TRUE);
735 nautilus_window_set_status (window, " ");
737 g_assert (window->details->pending_location == NULL);
738 g_assert (window->details->pending_selection == NULL);
740 window->details->pending_location = g_object_ref (location);
741 window->details->location_change_type = type;
742 window->details->location_change_distance = distance;
743 window->details->tried_mount = FALSE;
744 window->details->pending_selection = eel_g_object_list_copy (new_selection);
747 window->details->pending_scroll_to = g_strdup (scroll_pos);
749 directory = nautilus_directory_get (location);
751 /* The code to force a reload is here because if we do it
752 * after determining an initial view (in the components), then
753 * we end up fetching things twice.
755 if (type == NAUTILUS_LOCATION_CHANGE_RELOAD) {
756 force_reload = TRUE;
757 } else if (!nautilus_monitor_active ()) {
758 force_reload = TRUE;
759 } else {
760 force_reload = !nautilus_directory_is_local (directory);
763 if (force_reload) {
764 nautilus_directory_force_reload (directory);
765 file = nautilus_directory_get_corresponding_file (directory);
766 nautilus_file_invalidate_all_attributes (file);
767 nautilus_file_unref (file);
770 nautilus_directory_unref (directory);
772 /* Set current_bookmark scroll pos */
773 if (window->current_location_bookmark != NULL &&
774 window->content_view != NULL) {
775 current_pos = nautilus_view_get_first_visible_file (window->content_view);
776 nautilus_bookmark_set_scroll_pos (window->current_location_bookmark, current_pos);
777 g_free (current_pos);
780 /* Get the info needed for view selection */
782 window->details->determine_view_file = nautilus_file_get (location);
784 g_assert (window->details->determine_view_file != NULL);
786 /* if the currently viewed file is marked gone while loading the new location,
787 * this ensures that the window isn't destroyed */
788 cancel_viewed_file_changed_callback (window);
790 nautilus_file_call_when_ready (window->details->determine_view_file,
791 NAUTILUS_FILE_ATTRIBUTE_INFO |
792 NAUTILUS_FILE_ATTRIBUTE_MOUNT |
793 NAUTILUS_FILE_ATTRIBUTE_METADATA,
794 got_file_info_for_view_selection_callback,
795 window);
797 g_object_unref (window);
800 static void
801 setup_new_window (NautilusWindow *window, NautilusFile *file)
803 char *show_hidden_file_setting;
804 char *geometry_string;
805 char *scroll_string;
806 gboolean maximized, sticky, above;
808 if (NAUTILUS_IS_SPATIAL_WINDOW (window) && !NAUTILUS_IS_DESKTOP_WINDOW (window)) {
809 /* load show hidden state */
810 show_hidden_file_setting = nautilus_file_get_metadata
811 (file, NAUTILUS_METADATA_KEY_WINDOW_SHOW_HIDDEN_FILES,
812 NULL);
813 if (show_hidden_file_setting != NULL) {
814 if (strcmp (show_hidden_file_setting, "1") == 0) {
815 NAUTILUS_WINDOW (window)->details->show_hidden_files_mode = NAUTILUS_WINDOW_SHOW_HIDDEN_FILES_ENABLE;
816 } else {
817 NAUTILUS_WINDOW (window)->details->show_hidden_files_mode = NAUTILUS_WINDOW_SHOW_HIDDEN_FILES_DISABLE;
819 } else {
820 NAUTILUS_WINDOW (window)->details->show_hidden_files_mode = NAUTILUS_WINDOW_SHOW_HIDDEN_FILES_DEFAULT;
822 g_free (show_hidden_file_setting);
824 /* load the saved window geometry */
825 maximized = nautilus_file_get_boolean_metadata
826 (file, NAUTILUS_METADATA_KEY_WINDOW_MAXIMIZED, FALSE);
827 if (maximized) {
828 gtk_window_maximize (GTK_WINDOW (window));
829 } else {
830 gtk_window_unmaximize (GTK_WINDOW (window));
833 sticky = nautilus_file_get_boolean_metadata
834 (file, NAUTILUS_METADATA_KEY_WINDOW_STICKY, FALSE);
835 if (sticky) {
836 gtk_window_stick (GTK_WINDOW (window));
837 } else {
838 gtk_window_unstick (GTK_WINDOW (window));
841 above = nautilus_file_get_boolean_metadata
842 (file, NAUTILUS_METADATA_KEY_WINDOW_KEEP_ABOVE, FALSE);
843 if (above) {
844 gtk_window_set_keep_above (GTK_WINDOW (window), TRUE);
845 } else {
846 gtk_window_set_keep_above (GTK_WINDOW (window), FALSE);
849 geometry_string = nautilus_file_get_metadata
850 (file, NAUTILUS_METADATA_KEY_WINDOW_GEOMETRY, NULL);
851 if (geometry_string != NULL) {
852 eel_gtk_window_set_initial_geometry_from_string
853 (GTK_WINDOW (window),
854 geometry_string,
855 NAUTILUS_SPATIAL_WINDOW_MIN_WIDTH,
856 NAUTILUS_SPATIAL_WINDOW_MIN_HEIGHT,
857 FALSE);
859 g_free (geometry_string);
861 if (window->details->pending_selection == NULL) {
862 /* If there is no pending selection, then load the saved scroll position. */
863 scroll_string = nautilus_file_get_metadata
864 (file, NAUTILUS_METADATA_KEY_WINDOW_SCROLL_POSITION,
865 NULL);
866 } else {
867 /* If there is a pending selection, we want to scroll to an item in
868 * the pending selection list. */
869 scroll_string = g_file_get_uri (window->details->pending_selection->data);
872 /* scroll_string might be NULL if there was no saved scroll position. */
873 if (scroll_string != NULL) {
874 window->details->pending_scroll_to = scroll_string;
879 typedef struct {
880 GCancellable *cancellable;
881 NautilusWindow *window;
882 } MountNotMountedData;
884 static void
885 mount_not_mounted_callback (GObject *source_object,
886 GAsyncResult *res,
887 gpointer user_data)
889 MountNotMountedData *data;
890 NautilusWindow *window;
891 GError *error;
892 GCancellable *cancellable;
894 data = user_data;
895 window = data->window;
896 cancellable = data->cancellable;
897 g_free (data);
899 if (g_cancellable_is_cancelled (cancellable)) {
900 /* Cancelled, don't call back */
901 g_object_unref (cancellable);
902 return;
905 window->details->mount_cancellable = NULL;
907 window->details->determine_view_file = nautilus_file_get (window->details->pending_location);
909 error = NULL;
910 if (!g_file_mount_enclosing_volume_finish (G_FILE (source_object), res, &error)) {
911 window->details->mount_error = error;
912 got_file_info_for_view_selection_callback (window->details->determine_view_file, window);
913 window->details->mount_error = NULL;
914 g_error_free (error);
915 } else {
916 nautilus_file_invalidate_all_attributes (window->details->determine_view_file);
917 nautilus_file_call_when_ready (window->details->determine_view_file,
918 NAUTILUS_FILE_ATTRIBUTE_INFO |
919 NAUTILUS_FILE_ATTRIBUTE_METADATA,
920 got_file_info_for_view_selection_callback,
921 window);
924 g_object_unref (cancellable);
927 static void
928 got_file_info_for_view_selection_callback (NautilusFile *file,
929 gpointer callback_data)
931 GError *error;
932 char *view_id;
933 char *mimetype;
934 NautilusWindow *window;
935 NautilusFile *viewed_file;
936 GFile *location;
937 GMountOperation *mount_op;
938 MountNotMountedData *data;
940 window = callback_data;
942 g_assert (window->details->determine_view_file == file);
943 window->details->determine_view_file = NULL;
945 if (window->details->mount_error) {
946 error = window->details->mount_error;
947 } else {
948 error = nautilus_file_get_file_info_error (file);
951 if (error && error->domain == G_IO_ERROR && error->code == G_IO_ERROR_NOT_MOUNTED &&
952 !window->details->tried_mount) {
953 window->details->tried_mount = TRUE;
955 mount_op = eel_mount_operation_new (GTK_WINDOW (window));
956 location = nautilus_file_get_location (file);
957 data = g_new0 (MountNotMountedData, 1);
958 data->cancellable = g_cancellable_new ();
959 data->window = window;
960 window->details->mount_cancellable = data->cancellable;
961 g_file_mount_enclosing_volume (location, 0, mount_op, window->details->mount_cancellable,
962 mount_not_mounted_callback, data);
963 g_object_unref (location);
964 g_object_unref (mount_op);
966 nautilus_file_unref (file);
968 return;
971 location = window->details->pending_location;
973 view_id = NULL;
975 if (error == NULL ||
976 (error->domain == G_IO_ERROR && error->code == G_IO_ERROR_NOT_SUPPORTED)) {
977 /* We got the information we need, now pick what view to use: */
979 mimetype = nautilus_file_get_mime_type (file);
981 /* If fallback, don't use view from metadata */
982 if (window->details->location_change_type != NAUTILUS_LOCATION_CHANGE_FALLBACK) {
983 /* Look in metadata for view */
984 view_id = nautilus_file_get_metadata
985 (file, NAUTILUS_METADATA_KEY_DEFAULT_COMPONENT, NULL);
986 if (view_id != NULL &&
987 !nautilus_view_factory_view_supports_uri (view_id,
988 location,
989 nautilus_file_get_file_type (file),
990 mimetype)) {
991 g_free (view_id);
992 view_id = NULL;
996 /* Otherwise, use default */
997 if (view_id == NULL) {
998 view_id = nautilus_global_preferences_get_default_folder_viewer_preference_as_iid ();
1000 if (view_id != NULL &&
1001 !nautilus_view_factory_view_supports_uri (view_id,
1002 location,
1003 nautilus_file_get_file_type (file),
1004 mimetype)) {
1005 g_free (view_id);
1006 view_id = NULL;
1010 g_free (mimetype);
1013 if (view_id != NULL) {
1014 if (!GTK_WIDGET_VISIBLE (window)) {
1015 /* We now have the metadata to set up the window position, etc */
1016 setup_new_window (window, file);
1018 create_content_view (window, view_id);
1019 g_free (view_id);
1020 } else {
1021 display_view_selection_failure (window, file,
1022 location, error);
1024 if (!GTK_WIDGET_VISIBLE (GTK_WIDGET (window))) {
1025 /* Destroy never-had-a-chance-to-be-seen window. This case
1026 * happens when a new window cannot display its initial URI.
1028 /* if this is the only window, we don't want to quit, so we redirect it to home */
1029 if (nautilus_application_get_n_windows () <= 1) {
1030 g_assert (nautilus_application_get_n_windows () == 1);
1032 /* Make sure we re-use this window */
1033 if (NAUTILUS_IS_SPATIAL_WINDOW (window)) {
1034 NAUTILUS_SPATIAL_WINDOW (window)->affect_spatial_window_on_next_location_change = TRUE;
1036 /* the user could have typed in a home directory that doesn't exist,
1037 in which case going home would cause an infinite loop, so we
1038 better test for that */
1040 if (!nautilus_is_root_directory (location)) {
1041 if (!nautilus_is_home_directory (location)) {
1042 nautilus_window_go_home (NAUTILUS_WINDOW (window));
1043 } else {
1044 GFile *root;
1046 root = g_file_new_for_path ("/");
1047 /* the last fallback is to go to a known place that can't be deleted! */
1048 nautilus_window_go_to (NAUTILUS_WINDOW (window), root);
1049 g_object_unref (root);
1051 } else {
1052 gtk_object_destroy (GTK_OBJECT (window));
1054 } else {
1055 /* Since this is a window, destroying it will also unref it. */
1056 gtk_object_destroy (GTK_OBJECT (window));
1058 } else {
1059 /* Clean up state of already-showing window */
1060 end_location_change (window);
1062 /* We disconnected this, so we need to re-connect it */
1063 viewed_file = nautilus_file_get (window->details->location);
1064 nautilus_window_set_viewed_file (window, viewed_file);
1065 nautilus_file_monitor_add (viewed_file, &window->details->viewed_file, 0);
1066 g_signal_connect_object (viewed_file, "changed",
1067 G_CALLBACK (viewed_file_changed_callback), window, 0);
1068 nautilus_file_unref (viewed_file);
1070 /* Leave the location bar showing the bad location that the user
1071 * typed (or maybe achieved by dragging or something). Many times
1072 * the mistake will just be an easily-correctable typo. The user
1073 * can choose "Refresh" to get the original URI back in the location bar.
1078 nautilus_file_unref (file);
1081 /* Load a view into the window, either reusing the old one or creating
1082 * a new one. This happens when you want to load a new location, or just
1083 * switch to a different view.
1084 * If pending_location is set we're loading a new location and
1085 * pending_location/selection will be used. If not, we're just switching
1086 * view, and the current location will be used.
1088 static void
1089 create_content_view (NautilusWindow *window,
1090 const char *view_id)
1092 NautilusView *view;
1093 GList *selection;
1094 GtkAction *action;
1096 /* FIXME bugzilla.gnome.org 41243:
1097 * We should use inheritance instead of these special cases
1098 * for the desktop window.
1100 if (NAUTILUS_IS_DESKTOP_WINDOW (window)) {
1101 /* We force the desktop to use a desktop_icon_view. It's simpler
1102 * to fix it here than trying to make it pick the right view in
1103 * the first place.
1105 view_id = NAUTILUS_DESKTOP_ICON_VIEW_IID;
1108 action = gtk_action_group_get_action (window->details->main_action_group,
1109 NAUTILUS_ACTION_ZOOM_IN);
1110 gtk_action_set_sensitive (action, FALSE);
1111 action = gtk_action_group_get_action (window->details->main_action_group,
1112 NAUTILUS_ACTION_ZOOM_OUT);
1113 gtk_action_set_sensitive (action, FALSE);
1114 action = gtk_action_group_get_action (window->details->main_action_group,
1115 NAUTILUS_ACTION_ZOOM_NORMAL);
1116 gtk_action_set_sensitive (action, FALSE);
1118 if (window->content_view != NULL &&
1119 eel_strcmp (nautilus_view_get_view_id (window->content_view),
1120 view_id) == 0) {
1121 /* reuse existing content view */
1122 view = window->content_view;
1123 window->new_content_view = view;
1124 g_object_ref (view);
1125 } else {
1126 /* create a new content view */
1127 view = nautilus_view_factory_create (view_id,
1128 NAUTILUS_WINDOW_INFO (window));
1130 eel_accessibility_set_name (view, _("Content View"));
1131 eel_accessibility_set_description (view, _("View of the current folder"));
1133 connect_view (window, view);
1135 window->new_content_view = view;
1138 /* Actually load the pending location and selection: */
1140 if (window->details->pending_location != NULL) {
1141 load_new_location (window,
1142 window->details->pending_location,
1143 window->details->pending_selection,
1144 FALSE,
1145 TRUE);
1147 eel_g_object_list_free (window->details->pending_selection);
1148 window->details->pending_selection = NULL;
1149 } else if (window->details->location != NULL) {
1150 selection = nautilus_view_get_selection (window->content_view);
1151 load_new_location (window,
1152 window->details->location,
1153 selection,
1154 FALSE,
1155 TRUE);
1156 eel_g_object_list_free (selection);
1157 } else {
1158 /* Something is busted, there was no location to load.
1159 Just load the homedir. */
1160 nautilus_window_go_home (NAUTILUS_WINDOW (window));
1165 static void
1166 load_new_location (NautilusWindow *window,
1167 GFile *location,
1168 GList *selection,
1169 gboolean tell_current_content_view,
1170 gboolean tell_new_content_view)
1172 GList *selection_copy;
1173 NautilusView *view;
1174 char *uri;
1176 g_assert (NAUTILUS_IS_WINDOW (window));
1177 g_assert (location != NULL);
1179 selection_copy = eel_g_object_list_copy (selection);
1181 view = NULL;
1183 /* Note, these may recurse into report_load_underway */
1184 if (window->content_view != NULL && tell_current_content_view) {
1185 view = window->content_view;
1186 uri = g_file_get_uri (location);
1187 nautilus_view_load_location (window->content_view, uri);
1188 g_free (uri);
1191 if (window->new_content_view != NULL && tell_new_content_view &&
1192 (!tell_current_content_view ||
1193 window->new_content_view != window->content_view) ) {
1194 view = window->new_content_view;
1195 uri = g_file_get_uri (location);
1196 nautilus_view_load_location (window->new_content_view, uri);
1197 g_free (uri);
1199 if (view != NULL) {
1200 /* window->new_content_view might have changed here if
1201 report_load_underway was called from load_location */
1202 nautilus_view_set_selection (view, selection_copy);
1205 eel_g_object_list_free (selection_copy);
1208 /* A view started to load the location its viewing, either due to
1209 * a load_location request, or some internal reason. Expect
1210 * a matching load_compete later
1212 void
1213 nautilus_window_report_load_underway (NautilusWindow *window,
1214 NautilusView *view)
1216 g_assert (NAUTILUS_IS_WINDOW (window));
1218 if (view == window->new_content_view) {
1219 location_has_really_changed (window);
1220 } else if (view == window->content_view) {
1221 nautilus_window_allow_stop (window, TRUE);
1222 } else {
1223 g_warning ("Got load_underway report from unknown view");
1227 /* This is called when we have decided we can actually change to the new view/location situation. */
1228 static void
1229 location_has_really_changed (NautilusWindow *window)
1231 GtkWidget *widget;
1232 GFile *location_copy;
1233 char *uri;
1235 location_copy = NULL;
1237 if (window->new_content_view != NULL) {
1238 widget = nautilus_view_get_widget (window->new_content_view);
1239 /* Switch to the new content view. */
1240 if (widget->parent == NULL) {
1241 disconnect_view (window, window->content_view);
1242 nautilus_window_set_content_view_widget (window, window->new_content_view);
1244 g_object_unref (window->new_content_view);
1245 window->new_content_view = NULL;
1248 if (window->details->pending_location != NULL) {
1249 location_copy = g_object_ref (window->details->pending_location);
1250 /* Tell the window we are finished. */
1251 update_for_new_location (window);
1254 free_location_change (window);
1256 if (location_copy != NULL) {
1257 uri = g_file_get_uri (location_copy);
1258 g_signal_emit_by_name (window, "loading_uri", uri);
1259 g_free (uri);
1260 g_object_unref (location_copy);
1264 static void
1265 add_extension_extra_widgets (NautilusWindow *window, GFile *location)
1267 GList *providers, *l;
1268 GtkWidget *widget;
1269 char *uri;
1271 providers = nautilus_module_get_extensions_for_type (NAUTILUS_TYPE_LOCATION_WIDGET_PROVIDER);
1273 uri = g_file_get_uri (location);
1274 for (l = providers; l != NULL; l = l->next) {
1275 NautilusLocationWidgetProvider *provider;
1277 provider = NAUTILUS_LOCATION_WIDGET_PROVIDER (l->data);
1278 widget = nautilus_location_widget_provider_get_widget (provider, uri, GTK_WIDGET (window));
1279 if (widget != NULL) {
1280 nautilus_window_add_extra_location_widget (window, widget);
1283 g_free (uri);
1285 nautilus_module_extension_list_free (providers);
1288 static void
1289 nautilus_window_show_x_content_bar (NautilusWindow *window, GMount *mount, const char **x_content_types)
1291 unsigned int n;
1293 g_assert (NAUTILUS_IS_WINDOW (window));
1295 for (n = 0; x_content_types[n] != NULL; n++) {
1296 GAppInfo *default_app;
1298 /* skip blank media; the burn:/// location will provide it's own cluebar */
1299 if (g_str_has_prefix (x_content_types[n], "x-content/blank-")) {
1300 continue;
1303 /* only show the cluebar if a default app is available */
1304 default_app = g_app_info_get_default_for_type (x_content_types[n], FALSE);
1305 if (default_app != NULL) {
1306 GtkWidget *bar;
1307 bar = nautilus_x_content_bar_new (mount, x_content_types[n]);
1308 gtk_widget_show (bar);
1309 nautilus_window_add_extra_location_widget (window, bar);
1310 g_object_unref (default_app);
1315 static void
1316 nautilus_window_show_trash_bar (NautilusWindow *window)
1318 GtkWidget *bar;
1320 g_assert (NAUTILUS_IS_WINDOW (window));
1322 bar = nautilus_trash_bar_new ();
1323 gtk_widget_show (bar);
1325 nautilus_window_add_extra_location_widget (window, bar);
1328 typedef struct {
1329 NautilusWindow *window;
1330 GCancellable *cancellable;
1331 GMount *mount;
1332 } FindMountData;
1334 static void
1335 found_content_type_cb (const char **x_content_types, FindMountData *data)
1337 NautilusWindow *window;
1339 if (g_cancellable_is_cancelled (data->cancellable)) {
1340 goto out;
1343 window = data->window;
1345 if (x_content_types != NULL && x_content_types[0] != NULL) {
1346 nautilus_window_show_x_content_bar (window, data->mount, x_content_types);
1347 update_extra_location_widgets_visibility (window);
1350 window->details->find_mount_cancellable = NULL;
1352 out:
1353 g_object_unref (data->mount);
1354 g_object_unref (data->cancellable);
1355 g_free (data);
1358 static void
1359 found_mount_cb (GObject *source_object,
1360 GAsyncResult *res,
1361 gpointer user_data)
1363 FindMountData *data = user_data;
1364 GMount *mount;
1365 NautilusWindow *window;
1367 if (g_cancellable_is_cancelled (data->cancellable)) {
1368 goto out;
1371 window = data->window;
1373 mount = g_file_find_enclosing_mount_finish (G_FILE (source_object),
1374 res,
1375 NULL);
1376 if (mount != NULL) {
1377 data->mount = mount;
1378 nautilus_autorun_get_x_content_types_for_mount_async (mount,
1379 (NautilusAutorunGetContent)found_content_type_cb,
1380 data->cancellable,
1381 data);
1382 return;
1385 window->details->find_mount_cancellable = NULL;
1387 out:
1388 g_object_unref (data->cancellable);
1389 g_free (data);
1392 /* Handle the changes for the NautilusWindow itself. */
1393 static void
1394 update_for_new_location (NautilusWindow *window)
1396 GFile *new_location;
1397 NautilusFile *file;
1398 NautilusDirectory *directory;
1399 gboolean location_really_changed;
1400 char *uri;
1401 FindMountData *data;
1403 new_location = window->details->pending_location;
1404 window->details->pending_location = NULL;
1406 set_displayed_location (window, new_location);
1408 update_history (window, window->details->location_change_type, new_location);
1410 location_really_changed =
1411 window->details->location == NULL ||
1412 !g_file_equal (window->details->location, new_location);
1414 /* Set the new location. */
1415 if (window->details->location) {
1416 g_object_unref (window->details->location);
1418 window->details->location = new_location;
1420 /* Create a NautilusFile for this location, so we can catch it
1421 * if it goes away.
1423 cancel_viewed_file_changed_callback (window);
1424 file = nautilus_file_get (window->details->location);
1425 nautilus_window_set_viewed_file (window, file);
1426 window->details->viewed_file_seen = !nautilus_file_is_not_yet_confirmed (file);
1427 window->details->viewed_file_in_trash = nautilus_file_is_in_trash (file);
1428 nautilus_file_monitor_add (file, &window->details->viewed_file, 0);
1429 g_signal_connect_object (file, "changed",
1430 G_CALLBACK (viewed_file_changed_callback), window, 0);
1431 nautilus_file_unref (file);
1433 /* Check if we can go up. */
1434 update_up_button (window);
1436 /* Set up the initial zoom levels */
1437 zoom_parameters_changed_callback (window->content_view,
1438 window);
1440 /* Set up the content view menu for this new location. */
1441 nautilus_window_load_view_as_menus (window);
1443 /* Load menus from nautilus extensions for this location */
1444 nautilus_window_load_extension_menus (window);
1446 if (location_really_changed) {
1447 remove_extra_location_widgets (window);
1449 directory = nautilus_directory_get (window->details->location);
1450 if (NAUTILUS_IS_SEARCH_DIRECTORY (directory)) {
1451 nautilus_window_set_search_mode (window, TRUE, NAUTILUS_SEARCH_DIRECTORY (directory));
1452 } else {
1453 nautilus_window_set_search_mode (window, FALSE, NULL);
1456 if (nautilus_directory_is_in_trash (directory)) {
1457 nautilus_window_show_trash_bar (window);
1460 /* need the mount to determine if we should put up the x-content cluebar */
1461 if (window->details->find_mount_cancellable != NULL) {
1462 g_cancellable_cancel (window->details->find_mount_cancellable);
1463 window->details->find_mount_cancellable = NULL;
1466 data = g_new (FindMountData, 1);
1467 data->window = window;
1468 data->cancellable = g_cancellable_new ();
1469 data->mount = NULL;
1471 window->details->find_mount_cancellable = data->cancellable;
1472 g_file_find_enclosing_mount_async (window->details->location,
1473 G_PRIORITY_DEFAULT,
1474 data->cancellable,
1475 found_mount_cb,
1476 data);
1478 nautilus_directory_unref (directory);
1480 add_extension_extra_widgets (window, window->details->location);
1482 update_extra_location_widgets_visibility (window);
1485 #if !NEW_UI_COMPLETE
1486 if (NAUTILUS_IS_NAVIGATION_WINDOW (window)) {
1487 /* Check if the back and forward buttons need enabling or disabling. */
1488 nautilus_navigation_window_allow_back (NAUTILUS_NAVIGATION_WINDOW (window), NAUTILUS_NAVIGATION_WINDOW (window)->back_list != NULL);
1489 nautilus_navigation_window_allow_forward (NAUTILUS_NAVIGATION_WINDOW (window), NAUTILUS_NAVIGATION_WINDOW (window)->forward_list != NULL);
1491 /* Change the location bar and path bar to match the current location. */
1492 uri = g_file_get_uri (window->details->location);
1493 nautilus_navigation_bar_set_location (NAUTILUS_NAVIGATION_BAR (NAUTILUS_NAVIGATION_WINDOW (window)->navigation_bar),
1494 uri);
1495 g_free (uri);
1496 nautilus_path_bar_set_path (NAUTILUS_PATH_BAR (NAUTILUS_NAVIGATION_WINDOW (window)->path_bar),
1497 window->details->location);
1498 nautilus_navigation_window_load_extension_toolbar_items (NAUTILUS_NAVIGATION_WINDOW (window));
1501 if (NAUTILUS_IS_SPATIAL_WINDOW (window)) {
1502 /* Change the location button to match the current location. */
1503 nautilus_spatial_window_set_location_button (NAUTILUS_SPATIAL_WINDOW (window),
1504 window->details->location);
1506 #endif
1509 /* A location load previously announced by load_underway
1510 * has been finished */
1511 void
1512 nautilus_window_report_load_complete (NautilusWindow *window,
1513 NautilusView *view)
1515 g_assert (NAUTILUS_IS_WINDOW (window));
1517 /* Only handle this if we're expecting it.
1518 * Don't handle it if its from an old view we've switched from */
1519 if (view == window->content_view) {
1520 if (window->details->pending_scroll_to != NULL) {
1521 nautilus_view_scroll_to_file (window->content_view,
1522 window->details->pending_scroll_to);
1524 end_location_change (window);
1528 static void
1529 end_location_change (NautilusWindow *window)
1531 char *uri;
1533 uri = nautilus_window_get_location_uri (window);
1534 if (uri) {
1535 nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_USER,
1536 "finished loading window %p: %s", window, uri);
1537 g_free (uri);
1540 nautilus_window_allow_stop (window, FALSE);
1542 /* Now we can free pending_scroll_to, since the load_complete
1543 * callback already has been emitted.
1545 g_free (window->details->pending_scroll_to);
1546 window->details->pending_scroll_to = NULL;
1548 free_location_change (window);
1551 static void
1552 free_location_change (NautilusWindow *window)
1554 if (window->details->pending_location) {
1555 g_object_unref (window->details->pending_location);
1557 window->details->pending_location = NULL;
1559 eel_g_object_list_free (window->details->pending_selection);
1560 window->details->pending_selection = NULL;
1562 /* Don't free pending_scroll_to, since thats needed until
1563 * the load_complete callback.
1566 if (window->details->mount_cancellable != NULL) {
1567 g_cancellable_cancel (window->details->mount_cancellable);
1568 window->details->mount_cancellable = NULL;
1571 if (window->details->determine_view_file != NULL) {
1572 nautilus_file_cancel_call_when_ready
1573 (window->details->determine_view_file,
1574 got_file_info_for_view_selection_callback, window);
1575 window->details->determine_view_file = NULL;
1578 if (window->new_content_view != NULL) {
1579 disconnect_view (window, window->new_content_view);
1580 g_object_unref (window->new_content_view);
1581 window->new_content_view = NULL;
1585 static void
1586 cancel_location_change (NautilusWindow *window)
1588 GList *selection;
1590 if (window->details->pending_location != NULL
1591 && window->details->location != NULL
1592 && window->content_view != NULL) {
1594 /* No need to tell the new view - either it is the
1595 * same as the old view, in which case it will already
1596 * be told, or it is the very pending change we wish
1597 * to cancel.
1599 selection = nautilus_view_get_selection (window->content_view);
1600 load_new_location (window,
1601 window->details->location,
1602 selection,
1603 TRUE,
1604 FALSE);
1605 eel_g_object_list_free (selection);
1608 end_location_change (window);
1611 void
1612 nautilus_window_report_view_failed (NautilusWindow *window,
1613 NautilusView *view)
1615 gboolean do_close_window;
1616 GFile *fallback_load_location;
1617 g_warning ("A view failed. The UI will handle this with a dialog but this should be debugged.");
1620 do_close_window = FALSE;
1621 fallback_load_location = NULL;
1623 if (view == window->content_view) {
1624 disconnect_view (window, window->content_view);
1625 nautilus_window_set_content_view_widget (window, NULL);
1627 report_current_content_view_failure_to_user (window, view);
1628 } else {
1629 /* Only report error on first try */
1630 if (window->details->location_change_type != NAUTILUS_LOCATION_CHANGE_FALLBACK) {
1631 report_nascent_content_view_failure_to_user (window, view);
1633 fallback_load_location = g_object_ref (window->details->pending_location);
1634 } else {
1635 if (!GTK_WIDGET_VISIBLE (window)) {
1636 do_close_window = TRUE;
1641 cancel_location_change (window);
1643 if (fallback_load_location != NULL) {
1644 /* We loose the pending selection change here, but who cares... */
1645 begin_location_change (window, fallback_load_location, NULL,
1646 NAUTILUS_LOCATION_CHANGE_FALLBACK, 0, NULL);
1647 g_object_unref (fallback_load_location);
1650 if (do_close_window) {
1651 gtk_widget_destroy (GTK_WIDGET (window));
1655 static void
1656 display_view_selection_failure (NautilusWindow *window, NautilusFile *file,
1657 GFile *location, GError *error)
1659 char *full_uri_for_display;
1660 char *uri_for_display;
1661 char *error_message;
1662 char *detail_message;
1663 char *scheme_string;
1664 GtkDialog *dialog;
1666 /* Some sort of failure occurred. How 'bout we tell the user? */
1667 full_uri_for_display = g_file_get_parse_name (location);
1668 /* Truncate the URI so it doesn't get insanely wide. Note that even
1669 * though the dialog uses wrapped text, if the URI doesn't contain
1670 * white space then the text-wrapping code is too stupid to wrap it.
1672 uri_for_display = eel_str_middle_truncate
1673 (full_uri_for_display, MAX_URI_IN_DIALOG_LENGTH);
1674 g_free (full_uri_for_display);
1676 error_message = NULL;
1677 detail_message = NULL;
1678 if (error == NULL) {
1679 if (nautilus_file_is_directory (file)) {
1680 error_message = g_strdup_printf
1681 (_("Could not display \"%s\"."),
1682 uri_for_display);
1683 detail_message = g_strdup
1684 (_("Nautilus has no installed viewer capable of displaying the folder."));
1685 } else {
1686 error_message = g_strdup_printf
1687 (_("Could not display \"%s\"."),
1688 uri_for_display);
1689 detail_message = g_strdup
1690 (_("The location is not a folder."));
1692 } else if (error->domain == G_IO_ERROR) {
1693 switch (error->code) {
1694 case G_IO_ERROR_NOT_FOUND:
1695 error_message = g_strdup_printf
1696 (_("Could not find \"%s\"."),
1697 uri_for_display);
1698 detail_message = g_strdup
1699 (_("Please check the spelling and try again."));
1700 break;
1701 case G_IO_ERROR_NOT_SUPPORTED:
1702 scheme_string = g_file_get_uri_scheme (location);
1704 error_message = g_strdup_printf (_("Could not display \"%s\"."),
1705 uri_for_display);
1706 if (scheme_string != NULL) {
1707 detail_message = g_strdup_printf (_("Nautilus cannot handle \"%s\" locations."),
1708 scheme_string);
1709 } else {
1710 detail_message = g_strdup (_("Nautilus cannot handle this kind of locations."));
1712 g_free (scheme_string);
1713 break;
1714 case G_IO_ERROR_NOT_MOUNTED:
1715 error_message = g_strdup_printf (_("Could not display \"%s\"."),
1716 uri_for_display);
1717 detail_message = g_strdup (_("Unable to mount the location."));
1718 break;
1720 case G_IO_ERROR_PERMISSION_DENIED:
1721 error_message = g_strdup_printf (_("Could not display \"%s\"."),
1722 uri_for_display);
1723 detail_message = g_strdup (_("Access was denied."));
1724 break;
1726 case G_IO_ERROR_HOST_NOT_FOUND:
1727 /* This case can be hit for user-typed strings like "foo" due to
1728 * the code that guesses web addresses when there's no initial "/".
1729 * But this case is also hit for legitimate web addresses when
1730 * the proxy is set up wrong.
1732 error_message = g_strdup_printf (_("Could not display \"%s\", because the host could not be found."),
1733 uri_for_display);
1734 detail_message = g_strdup (_("Check that the spelling is correct and that your proxy settings are correct."));
1735 break;
1736 case G_IO_ERROR_CANCELLED:
1737 g_free (uri_for_display);
1738 return;
1740 default:
1741 break;
1745 if (error_message == NULL) {
1746 error_message = g_strdup_printf (_("Could not display \"%s\"."),
1747 uri_for_display);
1748 detail_message = g_strdup_printf (_("Error: %s\nPlease select another viewer and try again."), error->message);
1751 dialog = eel_show_error_dialog (error_message, detail_message, NULL);
1753 g_free (uri_for_display);
1754 g_free (error_message);
1755 g_free (detail_message);
1759 void
1760 nautilus_window_stop_loading (NautilusWindow *window)
1762 nautilus_view_stop_loading (window->content_view);
1764 if (window->new_content_view != NULL) {
1765 nautilus_view_stop_loading (window->new_content_view);
1768 cancel_location_change (window);
1771 void
1772 nautilus_window_set_content_view (NautilusWindow *window,
1773 const char *id)
1775 NautilusFile *file;
1776 char *location;
1778 g_return_if_fail (NAUTILUS_IS_WINDOW (window));
1779 g_return_if_fail (window->details->location != NULL);
1780 g_return_if_fail (id != NULL);
1782 location = nautilus_window_get_location_uri (window);
1783 nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_USER,
1784 "change view of window %p: \"%s\" to \"%s\"",
1785 window, location, id);
1786 g_free (location);
1788 if (nautilus_window_content_view_matches_iid (window, id)) {
1789 return;
1792 end_location_change (window);
1794 file = nautilus_file_get (window->details->location);
1795 nautilus_file_set_metadata
1796 (file, NAUTILUS_METADATA_KEY_DEFAULT_COMPONENT, NULL, id);
1797 nautilus_file_unref (file);
1799 nautilus_window_allow_stop (window, TRUE);
1801 if (nautilus_view_get_selection_count (window->content_view) == 0) {
1802 /* If there is no selection, queue a scroll to the same icon that
1803 * is currently visible */
1804 window->details->pending_scroll_to = nautilus_view_get_first_visible_file (window->content_view);
1806 window->details->location_change_type = NAUTILUS_LOCATION_CHANGE_RELOAD;
1808 create_content_view (window, id);
1811 static void
1812 zoom_level_changed_callback (NautilusView *view,
1813 NautilusWindow *window)
1815 GtkAction *action;
1816 gboolean supports_zooming;
1818 g_assert (NAUTILUS_IS_WINDOW (window));
1820 /* This is called each time the component successfully completed
1821 * a zooming operation.
1824 supports_zooming = nautilus_view_supports_zooming (view);
1826 action = gtk_action_group_get_action (window->details->main_action_group,
1827 NAUTILUS_ACTION_ZOOM_IN);
1828 gtk_action_set_visible (action, supports_zooming);
1829 gtk_action_set_sensitive (action,
1830 nautilus_view_can_zoom_in (view));
1832 action = gtk_action_group_get_action (window->details->main_action_group,
1833 NAUTILUS_ACTION_ZOOM_OUT);
1834 gtk_action_set_visible (action, supports_zooming);
1835 gtk_action_set_sensitive (action,
1836 nautilus_view_can_zoom_out (view));
1838 action = gtk_action_group_get_action (window->details->main_action_group,
1839 NAUTILUS_ACTION_ZOOM_NORMAL);
1840 gtk_action_set_visible (action, supports_zooming);
1841 gtk_action_set_sensitive (action, supports_zooming);
1844 static void
1845 zoom_parameters_changed_callback (NautilusView *view,
1846 NautilusWindow *window)
1848 float zoom_level;
1849 GtkAction *action;
1851 g_assert (NAUTILUS_IS_WINDOW (window));
1853 /* The initial zoom level of a component is allowed to be 0.0 if
1854 * there is no file loaded yet. In this case we need to set the
1855 * commands insensitive but display the zoom control nevertheless
1856 * (the component is just temporarily unable to zoom, but the
1857 * zoom control will "do the right thing" here).
1859 zoom_level = nautilus_view_get_zoom_level (view);
1860 if (zoom_level == 0.0) {
1861 action = gtk_action_group_get_action (window->details->main_action_group,
1862 NAUTILUS_ACTION_ZOOM_IN);
1863 gtk_action_set_sensitive (action, FALSE);
1864 action = gtk_action_group_get_action (window->details->main_action_group,
1865 NAUTILUS_ACTION_ZOOM_OUT);
1866 gtk_action_set_sensitive (action, FALSE);
1867 action = gtk_action_group_get_action (window->details->main_action_group,
1868 NAUTILUS_ACTION_ZOOM_NORMAL);
1869 gtk_action_set_sensitive (action, FALSE);
1871 /* Don't attempt to set 0.0 as zoom level. */
1872 return;
1875 /* "zoom_parameters_changed" always implies "zoom_level_changed",
1876 * but you won't get both signals, so we need to pass it down.
1878 zoom_level_changed_callback (view, window);
1881 static void
1882 title_changed_callback (NautilusView *view,
1883 NautilusWindow *window)
1885 g_assert (NAUTILUS_IS_WINDOW (window));
1887 nautilus_window_update_title (window);
1888 nautilus_window_update_icon (window);
1891 static void
1892 connect_view (NautilusWindow *window,
1893 NautilusView *view)
1895 g_signal_connect (view, "title_changed",
1896 G_CALLBACK (title_changed_callback), window);
1897 g_signal_connect (view, "zoom_level_changed",
1898 G_CALLBACK (zoom_level_changed_callback), window);
1899 g_signal_connect (view, "zoom_parameters_changed",
1900 G_CALLBACK (zoom_parameters_changed_callback), window);
1903 static void
1904 disconnect_view (NautilusWindow *window,
1905 NautilusView *view)
1907 if (view == NULL) {
1908 return;
1911 g_signal_handlers_disconnect_by_func (view, title_changed_callback, window);
1912 g_signal_handlers_disconnect_by_func (view, zoom_level_changed_callback, window);
1913 g_signal_handlers_disconnect_by_func (view, zoom_parameters_changed_callback, window);
1916 void
1917 nautilus_window_manage_views_destroy (NautilusWindow *window)
1919 /* Disconnect view signals here so they don't trigger when
1920 * views are destroyed.
1923 if (window->content_view != NULL) {
1924 disconnect_view (window, window->content_view);
1926 if (window->new_content_view != NULL) {
1927 disconnect_view (window, window->new_content_view);
1931 void
1932 nautilus_window_manage_views_finalize (NautilusWindow *window)
1934 free_location_change (window);
1935 cancel_viewed_file_changed_callback (window);
1938 void
1939 nautilus_navigation_window_back_or_forward (NautilusNavigationWindow *window,
1940 gboolean back, guint distance)
1942 GList *list;
1943 GFile *location;
1944 char *scroll_pos;
1945 guint len;
1946 NautilusBookmark *bookmark;
1948 list = back ? window->back_list : window->forward_list;
1950 len = (guint) g_list_length (list);
1952 /* If we can't move in the direction at all, just return. */
1953 if (len == 0)
1954 return;
1956 /* If the distance to move is off the end of the list, go to the end
1957 of the list. */
1958 if (distance >= len)
1959 distance = len - 1;
1961 bookmark = g_list_nth_data (list, distance);
1962 location = nautilus_bookmark_get_location (bookmark);
1963 scroll_pos = nautilus_bookmark_get_scroll_pos (bookmark);
1964 begin_location_change
1965 (NAUTILUS_WINDOW (window),
1966 location, NULL,
1967 back ? NAUTILUS_LOCATION_CHANGE_BACK : NAUTILUS_LOCATION_CHANGE_FORWARD,
1968 distance,
1969 scroll_pos);
1971 g_object_unref (location);
1972 g_free (scroll_pos);
1975 /* reload the contents of the window */
1976 void
1977 nautilus_window_reload (NautilusWindow *window)
1979 GFile *location;
1980 char *current_pos;
1981 GList *selection;
1983 g_return_if_fail (NAUTILUS_IS_WINDOW (window));
1985 if (window->details->location == NULL) {
1986 return;
1989 /* window->details->location can be free'd during the processing
1990 * of begin_location_change, so make a copy
1992 location = g_object_ref (window->details->location);
1993 current_pos = NULL;
1994 selection = NULL;
1995 if (window->content_view != NULL) {
1996 current_pos = nautilus_view_get_first_visible_file (window->content_view);
1997 selection = nautilus_view_get_selection (window->content_view);
1999 begin_location_change
2000 (window, location, selection,
2001 NAUTILUS_LOCATION_CHANGE_RELOAD, 0, current_pos);
2002 g_free (current_pos);
2003 g_object_unref (location);
2004 eel_g_object_list_free (selection);
2007 static void
2008 remove_all (GtkWidget *widget,
2009 gpointer data)
2011 GtkContainer *container;
2012 container = GTK_CONTAINER (data);
2014 gtk_container_remove (container, widget);
2017 static void
2018 remove_extra_location_widgets (NautilusWindow *window)
2020 gtk_container_foreach (GTK_CONTAINER (window->details->extra_location_widgets),
2021 remove_all,
2022 window->details->extra_location_widgets);
2025 void
2026 nautilus_window_add_extra_location_widget (NautilusWindow *window,
2027 GtkWidget *widget)
2029 gtk_box_pack_start (GTK_BOX (window->details->extra_location_widgets),
2030 widget, TRUE, TRUE, 0);
2033 static void
2034 update_extra_location_widgets_visibility (NautilusWindow *window)
2036 GList *children;
2038 children = gtk_container_get_children (GTK_CONTAINER (window->details->extra_location_widgets));
2040 if (children != NULL) {
2041 gtk_widget_show (window->details->extra_location_widgets);
2042 } else {
2043 gtk_widget_hide (window->details->extra_location_widgets);
2045 g_list_free (children);