Blob Blame History Raw
From fe7533b0b82e2ebc7767006ee9768572700a91df Mon Sep 17 00:00:00 2001
From: Sachin Daluja <30343-sachindaluja@users.noreply.gitlab.gnome.org>
Date: Sun, 10 May 2020 22:30:03 -0400
Subject: [PATCH] window, window-slot: Save and restore navigation history

When a new window slot instance replaces the existing one to handle the new
location.

This allows back and forward history lists to be preserved when the window
switches between instances of different window slot classes.

Closes https://gitlab.gnome.org/GNOME/nautilus/-/issues/32
---
 src/nautilus-window-slot.c | 48 +++++++++++++++++++---
 src/nautilus-window-slot.h | 13 ++++++
 src/nautilus-window.c      | 84 +++++++++++++++++++++++++++++++++++++-
 3 files changed, 138 insertions(+), 7 deletions(-)

diff --git a/src/nautilus-window-slot.c b/src/nautilus-window-slot.c
index e688f0716..69040fc44 100644
--- a/src/nautilus-window-slot.c
+++ b/src/nautilus-window-slot.c
@@ -176,6 +176,9 @@ nautilus_window_slot_restore_navigation_state (NautilusWindowSlot      *self,
 
     priv = nautilus_window_slot_get_instance_private (self);
 
+    /* We are restoring saved history to newly created slot with no history. */
+    g_warn_if_fail (priv->back_list == NULL && priv->forward_list == NULL);
+
     priv->back_list = g_steal_pointer (&data->back_list);
 
     priv->forward_list = g_steal_pointer (&data->forward_list);
@@ -2003,12 +2006,11 @@ nautilus_window_slot_set_content_view (NautilusWindowSlot *self,
 }
 
 void
-nautilus_window_back_or_forward (NautilusWindow          *window,
-                                 gboolean                 back,
-                                 guint                    distance,
-                                 NautilusWindowOpenFlags  flags)
+nautilus_window_slot_back_or_forward (NautilusWindowSlot      *self,
+                                      gboolean                 back,
+                                      guint                    distance,
+                                      NautilusWindowOpenFlags  flags)
 {
-    NautilusWindowSlot *self;
     GList *list;
     GFile *location;
     guint len;
@@ -2016,7 +2018,6 @@ nautilus_window_back_or_forward (NautilusWindow          *window,
     GFile *old_location;
     NautilusWindowSlotPrivate *priv;
 
-    self = nautilus_window_get_active_slot (window);
     priv = nautilus_window_slot_get_instance_private (self);
     list = back ? priv->back_list : priv->forward_list;
 
@@ -3308,3 +3309,38 @@ nautilus_window_slot_get_loading (NautilusWindowSlot *self)
 
     return priv->loading;
 }
+
+/*
+ * Open the specified location and set up the navigation history including the
+ * back and forward lists. This function is intended to be called when switching
+ * between NautilusWindowSlot and NautilusOtherLocationsWindowSlot. It allows
+ * the navigation history accumulated in the slot being replaced to be loaded
+ * into the replacing slot.
+ *
+ * The 'location' member variable is set to the new location before calling
+ * begin_location_change() to ensure that it matches the
+ * 'current_location_bookmark' member as expected by the location change
+ * pipeline.
+ */
+void
+nautilus_window_slot_open_location_set_navigation_state (NautilusWindowSlot         *self,
+                                                         GFile                      *location,
+                                                         NautilusWindowOpenFlags     flags,
+                                                         GList                      *new_selection,
+                                                         NautilusLocationChangeType  change_type,
+                                                         NautilusNavigationState    *navigation_state,
+                                                         guint                       distance)
+{
+    NautilusWindowSlotPrivate *priv;
+
+    priv = nautilus_window_slot_get_instance_private (self);
+
+    nautilus_window_slot_restore_navigation_state (self, navigation_state);
+
+    g_clear_object (&priv->location);
+
+    priv->location = nautilus_file_get_location (navigation_state->file);
+
+    begin_location_change (self, location, NULL, new_selection,
+                           change_type, distance, NULL);
+}
diff --git a/src/nautilus-window-slot.h b/src/nautilus-window-slot.h
index 2edc96786..cbd3454ce 100644
--- a/src/nautilus-window-slot.h
+++ b/src/nautilus-window-slot.h
@@ -82,6 +82,14 @@ void nautilus_window_slot_open_location_full              (NautilusWindowSlot
                                                            NautilusWindowOpenFlags  flags,
                                                            GList                   *new_selection);
 
+void nautilus_window_slot_open_location_set_navigation_state (NautilusWindowSlot         *slot,
+                                                              GFile                      *location,
+                                                              NautilusWindowOpenFlags     flags,
+                                                              GList                      *new_selection,
+                                                              NautilusLocationChangeType  change_type,
+                                                              NautilusNavigationState    *navigation_state,
+                                                              guint                       distance);
+
 GFile * nautilus_window_slot_get_location		   (NautilusWindowSlot *slot);
 
 NautilusBookmark *nautilus_window_slot_get_bookmark        (NautilusWindowSlot *slot);
@@ -126,5 +134,10 @@ NautilusNavigationState* nautilus_window_slot_get_navigation_state (NautilusWind
 /* Only used by slot-dnd */
 NautilusView*  nautilus_window_slot_get_current_view       (NautilusWindowSlot *slot);
 
+void nautilus_window_slot_back_or_forward                  (NautilusWindowSlot     *slot,
+                                                            gboolean                back,
+                                                            guint                   distance,
+                                                            NautilusWindowOpenFlags flags);
+
 void free_navigation_state                                 (gpointer data);
 #endif /* NAUTILUS_WINDOW_SLOT_H */
diff --git a/src/nautilus-window.c b/src/nautilus-window.c
index 900239cb8..af01b43e7 100644
--- a/src/nautilus-window.c
+++ b/src/nautilus-window.c
@@ -613,6 +613,7 @@ nautilus_window_open_location_full (NautilusWindow          *window,
 {
     NautilusWindowSlot *active_slot;
     gboolean new_tab_at_end;
+    NautilusNavigationState *navigation_state = NULL;
 
     /* The location owner can be one of the slots requesting to handle an
      * unhandled location. But this slot can be destroyed when switching to
@@ -644,6 +645,8 @@ nautilus_window_open_location_full (NautilusWindow          *window,
     }
     else if (!nautilus_window_slot_handles_location (target_slot, location))
     {
+        navigation_state = nautilus_window_slot_get_navigation_state (active_slot);
+
         target_slot = replace_active_slot (window, location, flags);
     }
 
@@ -655,7 +658,19 @@ nautilus_window_open_location_full (NautilusWindow          *window,
         nautilus_window_set_active_slot (window, target_slot);
     }
 
-    nautilus_window_slot_open_location_full (target_slot, location, flags, selection);
+    if (navigation_state != NULL)
+    {
+        nautilus_window_slot_open_location_set_navigation_state (target_slot,
+                                                                 location, flags, selection,
+                                                                 NAUTILUS_LOCATION_CHANGE_STANDARD,
+                                                                 navigation_state, 0);
+
+        free_navigation_state (navigation_state);
+    }
+    else
+    {
+        nautilus_window_slot_open_location_full (target_slot, location, flags, selection);
+    }
 
     g_object_unref (location);
 }
@@ -3099,3 +3114,70 @@ nautilus_window_search (NautilusWindow *window,
         g_warning ("Trying search on a slot but no active slot present");
     }
 }
+
+/* Ideally, this method should be a simple wrapper for the slot method. However,
+ * going back or forward can result in a new slot (or another subclass), so we
+ * workaround that by duplicating part of nautilus_window_slot_back_or_forward()
+ */
+void
+nautilus_window_back_or_forward (NautilusWindow          *window,
+                                 gboolean                 back,
+                                 guint                    distance,
+                                 NautilusWindowOpenFlags  flags)
+{
+    NautilusWindowSlot *slot;
+    GList *next_location_list, *back_list, *forward_list;
+    GFile *next_location;
+    guint len;
+    NautilusBookmark *next_location_bookmark;
+    gboolean active_slot_handles_location;
+
+    slot = nautilus_window_get_active_slot (window);
+    back_list = nautilus_window_slot_get_back_history (slot);
+    forward_list = nautilus_window_slot_get_forward_history (slot);
+
+    next_location_list = back ? back_list : forward_list;
+
+    len = (guint) g_list_length (next_location_list);
+
+    /* If we can't move in the direction at all, just return. */
+    if (len == 0)
+    {
+        return;
+    }
+
+    /* If the distance to move is off the end of the list, go to the end
+     *  of the list. */
+    if (distance >= len)
+    {
+        distance = len - 1;
+    }
+
+    next_location_bookmark = g_list_nth_data (next_location_list, distance);
+    next_location = nautilus_bookmark_get_location (next_location_bookmark);
+
+    active_slot_handles_location = nautilus_window_slot_handles_location (slot, next_location);
+
+    if (!active_slot_handles_location)
+    {
+        NautilusNavigationState *navigation_state;
+        NautilusLocationChangeType location_change_type;
+
+        navigation_state = nautilus_window_slot_get_navigation_state (slot);
+
+        location_change_type = back ? NAUTILUS_LOCATION_CHANGE_BACK : NAUTILUS_LOCATION_CHANGE_FORWARD;
+
+        slot = replace_active_slot (window, next_location, flags);
+
+        nautilus_window_slot_open_location_set_navigation_state (slot,
+                                                                 next_location, flags, NULL,
+                                                                 location_change_type,
+                                                                 navigation_state, distance);
+
+        free_navigation_state (navigation_state);
+    }
+    else
+    {
+        nautilus_window_slot_back_or_forward (slot, back, distance, flags);
+    }
+}
-- 
2.35.1