1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 /*
4 * Nemo
5 *
6 * Copyright (C) 1999, 2000 Red Hat, Inc.
7 * Copyright (C) 1999, 2000, 2001 Eazel, Inc.
8 *
9 * Nemo 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 * Nemo 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 Street, Suite 500, MA 02110-1335, 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 #include "nemo-window-manage-views.h"
30
31 #include "nemo-actions.h"
32 #include "nemo-application.h"
33 #include "nemo-floating-bar.h"
34 #include "nemo-location-bar.h"
35 #include "nemo-pathbar.h"
36 #include "nemo-window-private.h"
37 #include "nemo-window-slot.h"
38 #include "nemo-trash-bar.h"
39 #include "nemo-view-factory.h"
40 #include "nemo-x-content-bar.h"
41 #include "nemo-interesting-folder-bar.h"
42 #include "nemo-thumbnail-problem-bar.h"
43 #include <eel/eel-accessibility.h>
44 #include <eel/eel-debug.h>
45 #include <eel/eel-glib-extensions.h>
46 #include <eel/eel-stock-dialogs.h>
47 #include <eel/eel-string.h>
48 #include <eel/eel-vfs-extensions.h>
49 #include <gtk/gtk.h>
50 #include <gdk/gdkx.h>
51 #include <glib/gi18n.h>
52 #include <libnemo-extension/nemo-location-widget-provider.h>
53 #include <libnemo-private/nemo-desktop-directory.h>
54 #include <libnemo-private/nemo-file-attributes.h>
55 #include <libnemo-private/nemo-file-utilities.h>
56 #include <libnemo-private/nemo-file.h>
57 #include <libnemo-private/nemo-global-preferences.h>
58 #include <libnemo-private/nemo-metadata.h>
59 #include <libnemo-private/nemo-module.h>
60 #include <libnemo-private/nemo-monitor.h>
61 #include <libnemo-private/nemo-search-directory.h>
62
63 #define DEBUG_FLAG NEMO_DEBUG_WINDOW
64 #include <libnemo-private/nemo-debug.h>
65
66 /* FIXME bugzilla.gnome.org 41243:
67 * We should use inheritance instead of these special cases
68 * for the desktop window.
69 */
70 #include "nemo-desktop-window.h"
71
72 /* This number controls a maximum character count for a URL that is
73 * displayed as part of a dialog. It's fairly arbitrary -- big enough
74 * to allow most "normal" URIs to display in full, but small enough to
75 * prevent the dialog from getting insanely wide.
76 */
77 #define MAX_URI_IN_DIALOG_LENGTH 60
78
79 static void begin_location_change (NemoWindowSlot *slot,
80 GFile *location,
81 GFile *previous_location,
82 GList *new_selection,
83 NemoLocationChangeType type,
84 guint distance,
85 const char *scroll_pos,
86 gboolean mount,
87 NemoWindowGoToCallback callback,
88 gpointer user_data);
89 static void free_location_change (NemoWindowSlot *slot);
90 static void end_location_change (NemoWindowSlot *slot);
91 static void cancel_location_change (NemoWindowSlot *slot);
92 static void got_file_info_for_view_selection_callback (NemoFile *file,
93 gpointer callback_data);
94 static void create_content_view (NemoWindowSlot *slot,
95 const char *view_id);
96 static void display_view_selection_failure (NemoWindow *window,
97 NemoFile *file,
98 GFile *location,
99 GError *error);
100 static void load_new_location (NemoWindowSlot *slot,
101 GFile *location,
102 GList *selection,
103 gboolean tell_current_content_view,
104 gboolean tell_new_content_view);
105 static void location_has_really_changed (NemoWindowSlot *slot);
106 static void update_for_new_location (NemoWindowSlot *slot);
107
108 /* set_displayed_location:
109 */
110 static void
set_displayed_location(NemoWindowSlot * slot,GFile * location)111 set_displayed_location (NemoWindowSlot *slot, GFile *location)
112 {
113 GFile *bookmark_location;
114 gboolean recreate;
115
116 if (slot->current_location_bookmark == NULL || location == NULL) {
117 recreate = TRUE;
118 } else {
119 bookmark_location = nemo_bookmark_get_location (slot->current_location_bookmark);
120 recreate = !g_file_equal (bookmark_location, location);
121 g_object_unref (bookmark_location);
122 }
123
124 if (recreate) {
125 /* We've changed locations, must recreate bookmark for current location. */
126 g_clear_object (&slot->last_location_bookmark);
127
128 slot->last_location_bookmark = slot->current_location_bookmark;
129 slot->current_location_bookmark = (location == NULL) ?
130 NULL : nemo_bookmark_new (location, NULL, NULL, NULL);
131 }
132 }
133
134 static void
check_bookmark_location_matches(NemoBookmark * bookmark,GFile * location)135 check_bookmark_location_matches (NemoBookmark *bookmark, GFile *location)
136 {
137 GFile *bookmark_location;
138 char *bookmark_uri, *uri;
139
140 bookmark_location = nemo_bookmark_get_location (bookmark);
141 if (!g_file_equal (location, bookmark_location)) {
142 bookmark_uri = g_file_get_uri (bookmark_location);
143 uri = g_file_get_uri (location);
144 g_warning ("bookmark uri is %s, but expected %s", bookmark_uri, uri);
145 g_free (uri);
146 g_free (bookmark_uri);
147 }
148 g_object_unref (bookmark_location);
149 }
150
151 /* Debugging function used to verify that the last_location_bookmark
152 * is in the state we expect when we're about to use it to update the
153 * Back or Forward list.
154 */
155 static void
check_last_bookmark_location_matches_slot(NemoWindowSlot * slot)156 check_last_bookmark_location_matches_slot (NemoWindowSlot *slot)
157 {
158 check_bookmark_location_matches (slot->last_location_bookmark,
159 slot->location);
160 }
161
162 static void
handle_go_back(NemoWindowSlot * slot,GFile * location)163 handle_go_back (NemoWindowSlot *slot,
164 GFile *location)
165 {
166 guint i;
167 GList *link;
168 NemoBookmark *bookmark;
169
170 /* Going back. Move items from the back list to the forward list. */
171 g_assert (g_list_length (slot->back_list) > slot->location_change_distance);
172 check_bookmark_location_matches (NEMO_BOOKMARK (g_list_nth_data (slot->back_list,
173 slot->location_change_distance)),
174 location);
175 g_assert (slot->location != NULL);
176
177 /* Move current location to Forward list */
178
179 check_last_bookmark_location_matches_slot (slot);
180
181 /* Use the first bookmark in the history list rather than creating a new one. */
182 slot->forward_list = g_list_prepend (slot->forward_list,
183 slot->last_location_bookmark);
184 g_object_ref (slot->forward_list->data);
185
186 /* Move extra links from Back to Forward list */
187 for (i = 0; i < slot->location_change_distance; ++i) {
188 bookmark = NEMO_BOOKMARK (slot->back_list->data);
189 slot->back_list =
190 g_list_remove (slot->back_list, bookmark);
191 slot->forward_list =
192 g_list_prepend (slot->forward_list, bookmark);
193 }
194
195 /* One bookmark falls out of back/forward lists and becomes viewed location */
196 link = slot->back_list;
197 slot->back_list = g_list_remove_link (slot->back_list, link);
198 g_object_unref (link->data);
199 g_list_free_1 (link);
200 }
201
202 static void
handle_go_forward(NemoWindowSlot * slot,GFile * location)203 handle_go_forward (NemoWindowSlot *slot,
204 GFile *location)
205 {
206 guint i;
207 GList *link;
208 NemoBookmark *bookmark;
209
210 /* Going forward. Move items from the forward list to the back list. */
211 g_assert (g_list_length (slot->forward_list) > slot->location_change_distance);
212 check_bookmark_location_matches (NEMO_BOOKMARK (g_list_nth_data (slot->forward_list,
213 slot->location_change_distance)),
214 location);
215 g_assert (slot->location != NULL);
216
217 /* Move current location to Back list */
218 check_last_bookmark_location_matches_slot (slot);
219
220 /* Use the first bookmark in the history list rather than creating a new one. */
221 slot->back_list = g_list_prepend (slot->back_list,
222 slot->last_location_bookmark);
223 g_object_ref (slot->back_list->data);
224
225 /* Move extra links from Forward to Back list */
226 for (i = 0; i < slot->location_change_distance; ++i) {
227 bookmark = NEMO_BOOKMARK (slot->forward_list->data);
228 slot->forward_list =
229 g_list_remove (slot->back_list, bookmark);
230 slot->back_list =
231 g_list_prepend (slot->forward_list, bookmark);
232 }
233
234 /* One bookmark falls out of back/forward lists and becomes viewed location */
235 link = slot->forward_list;
236 slot->forward_list = g_list_remove_link (slot->forward_list, link);
237 g_object_unref (link->data);
238 g_list_free_1 (link);
239 }
240
241 static void
handle_go_elsewhere(NemoWindowSlot * slot,GFile * location)242 handle_go_elsewhere (NemoWindowSlot *slot,
243 GFile *location)
244 {
245 /* Clobber the entire forward list, and move displayed location to back list */
246 nemo_window_slot_clear_forward_list (slot);
247
248 if (slot->location != NULL) {
249 /* If we're returning to the same uri somehow, don't put this uri on back list.
250 * This also avoids a problem where set_displayed_location
251 * didn't update last_location_bookmark since the uri didn't change.
252 */
253 if (!g_file_equal (slot->location, location)) {
254 /* Store bookmark for current location in back list, unless there is no current location */
255 check_last_bookmark_location_matches_slot (slot);
256 /* Use the first bookmark in the history list rather than creating a new one. */
257 slot->back_list = g_list_prepend (slot->back_list,
258 slot->last_location_bookmark);
259 g_object_ref (slot->back_list->data);
260 }
261 }
262 }
263
264 static void
viewed_file_changed_callback(NemoFile * file,NemoWindowSlot * slot)265 viewed_file_changed_callback (NemoFile *file,
266 NemoWindowSlot *slot)
267 {
268 GFile *new_location;
269 gboolean is_in_trash, was_in_trash;
270
271 g_assert (NEMO_IS_FILE (file));
272 g_assert (NEMO_IS_WINDOW_PANE (slot->pane));
273 g_assert (file == slot->viewed_file);
274
275 if (!nemo_file_is_not_yet_confirmed (file)) {
276 slot->viewed_file_seen = TRUE;
277 }
278
279 was_in_trash = slot->viewed_file_in_trash;
280
281 slot->viewed_file_in_trash = is_in_trash = nemo_file_is_in_trash (file);
282
283 /* Close window if the file it's viewing has been deleted or moved to trash. */
284 if (nemo_file_is_gone (file) || (is_in_trash && !was_in_trash)) {
285 if (slot->back_list == NULL) {
286 end_location_change (slot);
287 gtk_widget_destroy (GTK_WIDGET (slot->content_view));
288 nemo_window_close (nemo_window_slot_get_window (slot));
289 return;
290 }
291
292 /* Don't close the window in the case where the
293 * file was never seen in the first place.
294 */
295 if (slot->viewed_file_seen) {
296 /* auto-show existing parent. */
297 GFile *go_to_file, *parent, *location;
298
299 /* Detecting a file is gone may happen in the
300 * middle of a pending location change, we
301 * need to cancel it before closing the window
302 * or things break.
303 */
304 /* FIXME: It makes no sense that this call is
305 * needed. When the window is destroyed, it
306 * calls nemo_window_manage_views_destroy,
307 * which calls free_location_change, which
308 * should be sufficient. Also, if this was
309 * really needed, wouldn't it be needed for
310 * all other nemo_window_close callers?
311 */
312 end_location_change (slot);
313
314 go_to_file = NULL;
315 location = nemo_file_get_location (file);
316 parent = g_file_get_parent (location);
317 g_object_unref (location);
318
319 if (parent) {
320 go_to_file = nemo_find_existing_uri_in_hierarchy (parent);
321 g_object_unref (parent);
322 }
323
324 if (go_to_file != NULL) {
325 /* the path bar URI will be set to go_to_uri immediately
326 * in begin_location_change, but we don't want the
327 * inexistant children to show up anymore */
328 if (slot == slot->pane->active_slot) {
329 /* multiview-TODO also update NemoWindowSlot
330 * [which as of writing doesn't save/store any path bar state]
331 */
332 nemo_path_bar_clear_buttons (NEMO_PATH_BAR (slot->pane->path_bar));
333 }
334
335 nemo_window_slot_open_location (slot, go_to_file, 0);
336 g_object_unref (go_to_file);
337 } else {
338 nemo_window_slot_go_home (slot, FALSE);
339 }
340 }
341 } else {
342 new_location = nemo_file_get_location (file);
343
344 /* If the file was renamed, update location and/or
345 * title. */
346 if (!g_file_equal (new_location, slot->location)) {
347 g_object_unref (slot->location);
348 slot->location = new_location;
349
350 if (slot == slot->pane->active_slot) {
351 nemo_window_pane_sync_location_widgets (slot->pane);
352 }
353 } else {
354 /* TODO?
355 * why do we update title & icon at all in this case? */
356 g_object_unref (new_location);
357 }
358
359 nemo_window_slot_update_title (slot);
360 nemo_window_slot_update_icon (slot);
361 }
362 }
363
364 static void
update_history(NemoWindowSlot * slot,NemoLocationChangeType type,GFile * new_location)365 update_history (NemoWindowSlot *slot,
366 NemoLocationChangeType type,
367 GFile *new_location)
368 {
369 switch (type) {
370 case NEMO_LOCATION_CHANGE_STANDARD:
371 handle_go_elsewhere (slot, new_location);
372 return;
373 case NEMO_LOCATION_CHANGE_RELOAD:
374 /* for reload there is no work to do */
375 return;
376 case NEMO_LOCATION_CHANGE_BACK:
377 handle_go_back (slot, new_location);
378 return;
379 case NEMO_LOCATION_CHANGE_FORWARD:
380 handle_go_forward (slot, new_location);
381 return;
382 default:
383 break;
384 }
385 g_return_if_fail (FALSE);
386 }
387
388 static void
cancel_viewed_file_changed_callback(NemoWindowSlot * slot)389 cancel_viewed_file_changed_callback (NemoWindowSlot *slot)
390 {
391 NemoFile *file;
392
393 file = slot->viewed_file;
394 if (file != NULL) {
395 g_signal_handlers_disconnect_by_func (G_OBJECT (file),
396 G_CALLBACK (viewed_file_changed_callback),
397 slot);
398 nemo_file_monitor_remove (file, &slot->viewed_file);
399 }
400 }
401
402 static void
new_window_show_callback(GtkWidget * widget,gpointer user_data)403 new_window_show_callback (GtkWidget *widget,
404 gpointer user_data){
405 NemoWindow *window;
406
407 window = NEMO_WINDOW (user_data);
408 nemo_window_close (window);
409
410 g_signal_handlers_disconnect_by_func (widget,
411 G_CALLBACK (new_window_show_callback),
412 user_data);
413 }
414
415 void
nemo_window_slot_open_location_full(NemoWindowSlot * slot,GFile * location,NemoWindowOpenFlags flags,GList * new_selection,NemoWindowGoToCallback callback,gpointer user_data)416 nemo_window_slot_open_location_full (NemoWindowSlot *slot,
417 GFile *location,
418 NemoWindowOpenFlags flags,
419 GList *new_selection,
420 NemoWindowGoToCallback callback,
421 gpointer user_data)
422 {
423 NemoWindow *window;
424 NemoWindow *target_window;
425 NemoWindowPane *pane;
426 NemoWindowSlot *target_slot;
427 NemoWindowOpenFlags slot_flags;
428 GFile *old_location;
429 char *old_uri, *new_uri;
430 int new_slot_position;
431 GList *l;
432 gboolean use_same;
433 gboolean is_desktop;
434 NemoApplication *app;
435
436 window = nemo_window_slot_get_window (slot);
437
438 target_window = NULL;
439 target_slot = NULL;
440 use_same = FALSE;
441
442 /* this happens at startup */
443 old_uri = nemo_window_slot_get_location_uri (slot);
444 if (old_uri == NULL) {
445 old_uri = g_strdup ("(none)");
446 use_same = TRUE;
447 }
448 new_uri = g_file_get_uri (location);
449
450 DEBUG ("Opening location, old: %s, new: %s", old_uri, new_uri);
451
452 g_free (old_uri);
453 g_free (new_uri);
454
455 is_desktop = NEMO_IS_DESKTOP_WINDOW (window);
456
457 if (is_desktop) {
458 use_same = !nemo_desktop_window_loaded (NEMO_DESKTOP_WINDOW (window));
459
460 /* if we're requested to open a new tab on the desktop, open a window
461 * instead.
462 */
463 if (flags & NEMO_WINDOW_OPEN_FLAG_NEW_TAB) {
464 flags ^= NEMO_WINDOW_OPEN_FLAG_NEW_TAB;
465 flags |= NEMO_WINDOW_OPEN_FLAG_NEW_WINDOW;
466 }
467 } else {
468 use_same |= g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_ALWAYS_USE_BROWSER);
469 }
470
471 g_assert (!((flags & NEMO_WINDOW_OPEN_FLAG_NEW_WINDOW) != 0 &&
472 (flags & NEMO_WINDOW_OPEN_FLAG_NEW_TAB) != 0));
473
474 /* and if the flags specify so, this is overridden */
475 if ((flags & NEMO_WINDOW_OPEN_FLAG_SEARCH) != 0) {
476 use_same = TRUE;
477 }
478 else if ((flags & NEMO_WINDOW_OPEN_FLAG_NEW_WINDOW) != 0) {
479 use_same = FALSE;
480 }
481
482 /* now get/create the window */
483 if (use_same) {
484 target_window = window;
485 } else {
486 app = nemo_application_get_singleton ();
487 target_window = nemo_application_create_window (app, gtk_window_get_screen (GTK_WINDOW (window)));
488 }
489
490 old_location = nemo_window_slot_get_location (slot);
491
492 g_assert (target_window != NULL);
493
494 /* if the flags say we want a new tab, open a slot in the current window */
495 if ((flags & NEMO_WINDOW_OPEN_FLAG_NEW_TAB) != 0) {
496 g_assert (target_window == window);
497
498 slot_flags = 0;
499
500 new_slot_position = g_settings_get_enum (nemo_preferences, NEMO_PREFERENCES_NEW_TAB_POSITION);
501 if (new_slot_position == NEMO_NEW_TAB_POSITION_END) {
502 slot_flags = NEMO_WINDOW_OPEN_SLOT_APPEND;
503 }
504
505 target_slot = nemo_window_pane_open_slot (nemo_window_get_active_pane (window),
506 slot_flags);
507 }
508
509 /* close the current window if the flags say so */
510 if ((flags & NEMO_WINDOW_OPEN_FLAG_CLOSE_BEHIND) != 0) {
511 if (!is_desktop) {
512 if (gtk_widget_get_visible (GTK_WIDGET (target_window))) {
513 nemo_window_close (window);
514 } else {
515 g_signal_connect_object (target_window,
516 "show",
517 G_CALLBACK (new_window_show_callback),
518 window,
519 G_CONNECT_AFTER);
520 }
521 }
522 }
523
524 if (target_slot == NULL) {
525 if (target_window == window) {
526 target_slot = slot;
527 } else {
528 target_slot = nemo_window_get_active_slot (target_window);
529 }
530 }
531
532 if (target_window == window && target_slot == slot &&
533 old_location && g_file_equal (old_location, location) &&
534 !is_desktop) {
535
536 if (callback != NULL) {
537 callback (window, NULL, user_data);
538 }
539
540 g_object_unref (old_location);
541 return;
542 }
543
544 begin_location_change (target_slot,
545 location,
546 old_location,
547 new_selection,
548 NEMO_LOCATION_CHANGE_STANDARD,
549 0, NULL,
550 (flags & NEMO_WINDOW_OPEN_FLAG_MOUNT),
551 callback,
552 user_data);
553
554 /* Additionally, load this in all slots that have no location, this means
555 we load both panes in e.g. a newly opened dual pane window. */
556 for (l = target_window->details->panes; l != NULL; l = l->next) {
557 pane = l->data;
558 slot = pane->active_slot;
559
560 if (slot->location == NULL && slot->pending_location == NULL) {
561 begin_location_change (slot,
562 location,
563 old_location,
564 new_selection,
565 NEMO_LOCATION_CHANGE_STANDARD,
566 0, NULL,
567 (flags & NEMO_WINDOW_OPEN_FLAG_MOUNT),
568 NULL,
569 NULL);
570 }
571 }
572
573 g_clear_object (&old_location);
574 }
575
576 const char *
nemo_window_slot_get_content_view_id(NemoWindowSlot * slot)577 nemo_window_slot_get_content_view_id (NemoWindowSlot *slot)
578 {
579 if (slot->content_view == NULL) {
580 return NULL;
581 }
582 return nemo_view_get_view_id (slot->content_view);
583 }
584
585 gboolean
nemo_window_slot_content_view_matches_iid(NemoWindowSlot * slot,const char * iid)586 nemo_window_slot_content_view_matches_iid (NemoWindowSlot *slot,
587 const char *iid)
588 {
589 if (slot->content_view == NULL) {
590 return FALSE;
591 }
592 return g_strcmp0 (nemo_view_get_view_id (slot->content_view), iid) == 0;
593 }
594
595 static gboolean
report_callback(NemoWindowSlot * slot,GError * error)596 report_callback (NemoWindowSlot *slot,
597 GError *error)
598 {
599 if (slot->open_callback != NULL) {
600 slot->open_callback (nemo_window_slot_get_window (slot),
601 error, slot->open_callback_user_data);
602 slot->open_callback = NULL;
603 slot->open_callback_user_data = NULL;
604
605 return TRUE;
606 }
607
608 return FALSE;
609 }
610
611 /*
612 * begin_location_change
613 *
614 * Change a window slot's location.
615 * @window: The NemoWindow whose location should be changed.
616 * @location: A url specifying the location to load
617 * @previous_location: The url that was previously shown in the window that initialized the change, if any
618 * @new_selection: The initial selection to present after loading the location
619 * @type: Which type of location change is this? Standard, back, forward, or reload?
620 * @distance: If type is back or forward, the index into the back or forward chain. If
621 * type is standard or reload, this is ignored, and must be 0.
622 * @scroll_pos: The file to scroll to when the location is loaded.
623 * @mount: is a mount (always force a reload).
624 * @callback: function to be called when the location is changed.
625 * @user_data: data for @callback.
626 *
627 * This is the core function for changing the location of a window. Every change to the
628 * location begins here.
629 */
630 static void
begin_location_change(NemoWindowSlot * slot,GFile * location,GFile * previous_location,GList * new_selection,NemoLocationChangeType type,guint distance,const char * scroll_pos,gboolean mount,NemoWindowGoToCallback callback,gpointer user_data)631 begin_location_change (NemoWindowSlot *slot,
632 GFile *location,
633 GFile *previous_location,
634 GList *new_selection,
635 NemoLocationChangeType type,
636 guint distance,
637 const char *scroll_pos,
638 gboolean mount,
639 NemoWindowGoToCallback callback,
640 gpointer user_data)
641 {
642 NemoDirectory *directory;
643 NemoFile *file;
644 gboolean force_reload;
645 char *current_pos;
646 GFile *from_folder, *parent;
647 GList *parent_selection = NULL;
648
649 g_assert (slot != NULL);
650 g_assert (location != NULL);
651 g_assert (type == NEMO_LOCATION_CHANGE_BACK
652 || type == NEMO_LOCATION_CHANGE_FORWARD
653 || distance == 0);
654
655 /* If there is no new selection and the new location is
656 * a (grand)parent of the old location then we automatically
657 * select the folder the previous location was in */
658 if (new_selection == NULL && previous_location != NULL &&
659 g_file_has_prefix (previous_location, location)) {
660 from_folder = g_object_ref (previous_location);
661 parent = g_file_get_parent (from_folder);
662 while (parent != NULL && !g_file_equal (parent, location)) {
663 g_object_unref (from_folder);
664 from_folder = parent;
665 parent = g_file_get_parent (from_folder);
666 }
667
668 if (parent != NULL) {
669 new_selection = parent_selection =
670 g_list_prepend (NULL, nemo_file_get (from_folder));
671 g_object_unref (parent);
672 }
673
674 g_object_unref (from_folder);
675 }
676
677 end_location_change (slot);
678
679 nemo_window_slot_set_allow_stop (slot, TRUE);
680 nemo_window_slot_set_status (slot, " ", NULL);
681
682 g_assert (slot->pending_location == NULL);
683 g_assert (slot->pending_selection == NULL);
684
685 slot->pending_location = g_object_ref (location);
686 slot->location_change_type = type;
687 slot->location_change_distance = distance;
688 slot->tried_mount = FALSE;
689 slot->pending_selection = eel_g_object_list_copy (new_selection);
690
691 slot->pending_scroll_to = g_strdup (scroll_pos);
692
693 slot->open_callback = callback;
694 slot->open_callback_user_data = user_data;
695
696 directory = nemo_directory_get (location);
697
698 /* The code to force a reload is here because if we do it
699 * after determining an initial view (in the components), then
700 * we end up fetching things twice.
701 */
702 if (type == NEMO_LOCATION_CHANGE_RELOAD || mount) {
703 force_reload = TRUE;
704 } else if (!nemo_monitor_active ()) {
705 force_reload = TRUE;
706 } else {
707 force_reload = !nemo_directory_is_local (directory);
708 }
709
710 if (force_reload) {
711 file = nemo_directory_get_corresponding_file (directory);
712 nemo_file_invalidate_all_attributes (file);
713 nemo_file_unref (file);
714
715 nemo_directory_force_reload (directory);
716
717 }
718
719 nemo_directory_unref (directory);
720
721 if (parent_selection != NULL) {
722 g_list_free_full (parent_selection, g_object_unref);
723 }
724
725 /* Set current_bookmark scroll pos */
726 if (slot->current_location_bookmark != NULL &&
727 slot->content_view != NULL) {
728 current_pos = nemo_view_get_first_visible_file (slot->content_view);
729 nemo_bookmark_set_scroll_pos (slot->current_location_bookmark, current_pos);
730 g_free (current_pos);
731 }
732
733 /* Get the info needed for view selection */
734
735 slot->determine_view_file = nemo_file_get (location);
736 g_assert (slot->determine_view_file != NULL);
737
738 /* if the currently viewed file is marked gone while loading the new location,
739 * this ensures that the window isn't destroyed */
740 cancel_viewed_file_changed_callback (slot);
741
742 nemo_file_call_when_ready (slot->determine_view_file,
743 NEMO_FILE_ATTRIBUTE_INFO |
744 NEMO_FILE_ATTRIBUTE_MOUNT,
745 got_file_info_for_view_selection_callback,
746 slot);
747 }
748
749 typedef struct {
750 GCancellable *cancellable;
751 NemoWindowSlot *slot;
752 } MountNotMountedData;
753
754 static void
mount_not_mounted_callback(GObject * source_object,GAsyncResult * res,gpointer user_data)755 mount_not_mounted_callback (GObject *source_object,
756 GAsyncResult *res,
757 gpointer user_data)
758 {
759 MountNotMountedData *data;
760 NemoWindowSlot *slot;
761 GError *error;
762 GCancellable *cancellable;
763
764 data = user_data;
765 slot = data->slot;
766 cancellable = data->cancellable;
767 g_free (data);
768
769 if (g_cancellable_is_cancelled (cancellable)) {
770 /* Cancelled, don't call back */
771 g_object_unref (cancellable);
772 return;
773 }
774
775 slot->mount_cancellable = NULL;
776
777 slot->determine_view_file = nemo_file_get (slot->pending_location);
778
779 error = NULL;
780 if (!g_file_mount_enclosing_volume_finish (G_FILE (source_object), res, &error)) {
781 slot->mount_error = error;
782 got_file_info_for_view_selection_callback (slot->determine_view_file, slot);
783 slot->mount_error = NULL;
784 g_error_free (error);
785 } else {
786 nemo_file_invalidate_all_attributes (slot->determine_view_file);
787 nemo_file_call_when_ready (slot->determine_view_file,
788 NEMO_FILE_ATTRIBUTE_INFO,
789 got_file_info_for_view_selection_callback,
790 slot);
791 }
792
793 g_object_unref (cancellable);
794 }
795
796 static void
got_file_info_for_view_selection_callback(NemoFile * file,gpointer callback_data)797 got_file_info_for_view_selection_callback (NemoFile *file,
798 gpointer callback_data)
799 {
800 GError *error;
801 char *view_id;
802 char *mimetype;
803 NemoWindow *window;
804 NemoWindowSlot *slot;
805 NemoFile *parent_file, *tmp;
806 GFile *location;
807 GMountOperation *mount_op;
808 MountNotMountedData *data;
809 NemoApplication *app;
810
811 slot = callback_data;
812 window = nemo_window_slot_get_window (slot);
813
814 g_assert (slot->determine_view_file == file);
815 slot->determine_view_file = NULL;
816
817 if (slot->mount_error) {
818 error = slot->mount_error;
819 } else {
820 error = nemo_file_get_file_info_error (file);
821 }
822
823 if (error && error->domain == G_IO_ERROR && error->code == G_IO_ERROR_NOT_MOUNTED &&
824 !slot->tried_mount) {
825 slot->tried_mount = TRUE;
826
827 mount_op = gtk_mount_operation_new (GTK_WINDOW (window));
828 g_mount_operation_set_password_save (mount_op, G_PASSWORD_SAVE_FOR_SESSION);
829 location = nemo_file_get_location (file);
830 data = g_new0 (MountNotMountedData, 1);
831 data->cancellable = g_cancellable_new ();
832 data->slot = slot;
833 slot->mount_cancellable = data->cancellable;
834 g_file_mount_enclosing_volume (location, 0, mount_op, slot->mount_cancellable,
835 mount_not_mounted_callback, data);
836 g_object_unref (location);
837 g_object_unref (mount_op);
838
839 nemo_file_unref (file);
840
841 return;
842 }
843
844 parent_file = nemo_file_get_parent (file);
845 if ((parent_file != NULL) &&
846 nemo_file_get_file_type (file) == G_FILE_TYPE_REGULAR) {
847 if (slot->pending_selection != NULL) {
848 g_list_free_full (slot->pending_selection, (GDestroyNotify) nemo_file_unref);
849 }
850
851 g_clear_object (&slot->pending_location);
852 g_free (slot->pending_scroll_to);
853
854 slot->pending_location = nemo_file_get_parent_location (file);
855 slot->pending_selection = g_list_prepend (NULL, nemo_file_ref (file));
856 slot->determine_view_file = parent_file;
857 slot->pending_scroll_to = nemo_file_get_uri (file);
858
859 nemo_file_invalidate_all_attributes (slot->determine_view_file);
860 nemo_file_call_when_ready (slot->determine_view_file,
861 NEMO_FILE_ATTRIBUTE_INFO,
862 got_file_info_for_view_selection_callback,
863 slot);
864
865 nemo_file_unref (file);
866
867 return;
868 }
869
870 nemo_file_unref (parent_file);
871 location = slot->pending_location;
872
873 view_id = NULL;
874
875 if (error == NULL ||
876 (error->domain == G_IO_ERROR && error->code == G_IO_ERROR_NOT_SUPPORTED)) {
877 /* We got the information we need, now pick what view to use: */
878
879 mimetype = nemo_file_get_mime_type (file);
880
881 /* Look in metadata for view */
882 if (nemo_global_preferences_get_inherit_folder_viewer_preference ()) {
883 if (nemo_global_preferences_get_ignore_view_metadata ()) {
884 view_id = g_strdup (nemo_window_get_ignore_meta_view_id (window));
885 } else {
886 parent_file = file;
887 nemo_file_ref(parent_file); // Do this once for the initial file
888 while (parent_file) {
889 view_id = nemo_file_get_metadata (parent_file, NEMO_METADATA_KEY_DEFAULT_VIEW, NULL);
890 tmp = nemo_file_get_parent (parent_file);
891 nemo_file_unref(parent_file);
892 if (view_id != NULL) {
893 parent_file = NULL;
894 } else {
895 parent_file = tmp;
896 }
897 }
898 }
899 } else {
900 view_id = nemo_global_preferences_get_ignore_view_metadata () ? g_strdup (nemo_window_get_ignore_meta_view_id (window)) :
901 nemo_file_get_metadata (file, NEMO_METADATA_KEY_DEFAULT_VIEW, NULL);
902 }
903
904 if (view_id != NULL &&
905 !nemo_view_factory_view_supports_uri (view_id,
906 location,
907 nemo_file_get_file_type (file),
908 mimetype)) {
909 g_free (view_id);
910 view_id = NULL;
911 }
912
913 /* Otherwise, use default */
914 if (view_id == NULL) {
915 gchar *name, *uri;
916 name = nemo_file_get_name (file);
917 uri = nemo_file_get_uri (file);
918
919 if (g_strcmp0 (name, "x-nemo-search") == 0) {
920 view_id = g_strdup (NEMO_LIST_VIEW_IID);
921 } else if (eel_uri_is_desktop (uri)) {
922 view_id = nemo_global_preferences_get_desktop_iid ();
923 } else {
924 view_id = nemo_global_preferences_get_default_folder_viewer_preference_as_iid ();
925 }
926
927 g_free (uri);
928 g_free (name);
929
930 if (view_id != NULL &&
931 !nemo_view_factory_view_supports_uri (view_id,
932 location,
933 nemo_file_get_file_type (file),
934 mimetype)) {
935 g_free (view_id);
936 view_id = NULL;
937 }
938 }
939
940 g_free (mimetype);
941 }
942
943 if (view_id != NULL) {
944 create_content_view (slot, view_id);
945 g_free (view_id);
946
947 report_callback (slot, NULL);
948 } else {
949 if (!report_callback (slot, error)) {
950 display_view_selection_failure (window, file,
951 location, error);
952 }
953
954 if (!gtk_widget_get_visible (GTK_WIDGET (window))) {
955 /* Destroy never-had-a-chance-to-be-seen window. This case
956 * happens when a new window cannot display its initial URI.
957 */
958 /* if this is the only window, we don't want to quit, so we redirect it to home */
959
960 app = nemo_application_get_singleton ();
961
962 if (g_list_length (gtk_application_get_windows (GTK_APPLICATION (app))) == 1) {
963 /* the user could have typed in a home directory that doesn't exist,
964 in which case going home would cause an infinite loop, so we
965 better test for that */
966
967 if (!nemo_is_root_directory (location)) {
968 if (!nemo_is_home_directory (location)) {
969 nemo_window_slot_go_home (slot, FALSE);
970 } else {
971 GFile *root;
972
973 root = g_file_new_for_path ("/");
974 /* the last fallback is to go to a known place that can't be deleted! */
975 nemo_window_slot_open_location (slot, location, 0);
976 g_object_unref (root);
977 }
978 } else {
979 gtk_widget_destroy (GTK_WIDGET (window));
980 }
981 } else {
982 /* Since this is a window, destroying it will also unref it. */
983 gtk_widget_destroy (GTK_WIDGET (window));
984 }
985 } else {
986 /* Clean up state of already-showing window */
987 end_location_change (slot);
988
989 /* TODO? shouldn't we call
990 * cancel_viewed_file_changed_callback (slot);
991 * at this point, or in end_location_change()
992 */
993 /* We're missing a previous location (if opened location
994 * in a new tab) so close it and return */
995 if (slot->location == NULL) {
996 nemo_window_pane_close_slot (slot->pane, slot);
997 } else {
998 /* We disconnected this, so we need to re-connect it */
999 NemoFile *viewed_file;
1000 viewed_file = nemo_file_get (slot->location);
1001 nemo_window_slot_set_viewed_file (slot, viewed_file);
1002 nemo_file_monitor_add (viewed_file, &slot->viewed_file, 0);
1003 g_signal_connect_object (viewed_file, "changed",
1004 G_CALLBACK (viewed_file_changed_callback), slot, 0);
1005 nemo_file_unref (viewed_file);
1006
1007 /* Leave the location bar showing the bad location that the user
1008 * typed (or maybe achieved by dragging or something). Many times
1009 * the mistake will just be an easily-correctable typo. The user
1010 * can choose "Refresh" to get the original URI back in the location bar.
1011 */
1012 }
1013 }
1014 }
1015
1016 nemo_file_unref (file);
1017 }
1018
1019 /* Load a view into the window, either reusing the old one or creating
1020 * a new one. This happens when you want to load a new location, or just
1021 * switch to a different view.
1022 * If pending_location is set we're loading a new location and
1023 * pending_location/selection will be used. If not, we're just switching
1024 * view, and the current location will be used.
1025 */
1026 static void
create_content_view(NemoWindowSlot * slot,const char * view_id)1027 create_content_view (NemoWindowSlot *slot,
1028 const char *view_id)
1029 {
1030 NemoWindow *window;
1031 NemoView *view;
1032 GList *selection;
1033
1034 window = nemo_window_slot_get_window (slot);
1035
1036 if (slot->content_view != NULL &&
1037 g_strcmp0 (nemo_view_get_view_id (slot->content_view),
1038 view_id) == 0) {
1039 /* reuse existing content view */
1040 view = slot->content_view;
1041 slot->new_content_view = view;
1042 g_object_ref (view);
1043 } else {
1044 /* create a new content view */
1045 view = nemo_view_factory_create (view_id, slot);
1046 slot->new_content_view = view;
1047 nemo_window_connect_content_view (window, slot->new_content_view);
1048 }
1049
1050 if (NEMO_IS_DESKTOP_WINDOW (window)) {
1051 NemoDesktopDirectory *directory;
1052
1053 directory = NEMO_DESKTOP_DIRECTORY (nemo_directory_get (slot->pending_location));
1054 directory->display_number = nemo_desktop_window_get_monitor (NEMO_DESKTOP_WINDOW (window));
1055
1056 nemo_directory_unref (NEMO_DIRECTORY (directory));
1057 }
1058
1059 /* Actually load the pending location and selection: */
1060
1061 if (slot->pending_location != NULL) {
1062 load_new_location (slot,
1063 slot->pending_location,
1064 slot->pending_selection,
1065 FALSE,
1066 TRUE);
1067
1068 g_list_free_full (slot->pending_selection, g_object_unref);
1069 slot->pending_selection = NULL;
1070 } else if (slot->location != NULL) {
1071 selection = nemo_view_get_selection (slot->content_view);
1072 load_new_location (slot,
1073 slot->location,
1074 selection,
1075 FALSE,
1076 TRUE);
1077 g_list_free_full (selection, g_object_unref);
1078 } else {
1079 /* Something is busted, there was no location to load.
1080 Just load the homedir. */
1081 nemo_window_slot_go_home (slot, FALSE);
1082
1083 }
1084 }
1085
1086 static void
load_new_location(NemoWindowSlot * slot,GFile * location,GList * selection,gboolean tell_current_content_view,gboolean tell_new_content_view)1087 load_new_location (NemoWindowSlot *slot,
1088 GFile *location,
1089 GList *selection,
1090 gboolean tell_current_content_view,
1091 gboolean tell_new_content_view)
1092 {
1093 GList *selection_copy;
1094 NemoView *view;
1095
1096 g_assert (slot != NULL);
1097 g_assert (location != NULL);
1098
1099 selection_copy = eel_g_object_list_copy (selection);
1100 view = NULL;
1101
1102 /* Note, these may recurse into report_load_underway */
1103 if (slot->content_view != NULL && tell_current_content_view) {
1104 view = slot->content_view;
1105 nemo_view_load_location (slot->content_view, location);
1106 }
1107
1108 if (slot->new_content_view != NULL && tell_new_content_view &&
1109 (!tell_current_content_view ||
1110 slot->new_content_view != slot->content_view) ) {
1111 view = slot->new_content_view;
1112 nemo_view_load_location (slot->new_content_view, location);
1113 }
1114 if (view != NULL) {
1115 /* slot->new_content_view might have changed here if
1116 report_load_underway was called from load_location */
1117 nemo_view_set_selection (view, selection_copy);
1118 }
1119
1120 g_list_free_full (selection_copy, g_object_unref);
1121 }
1122
1123 /* A view started to load the location its viewing, either due to
1124 * a load_location request, or some internal reason. Expect
1125 * a matching load_compete later
1126 */
1127 void
nemo_window_report_load_underway(NemoWindow * window,NemoView * view)1128 nemo_window_report_load_underway (NemoWindow *window,
1129 NemoView *view)
1130 {
1131 NemoWindowSlot *slot;
1132
1133 g_assert (NEMO_IS_WINDOW (window));
1134
1135 if (window->details->temporarily_ignore_view_signals) {
1136 return;
1137 }
1138
1139 slot = nemo_window_get_slot_for_view (window, view);
1140 g_assert (slot != NULL);
1141
1142 if (view == slot->new_content_view) {
1143 location_has_really_changed (slot);
1144 } else {
1145 nemo_window_slot_set_allow_stop (slot, TRUE);
1146 }
1147 }
1148
1149 static void
nemo_window_emit_location_change(NemoWindow * window,GFile * location)1150 nemo_window_emit_location_change (NemoWindow *window,
1151 GFile *location)
1152 {
1153 char *uri;
1154
1155 uri = g_file_get_uri (location);
1156 g_signal_emit_by_name (window, "loading_uri", uri);
1157 g_free (uri);
1158 }
1159
1160 static void
nemo_window_slot_emit_location_change(NemoWindowSlot * slot,GFile * from,GFile * to)1161 nemo_window_slot_emit_location_change (NemoWindowSlot *slot,
1162 GFile *from,
1163 GFile *to)
1164 {
1165 char *from_uri = NULL;
1166 char *to_uri = NULL;
1167
1168 if (from != NULL)
1169 from_uri = g_file_get_uri (from);
1170 if (to != NULL)
1171 to_uri = g_file_get_uri (to);
1172 g_signal_emit_by_name (slot, "location-changed", from_uri, to_uri);
1173 g_free (to_uri);
1174 g_free (from_uri);
1175 }
1176
1177 /* reports location change to window's "loading-uri" clients, i.e.
1178 * sidebar panels [used when switching tabs]. It will emit the pending
1179 * location, or the existing location if none is pending.
1180 */
1181 void
nemo_window_report_location_change(NemoWindow * window)1182 nemo_window_report_location_change (NemoWindow *window)
1183 {
1184 NemoWindowSlot *slot;
1185 GFile *location;
1186
1187 slot = nemo_window_get_active_slot (window);
1188 g_assert (NEMO_IS_WINDOW_SLOT (slot));
1189
1190 location = NULL;
1191
1192 if (slot->pending_location != NULL) {
1193 location = slot->pending_location;
1194 }
1195
1196 if (location == NULL && slot->location != NULL) {
1197 location = slot->location;
1198 }
1199
1200 if (location != NULL) {
1201 nemo_window_emit_location_change (window, location);
1202 }
1203 }
1204
1205 static void
real_setup_loading_floating_bar(NemoWindowSlot * slot)1206 real_setup_loading_floating_bar (NemoWindowSlot *slot)
1207 {
1208 gboolean disable_chrome;
1209
1210 g_object_get (nemo_window_slot_get_window (slot),
1211 "disable-chrome", &disable_chrome,
1212 NULL);
1213
1214 if (disable_chrome) {
1215 gtk_widget_hide (slot->floating_bar);
1216 return;
1217 }
1218
1219 nemo_floating_bar_set_label (NEMO_FLOATING_BAR (slot->floating_bar),
1220 NEMO_IS_SEARCH_DIRECTORY (nemo_view_get_model (slot->content_view)) ?
1221 _("Searching...") : _("Loading..."));
1222 nemo_floating_bar_set_show_spinner (NEMO_FLOATING_BAR (slot->floating_bar),
1223 TRUE);
1224 nemo_floating_bar_add_action (NEMO_FLOATING_BAR (slot->floating_bar),
1225 GTK_STOCK_STOP,
1226 NEMO_FLOATING_BAR_ACTION_ID_STOP);
1227
1228 gtk_widget_set_halign (slot->floating_bar, GTK_ALIGN_END);
1229 gtk_widget_show (slot->floating_bar);
1230 }
1231
1232 static gboolean
setup_loading_floating_bar_timeout_cb(gpointer user_data)1233 setup_loading_floating_bar_timeout_cb (gpointer user_data)
1234 {
1235 NemoWindowSlot *slot = user_data;
1236
1237 slot->loading_timeout_id = 0;
1238 real_setup_loading_floating_bar (slot);
1239
1240 return FALSE;
1241 }
1242
1243 static void
setup_loading_floating_bar(NemoWindowSlot * slot)1244 setup_loading_floating_bar (NemoWindowSlot *slot)
1245 {
1246 /* setup loading overlay */
1247 if (slot->set_status_timeout_id != 0) {
1248 g_source_remove (slot->set_status_timeout_id);
1249 slot->set_status_timeout_id = 0;
1250 }
1251
1252 if (slot->loading_timeout_id != 0) {
1253 g_source_remove (slot->loading_timeout_id);
1254 slot->loading_timeout_id = 0;
1255 }
1256
1257 slot->loading_timeout_id =
1258 g_timeout_add (500, setup_loading_floating_bar_timeout_cb, slot);
1259 }
1260
1261 /* This is called when we have decided we can actually change to the new view/location situation. */
1262 static void
location_has_really_changed(NemoWindowSlot * slot)1263 location_has_really_changed (NemoWindowSlot *slot)
1264 {
1265 NemoWindow *window;
1266 GtkWidget *widget;
1267 GFile *location_copy;
1268
1269 window = nemo_window_slot_get_window (slot);
1270
1271 if (slot->new_content_view != NULL) {
1272 widget = GTK_WIDGET (slot->new_content_view);
1273 /* Switch to the new content view. */
1274 if (gtk_widget_get_parent (widget) == NULL) {
1275 nemo_window_slot_set_content_view_widget (slot, slot->new_content_view);
1276 }
1277 g_object_unref (slot->new_content_view);
1278 slot->new_content_view = NULL;
1279 }
1280
1281 if (slot->pending_location != NULL) {
1282 /* Tell the window we are finished. */
1283 update_for_new_location (slot);
1284 }
1285
1286 location_copy = NULL;
1287 if (slot->location != NULL) {
1288 location_copy = g_object_ref (slot->location);
1289 }
1290
1291 free_location_change (slot);
1292
1293 if (location_copy != NULL) {
1294 if (slot == nemo_window_get_active_slot (window)) {
1295 nemo_window_emit_location_change (window, location_copy);
1296 }
1297
1298 g_object_unref (location_copy);
1299 }
1300
1301 setup_loading_floating_bar (slot);
1302 }
1303
1304 static void
slot_add_extension_extra_widgets(NemoWindowSlot * slot)1305 slot_add_extension_extra_widgets (NemoWindowSlot *slot)
1306 {
1307 GList *providers, *l;
1308 GtkWidget *widget;
1309 char *uri;
1310 NemoWindow *window;
1311
1312 providers = nemo_module_get_extensions_for_type (NEMO_TYPE_LOCATION_WIDGET_PROVIDER);
1313 window = nemo_window_slot_get_window (slot);
1314
1315 uri = g_file_get_uri (slot->location);
1316 for (l = providers; l != NULL; l = l->next) {
1317 NemoLocationWidgetProvider *provider;
1318
1319 provider = NEMO_LOCATION_WIDGET_PROVIDER (l->data);
1320 widget = nemo_location_widget_provider_get_widget (provider, uri, GTK_WIDGET (window));
1321 if (widget != NULL) {
1322 nemo_window_slot_add_extra_location_widget (slot, widget);
1323 }
1324 }
1325 g_free (uri);
1326
1327 nemo_module_extension_list_free (providers);
1328 }
1329
1330 static void
nemo_window_slot_show_x_content_bar(NemoWindowSlot * slot,GMount * mount,const char ** x_content_types)1331 nemo_window_slot_show_x_content_bar (NemoWindowSlot *slot, GMount *mount, const char **x_content_types)
1332 {
1333 unsigned int n;
1334
1335 g_assert (NEMO_IS_WINDOW_SLOT (slot));
1336
1337 for (n = 0; x_content_types[n] != NULL; n++) {
1338 GAppInfo *default_app;
1339
1340 /* skip blank media; the burn:/// location will provide it's own cluebar */
1341 if (g_str_has_prefix (x_content_types[n], "x-content/blank-")) {
1342 continue;
1343 }
1344
1345 /* don't show the cluebar for windows software */
1346 if (g_content_type_is_a (x_content_types[n], "x-content/win32-software")) {
1347 continue;
1348 }
1349
1350 /* only show the cluebar if a default app is available */
1351 default_app = g_app_info_get_default_for_type (x_content_types[n], FALSE);
1352 if (default_app != NULL) {
1353 GtkWidget *bar;
1354 bar = nemo_x_content_bar_new (mount, x_content_types[n]);
1355 gtk_widget_show (bar);
1356 nemo_window_slot_add_extra_location_widget (slot, bar);
1357 g_object_unref (default_app);
1358 }
1359 }
1360 }
1361
1362 static void
nemo_window_slot_show_trash_bar(NemoWindowSlot * slot)1363 nemo_window_slot_show_trash_bar (NemoWindowSlot *slot)
1364 {
1365 GtkWidget *bar;
1366 NemoView *view;
1367
1368 view = nemo_window_slot_get_current_view (slot);
1369 bar = nemo_trash_bar_new (view);
1370 gtk_widget_show (bar);
1371
1372 nemo_window_slot_add_extra_location_widget (slot, bar);
1373 }
1374
1375 static void
maybe_show_interesting_folder_bar(NemoWindowSlot * slot)1376 maybe_show_interesting_folder_bar (NemoWindowSlot *slot)
1377 {
1378 GtkWidget *bar = nemo_interesting_folder_bar_new_for_location (nemo_window_slot_get_current_view(slot),
1379 slot->location);
1380
1381 if (bar) {
1382 gtk_widget_show (bar);
1383 nemo_window_slot_add_extra_location_widget (slot, bar);
1384 }
1385 }
1386
1387 typedef struct {
1388 NemoWindowSlot *slot;
1389 GCancellable *cancellable;
1390 GMount *mount;
1391 } FindMountData;
1392
1393 static void
found_content_type_cb(const char ** x_content_types,gpointer user_data)1394 found_content_type_cb (const char **x_content_types,
1395 gpointer user_data)
1396 {
1397 NemoWindowSlot *slot;
1398 FindMountData *data = user_data;
1399
1400 if (g_cancellable_is_cancelled (data->cancellable)) {
1401 goto out;
1402 }
1403
1404 slot = data->slot;
1405
1406 if (x_content_types != NULL && x_content_types[0] != NULL) {
1407 nemo_window_slot_show_x_content_bar (slot, data->mount, x_content_types);
1408 }
1409
1410 slot->find_mount_cancellable = NULL;
1411
1412 out:
1413 g_object_unref (data->mount);
1414 g_object_unref (data->cancellable);
1415 g_free (data);
1416 }
1417
1418 static void
found_mount_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)1419 found_mount_cb (GObject *source_object,
1420 GAsyncResult *res,
1421 gpointer user_data)
1422 {
1423 FindMountData *data = user_data;
1424 GMount *mount;
1425
1426 if (g_cancellable_is_cancelled (data->cancellable)) {
1427 goto out;
1428 }
1429
1430 mount = g_file_find_enclosing_mount_finish (G_FILE (source_object),
1431 res,
1432 NULL);
1433 if (mount != NULL) {
1434 data->mount = mount;
1435 nemo_get_x_content_types_for_mount_async (mount,
1436 found_content_type_cb,
1437 data->cancellable,
1438 data);
1439 return;
1440 }
1441
1442 data->slot->find_mount_cancellable = NULL;
1443
1444 out:
1445 g_object_unref (data->cancellable);
1446 g_free (data);
1447 }
1448
1449 /* Handle the changes for the NemoWindow itself. */
1450 static void
update_for_new_location(NemoWindowSlot * slot)1451 update_for_new_location (NemoWindowSlot *slot)
1452 {
1453 NemoWindow *window;
1454 GFile *new_location;
1455 NemoFile *file;
1456 NemoDirectory *directory;
1457 gboolean location_really_changed;
1458 FindMountData *data;
1459
1460 window = nemo_window_slot_get_window (slot);
1461 new_location = slot->pending_location;
1462 slot->pending_location = NULL;
1463
1464 set_displayed_location (slot, new_location);
1465
1466 update_history (slot, slot->location_change_type, new_location);
1467
1468 location_really_changed =
1469 slot->location == NULL ||
1470 !g_file_equal (slot->location, new_location);
1471
1472 nemo_window_slot_emit_location_change (slot, slot->location, new_location);
1473
1474 /* Set the new location. */
1475 g_clear_object (&slot->location);
1476 slot->location = new_location;
1477
1478 /* Create a NemoFile for this location, so we can catch it
1479 * if it goes away.
1480 */
1481 cancel_viewed_file_changed_callback (slot);
1482 file = nemo_file_get (slot->location);
1483 nemo_window_slot_set_viewed_file (slot, file);
1484 slot->viewed_file_seen = !nemo_file_is_not_yet_confirmed (file);
1485 slot->viewed_file_in_trash = nemo_file_is_in_trash (file);
1486 nemo_file_monitor_add (file, &slot->viewed_file, 0);
1487 g_signal_connect_object (file, "changed",
1488 G_CALLBACK (viewed_file_changed_callback), slot, 0);
1489 nemo_file_unref (file);
1490
1491 if (slot == nemo_window_get_active_slot (window)) {
1492 /* Sync up and zoom action states */
1493 nemo_window_sync_up_button (window);
1494 nemo_window_sync_zoom_widgets (window);
1495 nemo_window_sync_bookmark_action (window);
1496 nemo_window_sync_view_type (window);
1497 nemo_window_sync_thumbnail_action(window);
1498
1499 /* Load menus from nemo extensions for this location */
1500 nemo_window_load_extension_menus (window);
1501 }
1502
1503 if (location_really_changed) {
1504 nemo_window_slot_remove_extra_location_widgets (slot);
1505
1506 directory = nemo_directory_get (slot->location);
1507
1508 if (nemo_directory_is_in_trash (directory)) {
1509 nemo_window_slot_show_trash_bar (slot);
1510 }
1511
1512 maybe_show_interesting_folder_bar (slot);
1513
1514 nemo_window_slot_check_bad_cache_bar (slot);
1515
1516 /* need the mount to determine if we should put up the x-content cluebar */
1517 if (slot->find_mount_cancellable != NULL) {
1518 g_cancellable_cancel (slot->find_mount_cancellable);
1519 slot->find_mount_cancellable = NULL;
1520 }
1521
1522 data = g_new (FindMountData, 1);
1523 data->slot = slot;
1524 data->cancellable = g_cancellable_new ();
1525 data->mount = NULL;
1526
1527 slot->find_mount_cancellable = data->cancellable;
1528 g_file_find_enclosing_mount_async (slot->location,
1529 G_PRIORITY_DEFAULT,
1530 data->cancellable,
1531 found_mount_cb,
1532 data);
1533
1534 nemo_directory_unref (directory);
1535
1536 slot_add_extension_extra_widgets (slot);
1537 }
1538
1539 nemo_window_slot_update_title (slot);
1540 nemo_window_slot_update_icon (slot);
1541
1542 if (slot == slot->pane->active_slot) {
1543 nemo_window_pane_sync_location_widgets (slot->pane);
1544
1545 if (location_really_changed) {
1546 nemo_window_pane_sync_search_widgets (slot->pane);
1547 }
1548 }
1549
1550 nemo_window_sync_menu_bar (window);
1551 }
1552
1553 /* A location load previously announced by load_underway
1554 * has been finished */
1555 void
nemo_window_report_load_complete(NemoWindow * window,NemoView * view)1556 nemo_window_report_load_complete (NemoWindow *window,
1557 NemoView *view)
1558 {
1559 NemoWindowSlot *slot;
1560
1561 g_assert (NEMO_IS_WINDOW (window));
1562
1563 if (window->details->temporarily_ignore_view_signals) {
1564 return;
1565 }
1566
1567 slot = nemo_window_get_slot_for_view (window, view);
1568 g_assert (slot != NULL);
1569
1570 /* Only handle this if we're expecting it.
1571 * Don't handle it if its from an old view we've switched from */
1572 if (view == slot->content_view) {
1573 if (slot->pending_scroll_to != NULL) {
1574 nemo_view_scroll_to_file (slot->content_view,
1575 slot->pending_scroll_to);
1576 }
1577 end_location_change (slot);
1578 }
1579 }
1580
1581 static void
remove_loading_floating_bar(NemoWindowSlot * slot)1582 remove_loading_floating_bar (NemoWindowSlot *slot)
1583 {
1584 if (slot->loading_timeout_id != 0) {
1585 g_source_remove (slot->loading_timeout_id);
1586 slot->loading_timeout_id = 0;
1587 }
1588
1589 gtk_widget_hide (slot->floating_bar);
1590 nemo_floating_bar_cleanup_actions (NEMO_FLOATING_BAR (slot->floating_bar));
1591 }
1592
1593 static void
end_location_change(NemoWindowSlot * slot)1594 end_location_change (NemoWindowSlot *slot)
1595 {
1596 char *uri;
1597
1598 uri = nemo_window_slot_get_location_uri (slot);
1599 if (uri) {
1600 DEBUG ("Finished loading window for uri %s", uri);
1601 g_free (uri);
1602 }
1603
1604 nemo_window_slot_set_allow_stop (slot, FALSE);
1605 remove_loading_floating_bar (slot);
1606
1607 /* Now we can free pending_scroll_to, since the load_complete
1608 * callback already has been emitted.
1609 */
1610 g_free (slot->pending_scroll_to);
1611 slot->pending_scroll_to = NULL;
1612
1613 free_location_change (slot);
1614 }
1615
1616 static void
free_location_change(NemoWindowSlot * slot)1617 free_location_change (NemoWindowSlot *slot)
1618 {
1619 NemoWindow *window;
1620
1621 window = nemo_window_slot_get_window (slot);
1622
1623 g_clear_object (&slot->pending_location);
1624 g_list_free_full (slot->pending_selection, g_object_unref);
1625 slot->pending_selection = NULL;
1626
1627 /* Don't free pending_scroll_to, since thats needed until
1628 * the load_complete callback.
1629 */
1630
1631 if (slot->mount_cancellable != NULL) {
1632 g_cancellable_cancel (slot->mount_cancellable);
1633 slot->mount_cancellable = NULL;
1634 }
1635
1636 if (slot->determine_view_file != NULL) {
1637 nemo_file_cancel_call_when_ready
1638 (slot->determine_view_file,
1639 got_file_info_for_view_selection_callback, slot);
1640 slot->determine_view_file = NULL;
1641 }
1642
1643 if (slot->new_content_view != NULL) {
1644 window->details->temporarily_ignore_view_signals = TRUE;
1645 nemo_view_stop_loading (slot->new_content_view);
1646 window->details->temporarily_ignore_view_signals = FALSE;
1647
1648 nemo_window_disconnect_content_view (window, slot->new_content_view);
1649 g_object_unref (slot->new_content_view);
1650 slot->new_content_view = NULL;
1651 }
1652 }
1653
1654 static void
cancel_location_change(NemoWindowSlot * slot)1655 cancel_location_change (NemoWindowSlot *slot)
1656 {
1657 GList *selection;
1658
1659 if (slot->pending_location != NULL
1660 && slot->location != NULL
1661 && slot->content_view != NULL) {
1662
1663 /* No need to tell the new view - either it is the
1664 * same as the old view, in which case it will already
1665 * be told, or it is the very pending change we wish
1666 * to cancel.
1667 */
1668 selection = nemo_view_get_selection (slot->content_view);
1669 load_new_location (slot,
1670 slot->location,
1671 selection,
1672 TRUE,
1673 FALSE);
1674 g_list_free_full (selection, g_object_unref);
1675 }
1676
1677 end_location_change (slot);
1678 }
1679
1680 static void
display_view_selection_failure(NemoWindow * window,NemoFile * file,GFile * location,GError * error)1681 display_view_selection_failure (NemoWindow *window, NemoFile *file,
1682 GFile *location, GError *error)
1683 {
1684 char *full_uri_for_display;
1685 char *uri_for_display;
1686 char *error_message;
1687 char *detail_message;
1688 char *scheme_string;
1689
1690 /* Some sort of failure occurred. How 'bout we tell the user? */
1691 full_uri_for_display = g_file_get_parse_name (location);
1692 /* Truncate the URI so it doesn't get insanely wide. Note that even
1693 * though the dialog uses wrapped text, if the URI doesn't contain
1694 * white space then the text-wrapping code is too stupid to wrap it.
1695 */
1696 uri_for_display = eel_str_middle_truncate
1697 (full_uri_for_display, MAX_URI_IN_DIALOG_LENGTH);
1698 g_free (full_uri_for_display);
1699
1700 error_message = NULL;
1701 detail_message = NULL;
1702 if (error == NULL) {
1703 if (nemo_file_is_directory (file)) {
1704 error_message = g_strdup_printf
1705 (_("Could not display \"%s\"."),
1706 uri_for_display);
1707 detail_message = g_strdup
1708 (_("Nemo has no installed viewer capable of displaying the folder."));
1709 } else {
1710 error_message = g_strdup_printf
1711 (_("Could not display \"%s\"."),
1712 uri_for_display);
1713 detail_message = g_strdup
1714 (_("The location is not a folder."));
1715 }
1716 } else if (error->domain == G_IO_ERROR) {
1717 switch (error->code) {
1718 case G_IO_ERROR_NOT_FOUND:
1719 error_message = g_strdup_printf
1720 (_("Could not find \"%s\"."),
1721 uri_for_display);
1722 detail_message = g_strdup
1723 (_("Please check the spelling and try again."));
1724 break;
1725 case G_IO_ERROR_NOT_SUPPORTED:
1726 scheme_string = g_file_get_uri_scheme (location);
1727
1728 error_message = g_strdup_printf (_("Could not display \"%s\"."),
1729 uri_for_display);
1730 if (scheme_string != NULL) {
1731 detail_message = g_strdup_printf (_("Nemo cannot handle \"%s\" locations."),
1732 scheme_string);
1733 } else {
1734 detail_message = g_strdup (_("Nemo cannot handle this kind of location."));
1735 }
1736 g_free (scheme_string);
1737 break;
1738 case G_IO_ERROR_NOT_MOUNTED:
1739 error_message = g_strdup_printf (_("Could not display \"%s\"."),
1740 uri_for_display);
1741 detail_message = g_strdup (_("Unable to mount the location."));
1742 break;
1743
1744 case G_IO_ERROR_PERMISSION_DENIED:
1745 error_message = g_strdup_printf (_("Could not display \"%s\"."),
1746 uri_for_display);
1747 detail_message = g_strdup (_("Access was denied."));
1748 break;
1749
1750 case G_IO_ERROR_HOST_NOT_FOUND:
1751 /* This case can be hit for user-typed strings like "foo" due to
1752 * the code that guesses web addresses when there's no initial "/".
1753 * But this case is also hit for legitimate web addresses when
1754 * the proxy is set up wrong.
1755 */
1756 error_message = g_strdup_printf (_("Could not display \"%s\", because the host could not be found."),
1757 uri_for_display);
1758 detail_message = g_strdup (_("Check that the spelling is correct and that your proxy settings are correct."));
1759 break;
1760 case G_IO_ERROR_CANCELLED:
1761 case G_IO_ERROR_FAILED_HANDLED:
1762 g_free (uri_for_display);
1763 return;
1764
1765 default:
1766 break;
1767 }
1768 }
1769
1770 if (error_message == NULL) {
1771 error_message = g_strdup_printf (_("Could not display \"%s\"."),
1772 uri_for_display);
1773 detail_message = g_strdup_printf (_("Error: %s\nPlease select another viewer and try again."), error->message);
1774 }
1775
1776 eel_show_error_dialog (error_message, detail_message, NULL);
1777
1778 g_free (uri_for_display);
1779 g_free (error_message);
1780 g_free (detail_message);
1781 }
1782
1783
1784 void
nemo_window_slot_stop_loading(NemoWindowSlot * slot)1785 nemo_window_slot_stop_loading (NemoWindowSlot *slot)
1786 {
1787 NemoWindow *window;
1788
1789 window = nemo_window_slot_get_window (slot);
1790
1791 nemo_view_stop_loading (slot->content_view);
1792
1793 if (slot->new_content_view != NULL) {
1794 window->details->temporarily_ignore_view_signals = TRUE;
1795 nemo_view_stop_loading (slot->new_content_view);
1796 window->details->temporarily_ignore_view_signals = FALSE;
1797 }
1798
1799 cancel_location_change (slot);
1800 }
1801
1802 void
nemo_window_slot_set_content_view(NemoWindowSlot * slot,const char * id)1803 nemo_window_slot_set_content_view (NemoWindowSlot *slot,
1804 const char *id)
1805 {
1806 NemoFile *file;
1807 char *uri;
1808
1809 g_assert (slot != NULL);
1810 g_assert (slot->location != NULL);
1811 g_assert (id != NULL);
1812
1813 uri = nemo_window_slot_get_location_uri (slot);
1814 DEBUG ("Change view of window %s to %s", uri, id);
1815 g_free (uri);
1816
1817 if (nemo_window_slot_content_view_matches_iid (slot, id)) {
1818 return;
1819 }
1820
1821 end_location_change (slot);
1822
1823 file = nemo_file_get (slot->location);
1824
1825 if (nemo_global_preferences_get_ignore_view_metadata ()) {
1826 nemo_window_set_ignore_meta_view_id (nemo_window_slot_get_window (slot), id);
1827 } else {
1828 nemo_file_set_metadata (file, NEMO_METADATA_KEY_DEFAULT_VIEW, NULL, id);
1829 }
1830
1831 nemo_file_unref (file);
1832
1833 nemo_window_slot_set_allow_stop (slot, TRUE);
1834
1835 if (nemo_view_get_selection_count (slot->content_view) == 0) {
1836 /* If there is no selection, queue a scroll to the same icon that
1837 * is currently visible */
1838 slot->pending_scroll_to = nemo_view_get_first_visible_file (slot->content_view);
1839 }
1840 slot->location_change_type = NEMO_LOCATION_CHANGE_RELOAD;
1841
1842 create_content_view (slot, id);
1843 }
1844
1845 void
nemo_window_manage_views_close_slot(NemoWindowSlot * slot)1846 nemo_window_manage_views_close_slot (NemoWindowSlot *slot)
1847 {
1848 if (slot->content_view != NULL) {
1849 nemo_window_disconnect_content_view (nemo_window_slot_get_window (slot),
1850 slot->content_view);
1851 }
1852
1853 free_location_change (slot);
1854 cancel_viewed_file_changed_callback (slot);
1855 }
1856
1857 void
nemo_window_back_or_forward(NemoWindow * window,gboolean back,guint distance,NemoWindowOpenFlags flags)1858 nemo_window_back_or_forward (NemoWindow *window,
1859 gboolean back,
1860 guint distance,
1861 NemoWindowOpenFlags flags)
1862 {
1863 NemoWindowSlot *slot;
1864 GList *list;
1865 GFile *location;
1866 guint len;
1867 NemoBookmark *bookmark;
1868 GFile *old_location;
1869
1870 slot = nemo_window_get_active_slot (window);
1871 list = back ? slot->back_list : slot->forward_list;
1872
1873 len = (guint) g_list_length (list);
1874
1875 /* If we can't move in the direction at all, just return. */
1876 if (len == 0)
1877 return;
1878
1879 /* If the distance to move is off the end of the list, go to the end
1880 of the list. */
1881 if (distance >= len)
1882 distance = len - 1;
1883
1884 bookmark = g_list_nth_data (list, distance);
1885 location = nemo_bookmark_get_location (bookmark);
1886
1887 if (flags != 0) {
1888 nemo_window_slot_open_location (slot, location, flags);
1889 } else {
1890 char *scroll_pos;
1891
1892 old_location = nemo_window_slot_get_location (slot);
1893 scroll_pos = nemo_bookmark_get_scroll_pos (bookmark);
1894 begin_location_change
1895 (slot,
1896 location, old_location, NULL,
1897 back ? NEMO_LOCATION_CHANGE_BACK : NEMO_LOCATION_CHANGE_FORWARD,
1898 distance,
1899 scroll_pos,
1900 FALSE,
1901 NULL, NULL);
1902
1903 g_clear_object (&old_location);
1904 g_free (scroll_pos);
1905 }
1906
1907 g_object_unref (location);
1908 }
1909
1910 /* reload the contents of the window */
1911 void
nemo_window_slot_force_reload(NemoWindowSlot * slot)1912 nemo_window_slot_force_reload (NemoWindowSlot *slot)
1913 {
1914 GFile *location;
1915 char *current_pos;
1916 GList *selection;
1917
1918 g_assert (NEMO_IS_WINDOW_SLOT (slot));
1919
1920 if (slot->location == NULL) {
1921 return;
1922 }
1923
1924 /* peek_slot_field (window, location) can be free'd during the processing
1925 * of begin_location_change, so make a copy
1926 */
1927 location = g_object_ref (slot->location);
1928 current_pos = NULL;
1929 selection = NULL;
1930 if (slot->content_view != NULL) {
1931 current_pos = nemo_view_get_first_visible_file (slot->content_view);
1932 selection = nemo_view_get_selection (slot->content_view);
1933 }
1934 begin_location_change
1935 (slot, location, location, selection,
1936 NEMO_LOCATION_CHANGE_RELOAD, 0, current_pos,
1937 FALSE, NULL, NULL);
1938 g_free (current_pos);
1939 g_object_unref (location);
1940 g_list_free_full (selection, g_object_unref);
1941 }
1942
1943 static void
clear_thumbnails_for_view(NemoView * view)1944 clear_thumbnails_for_view (NemoView *view)
1945 {
1946 NemoDirectory *directory;
1947 GList *file_list, *l;
1948
1949 directory = nemo_view_get_model (view);
1950
1951 file_list = nemo_directory_get_file_list (directory);
1952
1953 for (l = file_list; l != NULL; l = l->next) {
1954 NemoFile *file = NEMO_FILE (l->data);
1955
1956 nemo_file_delete_thumbnail (file);
1957 }
1958
1959 nemo_file_list_free (file_list);
1960
1961 nemo_icon_info_clear_caches ();
1962 }
1963
1964 void
nemo_window_slot_queue_reload(NemoWindowSlot * slot,gboolean clear_thumbs)1965 nemo_window_slot_queue_reload (NemoWindowSlot *slot,
1966 gboolean clear_thumbs)
1967 {
1968 g_assert (NEMO_IS_WINDOW_SLOT (slot));
1969
1970 if (slot->location == NULL) {
1971 return;
1972 }
1973
1974 if (slot->pending_location != NULL
1975 || slot->content_view == NULL
1976 || nemo_view_get_loading (slot->content_view)) {
1977 /* there is a reload in flight */
1978 slot->needs_reload = TRUE;
1979 return;
1980 }
1981
1982 if (clear_thumbs && !nemo_file_is_in_favorites (slot->viewed_file)) {
1983 clear_thumbnails_for_view (slot->content_view);
1984 }
1985
1986 nemo_window_slot_force_reload (slot);
1987 }
1988
1989 void
nemo_window_slot_check_bad_cache_bar(NemoWindowSlot * slot)1990 nemo_window_slot_check_bad_cache_bar (NemoWindowSlot *slot)
1991 {
1992 int show_image_thumbs;
1993 if (NEMO_IS_DESKTOP_WINDOW (nemo_window_slot_get_window (slot)))
1994 return;
1995
1996 show_image_thumbs = g_settings_get_enum (nemo_preferences, NEMO_PREFERENCES_SHOW_IMAGE_FILE_THUMBNAILS);
1997 if (show_image_thumbs != NEMO_SPEED_TRADEOFF_NEVER &&
1998 nemo_application_get_cache_bad (nemo_application_get_singleton ()) &&
1999 !nemo_application_get_cache_problem_ignored (nemo_application_get_singleton ())) {
2000 if (slot->cache_bar != NULL) {
2001 gtk_widget_show (slot->cache_bar);
2002 } else {
2003 GtkWidget *bad_bar = nemo_thumbnail_problem_bar_new (nemo_window_slot_get_current_view (slot));
2004 if (bad_bar) {
2005 gtk_widget_show (bad_bar);
2006 nemo_window_slot_add_extra_location_widget (slot, bad_bar);
2007 slot->cache_bar = bad_bar;
2008
2009 g_object_add_weak_pointer (G_OBJECT (bad_bar), (gpointer) &slot->cache_bar);
2010 }
2011 }
2012 } else {
2013 if (slot->cache_bar != NULL) {
2014 gtk_widget_hide (slot->cache_bar);
2015 }
2016 }
2017 }
2018