[nautilus/wip/toolbar-start-end: 1/4] general: Refactor toolbar children into HistoryControls and ToolbarEnd




commit 8395e9bb53680a2f3b4bdf86cbf0318ff486663e
Author: Christopher Davis <christopherdavis gnome org>
Date:   Wed Jul 20 21:31:46 2022 -0400

    general: Refactor toolbar children into HistoryControls and ToolbarEnd
    
    We need to use the children from the header bar in multiple places,
    but we don't want to duplicate the code or the logic. Thus, we should
    encapsulate the code and logic we need into distinct reusable
    components: NautilusHistoryControls and NautilusToolbarEnd.
    
    These components update their state properly when the window slot
    changes without needing to call any functions ourselves.

 src/meson.build                               |   4 +
 src/nautilus-history-controls.c               | 327 ++++++++++++
 src/nautilus-history-controls.h               |  34 ++
 src/nautilus-toolbar-end.c                    | 707 +++++++++++++++++++++++++
 src/nautilus-toolbar-end.h                    |  34 ++
 src/nautilus-toolbar.c                        | 732 +-------------------------
 src/resources/nautilus.gresource.xml          |   2 +
 src/resources/ui/nautilus-history-controls.ui |  35 ++
 src/resources/ui/nautilus-toolbar-end.ui      | 101 ++++
 src/resources/ui/nautilus-toolbar.ui          | 117 +---
 10 files changed, 1254 insertions(+), 839 deletions(-)
---
diff --git a/src/meson.build b/src/meson.build
index a0c92c92b..1f4b8f7ec 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -89,6 +89,8 @@ libnautilus_sources = [
   'nautilus-grid-cell.h',
   'nautilus-grid-view.c',
   'nautilus-grid-view.h',
+  'nautilus-history-controls.c',
+  'nautilus-history-controls.h',
   'nautilus-label-cell.c',
   'nautilus-label-cell.h',
   'nautilus-list-base.c',
@@ -124,6 +126,8 @@ libnautilus_sources = [
   'nautilus-star-cell.h',
   'nautilus-toolbar.c',
   'nautilus-toolbar.h',
+  'nautilus-toolbar-end.c',
+  'nautilus-toolbar-end.h',
   'nautilus-toolbar-menu-sections.h',
   'nautilus-trash-bar.c',
   'nautilus-trash-bar.h',
diff --git a/src/nautilus-history-controls.c b/src/nautilus-history-controls.c
new file mode 100644
index 000000000..d2d2234b1
--- /dev/null
+++ b/src/nautilus-history-controls.c
@@ -0,0 +1,327 @@
+/* nautilus-history-controls.c
+ *
+ * Copyright 2022 Christopher Davis <christopherdavis gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "nautilus-history-controls.h"
+
+#include "nautilus-bookmark.h"
+#include "nautilus-window.h"
+
+struct _NautilusHistoryControls
+{
+    AdwBin parent_instance;
+
+    GtkWidget *back_button;
+    GtkWidget *back_menu;
+
+    GtkWidget *forward_button;
+    GtkWidget *forward_menu;
+
+    NautilusWindowSlot *window_slot;
+};
+
+G_DEFINE_FINAL_TYPE (NautilusHistoryControls, nautilus_history_controls, ADW_TYPE_BIN)
+
+enum
+{
+    PROP_0,
+    PROP_WINDOW_SLOT,
+    N_PROPS
+};
+
+static GParamSpec *properties[N_PROPS];
+
+static void
+fill_menu (NautilusHistoryControls *self,
+           GMenu                   *menu,
+           gboolean                 back)
+{
+    guint index;
+    GList *list;
+    const gchar *name;
+
+    list = back ? nautilus_window_slot_get_back_history (self->window_slot) :
+           nautilus_window_slot_get_forward_history (self->window_slot);
+
+    index = 0;
+    while (list != NULL)
+    {
+        g_autoptr (GMenuItem) item = NULL;
+
+        name = nautilus_bookmark_get_name (NAUTILUS_BOOKMARK (list->data));
+        item = g_menu_item_new (name, NULL);
+        g_menu_item_set_action_and_target (item,
+                                           back ? "win.back-n" : "win.forward-n",
+                                           "u", index);
+        g_menu_append_item (menu, item);
+
+        list = g_list_next (list);
+        ++index;
+    }
+}
+
+static void
+show_menu (NautilusHistoryControls *self,
+           GtkWidget               *widget)
+{
+    g_autoptr (GMenu) menu = NULL;
+    NautilusNavigationDirection direction;
+    GtkPopoverMenu *popover;
+
+    menu = g_menu_new ();
+
+    direction = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (widget),
+                                                     "nav-direction"));
+
+    switch (direction)
+    {
+        case NAUTILUS_NAVIGATION_DIRECTION_FORWARD:
+        {
+            fill_menu (self, menu, FALSE);
+            popover = GTK_POPOVER_MENU (self->forward_menu);
+        }
+        break;
+
+        case NAUTILUS_NAVIGATION_DIRECTION_BACK:
+        {
+            fill_menu (self, menu, TRUE);
+            popover = GTK_POPOVER_MENU (self->back_menu);
+        }
+        break;
+
+        default:
+        {
+            g_assert_not_reached ();
+        }
+        break;
+    }
+
+    gtk_popover_menu_set_menu_model (popover, G_MENU_MODEL (menu));
+    gtk_popover_popup (GTK_POPOVER (popover));
+}
+
+static void
+navigation_button_press_cb (GtkGestureClick *gesture,
+                            gint             n_press,
+                            gdouble          x,
+                            gdouble          y,
+                            gpointer         user_data)
+{
+    NautilusHistoryControls *self;
+    NautilusWindow *window;
+    GtkWidget *widget;
+    guint button;
+
+    self = NAUTILUS_HISTORY_CONTROLS (user_data);
+    button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
+    widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
+    window = NAUTILUS_WINDOW (gtk_widget_get_root (GTK_WIDGET (self)));
+
+    if (button == GDK_BUTTON_PRIMARY)
+    {
+        /* Don't do anything, primary click is handled through activate */
+        gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_DENIED);
+        return;
+    }
+    else if (button == GDK_BUTTON_MIDDLE)
+    {
+        NautilusNavigationDirection direction;
+
+        direction = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (widget),
+                                                         "nav-direction"));
+
+        nautilus_window_back_or_forward_in_new_tab (window, direction);
+    }
+    else if (button == GDK_BUTTON_SECONDARY)
+    {
+        show_menu (self, widget);
+    }
+}
+
+static void
+back_button_longpress_cb (GtkGestureLongPress *gesture,
+                          double               x,
+                          double               y,
+                          gpointer             user_data)
+{
+    NautilusHistoryControls *self = user_data;
+
+    show_menu (self, self->back_button);
+}
+
+static void
+forward_button_longpress_cb (GtkGestureLongPress *gesture,
+                             double               x,
+                             double               y,
+                             gpointer             user_data)
+{
+    NautilusHistoryControls *self = user_data;
+
+    show_menu (self, self->forward_button);
+}
+
+
+static void
+nautilus_history_controls_contructed (GObject *object)
+{
+    NautilusHistoryControls *self;
+    GtkEventController *controller;
+
+    self = NAUTILUS_HISTORY_CONTROLS (object);
+
+    controller = GTK_EVENT_CONTROLLER (gtk_gesture_long_press_new ());
+    gtk_widget_add_controller (self->back_button, controller);
+    g_signal_connect (controller, "pressed",
+                      G_CALLBACK (back_button_longpress_cb), self);
+
+    controller = GTK_EVENT_CONTROLLER (gtk_gesture_long_press_new ());
+    gtk_widget_add_controller (self->forward_button, controller);
+    g_signal_connect (controller, "pressed",
+                      G_CALLBACK (forward_button_longpress_cb), self);
+
+    g_object_set_data (G_OBJECT (self->back_button), "nav-direction",
+                       GUINT_TO_POINTER (NAUTILUS_NAVIGATION_DIRECTION_BACK));
+    g_object_set_data (G_OBJECT (self->forward_button), "nav-direction",
+                       GUINT_TO_POINTER (NAUTILUS_NAVIGATION_DIRECTION_FORWARD));
+
+    controller = GTK_EVENT_CONTROLLER (gtk_gesture_click_new ());
+    gtk_widget_add_controller (self->back_button, controller);
+    gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (controller), 0);
+    g_signal_connect (controller, "pressed",
+                      G_CALLBACK (navigation_button_press_cb), self);
+
+    controller = GTK_EVENT_CONTROLLER (gtk_gesture_click_new ());
+    gtk_widget_add_controller (self->forward_button, controller);
+    gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (controller), 0);
+    g_signal_connect (controller, "pressed",
+                      G_CALLBACK (navigation_button_press_cb), self);
+}
+
+static void
+nautilus_history_controls_dispose (GObject *object)
+{
+    NautilusHistoryControls *self;
+
+    self = NAUTILUS_HISTORY_CONTROLS (object);
+
+    g_clear_pointer (&self->back_menu, gtk_widget_unparent);
+    g_clear_pointer (&self->forward_menu, gtk_widget_unparent);
+
+    G_OBJECT_CLASS (nautilus_history_controls_parent_class)->dispose (object);
+}
+
+static void
+nautilus_history_controls_set_window_slot (NautilusHistoryControls *self,
+                                           NautilusWindowSlot      *window_slot)
+{
+    g_return_if_fail (NAUTILUS_IS_HISTORY_CONTROLS (self));
+    g_return_if_fail (window_slot == NULL || NAUTILUS_IS_WINDOW_SLOT (window_slot));
+
+    if (self->window_slot == window_slot)
+    {
+        return;
+    }
+
+    self->window_slot = window_slot;
+
+    g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_WINDOW_SLOT]);
+}
+
+static void
+nautilus_history_controls_get_property (GObject    *object,
+                                        guint       prop_id,
+                                        GValue     *value,
+                                        GParamSpec *pspec)
+{
+    NautilusHistoryControls *self = NAUTILUS_HISTORY_CONTROLS (object);
+
+    switch (prop_id)
+    {
+        case PROP_WINDOW_SLOT:
+        {
+            g_value_set_object (value, G_OBJECT (self->window_slot));
+            break;
+        }
+
+        default:
+        {
+            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        }
+    }
+}
+
+static void
+nautilus_history_controls_set_property (GObject      *object,
+                                        guint         prop_id,
+                                        const GValue *value,
+                                        GParamSpec   *pspec)
+{
+    NautilusHistoryControls *self = NAUTILUS_HISTORY_CONTROLS (object);
+
+    switch (prop_id)
+    {
+        case PROP_WINDOW_SLOT:
+        {
+            nautilus_history_controls_set_window_slot (self, NAUTILUS_WINDOW_SLOT (g_value_get_object 
(value)));
+            break;
+        }
+
+        default:
+        {
+            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        }
+    }
+}
+
+static void
+nautilus_history_controls_class_init (NautilusHistoryControlsClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+    GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+    object_class->constructed = nautilus_history_controls_contructed;
+    object_class->dispose = nautilus_history_controls_dispose;
+    object_class->set_property = nautilus_history_controls_set_property;
+    object_class->get_property = nautilus_history_controls_get_property;
+
+    properties[PROP_WINDOW_SLOT] = g_param_spec_object ("window-slot",
+                                                        NULL, NULL,
+                                                        NAUTILUS_TYPE_WINDOW_SLOT,
+                                                        G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | 
G_PARAM_EXPLICIT_NOTIFY);
+
+    g_object_class_install_properties (object_class, N_PROPS, properties);
+
+    gtk_widget_class_set_template_from_resource (widget_class,
+                                                 "/org/gnome/nautilus/ui/nautilus-history-controls.ui");
+    gtk_widget_class_bind_template_child (widget_class, NautilusHistoryControls, back_button);
+    gtk_widget_class_bind_template_child (widget_class, NautilusHistoryControls, back_menu);
+    gtk_widget_class_bind_template_child (widget_class, NautilusHistoryControls, forward_button);
+    gtk_widget_class_bind_template_child (widget_class, NautilusHistoryControls, forward_menu);
+}
+
+static void
+nautilus_history_controls_init (NautilusHistoryControls *self)
+{
+    gtk_widget_init_template (GTK_WIDGET (self));
+
+    gtk_widget_set_parent (self->back_menu, self->back_button);
+    g_signal_connect (self->back_menu, "destroy", G_CALLBACK (gtk_widget_unparent), NULL);
+    gtk_widget_set_parent (self->forward_menu, self->forward_button);
+    g_signal_connect (self->forward_menu, "destroy", G_CALLBACK (gtk_widget_unparent), NULL);
+}
diff --git a/src/nautilus-history-controls.h b/src/nautilus-history-controls.h
new file mode 100644
index 000000000..aeb6eb488
--- /dev/null
+++ b/src/nautilus-history-controls.h
@@ -0,0 +1,34 @@
+/* nautilus-history-controls.h
+ *
+ * Copyright 2022 GNOME project contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#pragma once
+
+#include <gtk/gtk.h>
+#include <libadwaita-1/adwaita.h>
+
+#include "nautilus-window-slot.h"
+
+G_BEGIN_DECLS
+
+#define NAUTILUS_TYPE_HISTORY_CONTROLS nautilus_history_controls_get_type()
+
+G_DECLARE_FINAL_TYPE (NautilusHistoryControls, nautilus_history_controls, NAUTILUS, HISTORY_CONTROLS, AdwBin)
+
+G_END_DECLS
diff --git a/src/nautilus-toolbar-end.c b/src/nautilus-toolbar-end.c
new file mode 100644
index 000000000..82e0485ea
--- /dev/null
+++ b/src/nautilus-toolbar-end.c
@@ -0,0 +1,707 @@
+/* nautilus-toolbar-end.c
+ *
+ * Copyright 2022 GNOME project contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "nautilus-toolbar-end.h"
+
+#include "nautilus-file-operations.h"
+#include "nautilus-progress-info-manager.h"
+#include "nautilus-progress-info-widget.h"
+#include "nautilus-toolbar-menu-sections.h"
+#include "nautilus-window.h"
+
+#define OPERATION_MINIMUM_TIME 2 /*s */
+#define NEEDS_ATTENTION_ANIMATION_TIMEOUT 2000 /*ms */
+#define REMOVE_FINISHED_OPERATIONS_TIEMOUT 3 /*s */
+
+struct _NautilusToolbarEnd
+{
+    AdwBin parent_instance;
+
+    guint start_operations_timeout_id;
+    guint remove_finished_operations_timeout_id;
+    guint operations_button_attention_timeout_id;
+
+    GtkWidget *operations_button;
+    GtkWidget *operations_popover;
+    GtkWidget *operations_list;
+    GListStore *progress_infos_model;
+    GtkWidget *operations_revealer;
+    GtkWidget *operations_icon;
+
+    GtkWidget *view_split_button;
+    GMenuModel *view_menu;
+
+    NautilusProgressInfoManager *progress_manager;
+
+    NautilusWindowSlot *window_slot;
+};
+
+G_DEFINE_FINAL_TYPE (NautilusToolbarEnd, nautilus_toolbar_end, ADW_TYPE_BIN);
+
+
+static void update_operations (NautilusToolbarEnd *self);
+
+enum
+{
+    PROP_0,
+    PROP_WINDOW_SLOT,
+    N_PROPS
+};
+
+static GParamSpec *properties[N_PROPS];
+
+
+static gboolean
+should_show_progress_info (NautilusProgressInfo *info)
+{
+    return nautilus_progress_info_get_total_elapsed_time (info) +
+           nautilus_progress_info_get_remaining_time (info) > OPERATION_MINIMUM_TIME;
+}
+
+static GList *
+get_filtered_progress_infos (NautilusToolbarEnd *self)
+{
+    GList *l;
+    GList *filtered_progress_infos;
+    GList *progress_infos;
+
+    progress_infos = nautilus_progress_info_manager_get_all_infos (self->progress_manager);
+    filtered_progress_infos = NULL;
+
+    for (l = progress_infos; l != NULL; l = l->next)
+    {
+        if (should_show_progress_info (l->data))
+        {
+            filtered_progress_infos = g_list_append (filtered_progress_infos, l->data);
+        }
+    }
+
+    return filtered_progress_infos;
+}
+
+static gboolean
+should_hide_operations_button (NautilusToolbarEnd *self)
+{
+    GList *progress_infos;
+    GList *l;
+
+    progress_infos = get_filtered_progress_infos (self);
+
+    for (l = progress_infos; l != NULL; l = l->next)
+    {
+        if (nautilus_progress_info_get_total_elapsed_time (l->data) +
+            nautilus_progress_info_get_remaining_time (l->data) > OPERATION_MINIMUM_TIME &&
+            !nautilus_progress_info_get_is_cancelled (l->data) &&
+            !nautilus_progress_info_get_is_finished (l->data))
+        {
+            return FALSE;
+        }
+    }
+
+    g_list_free (progress_infos);
+
+    return TRUE;
+}
+
+static gboolean
+on_remove_finished_operations_timeout (NautilusToolbarEnd *self)
+{
+    nautilus_progress_info_manager_remove_finished_or_cancelled_infos (self->progress_manager);
+    if (should_hide_operations_button (self))
+    {
+        gtk_revealer_set_reveal_child (GTK_REVEALER (self->operations_revealer),
+                                       FALSE);
+    }
+    else
+    {
+        update_operations (self);
+    }
+
+    self->remove_finished_operations_timeout_id = 0;
+
+    return G_SOURCE_REMOVE;
+}
+
+static void
+unschedule_remove_finished_operations (NautilusToolbarEnd *self)
+{
+    if (self->remove_finished_operations_timeout_id != 0)
+    {
+        g_source_remove (self->remove_finished_operations_timeout_id);
+        self->remove_finished_operations_timeout_id = 0;
+    }
+}
+
+static void
+schedule_remove_finished_operations (NautilusToolbarEnd *self)
+{
+    if (self->remove_finished_operations_timeout_id == 0)
+    {
+        self->remove_finished_operations_timeout_id =
+            g_timeout_add_seconds (REMOVE_FINISHED_OPERATIONS_TIEMOUT,
+                                   (GSourceFunc) on_remove_finished_operations_timeout,
+                                   self);
+    }
+}
+
+static void
+remove_operations_button_attention_style (NautilusToolbarEnd *self)
+{
+    gtk_widget_remove_css_class (self->operations_button,
+                                 "nautilus-operations-button-needs-attention");
+}
+
+static gboolean
+on_remove_operations_button_attention_style_timeout (NautilusToolbarEnd *self)
+{
+    remove_operations_button_attention_style (self);
+    self->operations_button_attention_timeout_id = 0;
+
+    return G_SOURCE_REMOVE;
+}
+
+static void
+unschedule_operations_button_attention_style (NautilusToolbarEnd *self)
+{
+    if (self->operations_button_attention_timeout_id != 0)
+    {
+        g_source_remove (self->operations_button_attention_timeout_id);
+        self->operations_button_attention_timeout_id = 0;
+    }
+}
+
+static void
+add_operations_button_attention_style (NautilusToolbarEnd *self)
+{
+    unschedule_operations_button_attention_style (self);
+    remove_operations_button_attention_style (self);
+
+    gtk_widget_add_css_class (self->operations_button,
+                              "nautilus-operations-button-needs-attention");
+    self->operations_button_attention_timeout_id = g_timeout_add (NEEDS_ATTENTION_ANIMATION_TIMEOUT,
+                                                                  (GSourceFunc) 
on_remove_operations_button_attention_style_timeout,
+                                                                  self);
+}
+
+static void
+on_progress_info_cancelled (NautilusToolbarEnd *self)
+{
+    /* Update the pie chart progress */
+    gtk_widget_queue_draw (self->operations_icon);
+
+    if (!nautilus_progress_manager_has_viewers (self->progress_manager))
+    {
+        schedule_remove_finished_operations (self);
+    }
+}
+
+static void
+on_progress_info_progress_changed (NautilusToolbarEnd *self)
+{
+    /* Update the pie chart progress */
+    gtk_widget_queue_draw (self->operations_icon);
+}
+
+static void
+on_progress_info_finished (NautilusToolbarEnd   *self,
+                           NautilusProgressInfo *info)
+{
+    NautilusWindow *window;
+    gchar *main_label;
+    GFile *folder_to_open;
+
+    window = NAUTILUS_WINDOW (gtk_widget_get_root (GTK_WIDGET (self)));
+
+    /* Update the pie chart progress */
+    gtk_widget_queue_draw (self->operations_icon);
+
+    if (!nautilus_progress_manager_has_viewers (self->progress_manager))
+    {
+        schedule_remove_finished_operations (self);
+    }
+
+    folder_to_open = nautilus_progress_info_get_destination (info);
+    /* If destination is null, don't show a notification. This happens when the
+     * operation is a trash operation, which we already show a diferent kind of
+     * notification */
+    if (!gtk_widget_is_visible (self->operations_popover) &&
+        folder_to_open != NULL)
+    {
+        add_operations_button_attention_style (self);
+        main_label = nautilus_progress_info_get_status (info);
+        nautilus_window_show_operation_notification (window,
+                                                     main_label,
+                                                     folder_to_open);
+        g_free (main_label);
+    }
+
+    g_clear_object (&folder_to_open);
+}
+
+static void
+disconnect_progress_infos (NautilusToolbarEnd *self)
+{
+    GList *progress_infos;
+    GList *l;
+
+    progress_infos = nautilus_progress_info_manager_get_all_infos (self->progress_manager);
+    for (l = progress_infos; l != NULL; l = l->next)
+    {
+        g_signal_handlers_disconnect_by_data (l->data, self);
+    }
+}
+
+static void
+update_operations (NautilusToolbarEnd *self)
+{
+    GList *progress_infos;
+    GList *l;
+    gboolean should_show_progress_button = FALSE;
+
+    disconnect_progress_infos (self);
+    g_list_store_remove_all (self->progress_infos_model);
+
+    progress_infos = get_filtered_progress_infos (self);
+    for (l = progress_infos; l != NULL; l = l->next)
+    {
+        should_show_progress_button = should_show_progress_button ||
+                                      should_show_progress_info (l->data);
+
+        g_signal_connect_swapped (l->data, "finished",
+                                  G_CALLBACK (on_progress_info_finished), self);
+        g_signal_connect_swapped (l->data, "cancelled",
+                                  G_CALLBACK (on_progress_info_cancelled), self);
+        g_signal_connect_swapped (l->data, "progress-changed",
+                                  G_CALLBACK (on_progress_info_progress_changed), self);
+        g_list_store_append (self->progress_infos_model, l->data);
+    }
+
+    g_list_free (progress_infos);
+
+    if (should_show_progress_button &&
+        !gtk_revealer_get_reveal_child (GTK_REVEALER (self->operations_revealer)))
+    {
+        add_operations_button_attention_style (self);
+        gtk_revealer_set_reveal_child (GTK_REVEALER (self->operations_revealer),
+                                       TRUE);
+        gtk_widget_queue_draw (self->operations_icon);
+    }
+
+    /* Since we removed the info widgets, we need to restore the focus */
+    if (gtk_widget_get_visible (self->operations_popover))
+    {
+        gtk_widget_grab_focus (self->operations_popover);
+    }
+}
+
+static gboolean
+on_progress_info_started_timeout (NautilusToolbarEnd *self)
+{
+    GList *progress_infos;
+    GList *filtered_progress_infos;
+
+    update_operations (self);
+
+    /* In case we didn't show the operations button because the operation total
+     * time stimation is not good enough, update again to make sure we don't miss
+     * a long time operation because of that */
+
+    progress_infos = nautilus_progress_info_manager_get_all_infos (self->progress_manager);
+    filtered_progress_infos = get_filtered_progress_infos (self);
+    if (!nautilus_progress_manager_are_all_infos_finished_or_cancelled (self->progress_manager) &&
+        g_list_length (progress_infos) != g_list_length (filtered_progress_infos))
+    {
+        g_list_free (filtered_progress_infos);
+        return G_SOURCE_CONTINUE;
+    }
+    else
+    {
+        g_list_free (filtered_progress_infos);
+        self->start_operations_timeout_id = 0;
+        return G_SOURCE_REMOVE;
+    }
+}
+
+static void
+schedule_operations_start (NautilusToolbarEnd *self)
+{
+    if (self->start_operations_timeout_id == 0)
+    {
+        /* Timeout is a little more than what we require for a stimated operation
+         * total time, to make sure the stimated total time is correct */
+        self->start_operations_timeout_id =
+            g_timeout_add (SECONDS_NEEDED_FOR_APROXIMATE_TRANSFER_RATE * 1000 + 500,
+                           (GSourceFunc) on_progress_info_started_timeout,
+                           self);
+    }
+}
+
+static void
+unschedule_operations_start (NautilusToolbarEnd *self)
+{
+    if (self->start_operations_timeout_id != 0)
+    {
+        g_source_remove (self->start_operations_timeout_id);
+        self->start_operations_timeout_id = 0;
+    }
+}
+
+static void
+on_progress_info_started (NautilusProgressInfo *info,
+                          NautilusToolbarEnd   *self)
+{
+    g_signal_handlers_disconnect_by_data (info, self);
+    schedule_operations_start (self);
+}
+
+static void
+on_new_progress_info (NautilusProgressInfoManager *manager,
+                      NautilusProgressInfo        *info,
+                      NautilusToolbarEnd          *self)
+{
+    g_signal_connect (info, "started",
+                      G_CALLBACK (on_progress_info_started), self);
+}
+
+static void
+on_operations_icon_draw (GtkDrawingArea     *drawing_area,
+                         cairo_t            *cr,
+                         int                 width,
+                         int                 height,
+                         NautilusToolbarEnd *self)
+{
+    GtkWidget *widget = GTK_WIDGET (drawing_area);
+    gfloat elapsed_progress = 0;
+    gint remaining_progress = 0;
+    gint total_progress;
+    gdouble ratio;
+    GList *progress_infos;
+    GList *l;
+    gboolean all_cancelled;
+    GdkRGBA background;
+    GdkRGBA foreground;
+    GtkStyleContext *style_context;
+
+    style_context = gtk_widget_get_style_context (widget);
+    gtk_style_context_get_color (style_context, &foreground);
+    background = foreground;
+    background.alpha *= 0.3;
+
+    all_cancelled = TRUE;
+    progress_infos = get_filtered_progress_infos (self);
+    for (l = progress_infos; l != NULL; l = l->next)
+    {
+        if (!nautilus_progress_info_get_is_cancelled (l->data))
+        {
+            all_cancelled = FALSE;
+            remaining_progress += nautilus_progress_info_get_remaining_time (l->data);
+            elapsed_progress += nautilus_progress_info_get_elapsed_time (l->data);
+        }
+    }
+
+    g_list_free (progress_infos);
+
+    total_progress = remaining_progress + elapsed_progress;
+
+    if (all_cancelled)
+    {
+        ratio = 1.0;
+    }
+    else
+    {
+        if (total_progress > 0)
+        {
+            ratio = MAX (0.05, elapsed_progress / total_progress);
+        }
+        else
+        {
+            ratio = 0.05;
+        }
+    }
+
+
+    width = gtk_widget_get_allocated_width (widget);
+    height = gtk_widget_get_allocated_height (widget);
+
+    gdk_cairo_set_source_rgba (cr, &background);
+    cairo_arc (cr,
+               width / 2.0, height / 2.0,
+               MIN (width, height) / 2.0,
+               0, 2 * G_PI);
+    cairo_fill (cr);
+    cairo_move_to (cr, width / 2.0, height / 2.0);
+    gdk_cairo_set_source_rgba (cr, &foreground);
+    cairo_arc (cr,
+               width / 2.0, height / 2.0,
+               MIN (width, height) / 2.0,
+               -G_PI / 2.0, ratio * 2 * G_PI - G_PI / 2.0);
+
+    cairo_fill (cr);
+}
+
+static void
+on_operations_popover_notify_visible (NautilusToolbarEnd *self,
+                                      GParamSpec         *pspec,
+                                      GObject            *popover)
+{
+    if (gtk_widget_get_visible (GTK_WIDGET (popover)))
+    {
+        unschedule_remove_finished_operations (self);
+        nautilus_progress_manager_add_viewer (self->progress_manager,
+                                              G_OBJECT (self));
+    }
+    else
+    {
+        nautilus_progress_manager_remove_viewer (self->progress_manager,
+                                                 G_OBJECT (self));
+    }
+}
+
+static void
+on_progress_has_viewers_changed (NautilusProgressInfoManager *manager,
+                                 NautilusToolbarEnd          *self)
+{
+    if (nautilus_progress_manager_has_viewers (manager))
+    {
+        unschedule_remove_finished_operations (self);
+        return;
+    }
+
+    if (nautilus_progress_manager_are_all_infos_finished_or_cancelled (manager))
+    {
+        unschedule_remove_finished_operations (self);
+        schedule_remove_finished_operations (self);
+    }
+}
+
+static GtkWidget *
+operations_list_create_widget (GObject  *item,
+                               gpointer  user_data)
+{
+    NautilusProgressInfo *info = NAUTILUS_PROGRESS_INFO (item);
+    GtkWidget *widget;
+
+    widget = nautilus_progress_info_widget_new (info);
+    gtk_widget_show (widget);
+
+    return widget;
+}
+
+static void
+on_slot_toolbar_menu_sections_changed (NautilusToolbarEnd *self,
+                                       GParamSpec         *param,
+                                       NautilusWindowSlot *slot)
+{
+    NautilusToolbarMenuSections *new_sections;
+    g_autoptr (GMenuItem) zoom_item = NULL;
+    g_autoptr (GMenuItem) sort_item = NULL;
+
+    new_sections = nautilus_window_slot_get_toolbar_menu_sections (slot);
+
+    gtk_widget_set_sensitive (self->view_split_button, (new_sections != NULL));
+    if (new_sections == NULL)
+    {
+        return;
+    }
+
+    /* Let's assume that sort section is the first item
+     * in view_menu, as per nautilus-toolbar.ui. */
+
+    sort_item = g_menu_item_new_from_model (self->view_menu, 0);
+    g_menu_remove (G_MENU (self->view_menu), 0);
+    g_menu_item_set_section (sort_item, new_sections->sort_section);
+    g_menu_insert_item (G_MENU (self->view_menu), 0, sort_item);
+}
+
+static void
+disconnect_toolbar_menu_sections_change_handler (NautilusToolbarEnd *self)
+{
+    if (self->window_slot == NULL)
+    {
+        return;
+    }
+
+    g_signal_handlers_disconnect_by_func (self->window_slot,
+                                          G_CALLBACK (on_slot_toolbar_menu_sections_changed),
+                                          self);
+}
+
+
+static void
+nautilus_toolbar_end_set_window_slot (NautilusToolbarEnd *self,
+                                      NautilusWindowSlot *window_slot)
+{
+    g_return_if_fail (NAUTILUS_IS_TOOLBAR_END (self));
+    g_return_if_fail (window_slot == NULL || NAUTILUS_IS_WINDOW_SLOT (window_slot));
+
+    if (self->window_slot == window_slot)
+    {
+        return;
+    }
+
+    disconnect_toolbar_menu_sections_change_handler (self);
+
+    self->window_slot = window_slot;
+
+    if (self->window_slot != NULL)
+    {
+        on_slot_toolbar_menu_sections_changed (self, NULL, self->window_slot);
+        g_signal_connect_swapped (self->window_slot, "notify::toolbar-menu-sections",
+                                  G_CALLBACK (on_slot_toolbar_menu_sections_changed), self);
+    }
+
+    g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_WINDOW_SLOT]);
+}
+
+static void
+nautilus_toolbar_end_get_property (GObject    *object,
+                                   guint       prop_id,
+                                   GValue     *value,
+                                   GParamSpec *pspec)
+{
+    NautilusToolbarEnd *self = NAUTILUS_TOOLBAR_END (object);
+
+    switch (prop_id)
+    {
+        case PROP_WINDOW_SLOT:
+        {
+            g_value_set_object (value, G_OBJECT (self->window_slot));
+            break;
+        }
+
+        default:
+        {
+            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        }
+    }
+}
+
+static void
+nautilus_toolbar_end_set_property (GObject      *object,
+                                   guint         prop_id,
+                                   const GValue *value,
+                                   GParamSpec   *pspec)
+{
+    NautilusToolbarEnd *self = NAUTILUS_TOOLBAR_END (object);
+
+    switch (prop_id)
+    {
+        case PROP_WINDOW_SLOT:
+        {
+            nautilus_toolbar_end_set_window_slot (self, NAUTILUS_WINDOW_SLOT (g_value_get_object (value)));
+            break;
+        }
+
+        default:
+        {
+            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        }
+    }
+}
+
+static void
+nautilus_toolbar_end_constructed (GObject *object)
+{
+    NautilusToolbarEnd *self = NAUTILUS_TOOLBAR_END (object);
+
+    self->progress_manager = nautilus_progress_info_manager_dup_singleton ();
+    g_signal_connect (self->progress_manager, "new-progress-info",
+                      G_CALLBACK (on_new_progress_info), self);
+    g_signal_connect (self->progress_manager, "has-viewers-changed",
+                      G_CALLBACK (on_progress_has_viewers_changed), self);
+
+    self->progress_infos_model = g_list_store_new (NAUTILUS_TYPE_PROGRESS_INFO);
+    gtk_list_box_bind_model (GTK_LIST_BOX (self->operations_list),
+                             G_LIST_MODEL (self->progress_infos_model),
+                             (GtkListBoxCreateWidgetFunc) operations_list_create_widget,
+                             NULL,
+                             NULL);
+    update_operations (self);
+
+    g_signal_connect (self->operations_popover, "show",
+                      (GCallback) gtk_widget_grab_focus, NULL);
+    g_signal_connect_swapped (self->operations_popover, "closed",
+                              (GCallback) gtk_widget_grab_focus, self);
+}
+
+static void
+nautilus_toolbar_end_finalize (GObject *obj)
+{
+    NautilusToolbarEnd *self = NAUTILUS_TOOLBAR_END (obj);
+
+    if (self->window_slot != NULL)
+    {
+        g_signal_handlers_disconnect_by_data (self->window_slot, self);
+        self->window_slot = NULL;
+    }
+
+    disconnect_progress_infos (self);
+    unschedule_remove_finished_operations (self);
+    unschedule_operations_start (self);
+    unschedule_operations_button_attention_style (self);
+
+    g_clear_object (&self->progress_infos_model);
+    g_signal_handlers_disconnect_by_data (self->progress_manager, self);
+    g_clear_object (&self->progress_manager);
+
+    G_OBJECT_CLASS (nautilus_toolbar_end_parent_class)->finalize (obj);
+}
+
+static void
+nautilus_toolbar_end_class_init (NautilusToolbarEndClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+    GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+    object_class->constructed = nautilus_toolbar_end_constructed;
+    object_class->finalize = nautilus_toolbar_end_finalize;
+    object_class->get_property = nautilus_toolbar_end_get_property;
+    object_class->set_property = nautilus_toolbar_end_set_property;
+
+    properties[PROP_WINDOW_SLOT] = g_param_spec_object ("window-slot",
+                                                        NULL, NULL,
+                                                        NAUTILUS_TYPE_WINDOW_SLOT,
+                                                        G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | 
G_PARAM_EXPLICIT_NOTIFY);
+
+    g_object_class_install_properties (object_class, N_PROPS, properties);
+
+    gtk_widget_class_set_template_from_resource (widget_class,
+                                                 "/org/gnome/nautilus/ui/nautilus-toolbar-end.ui");
+    gtk_widget_class_bind_template_child (widget_class, NautilusToolbarEnd, operations_button);
+    gtk_widget_class_bind_template_child (widget_class, NautilusToolbarEnd, operations_icon);
+    gtk_widget_class_bind_template_child (widget_class, NautilusToolbarEnd, operations_popover);
+    gtk_widget_class_bind_template_child (widget_class, NautilusToolbarEnd, operations_list);
+    gtk_widget_class_bind_template_child (widget_class, NautilusToolbarEnd, operations_revealer);
+    gtk_widget_class_bind_template_child (widget_class, NautilusToolbarEnd, view_menu);
+    gtk_widget_class_bind_template_child (widget_class, NautilusToolbarEnd, view_split_button);
+
+    gtk_widget_class_bind_template_callback (widget_class, on_operations_popover_notify_visible);
+}
+
+static void
+nautilus_toolbar_end_init (NautilusToolbarEnd *self)
+{
+    gtk_widget_init_template (GTK_WIDGET (self));
+
+    gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (self->operations_icon),
+                                    (GtkDrawingAreaDrawFunc) on_operations_icon_draw,
+                                    self,
+                                    NULL);
+}
diff --git a/src/nautilus-toolbar-end.h b/src/nautilus-toolbar-end.h
new file mode 100644
index 000000000..036ccfb2c
--- /dev/null
+++ b/src/nautilus-toolbar-end.h
@@ -0,0 +1,34 @@
+/* nautilus-toolbar-end.h
+ *
+ * Copyright 2022 GNOME project contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#pragma once
+
+#include <gtk/gtk.h>
+#include <libadwaita-1/adwaita.h>
+
+#include "nautilus-window-slot.h"
+
+G_BEGIN_DECLS
+
+#define NAUTILUS_TYPE_TOOLBAR_END (nautilus_toolbar_end_get_type())
+
+G_DECLARE_FINAL_TYPE (NautilusToolbarEnd, nautilus_toolbar_end, NAUTILUS, TOOLBAR_END, AdwBin)
+
+G_END_DECLS
diff --git a/src/nautilus-toolbar.c b/src/nautilus-toolbar.c
index 27a5f6402..4bbc62f14 100644
--- a/src/nautilus-toolbar.c
+++ b/src/nautilus-toolbar.c
@@ -27,20 +27,17 @@
 
 #include "nautilus-application.h"
 #include "nautilus-bookmark.h"
-#include "nautilus-file-operations.h"
 #include "nautilus-file-undo-manager.h"
 #include "nautilus-global-preferences.h"
+#include "nautilus-history-controls.h"
 #include "nautilus-location-entry.h"
 #include "nautilus-pathbar.h"
-#include "nautilus-progress-info-manager.h"
-#include "nautilus-progress-info-widget.h"
-#include "nautilus-toolbar-menu-sections.h"
+#include "nautilus-toolbar-end.h"
 #include "nautilus-ui-utilities.h"
 #include "nautilus-window.h"
 
 #define OPERATION_MINIMUM_TIME 2 /*s */
 #define NEEDS_ATTENTION_ANIMATION_TIMEOUT 2000 /*ms */
-#define REMOVE_FINISHED_OPERATIONS_TIEMOUT 3 /*s */
 
 /* Just design, context at https://gitlab.gnome.org/GNOME/nautilus/issues/548#note_274131 */
 
@@ -60,20 +57,6 @@ struct _NautilusToolbar
     gboolean show_location_entry;
     gboolean location_entry_should_auto_hide;
 
-    guint start_operations_timeout_id;
-    guint remove_finished_operations_timeout_id;
-    guint operations_button_attention_timeout_id;
-
-    GtkWidget *operations_button;
-    GtkWidget *operations_popover;
-    GtkWidget *operations_list;
-    GListStore *progress_infos_model;
-    GtkWidget *operations_revealer;
-    GtkWidget *operations_icon;
-
-    GtkWidget *view_split_button;
-    GMenuModel *view_menu;
-
     GtkWidget *app_button;
     GMenuModel *undo_redo_section;
 
@@ -81,18 +64,10 @@ struct _NautilusToolbar
     gboolean show_sidebar_button;
     gboolean sidebar_button_active;
 
-    GtkWidget *forward_button;
-    GtkWidget *forward_menu;
-
-    GtkWidget *back_button;
-    GtkWidget *back_menu;
-
     GtkWidget *search_button;
 
     GtkWidget *location_entry_close_button;
 
-    NautilusProgressInfoManager *progress_manager;
-
     /* active slot & bindings */
     NautilusWindowSlot *window_slot;
     GBinding *search_binding;
@@ -115,8 +90,6 @@ G_DEFINE_TYPE (NautilusToolbar, nautilus_toolbar, ADW_TYPE_BIN);
 
 static void nautilus_toolbar_set_window_slot_real (NautilusToolbar    *self,
                                                    NautilusWindowSlot *slot);
-static void update_operations (NautilusToolbar *self);
-
 static void
 toolbar_update_appearance (NautilusToolbar *self)
 {
@@ -141,560 +114,6 @@ toolbar_update_appearance (NautilusToolbar *self)
     }
 }
 
-static void
-fill_menu (NautilusToolbar *self,
-           GMenu           *menu,
-           gboolean         back)
-{
-    guint index;
-    GList *list;
-    const gchar *name;
-
-    list = back ? nautilus_window_slot_get_back_history (self->window_slot) :
-           nautilus_window_slot_get_forward_history (self->window_slot);
-
-    index = 0;
-    while (list != NULL)
-    {
-        g_autoptr (GMenuItem) item = NULL;
-
-        name = nautilus_bookmark_get_name (NAUTILUS_BOOKMARK (list->data));
-        item = g_menu_item_new (name, NULL);
-        g_menu_item_set_action_and_target (item,
-                                           back ? "win.back-n" : "win.forward-n",
-                                           "u", index);
-        g_menu_append_item (menu, item);
-
-        list = g_list_next (list);
-        ++index;
-    }
-}
-
-static void
-show_menu (NautilusToolbar *self,
-           GtkWidget       *widget)
-{
-    g_autoptr (GMenu) menu = NULL;
-    NautilusNavigationDirection direction;
-    GtkPopoverMenu *popover;
-
-    menu = g_menu_new ();
-
-    direction = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (widget),
-                                                     "nav-direction"));
-
-    switch (direction)
-    {
-        case NAUTILUS_NAVIGATION_DIRECTION_FORWARD:
-        {
-            fill_menu (self, menu, FALSE);
-            popover = GTK_POPOVER_MENU (self->forward_menu);
-        }
-        break;
-
-        case NAUTILUS_NAVIGATION_DIRECTION_BACK:
-        {
-            fill_menu (self, menu, TRUE);
-            popover = GTK_POPOVER_MENU (self->back_menu);
-        }
-        break;
-
-        default:
-        {
-            g_assert_not_reached ();
-        }
-        break;
-    }
-
-    gtk_popover_menu_set_menu_model (popover, G_MENU_MODEL (menu));
-    gtk_popover_popup (GTK_POPOVER (popover));
-}
-
-static void
-navigation_button_press_cb (GtkGestureClick *gesture,
-                            gint             n_press,
-                            gdouble          x,
-                            gdouble          y,
-                            gpointer         user_data)
-{
-    NautilusToolbar *self;
-    GtkWidget *widget;
-    guint button;
-
-    self = NAUTILUS_TOOLBAR (user_data);
-    button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
-    widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
-
-    if (button == GDK_BUTTON_PRIMARY)
-    {
-        /* Don't do anything, primary click is handled through activate */
-        gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_DENIED);
-        return;
-    }
-    else if (button == GDK_BUTTON_MIDDLE)
-    {
-        NautilusNavigationDirection direction;
-
-        direction = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (widget),
-                                                         "nav-direction"));
-
-        nautilus_window_back_or_forward_in_new_tab (self->window, direction);
-    }
-    else if (button == GDK_BUTTON_SECONDARY)
-    {
-        show_menu (self, widget);
-    }
-}
-
-static void
-back_button_longpress_cb (GtkGestureLongPress *gesture,
-                          double               x,
-                          double               y,
-                          gpointer             user_data)
-{
-    NautilusToolbar *self = user_data;
-
-    show_menu (self, self->back_button);
-}
-
-static void
-forward_button_longpress_cb (GtkGestureLongPress *gesture,
-                             double               x,
-                             double               y,
-                             gpointer             user_data)
-{
-    NautilusToolbar *self = user_data;
-
-    show_menu (self, self->forward_button);
-}
-
-static gboolean
-should_show_progress_info (NautilusProgressInfo *info)
-{
-    return nautilus_progress_info_get_total_elapsed_time (info) +
-           nautilus_progress_info_get_remaining_time (info) > OPERATION_MINIMUM_TIME;
-}
-
-static GList *
-get_filtered_progress_infos (NautilusToolbar *self)
-{
-    GList *l;
-    GList *filtered_progress_infos;
-    GList *progress_infos;
-
-    progress_infos = nautilus_progress_info_manager_get_all_infos (self->progress_manager);
-    filtered_progress_infos = NULL;
-
-    for (l = progress_infos; l != NULL; l = l->next)
-    {
-        if (should_show_progress_info (l->data))
-        {
-            filtered_progress_infos = g_list_append (filtered_progress_infos, l->data);
-        }
-    }
-
-    return filtered_progress_infos;
-}
-
-static gboolean
-should_hide_operations_button (NautilusToolbar *self)
-{
-    GList *progress_infos;
-    GList *l;
-
-    progress_infos = get_filtered_progress_infos (self);
-
-    for (l = progress_infos; l != NULL; l = l->next)
-    {
-        if (nautilus_progress_info_get_total_elapsed_time (l->data) +
-            nautilus_progress_info_get_remaining_time (l->data) > OPERATION_MINIMUM_TIME &&
-            !nautilus_progress_info_get_is_cancelled (l->data) &&
-            !nautilus_progress_info_get_is_finished (l->data))
-        {
-            return FALSE;
-        }
-    }
-
-    g_list_free (progress_infos);
-
-    return TRUE;
-}
-
-static gboolean
-on_remove_finished_operations_timeout (NautilusToolbar *self)
-{
-    nautilus_progress_info_manager_remove_finished_or_cancelled_infos (self->progress_manager);
-    if (should_hide_operations_button (self))
-    {
-        gtk_revealer_set_reveal_child (GTK_REVEALER (self->operations_revealer),
-                                       FALSE);
-    }
-    else
-    {
-        update_operations (self);
-    }
-
-    self->remove_finished_operations_timeout_id = 0;
-
-    return G_SOURCE_REMOVE;
-}
-
-static void
-unschedule_remove_finished_operations (NautilusToolbar *self)
-{
-    if (self->remove_finished_operations_timeout_id != 0)
-    {
-        g_source_remove (self->remove_finished_operations_timeout_id);
-        self->remove_finished_operations_timeout_id = 0;
-    }
-}
-
-static void
-schedule_remove_finished_operations (NautilusToolbar *self)
-{
-    if (self->remove_finished_operations_timeout_id == 0)
-    {
-        self->remove_finished_operations_timeout_id =
-            g_timeout_add_seconds (REMOVE_FINISHED_OPERATIONS_TIEMOUT,
-                                   (GSourceFunc) on_remove_finished_operations_timeout,
-                                   self);
-    }
-}
-
-static void
-remove_operations_button_attention_style (NautilusToolbar *self)
-{
-    GtkStyleContext *style_context;
-
-    style_context = gtk_widget_get_style_context (self->operations_button);
-    gtk_style_context_remove_class (style_context,
-                                    "nautilus-operations-button-needs-attention");
-}
-
-static gboolean
-on_remove_operations_button_attention_style_timeout (NautilusToolbar *self)
-{
-    remove_operations_button_attention_style (self);
-    self->operations_button_attention_timeout_id = 0;
-
-    return G_SOURCE_REMOVE;
-}
-
-static void
-unschedule_operations_button_attention_style (NautilusToolbar *self)
-{
-    if (self->operations_button_attention_timeout_id != 0)
-    {
-        g_source_remove (self->operations_button_attention_timeout_id);
-        self->operations_button_attention_timeout_id = 0;
-    }
-}
-
-static void
-add_operations_button_attention_style (NautilusToolbar *self)
-{
-    GtkStyleContext *style_context;
-
-    style_context = gtk_widget_get_style_context (self->operations_button);
-
-    unschedule_operations_button_attention_style (self);
-    remove_operations_button_attention_style (self);
-
-    gtk_style_context_add_class (style_context,
-                                 "nautilus-operations-button-needs-attention");
-    self->operations_button_attention_timeout_id = g_timeout_add (NEEDS_ATTENTION_ANIMATION_TIMEOUT,
-                                                                  (GSourceFunc) 
on_remove_operations_button_attention_style_timeout,
-                                                                  self);
-}
-
-static void
-on_progress_info_cancelled (NautilusToolbar *self)
-{
-    /* Update the pie chart progress */
-    gtk_widget_queue_draw (self->operations_icon);
-
-    if (!nautilus_progress_manager_has_viewers (self->progress_manager))
-    {
-        schedule_remove_finished_operations (self);
-    }
-}
-
-static void
-on_progress_info_progress_changed (NautilusToolbar *self)
-{
-    /* Update the pie chart progress */
-    gtk_widget_queue_draw (self->operations_icon);
-}
-
-static void
-on_progress_info_finished (NautilusToolbar      *self,
-                           NautilusProgressInfo *info)
-{
-    gchar *main_label;
-    GFile *folder_to_open;
-
-    /* Update the pie chart progress */
-    gtk_widget_queue_draw (self->operations_icon);
-
-    if (!nautilus_progress_manager_has_viewers (self->progress_manager))
-    {
-        schedule_remove_finished_operations (self);
-    }
-
-    folder_to_open = nautilus_progress_info_get_destination (info);
-    /* If destination is null, don't show a notification. This happens when the
-     * operation is a trash operation, which we already show a diferent kind of
-     * notification */
-    if (!gtk_widget_is_visible (self->operations_popover) &&
-        folder_to_open != NULL)
-    {
-        add_operations_button_attention_style (self);
-        main_label = nautilus_progress_info_get_status (info);
-        nautilus_window_show_operation_notification (self->window,
-                                                     main_label,
-                                                     folder_to_open);
-        g_free (main_label);
-    }
-
-    g_clear_object (&folder_to_open);
-}
-
-static void
-disconnect_progress_infos (NautilusToolbar *self)
-{
-    GList *progress_infos;
-    GList *l;
-
-    progress_infos = nautilus_progress_info_manager_get_all_infos (self->progress_manager);
-    for (l = progress_infos; l != NULL; l = l->next)
-    {
-        g_signal_handlers_disconnect_by_data (l->data, self);
-    }
-}
-
-static void
-update_operations (NautilusToolbar *self)
-{
-    GList *progress_infos;
-    GList *l;
-    gboolean should_show_progress_button = FALSE;
-
-    disconnect_progress_infos (self);
-    g_list_store_remove_all (self->progress_infos_model);
-
-    progress_infos = get_filtered_progress_infos (self);
-    for (l = progress_infos; l != NULL; l = l->next)
-    {
-        should_show_progress_button = should_show_progress_button ||
-                                      should_show_progress_info (l->data);
-
-        g_signal_connect_swapped (l->data, "finished",
-                                  G_CALLBACK (on_progress_info_finished), self);
-        g_signal_connect_swapped (l->data, "cancelled",
-                                  G_CALLBACK (on_progress_info_cancelled), self);
-        g_signal_connect_swapped (l->data, "progress-changed",
-                                  G_CALLBACK (on_progress_info_progress_changed), self);
-        g_list_store_append (self->progress_infos_model, l->data);
-    }
-
-    g_list_free (progress_infos);
-
-    if (should_show_progress_button &&
-        !gtk_revealer_get_reveal_child (GTK_REVEALER (self->operations_revealer)))
-    {
-        add_operations_button_attention_style (self);
-        gtk_revealer_set_reveal_child (GTK_REVEALER (self->operations_revealer),
-                                       TRUE);
-        gtk_widget_queue_draw (self->operations_icon);
-    }
-
-    /* Since we removed the info widgets, we need to restore the focus */
-    if (gtk_widget_get_visible (self->operations_popover))
-    {
-        gtk_widget_grab_focus (self->operations_popover);
-    }
-}
-
-static gboolean
-on_progress_info_started_timeout (NautilusToolbar *self)
-{
-    GList *progress_infos;
-    GList *filtered_progress_infos;
-
-    update_operations (self);
-
-    /* In case we didn't show the operations button because the operation total
-     * time stimation is not good enough, update again to make sure we don't miss
-     * a long time operation because of that */
-
-    progress_infos = nautilus_progress_info_manager_get_all_infos (self->progress_manager);
-    filtered_progress_infos = get_filtered_progress_infos (self);
-    if (!nautilus_progress_manager_are_all_infos_finished_or_cancelled (self->progress_manager) &&
-        g_list_length (progress_infos) != g_list_length (filtered_progress_infos))
-    {
-        g_list_free (filtered_progress_infos);
-        return G_SOURCE_CONTINUE;
-    }
-    else
-    {
-        g_list_free (filtered_progress_infos);
-        self->start_operations_timeout_id = 0;
-        return G_SOURCE_REMOVE;
-    }
-}
-
-static void
-schedule_operations_start (NautilusToolbar *self)
-{
-    if (self->start_operations_timeout_id == 0)
-    {
-        /* Timeout is a little more than what we require for a stimated operation
-         * total time, to make sure the stimated total time is correct */
-        self->start_operations_timeout_id =
-            g_timeout_add (SECONDS_NEEDED_FOR_APROXIMATE_TRANSFER_RATE * 1000 + 500,
-                           (GSourceFunc) on_progress_info_started_timeout,
-                           self);
-    }
-}
-
-static void
-unschedule_operations_start (NautilusToolbar *self)
-{
-    if (self->start_operations_timeout_id != 0)
-    {
-        g_source_remove (self->start_operations_timeout_id);
-        self->start_operations_timeout_id = 0;
-    }
-}
-
-static void
-on_progress_info_started (NautilusProgressInfo *info,
-                          NautilusToolbar      *self)
-{
-    g_signal_handlers_disconnect_by_data (info, self);
-    schedule_operations_start (self);
-}
-
-static void
-on_new_progress_info (NautilusProgressInfoManager *manager,
-                      NautilusProgressInfo        *info,
-                      NautilusToolbar             *self)
-{
-    g_signal_connect (info, "started",
-                      G_CALLBACK (on_progress_info_started), self);
-}
-
-static void
-on_operations_icon_draw (GtkDrawingArea  *drawing_area,
-                         cairo_t         *cr,
-                         int              width,
-                         int              height,
-                         NautilusToolbar *self)
-{
-    GtkWidget *widget = GTK_WIDGET (drawing_area);
-    gfloat elapsed_progress = 0;
-    gint remaining_progress = 0;
-    gint total_progress;
-    gdouble ratio;
-    GList *progress_infos;
-    GList *l;
-    gboolean all_cancelled;
-    GdkRGBA background;
-    GdkRGBA foreground;
-    GtkStyleContext *style_context;
-
-    style_context = gtk_widget_get_style_context (widget);
-    gtk_style_context_get_color (style_context, &foreground);
-    background = foreground;
-    background.alpha *= 0.3;
-
-    all_cancelled = TRUE;
-    progress_infos = get_filtered_progress_infos (self);
-    for (l = progress_infos; l != NULL; l = l->next)
-    {
-        if (!nautilus_progress_info_get_is_cancelled (l->data))
-        {
-            all_cancelled = FALSE;
-            remaining_progress += nautilus_progress_info_get_remaining_time (l->data);
-            elapsed_progress += nautilus_progress_info_get_elapsed_time (l->data);
-        }
-    }
-
-    g_list_free (progress_infos);
-
-    total_progress = remaining_progress + elapsed_progress;
-
-    if (all_cancelled)
-    {
-        ratio = 1.0;
-    }
-    else
-    {
-        if (total_progress > 0)
-        {
-            ratio = MAX (0.05, elapsed_progress / total_progress);
-        }
-        else
-        {
-            ratio = 0.05;
-        }
-    }
-
-
-    width = gtk_widget_get_allocated_width (widget);
-    height = gtk_widget_get_allocated_height (widget);
-
-    gdk_cairo_set_source_rgba (cr, &background);
-    cairo_arc (cr,
-               width / 2.0, height / 2.0,
-               MIN (width, height) / 2.0,
-               0, 2 * G_PI);
-    cairo_fill (cr);
-    cairo_move_to (cr, width / 2.0, height / 2.0);
-    gdk_cairo_set_source_rgba (cr, &foreground);
-    cairo_arc (cr,
-               width / 2.0, height / 2.0,
-               MIN (width, height) / 2.0,
-               -G_PI / 2.0, ratio * 2 * G_PI - G_PI / 2.0);
-
-    cairo_fill (cr);
-}
-
-static void
-on_operations_popover_notify_visible (NautilusToolbar *self,
-                                      GParamSpec      *pspec,
-                                      GObject         *popover)
-{
-    if (gtk_widget_get_visible (GTK_WIDGET (popover)))
-    {
-        unschedule_remove_finished_operations (self);
-        nautilus_progress_manager_add_viewer (self->progress_manager,
-                                              G_OBJECT (self));
-    }
-    else
-    {
-        nautilus_progress_manager_remove_viewer (self->progress_manager,
-                                                 G_OBJECT (self));
-    }
-}
-
-static void
-on_progress_has_viewers_changed (NautilusProgressInfoManager *manager,
-                                 NautilusToolbar             *self)
-{
-    if (nautilus_progress_manager_has_viewers (manager))
-    {
-        unschedule_remove_finished_operations (self);
-        return;
-    }
-
-    if (nautilus_progress_manager_are_all_infos_finished_or_cancelled (manager))
-    {
-        unschedule_remove_finished_operations (self);
-        schedule_remove_finished_operations (self);
-    }
-}
-
 static void
 update_action (NautilusToolbar *self,
                const char      *action_name,
@@ -791,24 +210,10 @@ on_location_entry_focus_changed (GObject    *object,
     }
 }
 
-static GtkWidget *
-operations_list_create_widget (GObject  *item,
-                               gpointer  user_data)
-{
-    NautilusProgressInfo *info = NAUTILUS_PROGRESS_INFO (item);
-    GtkWidget *widget;
-
-    widget = nautilus_progress_info_widget_new (info);
-    gtk_widget_show (widget);
-
-    return widget;
-}
-
 static void
 nautilus_toolbar_constructed (GObject *object)
 {
     NautilusToolbar *self = NAUTILUS_TOOLBAR (object);
-    GtkEventController *controller;
 
     self->path_bar = GTK_WIDGET (g_object_new (NAUTILUS_TYPE_PATH_BAR, NULL));
     gtk_box_append (GTK_BOX (self->path_bar_container),
@@ -822,52 +227,6 @@ nautilus_toolbar_constructed (GObject *object)
                     self->location_entry_close_button);
     g_signal_connect (self->location_entry_close_button, "clicked",
                       G_CALLBACK (on_location_entry_close), self);
-
-    self->progress_manager = nautilus_progress_info_manager_dup_singleton ();
-    g_signal_connect (self->progress_manager, "new-progress-info",
-                      G_CALLBACK (on_new_progress_info), self);
-    g_signal_connect (self->progress_manager, "has-viewers-changed",
-                      G_CALLBACK (on_progress_has_viewers_changed), self);
-
-    self->progress_infos_model = g_list_store_new (NAUTILUS_TYPE_PROGRESS_INFO);
-    gtk_list_box_bind_model (GTK_LIST_BOX (self->operations_list),
-                             G_LIST_MODEL (self->progress_infos_model),
-                             (GtkListBoxCreateWidgetFunc) operations_list_create_widget,
-                             NULL,
-                             NULL);
-    update_operations (self);
-
-    controller = GTK_EVENT_CONTROLLER (gtk_gesture_long_press_new ());
-    gtk_widget_add_controller (self->back_button, controller);
-    g_signal_connect (controller, "pressed",
-                      G_CALLBACK (back_button_longpress_cb), self);
-
-    controller = GTK_EVENT_CONTROLLER (gtk_gesture_long_press_new ());
-    gtk_widget_add_controller (self->forward_button, controller);
-    g_signal_connect (controller, "pressed",
-                      G_CALLBACK (forward_button_longpress_cb), self);
-
-    g_object_set_data (G_OBJECT (self->back_button), "nav-direction",
-                       GUINT_TO_POINTER (NAUTILUS_NAVIGATION_DIRECTION_BACK));
-    g_object_set_data (G_OBJECT (self->forward_button), "nav-direction",
-                       GUINT_TO_POINTER (NAUTILUS_NAVIGATION_DIRECTION_FORWARD));
-
-    controller = GTK_EVENT_CONTROLLER (gtk_gesture_click_new ());
-    gtk_widget_add_controller (self->back_button, controller);
-    gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (controller), 0);
-    g_signal_connect (controller, "pressed",
-                      G_CALLBACK (navigation_button_press_cb), self);
-
-    controller = GTK_EVENT_CONTROLLER (gtk_gesture_click_new ());
-    gtk_widget_add_controller (self->forward_button, controller);
-    gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (controller), 0);
-    g_signal_connect (controller, "pressed",
-                      G_CALLBACK (navigation_button_press_cb), self);
-
-    g_signal_connect (self->operations_popover, "show",
-                      (GCallback) gtk_widget_grab_focus, NULL);
-    g_signal_connect_swapped (self->operations_popover, "closed",
-                              (GCallback) gtk_widget_grab_focus, self);
     g_signal_connect (self->location_entry, "notify::has-focus",
                       G_CALLBACK (on_location_entry_focus_changed), self);
 
@@ -882,17 +241,10 @@ nautilus_toolbar_constructed (GObject *object)
 static void
 nautilus_toolbar_init (NautilusToolbar *self)
 {
-    gtk_widget_init_template (GTK_WIDGET (self));
+    g_type_ensure (NAUTILUS_TYPE_HISTORY_CONTROLS);
+    g_type_ensure (NAUTILUS_TYPE_TOOLBAR_END);
 
-    gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (self->operations_icon),
-                                    (GtkDrawingAreaDrawFunc) on_operations_icon_draw,
-                                    self,
-                                    NULL);
-
-    gtk_widget_set_parent (self->back_menu, self->back_button);
-    g_signal_connect (self->back_menu, "destroy", G_CALLBACK (gtk_widget_unparent), NULL);
-    gtk_widget_set_parent (self->forward_menu, self->forward_button);
-    g_signal_connect (self->forward_menu, "destroy", G_CALLBACK (gtk_widget_unparent), NULL);
+    gtk_widget_init_template (GTK_WIDGET (self));
 }
 
 void
@@ -1083,8 +435,6 @@ nautilus_toolbar_dispose (GObject *object)
     self = NAUTILUS_TOOLBAR (object);
 
     g_clear_pointer (&self->search_binding, g_binding_unbind);
-    g_clear_pointer (&self->back_menu, gtk_widget_unparent);
-    g_clear_pointer (&self->forward_menu, gtk_widget_unparent);
 
     G_OBJECT_CLASS (nautilus_toolbar_parent_class)->dispose (object);
 }
@@ -1104,14 +454,6 @@ nautilus_toolbar_finalize (GObject *obj)
                              on_window_slot_destroyed, self);
         self->window_slot = NULL;
     }
-    disconnect_progress_infos (self);
-    unschedule_remove_finished_operations (self);
-    unschedule_operations_start (self);
-    unschedule_operations_button_attention_style (self);
-
-    g_clear_object (&self->progress_infos_model);
-    g_signal_handlers_disconnect_by_data (self->progress_manager, self);
-    g_clear_object (&self->progress_manager);
 
     g_signal_handlers_disconnect_by_func (self->window,
                                           on_window_focus_changed, self);
@@ -1174,19 +516,8 @@ nautilus_toolbar_class_init (NautilusToolbarClass *klass)
     gtk_widget_class_set_template_from_resource (widget_class,
                                                  "/org/gnome/nautilus/ui/nautilus-toolbar.ui");
 
-    gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, operations_button);
-    gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, operations_icon);
-    gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, operations_popover);
-    gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, operations_list);
-    gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, operations_revealer);
-    gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, view_menu);
-    gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, view_split_button);
     gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, app_button);
     gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, undo_redo_section);
-    gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, back_button);
-    gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, back_menu);
-    gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, forward_button);
-    gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, forward_menu);
     gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, toolbar_switcher);
     gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, search_container);
     gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, path_bar_container);
@@ -1194,8 +525,6 @@ nautilus_toolbar_class_init (NautilusToolbarClass *klass)
 
     gtk_widget_class_bind_template_child (widget_class, NautilusToolbar, search_button);
 
-    gtk_widget_class_bind_template_callback (widget_class, on_operations_popover_notify_visible);
-
     gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_TOOLBAR);
 }
 
@@ -1265,46 +594,6 @@ slot_on_templates_menu_changed (NautilusToolbar    *self,
                                           menu);
 }
 
-static void
-on_slot_toolbar_menu_sections_changed (NautilusToolbar    *self,
-                                       GParamSpec         *param,
-                                       NautilusWindowSlot *slot)
-{
-    NautilusToolbarMenuSections *new_sections;
-    g_autoptr (GMenuItem) zoom_item = NULL;
-    g_autoptr (GMenuItem) sort_item = NULL;
-
-    new_sections = nautilus_window_slot_get_toolbar_menu_sections (slot);
-
-    gtk_widget_set_sensitive (self->view_split_button, (new_sections != NULL));
-    if (new_sections == NULL)
-    {
-        return;
-    }
-
-    /* Let's assume that sort section is the first item
-     * in view_menu, as per nautilus-toolbar.ui. */
-
-    sort_item = g_menu_item_new_from_model (self->view_menu, 0);
-    g_menu_remove (G_MENU (self->view_menu), 0);
-    g_menu_item_set_section (sort_item, new_sections->sort_section);
-    g_menu_insert_item (G_MENU (self->view_menu), 0, sort_item);
-}
-
-
-static void
-disconnect_toolbar_menu_sections_change_handler (NautilusToolbar *self)
-{
-    if (self->window_slot == NULL)
-    {
-        return;
-    }
-
-    g_signal_handlers_disconnect_by_func (self->window_slot,
-                                          G_CALLBACK (on_slot_toolbar_menu_sections_changed),
-                                          self);
-}
-
 /* Called from on_window_slot_destroyed(), since bindings and signal handlers
  * are automatically removed once the slot goes away.
  */
@@ -1313,7 +602,6 @@ nautilus_toolbar_set_window_slot_real (NautilusToolbar    *self,
                                        NautilusWindowSlot *slot)
 {
     g_autoptr (GList) children = NULL;
-    GtkWidget *toggle_button;
 
     self->window_slot = slot;
 
@@ -1327,9 +615,6 @@ nautilus_toolbar_set_window_slot_real (NautilusToolbar    *self,
                                                        self, "searching",
                                                        G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
 
-        on_slot_toolbar_menu_sections_changed (self, NULL, self->window_slot);
-        g_signal_connect_swapped (self->window_slot, "notify::toolbar-menu-sections",
-                                  G_CALLBACK (on_slot_toolbar_menu_sections_changed), self);
         g_signal_connect_swapped (self->window_slot, "notify::extensions-background-menu",
                                   G_CALLBACK (slot_on_extensions_background_menu_changed), self);
         g_signal_connect_swapped (self->window_slot, "notify::templates-menu",
@@ -1366,7 +651,6 @@ nautilus_toolbar_set_window_slot (NautilusToolbar    *self,
 
     g_clear_pointer (&self->search_binding, g_binding_unbind);
 
-    disconnect_toolbar_menu_sections_change_handler (self);
     if (self->window_slot != NULL)
     {
         g_signal_handlers_disconnect_by_data (self->window_slot, self);
@@ -1389,9 +673,3 @@ nautilus_toolbar_is_menu_visible (NautilusToolbar *self)
 
     return gtk_widget_is_visible (menu);
 }
-
-gboolean
-nautilus_toolbar_is_operations_button_active (NautilusToolbar *self)
-{
-    return gtk_widget_is_visible (GTK_WIDGET (self->operations_popover));
-}
diff --git a/src/resources/nautilus.gresource.xml b/src/resources/nautilus.gresource.xml
index 3a6abce9a..435d6dfba 100644
--- a/src/resources/nautilus.gresource.xml
+++ b/src/resources/nautilus.gresource.xml
@@ -6,6 +6,8 @@
     <file>ui/nautilus-app-chooser.ui</file>
     <file>ui/nautilus-pathbar-context-menu.ui</file>
     <file>ui/nautilus-toolbar.ui</file>
+    <file>ui/nautilus-toolbar-end.ui</file>
+    <file>ui/nautilus-history-controls.ui</file>
     <file>ui/nautilus-toolbar-view-menu.ui</file>
     <file>ui/nautilus-column-chooser.ui</file>
     <file>ui/nautilus-list-view-column-editor.ui</file>
diff --git a/src/resources/ui/nautilus-history-controls.ui b/src/resources/ui/nautilus-history-controls.ui
new file mode 100644
index 000000000..3a52d14fd
--- /dev/null
+++ b/src/resources/ui/nautilus-history-controls.ui
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <object class="GtkPopoverMenu" id="back_menu"/>
+  <object class="GtkPopoverMenu" id="forward_menu"/>
+  <template class="NautilusHistoryControls" parent="AdwBin">
+    <property name="child">
+      <object class="GtkBox">
+        <property name="spacing">6</property>
+        <child>
+          <object class="GtkButton" id="back_button">
+            <property name="tooltip_text" translatable="yes">Go back</property>
+            <property name="valign">center</property>
+            <property name="action_name">win.back</property>
+            <property name="icon_name">go-previous-symbolic</property>
+          </object>
+        </child>
+        <child>
+          <object class="GtkButton" id="forward_button">
+            <property name="tooltip_text" translatable="yes">Go forward</property>
+            <property name="valign">center</property>
+            <property name="action_name">win.forward</property>
+            <property name="icon_name">go-next-symbolic</property>
+          </object>
+        </child>
+        <child>
+          <object class="GtkSeparator">
+            <style>
+              <class name="spacer"/>
+            </style>
+          </object>
+        </child>
+      </object>
+    </property>
+  </template>
+</interface>
diff --git a/src/resources/ui/nautilus-toolbar-end.ui b/src/resources/ui/nautilus-toolbar-end.ui
new file mode 100644
index 000000000..22bcffc88
--- /dev/null
+++ b/src/resources/ui/nautilus-toolbar-end.ui
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <menu id="view_menu">
+    <section>
+      <attribute name="label" translatable="yes" context="menu item" comments="Translators: a menu item in a 
group of sorting options in a toolbar menu, with criterions such as &quot;A-Z&quot; or &quot;Last 
Modified&quot;.">Sort</attribute>
+      <!--
+           Sort section.
+
+           The toolbar code assumes this is the second item of this menu model.
+           Its contents is provided by the view.
+      -->
+    </section>
+    <section>
+      <item>
+        <attribute name="label" translatable="yes">_Visible Columns…</attribute>
+        <attribute name="action">view.visible-columns</attribute>
+        <attribute name="hidden-when">action-missing</attribute>
+      </item>
+    </section>
+  </menu>
+  <object class="GtkPopover" id="operations_popover">
+    <property name="child">
+      <object class="GtkScrolledWindow">
+        <property name="hscrollbar_policy">never</property>
+        <property name="max_content_height">270</property>
+        <property name="propagate_natural_height">True</property>
+        <property name="child">
+          <object class="GtkListBox" id="operations_list">
+            <property name="margin_start">6</property>
+            <property name="margin_end">6</property>
+            <property name="margin_top">6</property>
+            <property name="margin_bottom">6</property>
+            <property name="selection-mode">none</property>
+            <property name="activate-on-single-click">False</property>
+            <style>
+              <class name="operations-list"/>
+            </style>
+          </object>
+        </property>
+      </object>
+    </property>
+    <signal name="notify::visible" handler="on_operations_popover_notify_visible" 
object="NautilusToolbarEnd" swapped="yes"/>
+  </object>
+  <template class="NautilusToolbarEnd" parent="AdwBin">
+    <property name="child">
+      <object class="GtkBox">
+        <property name="spacing">6</property>
+        <child>
+          <object class="GtkSeparator">
+            <style>
+              <class name="spacer"/>
+            </style>
+          </object>
+        </child>
+        <child>
+          <object class="GtkRevealer" id="operations_revealer">
+            <property name="halign">center</property>
+            <property name="valign">center</property>
+            <property name="transition_type">slide-right</property>
+            <property name="child">
+              <object class="GtkMenuButton" id="operations_button">
+                <property name="tooltip_text" translatable="yes">Show operations</property>
+                <property name="popover">operations_popover</property>
+                <child>
+                  <object class="GtkDrawingArea" id="operations_icon">
+                    <property name="width_request">16</property>
+                    <property name="height_request">16</property>
+                    <property name="halign">center</property>
+                    <property name="valign">center</property>
+                  </object>
+                </child>
+                <style>
+                  <class name="image-button"/>
+                </style>
+              </object>
+            </property>
+          </object>
+        </child>
+        <child>
+          <object class="AdwSplitButton" id="view_split_button">
+            <property name="halign">center</property>
+            <property name="valign">center</property>
+            <property name="tooltip_text" translatable="yes">Toggle view</property>
+            <property name="action_name">slot.files-view-mode-toggle</property>
+            <property name="menu-model">view_menu</property>
+            <binding name="icon-name">
+              <lookup name="icon-name">
+                <lookup name="window-slot">NautilusToolbarEnd</lookup>
+              </lookup>
+            </binding>
+            <binding name="tooltip-text">
+              <lookup name="tooltip">
+                <lookup name="window-slot">NautilusToolbarEnd</lookup>
+              </lookup>
+            </binding>
+          </object>
+        </child>
+      </object>
+    </property>
+  </template>
+</interface>
diff --git a/src/resources/ui/nautilus-toolbar.ui b/src/resources/ui/nautilus-toolbar.ui
index 682fff316..51b131e12 100644
--- a/src/resources/ui/nautilus-toolbar.ui
+++ b/src/resources/ui/nautilus-toolbar.ui
@@ -1,26 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <interface>
   <requires lib="gtk" version="4.0"/>
-  <object class="GtkPopoverMenu" id="back_menu"/>
-  <object class="GtkPopoverMenu" id="forward_menu"/>
-  <menu id="view_menu">
-    <section>
-      <attribute name="label" translatable="yes" context="menu item" comments="Translators: a menu item in a 
group of sorting options in a toolbar menu, with criterions such as &quot;A-Z&quot; or &quot;Last 
Modified&quot;.">Sort</attribute>
-      <!--
-           Sort section.
-
-           The toolbar code assumes this is the second item of this menu model.
-           Its contents is provided by the view.
-      -->
-    </section>
-    <section>
-      <item>
-        <attribute name="label" translatable="yes">_Visible Columns…</attribute>
-        <attribute name="action">view.visible-columns</attribute>
-        <attribute name="hidden-when">action-missing</attribute>
-      </item>
-    </section>
-  </menu>
   <menu id="app_menu">
     <section>
       <item>
@@ -82,29 +62,6 @@
       </item>
     </section>
   </menu>
-  <object class="GtkPopover" id="operations_popover">
-    <property name="child">
-      <object class="GtkScrolledWindow">
-        <property name="hscrollbar_policy">never</property>
-        <property name="max_content_height">270</property>
-        <property name="propagate_natural_height">True</property>
-        <property name="child">
-          <object class="GtkListBox" id="operations_list">
-            <property name="margin_start">6</property>
-            <property name="margin_end">6</property>
-            <property name="margin_top">6</property>
-            <property name="margin_bottom">6</property>
-            <property name="selection-mode">none</property>
-            <property name="activate-on-single-click">False</property>
-            <style>
-              <class name="operations-list"/>
-            </style>
-          </object>
-        </property>
-      </object>
-    </property>
-    <signal name="notify::visible" handler="on_operations_popover_notify_visible" object="NautilusToolbar" 
swapped="yes"/>
-  </object>
   <template class="NautilusToolbar" parent="AdwBin">
     <child>
       <object class="AdwHeaderBar">
@@ -169,28 +126,8 @@
           </object>
         </child>
         <child type="start">
-          <object class="GtkButton" id="back_button">
-            <property name="tooltip_text" translatable="yes">Go back</property>
-            <property name="halign">center</property>
-            <property name="valign">center</property>
-            <property name="action_name">win.back</property>
-            <property name="icon_name">go-previous-symbolic</property>
-          </object>
-        </child>
-        <child type="start">
-          <object class="GtkButton" id="forward_button">
-            <property name="tooltip_text" translatable="yes">Go forward</property>
-            <property name="halign">center</property>
-            <property name="valign">center</property>
-            <property name="action_name">win.forward</property>
-            <property name="icon_name">go-next-symbolic</property>
-          </object>
-        </child>
-        <child type="start">
-          <object class="GtkSeparator">
-            <style>
-              <class name="spacer"/>
-            </style>
+          <object class="NautilusHistoryControls">
+            <property name="window-slot" bind-source="NautilusToolbar" bind-property="window-slot" 
bind-flags="sync-create"/>
           </object>
         </child>
         <child type="end">
@@ -226,56 +163,12 @@
           </object>
         </child>
         <child type="end">
-          <object class="AdwSplitButton" id="view_split_button">
-            <property name="halign">center</property>
-            <property name="valign">center</property>
-            <property name="tooltip_text" translatable="yes" comments="Translators: This is a noun, meaning 
the options pertaining to the view.">View options</property>
-            <property name="action_name">slot.files-view-mode-toggle</property>
-            <property name="menu-model">view_menu</property>
-            <binding name="icon-name">
-              <lookup name="icon-name">
-                <lookup name="window-slot">NautilusToolbar</lookup>
-              </lookup>
-            </binding>
-            <binding name="tooltip-text">
-              <lookup name="tooltip">
-                <lookup name="window-slot">NautilusToolbar</lookup>
-              </lookup>
-            </binding>
-          </object>
-        </child>
-        <child type="end">
-          <object class="GtkRevealer" id="operations_revealer">
-            <property name="halign">center</property>
-            <property name="valign">center</property>
-            <property name="transition_type">slide-right</property>
-            <property name="child">
-              <object class="GtkMenuButton" id="operations_button">
-                <property name="tooltip_text" translatable="yes">Show operations</property>
-                <property name="popover">operations_popover</property>
-                <child>
-                  <object class="GtkDrawingArea" id="operations_icon">
-                    <property name="width_request">16</property>
-                    <property name="height_request">16</property>
-                    <property name="halign">center</property>
-                    <property name="valign">center</property>
-                  </object>
-                </child>
-                <style>
-                  <class name="image-button"/>
-                </style>
-              </object>
-            </property>
-          </object>
-        </child>
-        <child type="end">
-          <object class="GtkSeparator">
-            <style>
-              <class name="spacer"/>
-            </style>
+          <object class="NautilusToolbarEnd">
+            <property name="window-slot" bind-source="NautilusToolbar" bind-property="window-slot" 
bind-flags="sync-create"/>
           </object>
         </child>
       </object>
     </child>
   </template>
 </interface>
+


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]