1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3 /*
4 * Caja
5 *
6 * Copyright (C) 1999, 2000 Red Hat, Inc.
7 * Copyright (C) 1999, 2000, 2001 Eazel, Inc.
8 *
9 * Caja 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.
13 *
14 * Caja 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.
18 *
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
22 *
23 * Authors: Elliot Lee <sopwith@redhat.com>
24 * John Sullivan <sullivan@eazel.com>
25 * Darin Adler <darin@bentspoon.com>
26 */
27
28 #include <config.h>
29
30 #include <gtk/gtk.h>
31 #include <gdk/gdkx.h>
32 #include <glib/gi18n.h>
33
34 #include <eel/eel-accessibility.h>
35 #include <eel/eel-debug.h>
36 #include <eel/eel-gdk-extensions.h>
37 #include <eel/eel-glib-extensions.h>
38 #include <eel/eel-gtk-extensions.h>
39 #include <eel/eel-gtk-macros.h>
40 #include <eel/eel-stock-dialogs.h>
41 #include <eel/eel-string.h>
42 #include <eel/eel-vfs-extensions.h>
43
44 #include <libcaja-private/caja-debug-log.h>
45 #include <libcaja-private/caja-extensions.h>
46 #include <libcaja-private/caja-file-attributes.h>
47 #include <libcaja-private/caja-file-utilities.h>
48 #include <libcaja-private/caja-file.h>
49 #include <libcaja-private/caja-global-preferences.h>
50 #include <libcaja-private/caja-metadata.h>
51 #include <libcaja-private/caja-mime-actions.h>
52 #include <libcaja-private/caja-module.h>
53 #include <libcaja-private/caja-monitor.h>
54 #include <libcaja-private/caja-search-directory.h>
55 #include <libcaja-private/caja-view-factory.h>
56 #include <libcaja-private/caja-window-info.h>
57 #include <libcaja-private/caja-window-slot-info.h>
58 #include <libcaja-private/caja-autorun.h>
59
60 #include <libcaja-extension/caja-location-widget-provider.h>
61
62 #include "caja-window-manage-views.h"
63 #include "caja-actions.h"
64 #include "caja-application.h"
65 #include "caja-location-bar.h"
66 #include "caja-search-bar.h"
67 #include "caja-pathbar.h"
68 #include "caja-window-private.h"
69 #include "caja-window-slot.h"
70 #include "caja-navigation-window-slot.h"
71 #include "caja-trash-bar.h"
72 #include "caja-x-content-bar.h"
73 #include "caja-navigation-window-pane.h"
74
75 /* FIXME bugzilla.gnome.org 41243:
76 * We should use inheritance instead of these special cases
77 * for the desktop window.
78 */
79 #include "caja-desktop-window.h"
80
81 /* This number controls a maximum character count for a URL that is
82 * displayed as part of a dialog. It's fairly arbitrary -- big enough
83 * to allow most "normal" URIs to display in full, but small enough to
84 * prevent the dialog from getting insanely wide.
85 */
86 #define MAX_URI_IN_DIALOG_LENGTH 60
87
88 static void begin_location_change (CajaWindowSlot *slot,
89 GFile *location,
90 GFile *previous_location,
91 GList *new_selection,
92 CajaLocationChangeType type,
93 guint distance,
94 const char *scroll_pos,
95 CajaWindowGoToCallback callback,
96 gpointer user_data);
97 static void free_location_change (CajaWindowSlot *slot);
98 static void end_location_change (CajaWindowSlot *slot);
99 static void cancel_location_change (CajaWindowSlot *slot);
100 static void got_file_info_for_view_selection_callback (CajaFile *file,
101 gpointer callback_data);
102 static void create_content_view (CajaWindowSlot *slot,
103 const char *view_id);
104 static void display_view_selection_failure (CajaWindow *window,
105 CajaFile *file,
106 GFile *location,
107 GError *error);
108 static void load_new_location (CajaWindowSlot *slot,
109 GFile *location,
110 GList *selection,
111 gboolean tell_current_content_view,
112 gboolean tell_new_content_view);
113 static void location_has_really_changed (CajaWindowSlot *slot);
114 static void update_for_new_location (CajaWindowSlot *slot);
115
116 void
caja_window_report_selection_changed(CajaWindowInfo * window)117 caja_window_report_selection_changed (CajaWindowInfo *window)
118 {
119 if (window->details->temporarily_ignore_view_signals)
120 {
121 return;
122 }
123
124 g_signal_emit_by_name (window, "selection_changed");
125 }
126
127 /* set_displayed_location:
128 */
129 static void
set_displayed_location(CajaWindowSlot * slot,GFile * location)130 set_displayed_location (CajaWindowSlot *slot, GFile *location)
131 {
132 gboolean recreate;
133
134 if (slot->current_location_bookmark == NULL || location == NULL)
135 {
136 recreate = TRUE;
137 }
138 else
139 {
140 GFile *bookmark_location;
141
142 bookmark_location = caja_bookmark_get_location (slot->current_location_bookmark);
143 recreate = !g_file_equal (bookmark_location, location);
144 g_object_unref (bookmark_location);
145 }
146
147 if (recreate)
148 {
149 char *name;
150
151 /* We've changed locations, must recreate bookmark for current location. */
152 if (slot->last_location_bookmark != NULL)
153 {
154 g_object_unref (slot->last_location_bookmark);
155 }
156 slot->last_location_bookmark = slot->current_location_bookmark;
157 name = g_file_get_basename (location);
158 slot->current_location_bookmark = (location == NULL) ? NULL
159 : caja_bookmark_new (location, name, FALSE, NULL);
160 g_free (name);
161 }
162 }
163
164 static void
check_bookmark_location_matches(CajaBookmark * bookmark,GFile * location)165 check_bookmark_location_matches (CajaBookmark *bookmark, GFile *location)
166 {
167 GFile *bookmark_location;
168
169 bookmark_location = caja_bookmark_get_location (bookmark);
170 if (!g_file_equal (location, bookmark_location))
171 {
172 char *bookmark_uri, *uri;
173
174 bookmark_uri = g_file_get_uri (bookmark_location);
175 uri = g_file_get_uri (location);
176 g_warning ("bookmark uri is %s, but expected %s", bookmark_uri, uri);
177 g_free (uri);
178 g_free (bookmark_uri);
179 }
180 g_object_unref (bookmark_location);
181 }
182
183 /* Debugging function used to verify that the last_location_bookmark
184 * is in the state we expect when we're about to use it to update the
185 * Back or Forward list.
186 */
187 static void
check_last_bookmark_location_matches_slot(CajaWindowSlot * slot)188 check_last_bookmark_location_matches_slot (CajaWindowSlot *slot)
189 {
190 check_bookmark_location_matches (slot->last_location_bookmark,
191 slot->location);
192 }
193
194 static void
handle_go_back(CajaNavigationWindowSlot * navigation_slot,GFile * location)195 handle_go_back (CajaNavigationWindowSlot *navigation_slot,
196 GFile *location)
197 {
198 CajaWindowSlot *slot;
199 guint i;
200 GList *link;
201 CajaBookmark *bookmark = NULL;
202
203 slot = CAJA_WINDOW_SLOT (navigation_slot);
204
205 /* Going back. Move items from the back list to the forward list. */
206 g_assert (g_list_length (navigation_slot->back_list) > slot->location_change_distance);
207 check_bookmark_location_matches (CAJA_BOOKMARK (g_list_nth_data (navigation_slot->back_list,
208 slot->location_change_distance)),
209 location);
210 g_assert (slot->location != NULL);
211
212 /* Move current location to Forward list */
213
214 check_last_bookmark_location_matches_slot (slot);
215
216 /* Use the first bookmark in the history list rather than creating a new one. */
217 navigation_slot->forward_list = g_list_prepend (navigation_slot->forward_list,
218 slot->last_location_bookmark);
219 g_object_ref (navigation_slot->forward_list->data);
220
221 /* Move extra links from Back to Forward list */
222 for (i = 0; i < slot->location_change_distance; ++i)
223 {
224 bookmark = CAJA_BOOKMARK (navigation_slot->back_list->data);
225 navigation_slot->back_list =
226 g_list_remove (navigation_slot->back_list, bookmark);
227 navigation_slot->forward_list =
228 g_list_prepend (navigation_slot->forward_list, bookmark);
229 }
230
231 /* One bookmark falls out of back/forward lists and becomes viewed location */
232 link = navigation_slot->back_list;
233 navigation_slot->back_list = g_list_remove_link (navigation_slot->back_list, link);
234 g_object_unref (link->data);
235 g_list_free_1 (link);
236 }
237
238 static void
handle_go_forward(CajaNavigationWindowSlot * navigation_slot,GFile * location)239 handle_go_forward (CajaNavigationWindowSlot *navigation_slot,
240 GFile *location)
241 {
242 CajaWindowSlot *slot;
243 guint i;
244 GList *link;
245 CajaBookmark *bookmark = NULL;
246
247 slot = CAJA_WINDOW_SLOT (navigation_slot);
248
249 /* Going forward. Move items from the forward list to the back list. */
250 g_assert (g_list_length (navigation_slot->forward_list) > slot->location_change_distance);
251 check_bookmark_location_matches (CAJA_BOOKMARK (g_list_nth_data (navigation_slot->forward_list,
252 slot->location_change_distance)),
253 location);
254 g_assert (slot->location != NULL);
255
256 /* Move current location to Back list */
257 check_last_bookmark_location_matches_slot (slot);
258
259 /* Use the first bookmark in the history list rather than creating a new one. */
260 navigation_slot->back_list = g_list_prepend (navigation_slot->back_list,
261 slot->last_location_bookmark);
262 g_object_ref (navigation_slot->back_list->data);
263
264 /* Move extra links from Forward to Back list */
265 for (i = 0; i < slot->location_change_distance; ++i)
266 {
267 bookmark = CAJA_BOOKMARK (navigation_slot->forward_list->data);
268 navigation_slot->forward_list =
269 g_list_remove (navigation_slot->back_list, bookmark);
270 navigation_slot->back_list =
271 g_list_prepend (navigation_slot->forward_list, bookmark);
272 }
273
274 /* One bookmark falls out of back/forward lists and becomes viewed location */
275 link = navigation_slot->forward_list;
276 navigation_slot->forward_list = g_list_remove_link (navigation_slot->forward_list, link);
277 g_object_unref (link->data);
278 g_list_free_1 (link);
279 }
280
281 static void
handle_go_elsewhere(CajaWindowSlot * slot,GFile * location)282 handle_go_elsewhere (CajaWindowSlot *slot, GFile *location)
283 {
284 if (CAJA_IS_NAVIGATION_WINDOW_SLOT (slot))
285 {
286 CajaNavigationWindowSlot *navigation_slot;
287
288 navigation_slot = CAJA_NAVIGATION_WINDOW_SLOT (slot);
289
290 /* Clobber the entire forward list, and move displayed location to back list */
291 caja_navigation_window_slot_clear_forward_list (navigation_slot);
292
293 if (slot->location != NULL)
294 {
295 /* If we're returning to the same uri somehow, don't put this uri on back list.
296 * This also avoids a problem where set_displayed_location
297 * didn't update last_location_bookmark since the uri didn't change.
298 */
299 if (!g_file_equal (slot->location, location))
300 {
301 /* Store bookmark for current location in back list, unless there is no current location */
302 check_last_bookmark_location_matches_slot (slot);
303 /* Use the first bookmark in the history list rather than creating a new one. */
304 navigation_slot->back_list = g_list_prepend (navigation_slot->back_list,
305 slot->last_location_bookmark);
306 g_object_ref (navigation_slot->back_list->data);
307 }
308 }
309 }
310 }
311
312 void
caja_window_update_up_button(CajaWindow * window)313 caja_window_update_up_button (CajaWindow *window)
314 {
315 CajaWindowSlot *slot;
316 gboolean allowed;
317 GFile *parent;
318
319 slot = window->details->active_pane->active_slot;
320
321 allowed = FALSE;
322 if (slot->location != NULL)
323 {
324 parent = g_file_get_parent (slot->location);
325 allowed = parent != NULL;
326 if (parent != NULL)
327 {
328 g_object_unref (parent);
329 }
330 }
331
332 caja_window_allow_up (window, allowed);
333 }
334
335 static void
viewed_file_changed_callback(CajaFile * file,CajaWindowSlot * slot)336 viewed_file_changed_callback (CajaFile *file,
337 CajaWindowSlot *slot)
338 {
339 CajaWindow *window;
340 GFile *new_location;
341 gboolean is_in_trash, was_in_trash;
342
343 window = slot->pane->window;
344
345 g_assert (CAJA_IS_FILE (file));
346 g_assert (CAJA_IS_WINDOW_PANE (slot->pane));
347 g_assert (CAJA_IS_WINDOW (window));
348
349 g_assert (file == slot->viewed_file);
350
351 if (!caja_file_is_not_yet_confirmed (file))
352 {
353 slot->viewed_file_seen = TRUE;
354 }
355
356 was_in_trash = slot->viewed_file_in_trash;
357
358 slot->viewed_file_in_trash = is_in_trash = caja_file_is_in_trash (file);
359
360 /* Close window if the file it's viewing has been deleted or moved to trash. */
361 if (caja_file_is_gone (file) || (is_in_trash && !was_in_trash))
362 {
363 /* Don't close the window in the case where the
364 * file was never seen in the first place.
365 */
366 if (slot->viewed_file_seen)
367 {
368 /* Detecting a file is gone may happen in the
369 * middle of a pending location change, we
370 * need to cancel it before closing the window
371 * or things break.
372 */
373 /* FIXME: It makes no sense that this call is
374 * needed. When the window is destroyed, it
375 * calls caja_window_manage_views_destroy,
376 * which calls free_location_change, which
377 * should be sufficient. Also, if this was
378 * really needed, wouldn't it be needed for
379 * all other caja_window_close callers?
380 */
381 end_location_change (slot);
382
383 if (CAJA_IS_NAVIGATION_WINDOW (window))
384 {
385 /* auto-show existing parent. */
386 GFile *go_to_file, *parent, *location;
387
388 go_to_file = NULL;
389 location = caja_file_get_location (file);
390 parent = g_file_get_parent (location);
391 g_object_unref (location);
392 if (parent)
393 {
394 go_to_file = caja_find_existing_uri_in_hierarchy (parent);
395 g_object_unref (parent);
396 }
397
398 if (go_to_file != NULL)
399 {
400 /* the path bar URI will be set to go_to_uri immediately
401 * in begin_location_change, but we don't want the
402 * inexistant children to show up anymore */
403 if (slot == slot->pane->active_slot)
404 {
405 /* multiview-TODO also update CajaWindowSlot
406 * [which as of writing doesn't save/store any path bar state]
407 */
408 caja_path_bar_clear_buttons (CAJA_PATH_BAR (CAJA_NAVIGATION_WINDOW_PANE (slot->pane)->path_bar));
409 }
410
411 caja_window_slot_go_to (slot, go_to_file, FALSE);
412 g_object_unref (go_to_file);
413 }
414 else
415 {
416 caja_window_slot_go_home (slot, FALSE);
417 }
418 }
419 else
420 {
421 caja_window_close (window);
422 }
423 }
424 }
425 else
426 {
427 new_location = caja_file_get_location (file);
428
429 /* If the file was renamed, update location and/or
430 * title. */
431 if (!g_file_equal (new_location,
432 slot->location))
433 {
434 g_object_unref (slot->location);
435 slot->location = new_location;
436 if (slot == slot->pane->active_slot)
437 {
438 caja_window_pane_sync_location_widgets (slot->pane);
439 }
440 }
441 else
442 {
443 /* TODO?
444 * why do we update title & icon at all in this case? */
445 g_object_unref (new_location);
446 }
447
448 caja_window_slot_update_title (slot);
449 caja_window_slot_update_icon (slot);
450 }
451 }
452
453 static void
update_history(CajaWindowSlot * slot,CajaLocationChangeType type,GFile * new_location)454 update_history (CajaWindowSlot *slot,
455 CajaLocationChangeType type,
456 GFile *new_location)
457 {
458 switch (type)
459 {
460 case CAJA_LOCATION_CHANGE_STANDARD:
461 case CAJA_LOCATION_CHANGE_FALLBACK:
462 caja_window_slot_add_current_location_to_history_list (slot);
463 handle_go_elsewhere (slot, new_location);
464 return;
465 case CAJA_LOCATION_CHANGE_RELOAD:
466 /* for reload there is no work to do */
467 return;
468 case CAJA_LOCATION_CHANGE_BACK:
469 caja_window_slot_add_current_location_to_history_list (slot);
470 handle_go_back (CAJA_NAVIGATION_WINDOW_SLOT (slot), new_location);
471 return;
472 case CAJA_LOCATION_CHANGE_FORWARD:
473 caja_window_slot_add_current_location_to_history_list (slot);
474 handle_go_forward (CAJA_NAVIGATION_WINDOW_SLOT (slot), new_location);
475 return;
476 case CAJA_LOCATION_CHANGE_REDIRECT:
477 /* for the redirect case, the caller can do the updating */
478 return;
479 }
480 g_return_if_fail (FALSE);
481 }
482
483 static void
cancel_viewed_file_changed_callback(CajaWindowSlot * slot)484 cancel_viewed_file_changed_callback (CajaWindowSlot *slot)
485 {
486 CajaFile *file;
487
488 file = slot->viewed_file;
489 if (file != NULL)
490 {
491 g_signal_handlers_disconnect_by_func (G_OBJECT (file),
492 G_CALLBACK (viewed_file_changed_callback),
493 slot);
494 caja_file_monitor_remove (file, &slot->viewed_file);
495 }
496 }
497
498 static void
new_window_show_callback(GtkWidget * widget,gpointer user_data)499 new_window_show_callback (GtkWidget *widget,
500 gpointer user_data)
501 {
502 CajaWindow *window;
503
504 window = CAJA_WINDOW (user_data);
505
506 caja_window_close (window);
507
508 g_signal_handlers_disconnect_by_func (widget,
509 G_CALLBACK (new_window_show_callback),
510 user_data);
511 }
512
513
514 void
caja_window_slot_open_location_full(CajaWindowSlot * slot,GFile * location,CajaWindowOpenMode mode,CajaWindowOpenFlags flags,GList * new_selection,CajaWindowGoToCallback callback,gpointer user_data)515 caja_window_slot_open_location_full (CajaWindowSlot *slot,
516 GFile *location,
517 CajaWindowOpenMode mode,
518 CajaWindowOpenFlags flags,
519 GList *new_selection,
520 CajaWindowGoToCallback callback,
521 gpointer user_data)
522 {
523 CajaWindow *window;
524 CajaWindow *target_window;
525 CajaWindowPane *pane;
526 CajaWindowSlot *target_slot;
527 CajaWindowOpenFlags slot_flags;
528 gboolean existing = FALSE;
529 GFile *old_location;
530 char *old_uri, *new_uri;
531 GList *l;
532 gboolean target_navigation = FALSE;
533 gboolean target_same = FALSE;
534 gboolean is_desktop = FALSE;
535 gboolean is_navigation = FALSE;
536
537 window = slot->pane->window;
538
539 target_window = NULL;
540 target_slot = NULL;
541
542 old_uri = caja_window_slot_get_location_uri (slot);
543 if (old_uri == NULL)
544 {
545 old_uri = g_strdup ("(none)");
546 }
547 new_uri = g_file_get_uri (location);
548 caja_debug_log (FALSE, CAJA_DEBUG_LOG_DOMAIN_USER,
549 "window %p open location: old=\"%s\", new=\"%s\"",
550 window,
551 old_uri,
552 new_uri);
553 g_free (old_uri);
554 g_free (new_uri);
555
556 g_assert (!((flags & CAJA_WINDOW_OPEN_FLAG_NEW_WINDOW) != 0 &&
557 (flags & CAJA_WINDOW_OPEN_FLAG_NEW_TAB) != 0));
558
559 is_desktop = CAJA_IS_DESKTOP_WINDOW (window);
560 is_navigation = CAJA_IS_NAVIGATION_WINDOW (window);
561 target_same = is_desktop &&
562 !caja_desktop_window_loaded (CAJA_DESKTOP_WINDOW (window));
563
564 old_location = caja_window_slot_get_location (slot);
565
566 switch (mode)
567 {
568 case CAJA_WINDOW_OPEN_ACCORDING_TO_MODE :
569 if (g_settings_get_boolean (caja_preferences, CAJA_PREFERENCES_ALWAYS_USE_BROWSER)) {
570 /* always use browser: if we're on the desktop the target is a new navigation window,
571 * otherwise it's the same window.
572 */
573 if (is_desktop) {
574 new_uri = g_file_get_uri (location);
575 if (g_str_has_prefix (new_uri, EEL_DESKTOP_URI))
576 target_same = TRUE;
577 else
578 target_navigation = TRUE;
579 g_free (new_uri);
580 } else {
581 target_same = TRUE;
582 }
583 } else if (flags & CAJA_WINDOW_OPEN_FLAG_NEW_WINDOW) {
584 /* if it's specified to open a new window, and we're not using spatial,
585 * the target is a navigation.
586 */
587 target_navigation = TRUE;
588 } else if (is_navigation) {
589 target_same = TRUE;
590 }
591 break;
592 case CAJA_WINDOW_OPEN_IN_NAVIGATION :
593 target_navigation = TRUE;
594 break;
595 default :
596 g_critical ("Unknown open location mode");
597 g_object_unref (old_location);
598 return;
599 }
600
601 /* now get/create the window according to the mode */
602 if (target_same) {
603 target_window = window;
604 } else if (target_navigation) {
605 target_window = caja_application_create_navigation_window
606 (window->application,
607 gtk_window_get_screen (GTK_WINDOW (window)));
608 } else {
609 target_window = caja_application_get_spatial_window
610 (window->application,
611 window,
612 NULL,
613 location,
614 gtk_window_get_screen (GTK_WINDOW (window)),
615 &existing);
616 }
617
618 /* if the spatial window is already showing, present it and set the
619 * new selection, if present.
620 */
621 if (existing) {
622 target_slot = target_window->details->active_pane->active_slot;
623
624 gtk_window_present (GTK_WINDOW (target_window));
625
626 if (new_selection != NULL && slot->content_view != NULL) {
627 caja_view_set_selection (target_slot->content_view, new_selection);
628 }
629
630 /* call the callback successfully */
631 if (callback != NULL) {
632 callback (window, NULL, user_data);
633 }
634
635 return;
636 }
637
638 g_assert (target_window != NULL);
639
640 if ((flags & CAJA_WINDOW_OPEN_FLAG_NEW_TAB) != 0 &&
641 CAJA_IS_NAVIGATION_WINDOW (window))
642 {
643 g_assert (target_window == window);
644
645 int new_slot_position;
646
647 slot_flags = 0;
648
649 new_slot_position = g_settings_get_enum (caja_preferences, CAJA_PREFERENCES_NEW_TAB_POSITION);
650 if (new_slot_position == CAJA_NEW_TAB_POSITION_END)
651 {
652 slot_flags = CAJA_WINDOW_OPEN_SLOT_APPEND;
653 }
654
655 target_slot = caja_window_open_slot (window->details->active_pane, slot_flags);
656 }
657
658 if ((flags & CAJA_WINDOW_OPEN_FLAG_CLOSE_BEHIND) != 0)
659 {
660 if (CAJA_IS_SPATIAL_WINDOW (window) && !CAJA_IS_DESKTOP_WINDOW (window))
661 {
662 if (gtk_widget_get_visible (GTK_WIDGET (target_window)))
663 {
664 caja_window_close (window);
665 }
666 else
667 {
668 g_signal_connect_object (target_window,
669 "show",
670 G_CALLBACK (new_window_show_callback),
671 window,
672 G_CONNECT_AFTER);
673 }
674 }
675 }
676
677 if (target_slot == NULL)
678 {
679 if (target_window == window)
680 {
681 target_slot = slot;
682 }
683 else
684 {
685 target_slot = target_window->details->active_pane->active_slot;
686 }
687 }
688
689 if (!(is_desktop && target_same) && (target_window == window && target_slot == slot &&
690 old_location && g_file_equal (old_location, location))) {
691
692 if (callback != NULL) {
693 callback (window, NULL, user_data);
694 }
695
696 g_object_unref (old_location);
697 return;
698 }
699
700 begin_location_change (target_slot, location, old_location, new_selection,
701 (is_desktop && target_same) ? CAJA_LOCATION_CHANGE_RELOAD : CAJA_LOCATION_CHANGE_STANDARD, 0, NULL, callback, user_data);
702
703 /* Additionally, load this in all slots that have no location, this means
704 we load both panes in e.g. a newly opened dual pane window. */
705 for (l = target_window->details->panes; l != NULL; l = l->next)
706 {
707 pane = l->data;
708 slot = pane->active_slot;
709 if (slot->location == NULL && slot->pending_location == NULL) {
710 begin_location_change (slot, location, old_location, new_selection,
711 CAJA_LOCATION_CHANGE_STANDARD, 0, NULL, NULL, NULL);
712 }
713 }
714
715 if (old_location)
716 {
717 g_object_unref (old_location);
718 }
719 }
720
721 void
caja_window_slot_open_location(CajaWindowSlot * slot,GFile * location,gboolean close_behind)722 caja_window_slot_open_location (CajaWindowSlot *slot,
723 GFile *location,
724 gboolean close_behind)
725 {
726 CajaWindowOpenFlags flags;
727
728 flags = 0;
729 if (close_behind)
730 {
731 flags = CAJA_WINDOW_OPEN_FLAG_CLOSE_BEHIND;
732 }
733
734 caja_window_slot_open_location_full (slot, location,
735 CAJA_WINDOW_OPEN_ACCORDING_TO_MODE,
736 flags, NULL, NULL, NULL);
737 }
738
739 void
caja_window_slot_open_location_with_selection(CajaWindowSlot * slot,GFile * location,GList * selection,gboolean close_behind)740 caja_window_slot_open_location_with_selection (CajaWindowSlot *slot,
741 GFile *location,
742 GList *selection,
743 gboolean close_behind)
744 {
745 CajaWindowOpenFlags flags;
746
747 flags = 0;
748 if (close_behind)
749 {
750 flags = CAJA_WINDOW_OPEN_FLAG_CLOSE_BEHIND;
751 }
752 caja_window_slot_open_location_full (slot, location,
753 CAJA_WINDOW_OPEN_ACCORDING_TO_MODE,
754 flags, selection, NULL, NULL);
755 }
756
757
758 void
caja_window_slot_go_home(CajaWindowSlot * slot,gboolean new_tab)759 caja_window_slot_go_home (CajaWindowSlot *slot, gboolean new_tab)
760 {
761 GFile *home;
762 CajaWindowOpenFlags flags;
763
764 g_return_if_fail (CAJA_IS_WINDOW_SLOT (slot));
765
766 if (new_tab)
767 {
768 flags = CAJA_WINDOW_OPEN_FLAG_NEW_TAB;
769 }
770 else
771 {
772 flags = 0;
773 }
774
775 home = g_file_new_for_path (g_get_home_dir ());
776 caja_window_slot_open_location_full (slot, home,
777 CAJA_WINDOW_OPEN_ACCORDING_TO_MODE,
778 flags, NULL, NULL, NULL);
779 g_object_unref (home);
780 }
781
782 static char *
caja_window_slot_get_view_error_label(CajaWindowSlot * slot)783 caja_window_slot_get_view_error_label (CajaWindowSlot *slot)
784 {
785 const CajaViewInfo *info;
786
787 info = caja_view_factory_lookup (caja_window_slot_get_content_view_id (slot));
788
789 return g_strdup (info->error_label);
790 }
791
792 static char *
caja_window_slot_get_view_startup_error_label(CajaWindowSlot * slot)793 caja_window_slot_get_view_startup_error_label (CajaWindowSlot *slot)
794 {
795 const CajaViewInfo *info;
796
797 info = caja_view_factory_lookup (caja_window_slot_get_content_view_id (slot));
798
799 return g_strdup (info->startup_error_label);
800 }
801
802 static void
report_current_content_view_failure_to_user(CajaWindowSlot * slot)803 report_current_content_view_failure_to_user (CajaWindowSlot *slot)
804 {
805 CajaWindow *window;
806 char *message;
807
808 window = slot->pane->window;
809
810 message = caja_window_slot_get_view_startup_error_label (slot);
811 eel_show_error_dialog (message,
812 _("You can choose another view or go to a different location."),
813 GTK_WINDOW (window));
814 g_free (message);
815 }
816
817 static void
report_nascent_content_view_failure_to_user(CajaWindowSlot * slot,CajaView * view)818 report_nascent_content_view_failure_to_user (CajaWindowSlot *slot,
819 CajaView *view)
820 {
821 CajaWindow *window;
822 char *message;
823
824 window = slot->pane->window;
825
826 /* TODO? why are we using the current view's error label here, instead of the next view's?
827 * This behavior has already been present in pre-slot days.
828 */
829 message = caja_window_slot_get_view_error_label (slot);
830 eel_show_error_dialog (message,
831 _("The location cannot be displayed with this viewer."),
832 GTK_WINDOW (window));
833 g_free (message);
834 }
835
836
837 const char *
caja_window_slot_get_content_view_id(CajaWindowSlot * slot)838 caja_window_slot_get_content_view_id (CajaWindowSlot *slot)
839 {
840 if (slot->content_view == NULL)
841 {
842 return NULL;
843 }
844 return caja_view_get_view_id (slot->content_view);
845 }
846
847 gboolean
caja_window_slot_content_view_matches_iid(CajaWindowSlot * slot,const char * iid)848 caja_window_slot_content_view_matches_iid (CajaWindowSlot *slot,
849 const char *iid)
850 {
851 if (slot->content_view == NULL)
852 {
853 return FALSE;
854 }
855 return g_strcmp0 (caja_view_get_view_id (slot->content_view), iid) == 0;
856 }
857
858 static gboolean
report_callback(CajaWindowSlot * slot,GError * error)859 report_callback (CajaWindowSlot *slot,
860 GError *error)
861 {
862 if (slot->open_callback != NULL) {
863 slot->open_callback (slot->pane->window, error, slot->open_callback_user_data);
864 slot->open_callback = NULL;
865 slot->open_callback_user_data = NULL;
866
867 return TRUE;
868 }
869
870 return FALSE;
871 }
872
873 static gpointer
copy_object(gconstpointer obj,gpointer user_data)874 copy_object (gconstpointer obj,
875 gpointer user_data)
876 {
877 (void) user_data;
878 return g_object_ref (G_OBJECT (obj));
879 }
880
881 /*
882 * begin_location_change
883 *
884 * Change a window's location.
885 * @window: The CajaWindow whose location should be changed.
886 * @location: A url specifying the location to load
887 * @previous_location: The url that was previously shown in the window that initialized the change, if any
888 * @new_selection: The initial selection to present after loading the location
889 * @type: Which type of location change is this? Standard, back, forward, or reload?
890 * @distance: If type is back or forward, the index into the back or forward chain. If
891 * type is standard or reload, this is ignored, and must be 0.
892 * @scroll_pos: The file to scroll to when the location is loaded.
893 * @callback: function to be called when the location is changed.
894 * @user_data: data for @callback.
895 *
896 * This is the core function for changing the location of a window. Every change to the
897 * location begins here.
898 */
899 static void
begin_location_change(CajaWindowSlot * slot,GFile * location,GFile * previous_location,GList * new_selection,CajaLocationChangeType type,guint distance,const char * scroll_pos,CajaWindowGoToCallback callback,gpointer user_data)900 begin_location_change (CajaWindowSlot *slot,
901 GFile *location,
902 GFile *previous_location,
903 GList *new_selection,
904 CajaLocationChangeType type,
905 guint distance,
906 const char *scroll_pos,
907 CajaWindowGoToCallback callback,
908 gpointer user_data)
909 {
910 CajaWindow *window;
911 CajaDirectory *directory;
912 gboolean force_reload;
913 GFile *parent;
914
915 g_assert (slot != NULL);
916 g_assert (location != NULL);
917 g_assert (type == CAJA_LOCATION_CHANGE_BACK
918 || type == CAJA_LOCATION_CHANGE_FORWARD
919 || distance == 0);
920
921 /* If there is no new selection and the new location is
922 * a (grand)parent of the old location then we automatically
923 * select the folder the previous location was in */
924 if (new_selection == NULL && previous_location != NULL &&
925 g_file_has_prefix (previous_location, location)) {
926 GFile *from_folder;
927
928 from_folder = g_object_ref (previous_location);
929 parent = g_file_get_parent (from_folder);
930 while (parent != NULL && !g_file_equal (parent, location)) {
931 g_object_unref (from_folder);
932 from_folder = parent;
933 parent = g_file_get_parent (from_folder);
934 }
935 if (parent != NULL) {
936 new_selection = g_list_prepend (NULL, g_object_ref(from_folder));
937 }
938 g_object_unref (from_folder);
939 g_object_unref (parent);
940 }
941
942 window = slot->pane->window;
943 g_assert (CAJA_IS_WINDOW (window));
944 g_object_ref (window);
945
946 end_location_change (slot);
947
948 caja_window_slot_set_allow_stop (slot, TRUE);
949 caja_window_slot_set_status (slot, " ");
950
951 g_assert (slot->pending_location == NULL);
952 g_assert (slot->pending_selection == NULL);
953
954 slot->pending_location = g_object_ref (location);
955 slot->location_change_type = type;
956 slot->location_change_distance = distance;
957 slot->tried_mount = FALSE;
958 slot->pending_selection = g_list_copy_deep (new_selection, copy_object, NULL);
959
960 slot->pending_scroll_to = g_strdup (scroll_pos);
961
962 slot->open_callback = callback;
963 slot->open_callback_user_data = user_data;
964
965 directory = caja_directory_get (location);
966
967 /* The code to force a reload is here because if we do it
968 * after determining an initial view (in the components), then
969 * we end up fetching things twice.
970 */
971 if (type == CAJA_LOCATION_CHANGE_RELOAD)
972 {
973 force_reload = TRUE;
974 }
975 else if (!caja_monitor_active ())
976 {
977 force_reload = TRUE;
978 }
979 else
980 {
981 force_reload = !caja_directory_is_local (directory);
982 }
983
984 if (force_reload)
985 {
986 CajaFile *file;
987
988 caja_directory_force_reload (directory);
989 file = caja_directory_get_corresponding_file (directory);
990 caja_file_invalidate_all_attributes (file);
991 caja_file_unref (file);
992 }
993
994 caja_directory_unref (directory);
995
996 /* Set current_bookmark scroll pos */
997 if (slot->current_location_bookmark != NULL &&
998 slot->content_view != NULL)
999 {
1000 char *current_pos;
1001
1002 current_pos = caja_view_get_first_visible_file (slot->content_view);
1003 caja_bookmark_set_scroll_pos (slot->current_location_bookmark, current_pos);
1004 g_free (current_pos);
1005 }
1006
1007 /* Get the info needed for view selection */
1008
1009 slot->determine_view_file = caja_file_get (location);
1010 g_assert (slot->determine_view_file != NULL);
1011
1012 /* if the currently viewed file is marked gone while loading the new location,
1013 * this ensures that the window isn't destroyed */
1014 cancel_viewed_file_changed_callback (slot);
1015
1016 caja_file_call_when_ready (slot->determine_view_file,
1017 CAJA_FILE_ATTRIBUTE_INFO |
1018 CAJA_FILE_ATTRIBUTE_MOUNT,
1019 got_file_info_for_view_selection_callback,
1020 slot);
1021
1022 g_object_unref (window);
1023 }
1024
1025 static void
setup_new_spatial_window(CajaWindowSlot * slot,CajaFile * file)1026 setup_new_spatial_window (CajaWindowSlot *slot, CajaFile *file)
1027 {
1028 CajaWindow *window;
1029 char *scroll_string;
1030 gboolean maximized, sticky, above;
1031
1032 window = slot->pane->window;
1033
1034 if (CAJA_IS_SPATIAL_WINDOW (window) && !CAJA_IS_DESKTOP_WINDOW (window))
1035 {
1036 char *show_hidden_file_setting;
1037 char *geometry_string;
1038
1039 /* load show hidden state */
1040 show_hidden_file_setting = caja_file_get_metadata
1041 (file, CAJA_METADATA_KEY_WINDOW_SHOW_HIDDEN_FILES,
1042 NULL);
1043 if (show_hidden_file_setting != NULL)
1044 {
1045 GtkAction *action;
1046
1047 if (strcmp (show_hidden_file_setting, "1") == 0)
1048 {
1049 window->details->show_hidden_files_mode = CAJA_WINDOW_SHOW_HIDDEN_FILES_ENABLE;
1050 }
1051 else
1052 {
1053 window->details->show_hidden_files_mode = CAJA_WINDOW_SHOW_HIDDEN_FILES_DISABLE;
1054 }
1055
1056 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1057 /* Update the UI, since we initialize it to the default */
1058 action = gtk_action_group_get_action (window->details->main_action_group, CAJA_ACTION_SHOW_HIDDEN_FILES);
1059 gtk_action_block_activate (action);
1060 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1061 window->details->show_hidden_files_mode == CAJA_WINDOW_SHOW_HIDDEN_FILES_ENABLE);
1062 gtk_action_unblock_activate (action);
1063 G_GNUC_END_IGNORE_DEPRECATIONS;
1064 }
1065 else
1066 {
1067 CAJA_WINDOW (window)->details->show_hidden_files_mode = CAJA_WINDOW_SHOW_HIDDEN_FILES_DEFAULT;
1068 }
1069 g_free (show_hidden_file_setting);
1070
1071 /* load the saved window geometry */
1072 maximized = caja_file_get_boolean_metadata
1073 (file, CAJA_METADATA_KEY_WINDOW_MAXIMIZED, FALSE);
1074 if (maximized)
1075 {
1076 gtk_window_maximize (GTK_WINDOW (window));
1077 }
1078 else
1079 {
1080 gtk_window_unmaximize (GTK_WINDOW (window));
1081 }
1082
1083 sticky = caja_file_get_boolean_metadata
1084 (file, CAJA_METADATA_KEY_WINDOW_STICKY, FALSE);
1085 if (sticky)
1086 {
1087 gtk_window_stick (GTK_WINDOW (window));
1088 }
1089 else
1090 {
1091 gtk_window_unstick (GTK_WINDOW (window));
1092 }
1093
1094 above = caja_file_get_boolean_metadata
1095 (file, CAJA_METADATA_KEY_WINDOW_KEEP_ABOVE, FALSE);
1096 if (above)
1097 {
1098 gtk_window_set_keep_above (GTK_WINDOW (window), TRUE);
1099 }
1100 else
1101 {
1102 gtk_window_set_keep_above (GTK_WINDOW (window), FALSE);
1103 }
1104
1105 geometry_string = caja_file_get_metadata
1106 (file, CAJA_METADATA_KEY_WINDOW_GEOMETRY, NULL);
1107 if (geometry_string != NULL)
1108 {
1109 eel_gtk_window_set_initial_geometry_from_string
1110 (GTK_WINDOW (window),
1111 geometry_string,
1112 CAJA_SPATIAL_WINDOW_MIN_WIDTH,
1113 CAJA_SPATIAL_WINDOW_MIN_HEIGHT,
1114 FALSE);
1115 }
1116 g_free (geometry_string);
1117
1118 if (slot->pending_selection == NULL)
1119 {
1120 /* If there is no pending selection, then load the saved scroll position. */
1121 scroll_string = caja_file_get_metadata
1122 (file, CAJA_METADATA_KEY_WINDOW_SCROLL_POSITION,
1123 NULL);
1124 }
1125 else
1126 {
1127 /* If there is a pending selection, we want to scroll to an item in
1128 * the pending selection list. */
1129 scroll_string = g_file_get_uri (slot->pending_selection->data);
1130 }
1131
1132 /* scroll_string might be NULL if there was no saved scroll position. */
1133 if (scroll_string != NULL)
1134 {
1135 slot->pending_scroll_to = scroll_string;
1136 }
1137 }
1138 }
1139
1140 typedef struct
1141 {
1142 GCancellable *cancellable;
1143 CajaWindowSlot *slot;
1144 } MountNotMountedData;
1145
1146 static void
mount_not_mounted_callback(GObject * source_object,GAsyncResult * res,gpointer user_data)1147 mount_not_mounted_callback (GObject *source_object,
1148 GAsyncResult *res,
1149 gpointer user_data)
1150 {
1151 MountNotMountedData *data;
1152 CajaWindowSlot *slot;
1153 GError *error;
1154 GCancellable *cancellable;
1155
1156 data = user_data;
1157 slot = data->slot;
1158 cancellable = data->cancellable;
1159 g_free (data);
1160
1161 if (g_cancellable_is_cancelled (cancellable))
1162 {
1163 /* Cancelled, don't call back */
1164 g_object_unref (cancellable);
1165 return;
1166 }
1167
1168 slot->mount_cancellable = NULL;
1169
1170 slot->determine_view_file = caja_file_get (slot->pending_location);
1171
1172 error = NULL;
1173 if (!g_file_mount_enclosing_volume_finish (G_FILE (source_object), res, &error))
1174 {
1175 slot->mount_error = error;
1176 got_file_info_for_view_selection_callback (slot->determine_view_file, slot);
1177 slot->mount_error = NULL;
1178 g_error_free (error);
1179 }
1180 else
1181 {
1182 caja_file_invalidate_all_attributes (slot->determine_view_file);
1183 caja_file_call_when_ready (slot->determine_view_file,
1184 CAJA_FILE_ATTRIBUTE_INFO,
1185 got_file_info_for_view_selection_callback,
1186 slot);
1187 }
1188
1189 g_object_unref (cancellable);
1190 }
1191
1192 static void
got_file_info_for_view_selection_callback(CajaFile * file,gpointer callback_data)1193 got_file_info_for_view_selection_callback (CajaFile *file,
1194 gpointer callback_data)
1195 {
1196 GError *error;
1197 char *view_id;
1198 CajaWindow *window;
1199 CajaWindowSlot *slot;
1200 GFile *location;
1201 MountNotMountedData *data;
1202 slot = callback_data;
1203 g_assert (CAJA_IS_WINDOW_SLOT (slot));
1204 g_assert (slot->determine_view_file == file);
1205
1206 window = slot->pane->window;
1207 g_assert (CAJA_IS_WINDOW (window));
1208
1209 slot->determine_view_file = NULL;
1210
1211 if (slot->mount_error)
1212 {
1213 error = slot->mount_error;
1214 }
1215 else
1216 {
1217 error = caja_file_get_file_info_error (file);
1218 }
1219
1220 if (error && error->domain == G_IO_ERROR && error->code == G_IO_ERROR_NOT_MOUNTED &&
1221 !slot->tried_mount)
1222 {
1223 GMountOperation *mount_op;
1224
1225 slot->tried_mount = TRUE;
1226
1227 mount_op = gtk_mount_operation_new (GTK_WINDOW (window));
1228 g_mount_operation_set_password_save (mount_op, G_PASSWORD_SAVE_FOR_SESSION);
1229 location = caja_file_get_location (file);
1230 data = g_new0 (MountNotMountedData, 1);
1231 data->cancellable = g_cancellable_new ();
1232 data->slot = slot;
1233 slot->mount_cancellable = data->cancellable;
1234 g_file_mount_enclosing_volume (location, 0, mount_op, slot->mount_cancellable,
1235 mount_not_mounted_callback, data);
1236 g_object_unref (location);
1237 g_object_unref (mount_op);
1238
1239 caja_file_unref (file);
1240
1241 return;
1242 }
1243
1244 location = slot->pending_location;
1245
1246 view_id = NULL;
1247
1248 if (error == NULL ||
1249 (error->domain == G_IO_ERROR && error->code == G_IO_ERROR_NOT_SUPPORTED))
1250 {
1251 char *mimetype;
1252
1253 /* We got the information we need, now pick what view to use: */
1254
1255 mimetype = caja_file_get_mime_type (file);
1256
1257 /* If fallback, don't use view from metadata */
1258 if (slot->location_change_type != CAJA_LOCATION_CHANGE_FALLBACK)
1259 {
1260 /* Look in metadata for view */
1261 view_id = caja_file_get_metadata
1262 (file, CAJA_METADATA_KEY_DEFAULT_VIEW, NULL);
1263 if (view_id != NULL &&
1264 !caja_view_factory_view_supports_uri (view_id,
1265 location,
1266 caja_file_get_file_type (file),
1267 mimetype))
1268 {
1269 g_free (view_id);
1270 view_id = NULL;
1271 }
1272 }
1273
1274 /* Otherwise, use default */
1275 if (view_id == NULL)
1276 {
1277 char *uri;
1278 uri = caja_file_get_uri (file);
1279
1280 /* Use same view settings for search results as the current folder */
1281 if (eel_uri_is_search (uri))
1282 {
1283 view_id = g_strdup (caja_view_get_view_id (slot->content_view));
1284 }
1285 else
1286 {
1287 view_id = caja_global_preferences_get_default_folder_viewer_preference_as_iid ();
1288 }
1289
1290 g_free (uri);
1291
1292 if (view_id != NULL &&
1293 !caja_view_factory_view_supports_uri (view_id,
1294 location,
1295 caja_file_get_file_type (file),
1296 mimetype))
1297 {
1298 g_free (view_id);
1299 view_id = NULL;
1300 }
1301 }
1302
1303 g_free (mimetype);
1304 }
1305
1306 if (view_id != NULL)
1307 {
1308 if (!gtk_widget_get_visible (GTK_WIDGET (window)) && CAJA_IS_SPATIAL_WINDOW (window))
1309 {
1310 /* We now have the metadata to set up the window position, etc */
1311 setup_new_spatial_window (slot, file);
1312 }
1313 create_content_view (slot, view_id);
1314 g_free (view_id);
1315
1316 report_callback (slot, NULL);
1317 }
1318 else
1319 {
1320 if (!report_callback (slot, error)) {
1321 display_view_selection_failure (window, file,
1322 location, error);
1323 }
1324
1325 if (!gtk_widget_get_visible (GTK_WIDGET (window)))
1326 {
1327 CajaApplication *app;
1328
1329 /* Destroy never-had-a-chance-to-be-seen window. This case
1330 * happens when a new window cannot display its initial URI.
1331 */
1332 /* if this is the only window, we don't want to quit, so we redirect it to home */
1333 app = CAJA_APPLICATION (g_application_get_default ());
1334
1335 if (g_list_length (gtk_application_get_windows (GTK_APPLICATION (app))) == 1) {
1336
1337 /* the user could have typed in a home directory that doesn't exist,
1338 in which case going home would cause an infinite loop, so we
1339 better test for that */
1340
1341 if (!caja_is_root_directory (location))
1342 {
1343 if (!caja_is_home_directory (location))
1344 {
1345 caja_window_slot_go_home (slot, FALSE);
1346 }
1347 else
1348 {
1349 GFile *root;
1350
1351 root = g_file_new_for_path ("/");
1352 /* the last fallback is to go to a known place that can't be deleted! */
1353 caja_window_slot_go_to (slot, location, FALSE);
1354 g_object_unref (root);
1355 }
1356 }
1357 else
1358 {
1359 gtk_widget_destroy (GTK_WIDGET (window));
1360 }
1361 }
1362 else
1363 {
1364 /* Since this is a window, destroying it will also unref it. */
1365 gtk_widget_destroy (GTK_WIDGET (window));
1366 }
1367 }
1368 else
1369 {
1370 /* Clean up state of already-showing window */
1371 end_location_change (slot);
1372
1373 /* TODO? shouldn't we call
1374 * cancel_viewed_file_changed_callback (slot);
1375 * at this point, or in end_location_change()
1376 */
1377 /* We're missing a previous location (if opened location
1378 * in a new tab) so close it and return */
1379 if (slot->location == NULL)
1380 {
1381 caja_window_slot_close (slot);
1382 }
1383 else
1384 {
1385 CajaFile *viewed_file;
1386
1387 /* We disconnected this, so we need to re-connect it */
1388 viewed_file = caja_file_get (slot->location);
1389 caja_window_slot_set_viewed_file (slot, viewed_file);
1390 caja_file_monitor_add (viewed_file, &slot->viewed_file, 0);
1391 g_signal_connect_object (viewed_file, "changed",
1392 G_CALLBACK (viewed_file_changed_callback), slot, 0);
1393 caja_file_unref (viewed_file);
1394
1395 /* Leave the location bar showing the bad location that the user
1396 * typed (or maybe achieved by dragging or something). Many times
1397 * the mistake will just be an easily-correctable typo. The user
1398 * can choose "Refresh" to get the original URI back in the location bar.
1399 */
1400 }
1401 }
1402 }
1403
1404 caja_file_unref (file);
1405 }
1406
1407 /* Load a view into the window, either reusing the old one or creating
1408 * a new one. This happens when you want to load a new location, or just
1409 * switch to a different view.
1410 * If pending_location is set we're loading a new location and
1411 * pending_location/selection will be used. If not, we're just switching
1412 * view, and the current location will be used.
1413 */
1414 static void
create_content_view(CajaWindowSlot * slot,const char * view_id)1415 create_content_view (CajaWindowSlot *slot,
1416 const char *view_id)
1417 {
1418 CajaWindow *window;
1419 CajaView *view;
1420 GList *selection;
1421
1422 window = slot->pane->window;
1423
1424 /* FIXME bugzilla.gnome.org 41243:
1425 * We should use inheritance instead of these special cases
1426 * for the desktop window.
1427 */
1428 if (CAJA_IS_DESKTOP_WINDOW (window))
1429 {
1430 /* We force the desktop to use a desktop_icon_view. It's simpler
1431 * to fix it here than trying to make it pick the right view in
1432 * the first place.
1433 */
1434 view_id = CAJA_DESKTOP_ICON_VIEW_IID;
1435 }
1436
1437 if (slot->content_view != NULL &&
1438 g_strcmp0 (caja_view_get_view_id (slot->content_view),
1439 view_id) == 0)
1440 {
1441 /* reuse existing content view */
1442 view = slot->content_view;
1443 slot->new_content_view = view;
1444 g_object_ref (view);
1445 }
1446 else
1447 {
1448 /* create a new content view */
1449 view = caja_view_factory_create (view_id,
1450 CAJA_WINDOW_SLOT_INFO (slot));
1451
1452 eel_accessibility_set_name (view, _("Content View"));
1453 eel_accessibility_set_description (view, _("View of the current folder"));
1454
1455 slot->new_content_view = view;
1456 caja_window_slot_connect_content_view (slot, slot->new_content_view);
1457 }
1458
1459 /* Actually load the pending location and selection: */
1460
1461 if (slot->pending_location != NULL)
1462 {
1463 load_new_location (slot,
1464 slot->pending_location,
1465 slot->pending_selection,
1466 FALSE,
1467 TRUE);
1468
1469 g_list_free_full (slot->pending_selection, g_object_unref);
1470 slot->pending_selection = NULL;
1471 }
1472 else if (slot->location != NULL)
1473 {
1474 selection = caja_view_get_selection (slot->content_view);
1475 load_new_location (slot,
1476 slot->location,
1477 selection,
1478 FALSE,
1479 TRUE);
1480 g_list_free_full (selection, g_object_unref);
1481 }
1482 else
1483 {
1484 /* Something is busted, there was no location to load.
1485 Just load the homedir. */
1486 caja_window_slot_go_home (slot, FALSE);
1487
1488 }
1489 }
1490
1491 static void
load_new_location(CajaWindowSlot * slot,GFile * location,GList * selection,gboolean tell_current_content_view,gboolean tell_new_content_view)1492 load_new_location (CajaWindowSlot *slot,
1493 GFile *location,
1494 GList *selection,
1495 gboolean tell_current_content_view,
1496 gboolean tell_new_content_view)
1497 {
1498 CajaWindow *window;
1499 GList *selection_copy;
1500 CajaView *view;
1501 char *uri;
1502
1503 g_assert (slot != NULL);
1504 g_assert (location != NULL);
1505
1506 window = slot->pane->window;
1507 g_assert (CAJA_IS_WINDOW (window));
1508
1509 selection_copy = g_list_copy_deep (selection, copy_object, NULL);
1510
1511 view = NULL;
1512
1513 /* Note, these may recurse into report_load_underway */
1514 if (slot->content_view != NULL && tell_current_content_view)
1515 {
1516 view = slot->content_view;
1517 uri = g_file_get_uri (location);
1518 caja_view_load_location (slot->content_view, uri);
1519 g_free (uri);
1520 }
1521
1522 if (slot->new_content_view != NULL && tell_new_content_view &&
1523 (!tell_current_content_view ||
1524 slot->new_content_view != slot->content_view) )
1525 {
1526 view = slot->new_content_view;
1527 uri = g_file_get_uri (location);
1528 caja_view_load_location (slot->new_content_view, uri);
1529 g_free (uri);
1530 }
1531 if (view != NULL)
1532 {
1533 /* slot->new_content_view might have changed here if
1534 report_load_underway was called from load_location */
1535 caja_view_set_selection (view, selection_copy);
1536 }
1537
1538 g_list_free_full (selection_copy, g_object_unref);
1539 }
1540
1541 /* A view started to load the location its viewing, either due to
1542 * a load_location request, or some internal reason. Expect
1543 * a matching load_compete later
1544 */
1545 void
caja_window_report_load_underway(CajaWindow * window,CajaView * view)1546 caja_window_report_load_underway (CajaWindow *window,
1547 CajaView *view)
1548 {
1549 CajaWindowSlot *slot;
1550
1551 g_assert (CAJA_IS_WINDOW (window));
1552
1553 if (window->details->temporarily_ignore_view_signals)
1554 {
1555 return;
1556 }
1557
1558 slot = caja_window_get_slot_for_view (window, view);
1559 g_assert (slot != NULL);
1560
1561 if (view == slot->new_content_view)
1562 {
1563 location_has_really_changed (slot);
1564 }
1565 else
1566 {
1567 caja_window_slot_set_allow_stop (slot, TRUE);
1568 }
1569 }
1570
1571 static void
caja_window_emit_location_change(CajaWindow * window,GFile * location)1572 caja_window_emit_location_change (CajaWindow *window,
1573 GFile *location)
1574 {
1575 char *uri;
1576
1577 uri = g_file_get_uri (location);
1578 g_signal_emit_by_name (window, "loading_uri", uri);
1579 g_free (uri);
1580 }
1581
1582 /* reports location change to window's "loading-uri" clients, i.e.
1583 * sidebar panels [used when switching tabs]. It will emit the pending
1584 * location, or the existing location if none is pending.
1585 */
1586 void
caja_window_report_location_change(CajaWindow * window)1587 caja_window_report_location_change (CajaWindow *window)
1588 {
1589 CajaWindowSlot *slot;
1590 GFile *location;
1591
1592 g_assert (CAJA_IS_WINDOW (window));
1593
1594 slot = window->details->active_pane->active_slot;
1595 g_assert (CAJA_IS_WINDOW_SLOT (slot));
1596
1597 location = NULL;
1598
1599 if (slot->pending_location != NULL)
1600 {
1601 location = slot->pending_location;
1602 }
1603
1604 if (location == NULL && slot->location != NULL)
1605 {
1606 location = slot->location;
1607 }
1608
1609 if (location != NULL)
1610 {
1611 caja_window_emit_location_change (window, location);
1612 }
1613 }
1614
1615 /* This is called when we have decided we can actually change to the new view/location situation. */
1616 static void
location_has_really_changed(CajaWindowSlot * slot)1617 location_has_really_changed (CajaWindowSlot *slot)
1618 {
1619 CajaWindow *window;
1620 GFile *location_copy;
1621
1622 window = slot->pane->window;
1623
1624 if (slot->new_content_view != NULL)
1625 {
1626 GtkWidget *widget;
1627
1628 widget = caja_view_get_widget (slot->new_content_view);
1629 /* Switch to the new content view. */
1630 if (gtk_widget_get_parent (widget) == NULL)
1631 {
1632 if (slot->content_view != NULL)
1633 {
1634 caja_window_slot_disconnect_content_view (slot, slot->content_view);
1635 }
1636 caja_window_slot_set_content_view_widget (slot, slot->new_content_view);
1637 }
1638 g_object_unref (slot->new_content_view);
1639 slot->new_content_view = NULL;
1640 }
1641
1642 if (slot->pending_location != NULL)
1643 {
1644 /* Tell the window we are finished. */
1645 update_for_new_location (slot);
1646 }
1647
1648 location_copy = NULL;
1649 if (slot->location != NULL)
1650 {
1651 location_copy = g_object_ref (slot->location);
1652 }
1653
1654 free_location_change (slot);
1655
1656 if (location_copy != NULL)
1657 {
1658 if (slot == caja_window_get_active_slot (window))
1659 {
1660 caja_window_emit_location_change (window, location_copy);
1661 }
1662
1663 g_object_unref (location_copy);
1664 }
1665 }
1666
1667 static void
slot_add_extension_extra_widgets(CajaWindowSlot * slot)1668 slot_add_extension_extra_widgets (CajaWindowSlot *slot)
1669 {
1670 GList *providers, *l;
1671 char *uri;
1672 GtkWidget *widget = NULL;
1673
1674 providers = caja_extensions_get_for_type (CAJA_TYPE_LOCATION_WIDGET_PROVIDER);
1675
1676 uri = g_file_get_uri (slot->location);
1677 for (l = providers; l != NULL; l = l->next)
1678 {
1679 CajaLocationWidgetProvider *provider;
1680
1681 provider = CAJA_LOCATION_WIDGET_PROVIDER (l->data);
1682 widget = caja_location_widget_provider_get_widget (provider, uri, GTK_WIDGET (slot->pane->window));
1683 if (widget != NULL)
1684 {
1685 caja_window_slot_add_extra_location_widget (slot, widget);
1686 }
1687 }
1688 g_free (uri);
1689
1690 caja_module_extension_list_free (providers);
1691 }
1692
1693 static void
caja_window_slot_show_x_content_bar(CajaWindowSlot * slot,GMount * mount,const char ** x_content_types)1694 caja_window_slot_show_x_content_bar (CajaWindowSlot *slot, GMount *mount, const char **x_content_types)
1695 {
1696 unsigned int n;
1697
1698 g_assert (CAJA_IS_WINDOW_SLOT (slot));
1699
1700 for (n = 0; x_content_types[n] != NULL; n++)
1701 {
1702 GAppInfo *default_app;
1703
1704 /* skip blank media; the burn:/// location will provide it's own cluebar */
1705 if (g_str_has_prefix (x_content_types[n], "x-content/blank-"))
1706 {
1707 continue;
1708 }
1709
1710 /* don't show the cluebar for windows software */
1711 if (g_content_type_is_a (x_content_types[n], "x-content/win32-software"))
1712 {
1713 continue;
1714 }
1715
1716 /* only show the cluebar if a default app is available */
1717 default_app = g_app_info_get_default_for_type (x_content_types[n], FALSE);
1718 if (default_app != NULL)
1719 {
1720 GtkWidget *bar;
1721 bar = caja_x_content_bar_new (mount, x_content_types[n]);
1722 gtk_widget_show (bar);
1723 caja_window_slot_add_extra_location_widget (slot, bar);
1724 g_object_unref (default_app);
1725 }
1726 }
1727 }
1728
1729 static void
caja_window_slot_show_trash_bar(CajaWindowSlot * slot,CajaWindow * window)1730 caja_window_slot_show_trash_bar (CajaWindowSlot *slot,
1731 CajaWindow *window)
1732 {
1733 GtkWidget *bar;
1734
1735 bar = caja_trash_bar_new (window);
1736 gtk_widget_show (bar);
1737
1738 caja_window_slot_add_extra_location_widget (slot, bar);
1739 }
1740
1741 typedef struct
1742 {
1743 CajaWindowSlot *slot;
1744 GCancellable *cancellable;
1745 GMount *mount;
1746 } FindMountData;
1747
1748 static void
found_content_type_cb(const char ** x_content_types,FindMountData * data)1749 found_content_type_cb (const char **x_content_types, FindMountData *data)
1750 {
1751 CajaWindowSlot *slot;
1752
1753 if (g_cancellable_is_cancelled (data->cancellable))
1754 {
1755 goto out;
1756 }
1757
1758 slot = data->slot;
1759
1760 if (x_content_types != NULL && x_content_types[0] != NULL)
1761 {
1762 caja_window_slot_show_x_content_bar (slot, data->mount, x_content_types);
1763 }
1764
1765 slot->find_mount_cancellable = NULL;
1766
1767 out:
1768 g_object_unref (data->mount);
1769 g_object_unref (data->cancellable);
1770 g_free (data);
1771 }
1772
1773 static void
found_mount_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)1774 found_mount_cb (GObject *source_object,
1775 GAsyncResult *res,
1776 gpointer user_data)
1777 {
1778 FindMountData *data = user_data;
1779 GMount *mount;
1780
1781 if (g_cancellable_is_cancelled (data->cancellable))
1782 {
1783 goto out;
1784 }
1785
1786 mount = g_file_find_enclosing_mount_finish (G_FILE (source_object),
1787 res,
1788 NULL);
1789 if (mount != NULL)
1790 {
1791 data->mount = mount;
1792 caja_autorun_get_x_content_types_for_mount_async (mount,
1793 (CajaAutorunGetContent)found_content_type_cb,
1794 data->cancellable,
1795 data);
1796 return;
1797 }
1798
1799 data->slot->find_mount_cancellable = NULL;
1800
1801 out:
1802 g_object_unref (data->cancellable);
1803 g_free (data);
1804 }
1805
1806 /* Handle the changes for the CajaWindow itself. */
1807 static void
update_for_new_location(CajaWindowSlot * slot)1808 update_for_new_location (CajaWindowSlot *slot)
1809 {
1810 CajaWindow *window;
1811 GFile *new_location;
1812 CajaFile *file;
1813 gboolean location_really_changed;
1814 FindMountData *data;
1815
1816 window = slot->pane->window;
1817
1818 new_location = slot->pending_location;
1819 slot->pending_location = NULL;
1820
1821 set_displayed_location (slot, new_location);
1822
1823 update_history (slot, slot->location_change_type, new_location);
1824
1825 location_really_changed =
1826 slot->location == NULL ||
1827 !g_file_equal (slot->location, new_location);
1828
1829 /* Set the new location. */
1830 if (slot->location)
1831 {
1832 g_object_unref (slot->location);
1833 }
1834 slot->location = new_location;
1835
1836 /* Create a CajaFile for this location, so we can catch it
1837 * if it goes away.
1838 */
1839 cancel_viewed_file_changed_callback (slot);
1840 file = caja_file_get (slot->location);
1841 caja_window_slot_set_viewed_file (slot, file);
1842 slot->viewed_file_seen = !caja_file_is_not_yet_confirmed (file);
1843 slot->viewed_file_in_trash = caja_file_is_in_trash (file);
1844 caja_file_monitor_add (file, &slot->viewed_file, 0);
1845 g_signal_connect_object (file, "changed",
1846 G_CALLBACK (viewed_file_changed_callback), slot, 0);
1847 caja_file_unref (file);
1848
1849 if (slot == window->details->active_pane->active_slot)
1850 {
1851 /* Check if we can go up. */
1852 caja_window_update_up_button (window);
1853
1854 caja_window_sync_zoom_widgets (window);
1855
1856 /* Set up the content view menu for this new location. */
1857 caja_window_load_view_as_menus (window);
1858
1859 /* Load menus from caja extensions for this location */
1860 caja_window_load_extension_menus (window);
1861 }
1862
1863 if (location_really_changed)
1864 {
1865 CajaDirectory *directory;
1866
1867 caja_window_slot_remove_extra_location_widgets (slot);
1868
1869 directory = caja_directory_get (slot->location);
1870
1871 caja_window_slot_update_query_editor (slot);
1872
1873 if (caja_directory_is_in_trash (directory))
1874 {
1875 caja_window_slot_show_trash_bar (slot, window);
1876 }
1877
1878 /* need the mount to determine if we should put up the x-content cluebar */
1879 if (slot->find_mount_cancellable != NULL)
1880 {
1881 g_cancellable_cancel (slot->find_mount_cancellable);
1882 slot->find_mount_cancellable = NULL;
1883 }
1884
1885 data = g_new (FindMountData, 1);
1886 data->slot = slot;
1887 data->cancellable = g_cancellable_new ();
1888 data->mount = NULL;
1889
1890 slot->find_mount_cancellable = data->cancellable;
1891 g_file_find_enclosing_mount_async (slot->location,
1892 G_PRIORITY_DEFAULT,
1893 data->cancellable,
1894 found_mount_cb,
1895 data);
1896
1897 caja_directory_unref (directory);
1898
1899 slot_add_extension_extra_widgets (slot);
1900 }
1901
1902 caja_window_slot_update_title (slot);
1903 caja_window_slot_update_icon (slot);
1904
1905 if (slot == slot->pane->active_slot)
1906 {
1907 caja_window_pane_sync_location_widgets (slot->pane);
1908
1909 if (location_really_changed)
1910 {
1911 caja_window_pane_sync_search_widgets (slot->pane);
1912 }
1913
1914 if (CAJA_IS_NAVIGATION_WINDOW (window) &&
1915 slot->pane == window->details->active_pane)
1916 {
1917 caja_navigation_window_load_extension_toolbar_items (CAJA_NAVIGATION_WINDOW (window));
1918 }
1919 }
1920 }
1921
1922 /* A location load previously announced by load_underway
1923 * has been finished */
1924 void
caja_window_report_load_complete(CajaWindow * window,CajaView * view)1925 caja_window_report_load_complete (CajaWindow *window,
1926 CajaView *view)
1927 {
1928 CajaWindowSlot *slot;
1929
1930 g_assert (CAJA_IS_WINDOW (window));
1931
1932 if (window->details->temporarily_ignore_view_signals)
1933 {
1934 return;
1935 }
1936
1937 slot = caja_window_get_slot_for_view (window, view);
1938 g_assert (slot != NULL);
1939
1940 /* Only handle this if we're expecting it.
1941 * Don't handle it if its from an old view we've switched from */
1942 if (view == slot->content_view)
1943 {
1944 if (slot->pending_scroll_to != NULL)
1945 {
1946 caja_view_scroll_to_file (slot->content_view,
1947 slot->pending_scroll_to);
1948 }
1949 end_location_change (slot);
1950 }
1951 }
1952
1953 static void
end_location_change(CajaWindowSlot * slot)1954 end_location_change (CajaWindowSlot *slot)
1955 {
1956 CajaWindow *window;
1957 char *uri;
1958
1959 window = slot->pane->window;
1960
1961 uri = caja_window_slot_get_location_uri (slot);
1962 if (uri)
1963 {
1964 caja_debug_log (FALSE, CAJA_DEBUG_LOG_DOMAIN_USER,
1965 "finished loading window %p: %s", window, uri);
1966 g_free (uri);
1967 }
1968
1969 caja_window_slot_set_allow_stop (slot, FALSE);
1970
1971 /* Now we can free pending_scroll_to, since the load_complete
1972 * callback already has been emitted.
1973 */
1974 g_free (slot->pending_scroll_to);
1975 slot->pending_scroll_to = NULL;
1976
1977 free_location_change (slot);
1978 }
1979
1980 static void
free_location_change(CajaWindowSlot * slot)1981 free_location_change (CajaWindowSlot *slot)
1982 {
1983 CajaWindow *window;
1984
1985 window = slot->pane->window;
1986 g_assert (CAJA_IS_WINDOW (window));
1987
1988 if (slot->pending_location)
1989 {
1990 g_object_unref (slot->pending_location);
1991 }
1992 slot->pending_location = NULL;
1993
1994 g_list_free_full (slot->pending_selection, g_object_unref);
1995 slot->pending_selection = NULL;
1996
1997 /* Don't free pending_scroll_to, since thats needed until
1998 * the load_complete callback.
1999 */
2000
2001 if (slot->mount_cancellable != NULL)
2002 {
2003 g_cancellable_cancel (slot->mount_cancellable);
2004 slot->mount_cancellable = NULL;
2005 }
2006
2007 if (slot->determine_view_file != NULL)
2008 {
2009 caja_file_cancel_call_when_ready
2010 (slot->determine_view_file,
2011 got_file_info_for_view_selection_callback, slot);
2012 slot->determine_view_file = NULL;
2013 }
2014
2015 if (slot->new_content_view != NULL)
2016 {
2017 window->details->temporarily_ignore_view_signals = TRUE;
2018 caja_view_stop_loading (slot->new_content_view);
2019 window->details->temporarily_ignore_view_signals = FALSE;
2020
2021 caja_window_slot_disconnect_content_view (slot, slot->new_content_view);
2022 g_object_unref (slot->new_content_view);
2023 slot->new_content_view = NULL;
2024 }
2025 }
2026
2027 static void
cancel_location_change(CajaWindowSlot * slot)2028 cancel_location_change (CajaWindowSlot *slot)
2029 {
2030 if (slot->pending_location != NULL
2031 && slot->location != NULL
2032 && slot->content_view != NULL)
2033 {
2034 GList *selection;
2035
2036 /* No need to tell the new view - either it is the
2037 * same as the old view, in which case it will already
2038 * be told, or it is the very pending change we wish
2039 * to cancel.
2040 */
2041 selection = caja_view_get_selection (slot->content_view);
2042 load_new_location (slot,
2043 slot->location,
2044 selection,
2045 TRUE,
2046 FALSE);
2047 g_list_free_full (selection, g_object_unref);
2048 }
2049
2050 end_location_change (slot);
2051 }
2052
2053 void
caja_window_report_view_failed(CajaWindow * window,CajaView * view)2054 caja_window_report_view_failed (CajaWindow *window,
2055 CajaView *view)
2056 {
2057 CajaWindowSlot *slot;
2058 gboolean do_close_window;
2059 GFile *fallback_load_location;
2060
2061 if (window->details->temporarily_ignore_view_signals)
2062 {
2063 return;
2064 }
2065
2066 slot = caja_window_get_slot_for_view (window, view);
2067 g_assert (slot != NULL);
2068
2069 g_warning ("A view failed. The UI will handle this with a dialog but this should be debugged.");
2070
2071 do_close_window = FALSE;
2072 fallback_load_location = NULL;
2073
2074 if (view == slot->content_view)
2075 {
2076 caja_window_slot_disconnect_content_view (slot, view);
2077 caja_window_slot_set_content_view_widget (slot, NULL);
2078
2079 report_current_content_view_failure_to_user (slot);
2080 }
2081 else
2082 {
2083 /* Only report error on first try */
2084 if (slot->location_change_type != CAJA_LOCATION_CHANGE_FALLBACK)
2085 {
2086 report_nascent_content_view_failure_to_user (slot, view);
2087
2088 fallback_load_location = g_object_ref (slot->pending_location);
2089 }
2090 else
2091 {
2092 if (!gtk_widget_get_visible (GTK_WIDGET (window)))
2093 {
2094 do_close_window = TRUE;
2095 }
2096 }
2097 }
2098
2099 cancel_location_change (slot);
2100
2101 if (fallback_load_location != NULL)
2102 {
2103 /* We loose the pending selection change here, but who cares... */
2104 begin_location_change (slot, fallback_load_location, NULL, NULL,
2105 CAJA_LOCATION_CHANGE_FALLBACK, 0, NULL, NULL, NULL);
2106 g_object_unref (fallback_load_location);
2107 }
2108
2109 if (do_close_window)
2110 {
2111 gtk_widget_destroy (GTK_WIDGET (window));
2112 }
2113 }
2114
2115 static void
display_view_selection_failure(CajaWindow * window,CajaFile * file,GFile * location,GError * error)2116 display_view_selection_failure (CajaWindow *window, CajaFile *file,
2117 GFile *location, GError *error)
2118 {
2119 char *full_uri_for_display;
2120 char *uri_for_display;
2121 char *error_message;
2122 char *detail_message;
2123 char *scheme_string;
2124
2125 /* Some sort of failure occurred. How 'bout we tell the user? */
2126 full_uri_for_display = g_file_get_parse_name (location);
2127 /* Truncate the URI so it doesn't get insanely wide. Note that even
2128 * though the dialog uses wrapped text, if the URI doesn't contain
2129 * white space then the text-wrapping code is too stupid to wrap it.
2130 */
2131 uri_for_display = eel_str_middle_truncate
2132 (full_uri_for_display, MAX_URI_IN_DIALOG_LENGTH);
2133 g_free (full_uri_for_display);
2134
2135 error_message = NULL;
2136 detail_message = NULL;
2137 if (error == NULL)
2138 {
2139 if (caja_file_is_directory (file))
2140 {
2141 error_message = g_strdup_printf
2142 (_("Could not display \"%s\"."),
2143 uri_for_display);
2144 detail_message = g_strdup
2145 (_("Caja has no installed viewer capable of displaying the folder."));
2146 }
2147 else
2148 {
2149 error_message = g_strdup_printf
2150 (_("Could not display \"%s\"."),
2151 uri_for_display);
2152 detail_message = g_strdup
2153 (_("The location is not a folder."));
2154 }
2155 }
2156 else if (error->domain == G_IO_ERROR)
2157 {
2158 switch (error->code)
2159 {
2160 case G_IO_ERROR_NOT_FOUND:
2161 error_message = g_strdup_printf
2162 (_("Could not find \"%s\"."),
2163 uri_for_display);
2164 detail_message = g_strdup
2165 (_("Please check the spelling and try again."));
2166 break;
2167 case G_IO_ERROR_NOT_SUPPORTED:
2168 scheme_string = g_file_get_uri_scheme (location);
2169
2170 error_message = g_strdup_printf (_("Could not display \"%s\"."),
2171 uri_for_display);
2172 if (scheme_string != NULL)
2173 {
2174 detail_message = g_strdup_printf (_("Caja cannot handle \"%s\" locations."),
2175 scheme_string);
2176 }
2177 else
2178 {
2179 detail_message = g_strdup (_("Caja cannot handle this kind of location."));
2180 }
2181 g_free (scheme_string);
2182 break;
2183 case G_IO_ERROR_NOT_MOUNTED:
2184 error_message = g_strdup_printf (_("Could not display \"%s\"."),
2185 uri_for_display);
2186 detail_message = g_strdup (_("Unable to mount the location."));
2187 break;
2188
2189 case G_IO_ERROR_PERMISSION_DENIED:
2190 error_message = g_strdup_printf (_("Could not display \"%s\"."),
2191 uri_for_display);
2192 detail_message = g_strdup (_("Access was denied."));
2193 break;
2194
2195 case G_IO_ERROR_HOST_NOT_FOUND:
2196 /* This case can be hit for user-typed strings like "foo" due to
2197 * the code that guesses web addresses when there's no initial "/".
2198 * But this case is also hit for legitimate web addresses when
2199 * the proxy is set up wrong.
2200 */
2201 error_message = g_strdup_printf (_("Could not display \"%s\", because the host could not be found."),
2202 uri_for_display);
2203 detail_message = g_strdup (_("Check that the spelling is correct and that your proxy settings are correct."));
2204 break;
2205 case G_IO_ERROR_CANCELLED:
2206 case G_IO_ERROR_FAILED_HANDLED:
2207 g_free (uri_for_display);
2208 return;
2209
2210 default:
2211 break;
2212 }
2213 }
2214
2215 if (error_message == NULL)
2216 {
2217 error_message = g_strdup_printf (_("Could not display \"%s\"."),
2218 uri_for_display);
2219 detail_message = g_strdup_printf (_("Error: %s\nPlease select another viewer and try again."), error->message);
2220 }
2221
2222 eel_show_error_dialog (error_message, detail_message, NULL);
2223
2224 g_free (uri_for_display);
2225 g_free (error_message);
2226 g_free (detail_message);
2227 }
2228
2229
2230 void
caja_window_slot_stop_loading(CajaWindowSlot * slot)2231 caja_window_slot_stop_loading (CajaWindowSlot *slot)
2232 {
2233 CajaWindow *window;
2234
2235 window = CAJA_WINDOW (slot->pane->window);
2236 g_assert (CAJA_IS_WINDOW (window));
2237
2238 caja_view_stop_loading (slot->content_view);
2239
2240 if (slot->new_content_view != NULL)
2241 {
2242 window->details->temporarily_ignore_view_signals = TRUE;
2243 caja_view_stop_loading (slot->new_content_view);
2244 window->details->temporarily_ignore_view_signals = FALSE;
2245 }
2246
2247 cancel_location_change (slot);
2248 }
2249
2250 void
caja_window_slot_set_content_view(CajaWindowSlot * slot,const char * id)2251 caja_window_slot_set_content_view (CajaWindowSlot *slot,
2252 const char *id)
2253 {
2254 CajaWindow *window;
2255 CajaFile *file;
2256 char *uri;
2257
2258 g_assert (slot != NULL);
2259 g_assert (slot->location != NULL);
2260 g_assert (id != NULL);
2261
2262 window = slot->pane->window;
2263 g_assert (CAJA_IS_WINDOW (window));
2264
2265 uri = caja_window_slot_get_location_uri (slot);
2266 caja_debug_log (FALSE, CAJA_DEBUG_LOG_DOMAIN_USER,
2267 "change view of window %p: \"%s\" to \"%s\"",
2268 window, uri, id);
2269 g_free (uri);
2270
2271 if (caja_window_slot_content_view_matches_iid (slot, id))
2272 {
2273 return;
2274 }
2275
2276 end_location_change (slot);
2277
2278 file = caja_file_get (slot->location);
2279 caja_file_set_metadata
2280 (file, CAJA_METADATA_KEY_DEFAULT_VIEW, NULL, id);
2281 caja_file_unref (file);
2282
2283 caja_window_slot_set_allow_stop (slot, TRUE);
2284
2285 if (caja_view_get_selection_count (slot->content_view) == 0)
2286 {
2287 /* If there is no selection, queue a scroll to the same icon that
2288 * is currently visible */
2289 slot->pending_scroll_to = caja_view_get_first_visible_file (slot->content_view);
2290 }
2291 slot->location_change_type = CAJA_LOCATION_CHANGE_RELOAD;
2292
2293 create_content_view (slot, id);
2294 }
2295
2296 void
caja_window_manage_views_close_slot(CajaWindowPane * pane,CajaWindowSlot * slot)2297 caja_window_manage_views_close_slot (CajaWindowPane *pane,
2298 CajaWindowSlot *slot)
2299 {
2300 if (slot->content_view != NULL)
2301 {
2302 caja_window_slot_disconnect_content_view (slot, slot->content_view);
2303 }
2304
2305 free_location_change (slot);
2306 cancel_viewed_file_changed_callback (slot);
2307 }
2308
2309 void
caja_navigation_window_back_or_forward(CajaNavigationWindow * window,gboolean back,guint distance,gboolean new_tab)2310 caja_navigation_window_back_or_forward (CajaNavigationWindow *window,
2311 gboolean back, guint distance, gboolean new_tab)
2312 {
2313 CajaWindowSlot *slot;
2314 CajaNavigationWindowSlot *navigation_slot;
2315 GList *list;
2316 GFile *location;
2317 guint len;
2318 CajaBookmark *bookmark;
2319
2320 slot = CAJA_WINDOW (window)->details->active_pane->active_slot;
2321 navigation_slot = (CajaNavigationWindowSlot *) slot;
2322 list = back ? navigation_slot->back_list : navigation_slot->forward_list;
2323
2324 len = (guint) g_list_length (list);
2325
2326 /* If we can't move in the direction at all, just return. */
2327 if (len == 0)
2328 return;
2329
2330 /* If the distance to move is off the end of the list, go to the end
2331 of the list. */
2332 if (distance >= len)
2333 distance = len - 1;
2334
2335 bookmark = g_list_nth_data (list, distance);
2336 location = caja_bookmark_get_location (bookmark);
2337
2338 if (new_tab)
2339 {
2340 caja_window_slot_open_location_full (slot, location,
2341 CAJA_WINDOW_OPEN_ACCORDING_TO_MODE,
2342 CAJA_WINDOW_OPEN_FLAG_NEW_TAB,
2343 NULL, NULL, NULL);
2344 }
2345 else
2346 {
2347 GFile *old_location;
2348 char *scroll_pos;
2349
2350 old_location = caja_window_slot_get_location (slot);
2351 scroll_pos = caja_bookmark_get_scroll_pos (bookmark);
2352 begin_location_change
2353 (slot,
2354 location, old_location, NULL,
2355 back ? CAJA_LOCATION_CHANGE_BACK : CAJA_LOCATION_CHANGE_FORWARD,
2356 distance,
2357 scroll_pos,
2358 NULL, NULL);
2359
2360 if (old_location) {
2361 g_object_unref (old_location);
2362 }
2363
2364 g_free (scroll_pos);
2365 }
2366
2367 g_object_unref (location);
2368 }
2369
2370 /* reload the contents of the window */
2371 void
caja_window_slot_reload(CajaWindowSlot * slot)2372 caja_window_slot_reload (CajaWindowSlot *slot)
2373 {
2374 GFile *location;
2375 char *current_pos;
2376 GList *selection;
2377
2378 g_assert (CAJA_IS_WINDOW_SLOT (slot));
2379
2380 if (slot->location == NULL)
2381 {
2382 return;
2383 }
2384
2385 /* peek_slot_field (window, location) can be free'd during the processing
2386 * of begin_location_change, so make a copy
2387 */
2388 location = g_object_ref (slot->location);
2389 current_pos = NULL;
2390 selection = NULL;
2391 if (slot->content_view != NULL)
2392 {
2393 current_pos = caja_view_get_first_visible_file (slot->content_view);
2394 selection = caja_view_get_selection (slot->content_view);
2395 }
2396 begin_location_change
2397 (slot, location, location, selection,
2398 CAJA_LOCATION_CHANGE_RELOAD, 0, current_pos,
2399 NULL, NULL);
2400 g_free (current_pos);
2401 g_object_unref (location);
2402 g_list_free_full (selection, g_object_unref);
2403 }
2404
2405