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