[Xfce4-commits] <thunar:nick/tabs> Implement tabs in Thunar.

Nick Schermer noreply at xfce.org
Sun Oct 28 17:58:02 CET 2012


Updating branch refs/heads/nick/tabs
         to c588849f6108c04ebb05683c12358fcd86dc2422 (commit)
       from 4699dd387aede8a6d337809cf4edfcdb656844b3 (commit)

commit c588849f6108c04ebb05683c12358fcd86dc2422
Author: Nick Schermer <nick at xfce.org>
Date:   Sat Oct 27 18:12:49 2012 +0200

    Implement tabs in Thunar.

 thunar/thunar-abstract-icon-view.c |   34 ++-
 thunar/thunar-application.c        |    5 +-
 thunar/thunar-device.c             |    4 +-
 thunar/thunar-launcher-ui.xml      |    2 +
 thunar/thunar-launcher.c           |  164 +++++--
 thunar/thunar-navigator.c          |   21 +
 thunar/thunar-navigator.h          |    5 +
 thunar/thunar-preferences-dialog.c |   24 +
 thunar/thunar-preferences.c        |   43 ++
 thunar/thunar-shortcuts-pane.c     |    1 +
 thunar/thunar-shortcuts-view.c     |  101 +++--
 thunar/thunar-standard-view-ui.xml |   14 +
 thunar/thunar-standard-view.c      |  374 ++++++++++++++--
 thunar/thunar-tree-pane.c          |    1 +
 thunar/thunar-tree-view.c          |  128 +++++-
 thunar/thunar-window-ui.xml        |   23 +-
 thunar/thunar-window.c             |  868 ++++++++++++++++++++++++++----------
 17 files changed, 1425 insertions(+), 387 deletions(-)

diff --git a/thunar/thunar-abstract-icon-view.c b/thunar/thunar-abstract-icon-view.c
index 5def67d..f6e34df 100644
--- a/thunar/thunar-abstract-icon-view.c
+++ b/thunar/thunar-abstract-icon-view.c
@@ -27,6 +27,7 @@
 #include <thunar/thunar-abstract-icon-view-ui.h>
 #include <thunar/thunar-gobject-extensions.h>
 #include <thunar/thunar-gtk-extensions.h>
+#include <thunar/thunar-preferences.h>
 #include <thunar/thunar-private.h>
 
 
@@ -475,10 +476,13 @@ thunar_abstract_icon_view_button_press_event (ExoIconView            *view,
                                               GdkEventButton         *event,
                                               ThunarAbstractIconView *abstract_icon_view)
 {
-  GtkTreePath *path;
-  GtkTreeIter  iter;
-  ThunarFile  *file;
-  GtkAction   *action;
+  GtkTreePath       *path;
+  GtkTreeIter        iter;
+  ThunarFile        *file;
+  GtkAction         *action;
+  ThunarPreferences *preferences;
+  gboolean           in_tab;
+  const gchar       *action_name;
 
   if (event->type == GDK_BUTTON_PRESS && event->button == 3)
     {
@@ -533,10 +537,26 @@ thunar_abstract_icon_view_button_press_event (ExoIconView            *view,
               if (G_LIKELY (file != NULL))
                 {
                   /* determine the action to perform depending on the type of the file */
-                  action = thunar_gtk_ui_manager_get_action_by_name (THUNAR_STANDARD_VIEW (abstract_icon_view)->ui_manager,
-                      thunar_file_is_directory (file) ? "open-in-new-window" : "open");
-      
+                  if (thunar_file_is_directory (file))
+                    {
+                      /* lookup setting if we should open in a tab or a window */
+                      preferences = thunar_preferences_get ();
+                      g_object_get (preferences, "misc-middle-click-in-tab", &in_tab, NULL);
+                      g_object_unref (preferences);
+
+                      /* holding ctrl inverts the action */
+                      if ((event->state & GDK_CONTROL_MASK) != 0)
+                        in_tab = !in_tab;
+
+                      action_name = in_tab ? "open-in-new-tab" : "open-in-new-window";
+                    }
+                  else
+                    {
+                      action_name = "open";
+                    }
+
                   /* emit the action */
+                  action = thunar_gtk_ui_manager_get_action_by_name (THUNAR_STANDARD_VIEW (abstract_icon_view)->ui_manager, action_name);
                   if (G_LIKELY (action != NULL))
                     gtk_action_activate (action);
 
diff --git a/thunar/thunar-application.c b/thunar/thunar-application.c
index 47ad8f6..458760d 100644
--- a/thunar/thunar-application.c
+++ b/thunar/thunar-application.c
@@ -930,7 +930,7 @@ thunar_application_open_window (ThunarApplication *application,
   gchar     *role;
 
   _thunar_return_val_if_fail (THUNAR_IS_APPLICATION (application), NULL);
-  _thunar_return_val_if_fail (THUNAR_IS_FILE (directory), NULL);
+  _thunar_return_val_if_fail (directory == NULL || THUNAR_IS_FILE (directory), NULL);
   _thunar_return_val_if_fail (screen == NULL || GDK_IS_SCREEN (screen), NULL);
 
   if (G_UNLIKELY (screen == NULL))
@@ -959,7 +959,8 @@ thunar_application_open_window (ThunarApplication *application,
   gtk_widget_show (window);
 
   /* change the directory */
-  thunar_window_set_current_directory (THUNAR_WINDOW (window), directory);
+  if (directory != NULL)
+    thunar_window_set_current_directory (THUNAR_WINDOW (window), directory);
 
   return window;
 }
diff --git a/thunar/thunar-device.c b/thunar/thunar-device.c
index 5692b09..3b5790e 100644
--- a/thunar/thunar-device.c
+++ b/thunar/thunar-device.c
@@ -718,7 +718,7 @@ thunar_device_eject (ThunarDevice         *device,
       if (drive != NULL)
         {
           if (g_drive_can_stop (drive))
-            {g_message ("stop drive");
+            {
               /* inform user */
               thunar_notify_eject (device);
 
@@ -739,7 +739,7 @@ thunar_device_eject (ThunarDevice         *device,
               return;
             }
           else if (g_drive_can_eject (drive))
-            {g_message ("eject drive");
+            {
               /* inform user */
               thunar_notify_eject (device);
 
diff --git a/thunar/thunar-launcher-ui.xml b/thunar/thunar-launcher-ui.xml
index 2567ff8..8fb0ae8 100644
--- a/thunar/thunar-launcher-ui.xml
+++ b/thunar/thunar-launcher-ui.xml
@@ -14,6 +14,7 @@
     <menu action="file-menu">
       <placeholder name="placeholder-launcher">
         <menuitem action="open" />
+        <menuitem action="open-in-new-tab" />
         <menuitem action="open-in-new-window" />
         <placeholder name="placeholder-applications" />
         <menuitem action="open-with-other" />
@@ -37,6 +38,7 @@
   <popup action="file-context-menu">
     <placeholder name="placeholder-launcher">
       <menuitem action="open" />
+      <menuitem action="open-in-new-tab" />
       <menuitem action="open-in-new-window" />
       <placeholder name="placeholder-applications" />
       <menuitem action="open-with-other" />
diff --git a/thunar/thunar-launcher.c b/thunar/thunar-launcher.c
index b63407b..a155fa1 100644
--- a/thunar/thunar-launcher.c
+++ b/thunar/thunar-launcher.c
@@ -42,6 +42,7 @@
 #include <thunar/thunar-sendto-model.h>
 #include <thunar/thunar-stock.h>
 #include <thunar/thunar-device-monitor.h>
+#include <thunar/thunar-window.h>
 
 
 
@@ -99,6 +100,8 @@ static void                    thunar_launcher_action_open_with_other     (GtkAc
                                                                            ThunarLauncher           *launcher);
 static void                    thunar_launcher_action_open_in_new_window  (GtkAction                *action,
                                                                            ThunarLauncher           *launcher);
+static void                    thunar_launcher_action_open_in_new_tab     (GtkAction                *action,
+                                                                           ThunarLauncher           *launcher);
 static void                    thunar_launcher_action_sendto_desktop      (GtkAction                *action,
                                                                            ThunarLauncher           *launcher);
 static void                    thunar_launcher_action_sendto_device       (GtkAction                *action,
@@ -141,6 +144,7 @@ struct _ThunarLauncher
   GtkAction              *action_open;
   GtkAction              *action_open_with_other;
   GtkAction              *action_open_in_new_window;
+  GtkAction              *action_open_in_new_tab;
   GtkAction              *action_open_with_other_in_menu;
 
   GtkWidget              *widget;
@@ -167,7 +171,8 @@ struct _ThunarLauncherPokeData
 static const GtkActionEntry action_entries[] =
 {
   { "open", GTK_STOCK_OPEN, N_ ("_Open"), "<control>O", NULL, G_CALLBACK (thunar_launcher_action_open), },
-  { "open-in-new-window", NULL, N_ ("Open in New Window"), "<control><shift>O", N_ ("Open the selected directory in a new window"), G_CALLBACK (thunar_launcher_action_open_in_new_window), },
+  { "open-in-new-tab", NULL, N_ ("Open in New _Tab"), "<control><shift>P", NULL, G_CALLBACK (thunar_launcher_action_open_in_new_tab), },
+  { "open-in-new-window", NULL, N_ ("Open in New _Window"), "<control><shift>O", NULL, G_CALLBACK (thunar_launcher_action_open_in_new_window), },
   { "open-with-other", NULL, N_ ("Open With Other _Application..."), NULL, N_ ("Choose another application with which to open the selected file"), G_CALLBACK (thunar_launcher_action_open_with_other), },
   { "open-with-menu", NULL, N_ ("Open With"), NULL, NULL, NULL, },
   { "open-with-other-in-menu", NULL, N_ ("Open With Other _Application..."), NULL, N_ ("Choose another application with which to open the selected file"), G_CALLBACK (thunar_launcher_action_open_with_other), },
@@ -192,7 +197,7 @@ thunar_launcher_class_init (ThunarLauncherClass *klass)
 
   /* determine the "thunar-launcher-handler" quark */
   thunar_launcher_handler_quark = g_quark_from_static_string ("thunar-launcher-handler");
-  
+
   gobject_class = G_OBJECT_CLASS (klass);
   gobject_class->dispose = thunar_launcher_dispose;
   gobject_class->finalize = thunar_launcher_finalize;
@@ -254,6 +259,7 @@ thunar_launcher_init (ThunarLauncher *launcher)
   launcher->action_open = gtk_action_group_get_action (launcher->action_group, "open");
   launcher->action_open_with_other = gtk_action_group_get_action (launcher->action_group, "open-with-other");
   launcher->action_open_in_new_window = gtk_action_group_get_action (launcher->action_group, "open-in-new-window");
+  launcher->action_open_in_new_tab = gtk_action_group_get_action (launcher->action_group, "open-in-new-tab");
   launcher->action_open_with_other_in_menu = gtk_action_group_get_action (launcher->action_group, "open-with-other-in-menu");
 
   /* initialize and add our custom icon factory for the application/action icons */
@@ -760,8 +766,8 @@ thunar_launcher_update (ThunarLauncher *launcher)
   /* determine the number of files/directories/executables */
   for (lp = launcher->selected_files; lp != NULL; lp = lp->next, ++n_selected_files)
     {
-      if (thunar_file_is_directory (lp->data) 
-          || thunar_file_is_shortcut (lp->data) 
+      if (thunar_file_is_directory (lp->data)
+          || thunar_file_is_shortcut (lp->data)
           || thunar_file_is_mountable (lp->data))
         {
           ++n_directories;
@@ -779,47 +785,81 @@ thunar_launcher_update (ThunarLauncher *launcher)
     {
       /** CASE 1: nothing selected or atleast one directory in the selection
        **
-       ** - "Open" and "Open in n New Windows" actions
+       ** - "Open", "Open in n New Windows" and "Open in n New Tabs" actions
        **/
 
-      /* the "Open" action is "Open in n New Windows" if we have two or more directories */
-      if (G_UNLIKELY (n_selected_files == n_directories && n_directories > 1))
+      /* Prepare "Open" label */
+      gtk_action_set_label (launcher->action_open, _("_Open"));
+
+      if (n_selected_files == n_directories && n_directories >= 1)
         {
-          /* turn "Open" into "Open in n New Windows" */
-          label = g_strdup_printf (ngettext ("Open in %d New Window", "Open in %d New Windows", n_directories), n_directories);
-          tooltip = g_strdup_printf (ngettext ("Open the selected directory in %d new window",
-                                               "Open the selected directories in %d new windows",
-                                               n_directories), n_directories);
-          g_object_set (G_OBJECT (launcher->action_open),
-                        "label", label,
-                        "sensitive", TRUE,
-                        "tooltip", tooltip,
-                        NULL);
-          g_free (tooltip);
-          g_free (label);
+          if (n_directories > 1)
+            {
+              /* turn "Open New Window" into "Open in n New Windows" */
+              label = g_strdup_printf (ngettext ("Open in %d New _Window", "Open in %d New _Windows", n_directories), n_directories);
+              tooltip = g_strdup_printf (ngettext ("Open the selected directory in %d new window",
+                                                   "Open the selected directories in %d new windows",
+                                                   n_directories), n_directories);
+              g_object_set (G_OBJECT (launcher->action_open_in_new_window),
+                            "label", label,
+                            "tooltip", tooltip,
+                            NULL);
+              g_free (tooltip);
+              g_free (label);
+
+              /* turn "Open in New Tab" into "Open in x New Tabs" */
+              label = g_strdup_printf (ngettext ("Open in %d New _Tab", "Open in %d New _Tabs", n_directories), n_directories);
+              tooltip = g_strdup_printf (ngettext ("Open the selected directory in %d new tab",
+                                                   "Open the selected directories in %d new tabs",
+                                                   n_directories), n_directories);
+              g_object_set (G_OBJECT (launcher->action_open_in_new_tab),
+                            "label", label,
+                            "tooltip", tooltip,
+                            NULL);
+              g_free (tooltip);
+              g_free (label);
+            }
+          else if (n_directories == 1)
+            {
+              /* prepare "Open in New Window" */
+              g_object_set (G_OBJECT (launcher->action_open_in_new_window),
+                            "label", _("Open in New _Window"),
+                            "tooltip", _("Open the selected directory in a new window"),
+                            NULL);
+
+              /* prepare "Open in New Tab" */
+              g_object_set (G_OBJECT (launcher->action_open_in_new_tab),
+                            "label", _("Open in New _Tab"),
+                            "tooltip", _("Open the selected directory in a new tab"),
+                            NULL);
+
+              /* set tooltip that makes sence */
+              gtk_action_set_tooltip (launcher->action_open, _("Open the selected directory"));
+            }
+
+          /* Show Window/Tab action if there are only directories selected */
+          gtk_action_set_visible (launcher->action_open_in_new_window, n_directories > 0);
+          gtk_action_set_visible (launcher->action_open_in_new_tab, n_directories > 0);
+
+          /* Show open if there is exactly 1 directory selected */
+          gtk_action_set_visible (launcher->action_open, n_directories == 1);
+          gtk_action_set_sensitive (launcher->action_open, TRUE);
         }
       else
         {
-          /* the "Open" action is sensitive if we have atleast one selected file,
-           * the label is set to "Open in New Window" if we're not in a regular
-           * view (i.e. current_directory is not set) and have only one directory
-           * selected to reflect that this action will open a new window.
-           */
-          g_object_set (G_OBJECT (launcher->action_open),
-                        "label", (launcher->current_directory == NULL && n_directories == n_selected_files && n_directories == 1)
-                                 ? _("_Open in New Window")
-                                 : _("_Open"),
-                        "sensitive", (n_selected_files > 0),
-                        "tooltip", ngettext ("Open the selected file", "Open the selected files", n_selected_files),
-                        NULL);
+          /* Hide New Window and Tab action */
+          gtk_action_set_visible (launcher->action_open_in_new_window, FALSE);
+          gtk_action_set_visible (launcher->action_open_in_new_tab, FALSE);
+
+          /* Normal open action, because there are also directories included */
+          gtk_action_set_visible (launcher->action_open, TRUE);
+          gtk_action_set_sensitive (launcher->action_open, n_selected_files > 0);
+          gtk_action_set_tooltip (launcher->action_open,
+                                  ngettext ("Open the selected file",
+                                            "Open the selected files",
+                                            n_selected_files));
         }
 
-      /* the "Open in New Window" action is visible if we have exactly one directory */
-      g_object_set (G_OBJECT (launcher->action_open_in_new_window),
-                    "sensitive", (n_directories == 1),
-                    "visible", (n_directories == n_selected_files && n_selected_files <= 1 && launcher->current_directory != NULL),
-                    NULL);
-
       /* hide the "Open With Other Application" actions */
       gtk_action_set_visible (launcher->action_open_with_other, FALSE);
       gtk_action_set_visible (launcher->action_open_with_other_in_menu, FALSE);
@@ -845,8 +885,9 @@ thunar_launcher_update (ThunarLauncher *launcher)
       /* make the "Open" action sensitive */
       gtk_action_set_sensitive (launcher->action_open, TRUE);
 
-      /* hide the "Open in n New Windows" action */
+      /* hide the "Open in n New Windows/Tabs" action */
       gtk_action_set_visible (launcher->action_open_in_new_window, FALSE);
+      gtk_action_set_visible (launcher->action_open_in_new_tab, FALSE);
 
       /* determine the set of applications that work for all selected files */
       applications = thunar_file_list_get_applications (launcher->selected_files);
@@ -880,7 +921,7 @@ thunar_launcher_update (ThunarLauncher *launcher)
           /* remember the default application for the "Open" action */
           g_object_set_qdata_full (G_OBJECT (launcher->action_open), thunar_launcher_handler_quark, applications->data, g_object_unref);
 
-          /* FIXME Add the desktop actions for this application. 
+          /* FIXME Add the desktop actions for this application.
            * Unfortunately this is not supported by GIO directly */
 
           /* drop the default application from the list */
@@ -947,7 +988,7 @@ thunar_launcher_update (ThunarLauncher *launcher)
           /* process all applications and determine the desktop actions */
           for (lp = applications, n = 0; lp != NULL; lp = lp->next, ++n)
             {
-              /* FIXME Determine the desktop actions for this application. 
+              /* FIXME Determine the desktop actions for this application.
                * Unfortunately this is not supported by GIO directly. */
 
               /* generate a unique label, unique id and tooltip for the application's action */
@@ -981,7 +1022,7 @@ thunar_launcher_update (ThunarLauncher *launcher)
           g_list_free (applications);
         }
 
-      /* FIXME Add desktop actions here. Unfortunately they are not supported by 
+      /* FIXME Add desktop actions here. Unfortunately they are not supported by
        * GIO, so we'll have to roll our own thing here */
     }
 
@@ -1003,7 +1044,7 @@ thunar_launcher_open_file (ThunarLauncher *launcher,
 
   _thunar_return_if_fail (THUNAR_IS_LAUNCHER (launcher));
   _thunar_return_if_fail (THUNAR_IS_FILE (file));
-            
+
   files.data = file;
   files.next = NULL;
   files.prev = NULL;
@@ -1053,7 +1094,7 @@ thunar_launcher_poke_file_finish (ThunarBrowser *browser,
   else
     {
       thunar_dialogs_show_error (THUNAR_LAUNCHER (browser)->widget, error,
-                                 _("Failed to open \"%s\""), 
+                                 _("Failed to open \"%s\""),
                                  thunar_file_get_display_name (file));
     }
 }
@@ -1069,7 +1110,7 @@ thunar_launcher_poke_files (ThunarLauncher         *launcher,
   _thunar_return_if_fail (poke_data->files != NULL);
 
   thunar_browser_poke_file (THUNAR_BROWSER (launcher), poke_data->files->data,
-                            launcher->widget, thunar_launcher_poke_files_finish, 
+                            launcher->widget, thunar_launcher_poke_files_finish,
                             poke_data);
 }
 
@@ -1092,12 +1133,12 @@ thunar_launcher_poke_files_finish (ThunarBrowser *browser,
   _thunar_return_if_fail (THUNAR_IS_FILE (file));
   _thunar_return_if_fail (poke_data != NULL);
   _thunar_return_if_fail (poke_data->files != NULL);
-  
+
   /* check if poking succeeded */
   if (error == NULL)
     {
       /* add the resolved file to the list of file to be opened/executed later */
-      poke_data->resolved_files = g_list_prepend (poke_data->resolved_files, 
+      poke_data->resolved_files = g_list_prepend (poke_data->resolved_files,
                                                   g_object_ref (target_file));
     }
 
@@ -1186,14 +1227,14 @@ thunar_launcher_action_open (GtkAction      *action,
     }
   else if (g_list_length (launcher->selected_files) == 1)
     {
-      thunar_browser_poke_file (THUNAR_BROWSER (launcher), 
+      thunar_browser_poke_file (THUNAR_BROWSER (launcher),
                                 launcher->selected_files->data, launcher->widget,
                                 thunar_launcher_poke_file_finish, NULL);
     }
   else
     {
       /* resolve files one after another until none is left. Open/execute
-       * the resolved files/directories when all this is done at a later 
+       * the resolved files/directories when all this is done at a later
        * stage */
       poke_data = thunar_launcher_poke_data_new (launcher->selected_files);
       thunar_launcher_poke_files (launcher, poke_data);
@@ -1233,6 +1274,29 @@ thunar_launcher_action_open_in_new_window (GtkAction      *action,
 
 
 static void
+thunar_launcher_action_open_in_new_tab (GtkAction      *action,
+                                        ThunarLauncher *launcher)
+{
+  GList *lp;
+  GList *selected_files;
+
+  _thunar_return_if_fail (GTK_IS_ACTION (action));
+  _thunar_return_if_fail (THUNAR_IS_LAUNCHER (launcher));
+
+  /* open all selected directories in a new tab */
+  selected_files = thunar_g_file_list_copy (launcher->selected_files);
+  for (lp = selected_files; lp != NULL; lp = lp->next)
+    {
+      if (thunar_file_is_directory (lp->data))
+        thunar_navigator_open_new_tab (THUNAR_NAVIGATOR (launcher), lp->data);
+      g_object_unref (G_OBJECT (lp->data));
+    }
+  g_list_free (selected_files);
+}
+
+
+
+static void
 thunar_launcher_action_sendto_desktop (GtkAction      *action,
                                        ThunarLauncher *launcher)
 {
@@ -1332,7 +1396,7 @@ thunar_launcher_sendto_device (ThunarLauncher *launcher,
 
   if (!thunar_device_is_mounted (device))
     return;
-  
+
   mount_point = thunar_device_get_root (device);
   if (mount_point != NULL)
     {
@@ -1361,7 +1425,7 @@ thunar_launcher_sendto_mount_finish (ThunarDevice *device,
 
   if (error != NULL)
     {
-      /* tell the user that we were unable to mount the device, which is 
+      /* tell the user that we were unable to mount the device, which is
        * required to send files to it */
       device_name = thunar_device_get_name (device);
       thunar_dialogs_show_error (data->launcher->widget, error, _("Failed to mount \"%s\""), device_name);
diff --git a/thunar/thunar-navigator.c b/thunar/thunar-navigator.c
index c7def2f..ae965a5 100644
--- a/thunar/thunar-navigator.c
+++ b/thunar/thunar-navigator.c
@@ -29,6 +29,7 @@
 enum
 {
   CHANGE_DIRECTORY,
+  OPEN_NEW_TAB,
   LAST_SIGNAL,
 };
 
@@ -110,6 +111,15 @@ thunar_navigator_base_init (gpointer klass)
                       g_cclosure_marshal_VOID__OBJECT,
                       G_TYPE_NONE, 1, THUNAR_TYPE_FILE);
 
+      navigator_signals[OPEN_NEW_TAB] =
+        g_signal_new (I_("open-new-tab"),
+                      G_TYPE_FROM_INTERFACE (klass),
+                      G_SIGNAL_RUN_LAST,
+                      G_STRUCT_OFFSET (ThunarNavigatorIface, open_new_tab),
+                      NULL, NULL,
+                      g_cclosure_marshal_VOID__OBJECT,
+                      G_TYPE_NONE, 1, THUNAR_TYPE_FILE);
+
       initialized = TRUE;
     }
 }
@@ -212,3 +222,14 @@ thunar_navigator_change_directory (ThunarNavigator *navigator,
 }
 
 
+
+void
+thunar_navigator_open_new_tab (ThunarNavigator *navigator,
+                               ThunarFile      *directory)
+{
+  _thunar_return_if_fail (THUNAR_IS_NAVIGATOR (navigator));
+  _thunar_return_if_fail (THUNAR_IS_FILE (directory));
+  _thunar_return_if_fail (thunar_file_is_directory (directory));
+
+  g_signal_emit (G_OBJECT (navigator), navigator_signals[OPEN_NEW_TAB], 0, directory);
+}
diff --git a/thunar/thunar-navigator.h b/thunar/thunar-navigator.h
index d4e9b0e..481739a 100644
--- a/thunar/thunar-navigator.h
+++ b/thunar/thunar-navigator.h
@@ -44,6 +44,8 @@ struct _ThunarNavigatorIface
   /* signals */
   void        (*change_directory)      (ThunarNavigator *navigator,
                                         ThunarFile      *directory);
+  void        (*open_new_tab)          (ThunarNavigator *navigator,
+                                        ThunarFile      *directory);
 };
 
 GType       thunar_navigator_get_type              (void) G_GNUC_CONST;
@@ -55,6 +57,9 @@ void        thunar_navigator_set_current_directory (ThunarNavigator *navigator,
 void        thunar_navigator_change_directory      (ThunarNavigator *navigator,
                                                     ThunarFile      *directory);
 
+void        thunar_navigator_open_new_tab          (ThunarNavigator *navigator,
+                                                    ThunarFile      *directory);
+
 G_END_DECLS;
 
 #endif /* !__THUNAR_NAVIGATOR_H__ */
diff --git a/thunar/thunar-preferences-dialog.c b/thunar/thunar-preferences-dialog.c
index 0ef2ec0..a6efc4d 100644
--- a/thunar/thunar-preferences-dialog.c
+++ b/thunar/thunar-preferences-dialog.c
@@ -505,6 +505,30 @@ thunar_preferences_dialog_init (ThunarPreferencesDialog *dialog)
   gtk_table_attach (GTK_TABLE (table), button, 0, 1, 2, 3, GTK_EXPAND | GTK_FILL, 0, 0, 0);
   gtk_widget_show (button);
 
+  frame = g_object_new (GTK_TYPE_FRAME, "border-width", 0, "shadow-type", GTK_SHADOW_NONE, NULL);
+  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0);
+  gtk_widget_show (frame);
+
+  label = gtk_label_new (_("Middle Click"));
+  gtk_label_set_attributes (GTK_LABEL (label), thunar_pango_attr_list_bold ());
+  gtk_frame_set_label_widget (GTK_FRAME (frame), label);
+  gtk_widget_show (label);
+
+  vbox = gtk_vbox_new (FALSE, 6);
+  gtk_container_add (GTK_CONTAINER (frame), vbox);
+  gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
+  gtk_widget_show (vbox);
+
+  button = gtk_radio_button_new_with_mnemonic_from_widget (NULL, _("Open folder in new _window"));
+  g_signal_connect (G_OBJECT (button), "toggled", G_CALLBACK (g_object_notify), "active");
+  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, TRUE, 0);
+  gtk_widget_show (button);
+
+  button = gtk_radio_button_new_with_mnemonic_from_widget (GTK_RADIO_BUTTON (button), _("Open folder in new _tab"));
+  exo_mutual_binding_new (G_OBJECT (dialog->preferences), "misc-middle-click-in-tab", G_OBJECT (button), "active");
+  g_signal_connect (G_OBJECT (button), "toggled", G_CALLBACK (g_object_notify), "active");
+  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, TRUE, 0);
+  gtk_widget_show (button);
 
   /*
      Advanced
diff --git a/thunar/thunar-preferences.c b/thunar/thunar-preferences.c
index 4e1de11..b2ab0bb 100644
--- a/thunar/thunar-preferences.c
+++ b/thunar/thunar-preferences.c
@@ -71,18 +71,21 @@ enum
   PROP_LAST_WINDOW_HEIGHT,
   PROP_LAST_WINDOW_WIDTH,
   PROP_LAST_WINDOW_FULLSCREEN,
+  PROP_MISC_ALWAYS_SHOW_TABS,
   PROP_MISC_VOLUME_MANAGEMENT,
   PROP_MISC_CASE_SENSITIVE,
   PROP_MISC_DATE_STYLE,
   PROP_MISC_FOLDERS_FIRST,
   PROP_MISC_FULL_PATH_IN_TITLE,
   PROP_MISC_HORIZONTAL_WHEEL_NAVIGATES,
+  PROP_MISC_MIDDLE_CLICK_IN_TAB,
   PROP_MISC_RECURSIVE_PERMISSIONS,
   PROP_MISC_REMEMBER_GEOMETRY,
   PROP_MISC_SHOW_ABOUT_TEMPLATES,
   PROP_MISC_SHOW_THUMBNAILS,
   PROP_MISC_SINGLE_CLICK,
   PROP_MISC_SINGLE_CLICK_TIMEOUT,
+  PROP_MISC_TAB_CLOSE_MIDDLE_CLICK,
   PROP_MISC_TEXT_BESIDE_ICONS,
   PROP_SHORTCUTS_ICON_EMBLEMS,
   PROP_SHORTCUTS_ICON_SIZE,
@@ -449,6 +452,19 @@ thunar_preferences_class_init (ThunarPreferencesClass *klass)
                                                          EXO_PARAM_READWRITE));
 
   /**
+   * ThunarPreferences:misc-always-show-tabs:
+   *
+   * If the view tabs should always be visible.
+   **/
+  g_object_class_install_property (gobject_class,
+                                   PROP_MISC_ALWAYS_SHOW_TABS,
+                                   g_param_spec_boolean ("misc-always-show-tabs",
+                                                         NULL,
+                                                         NULL,
+                                                         FALSE,
+                                                         EXO_PARAM_READWRITE));
+
+  /**
    * ThunarPreferences:misc-volume-management:
    *
    * Whether to enable volume management capabilities (requires HAL and the
@@ -531,6 +547,19 @@ thunar_preferences_class_init (ThunarPreferencesClass *klass)
                                                          EXO_PARAM_READWRITE));
 
   /**
+   * ThunarPreferences:misc-middle-click-in-tab:
+   *
+   * If middle click opens a folder in a new window (FALSE) or in a new window (TRUE);
+   **/
+  g_object_class_install_property (gobject_class,
+                                   PROP_MISC_MIDDLE_CLICK_IN_TAB,
+                                   g_param_spec_boolean ("misc-middle-click-in-tab",
+                                                         NULL,
+                                                         NULL,
+                                                         FALSE,
+                                                         EXO_PARAM_READWRITE));
+
+  /**
    * ThunarPreferences:misc-recursive-permissions:
    *
    * Whether to apply permissions recursively everytime the
@@ -619,6 +648,20 @@ thunar_preferences_class_init (ThunarPreferencesClass *klass)
                                                       EXO_PARAM_READWRITE));
 
   /**
+   * ThunarPreferences:misc-tab-close-middle-click:
+   *
+   * Whether to close tabs when the tab label is clicked with the 2nd
+   * mouse button.
+   **/
+  g_object_class_install_property (gobject_class,
+                                   PROP_MISC_TAB_CLOSE_MIDDLE_CLICK,
+                                   g_param_spec_boolean ("misc-tab-close-middle-click",
+                                                         NULL,
+                                                         NULL,
+                                                         TRUE,
+                                                         EXO_PARAM_READWRITE));
+
+  /**
    * ThunarPreferences:misc-text-beside-icons:
    *
    * Whether the icon view should display the file names beside the
diff --git a/thunar/thunar-shortcuts-pane.c b/thunar/thunar-shortcuts-pane.c
index 4f02ae6..03b0fe6 100644
--- a/thunar/thunar-shortcuts-pane.c
+++ b/thunar/thunar-shortcuts-pane.c
@@ -179,6 +179,7 @@ thunar_shortcuts_pane_init (ThunarShortcutsPane *shortcuts_pane)
 
   /* connect the "shortcut-activated" signal */
   g_signal_connect_swapped (G_OBJECT (shortcuts_pane->view), "shortcut-activated", G_CALLBACK (thunar_navigator_change_directory), shortcuts_pane);
+  g_signal_connect_swapped (G_OBJECT (shortcuts_pane->view), "shortcut-activated-tab", G_CALLBACK (thunar_navigator_open_new_tab), shortcuts_pane);
 }
 
 
diff --git a/thunar/thunar-shortcuts-view.c b/thunar/thunar-shortcuts-view.c
index 7b36a67..07463c6 100644
--- a/thunar/thunar-shortcuts-view.c
+++ b/thunar/thunar-shortcuts-view.c
@@ -53,6 +53,7 @@
 enum
 {
   SHORTCUT_ACTIVATED,
+  SHORTCUT_ACTIVATED_TAB,
   LAST_SIGNAL,
 };
 
@@ -63,6 +64,15 @@ enum
   TEXT_URI_LIST,
 };
 
+/* Target for open action */
+typedef enum
+{
+  OPEN_IN_VIEW,
+  OPEN_IN_WINDOW,
+  OPEN_IN_TAB
+}
+OpenTarget;
+
 
 
 static void           thunar_shortcuts_view_finalize                     (GObject                  *object);
@@ -130,8 +140,9 @@ static void           thunar_shortcuts_view_drop_uri_list                (Thunar
                                                                           GtkTreePath              *dst_path);
 static void           thunar_shortcuts_view_open_clicked                 (ThunarShortcutsView      *view);
 static void           thunar_shortcuts_view_open                         (ThunarShortcutsView      *view,
-                                                                          gboolean                  new_window);
+                                                                          OpenTarget                open_in);
 static void           thunar_shortcuts_view_open_in_new_window_clicked   (ThunarShortcutsView      *view);
+static void           thunar_shortcuts_view_open_in_new_tab_clicked      (ThunarShortcutsView      *view);
 static void           thunar_shortcuts_view_empty_trash                  (ThunarShortcutsView      *view);
 static void           thunar_shortcuts_view_create_shortcut              (ThunarShortcutsView      *view);
 static void           thunar_shortcuts_view_eject                        (ThunarShortcutsView      *view);
@@ -231,6 +242,19 @@ thunar_shortcuts_view_class_init (ThunarShortcutsViewClass *klass)
                   0, NULL, NULL,
                   g_cclosure_marshal_VOID__OBJECT,
                   G_TYPE_NONE, 1, THUNAR_TYPE_FILE);
+
+  /**
+   * ThunarShortcutsView:shortcut-activated-tab:
+   *
+   * Invoked whenever a shortcut is activated by the user and should be opened in a new tab,
+   **/
+  view_signals[SHORTCUT_ACTIVATED_TAB] =
+    g_signal_new (I_("shortcut-activated-tab"),
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL,
+                  g_cclosure_marshal_VOID__OBJECT,
+                  G_TYPE_NONE, 1, THUNAR_TYPE_FILE);
 }
 
 
@@ -384,6 +408,7 @@ thunar_shortcuts_view_button_press_event (GtkWidget      *widget,
   GtkTreeIter          iter;
   gboolean             result;
   gboolean             can_eject;
+  gint                 icon_width, icon_height, column_width;
 
   /* reset the pressed button state */
   view->pressed_button = -1;
@@ -413,11 +438,11 @@ thunar_shortcuts_view_button_press_event (GtkWidget      *widget,
               result = TRUE;
             }
         }
-      else if ((event->button == 1 || event->button == 2) && event->type == GDK_BUTTON_PRESS
-            && (event->state & gtk_accelerator_get_default_mod_mask ()) == 0)
+      else if ((event->button == 1 || event->button == 2)
+               && event->type == GDK_BUTTON_PRESS
+               && (event->state & gtk_accelerator_get_default_mod_mask ()) == 0)
         {
           /* check if we clicked the eject button area */
-          gint icon_width, icon_height, column_width;
           column_width = gtk_tree_view_column_get_width (gtk_tree_view_get_column (GTK_TREE_VIEW (view), 0));
           gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &icon_width, &icon_height);
           if (event->x >= column_width - icon_width - 3)
@@ -432,15 +457,8 @@ thunar_shortcuts_view_button_press_event (GtkWidget      *widget,
                 }
             }
 
-          /*
-          g_debug("thunar_shortcuts_view_button_press_event(): x: %f, y: %f; my width: %i, eject width: %i, eject: %i",
-                  event->x, event->y, column_width, icon_width, view->pressed_eject_button);
-          */
-
           /* remember the button as pressed and handle it in the release handler */
           view->pressed_button = event->button;
-
-
         }
 
       /* release the path */
@@ -457,19 +475,27 @@ thunar_shortcuts_view_button_release_event (GtkWidget      *widget,
                                             GdkEventButton *event)
 {
   ThunarShortcutsView *view = THUNAR_SHORTCUTS_VIEW (widget);
+  gboolean             in_tab;
 
   /* check if we have an event matching the pressed button state */
   if (G_LIKELY (view->pressed_button == (gint) event->button))
     {
       /* check if the eject button has been pressed */
       if (view->pressed_eject_button)
-        thunar_shortcuts_view_eject (view);
-      /* button 1 opens in the same window */
+        {
+          thunar_shortcuts_view_eject (view);
+        }
       else if (G_LIKELY (event->button == 1))
-        thunar_shortcuts_view_open (view, FALSE);
-      /* button 2 opens in a new window */
+        {
+          /* button 1 opens in the same window */
+          thunar_shortcuts_view_open (view, OPEN_IN_VIEW);
+        }
       else if (G_UNLIKELY (event->button == 2))
-        thunar_shortcuts_view_open (view, TRUE);
+        {
+          /* button 2 opens in a new window or tab */
+          g_object_get (view->preferences, "misc-middle-click-in-tab", &in_tab, NULL);
+          thunar_shortcuts_view_open (view, in_tab ? OPEN_IN_TAB : OPEN_IN_WINDOW);
+        }
     }
 
   /* reset the pressed button state */
@@ -495,7 +521,7 @@ thunar_shortcuts_view_key_release_event (GtkWidget   *widget,
     case GDK_Down:
     case GDK_KP_Up:
     case GDK_KP_Down:
-      thunar_shortcuts_view_open (view, FALSE);
+      thunar_shortcuts_view_open (view, OPEN_IN_VIEW);
 
       /* keep focus on us */
       gtk_widget_grab_focus (widget);
@@ -869,7 +895,7 @@ thunar_shortcuts_view_row_activated (GtkTreeView       *tree_view,
     (*GTK_TREE_VIEW_CLASS (thunar_shortcuts_view_parent_class)->row_activated) (tree_view, path, column);
 
   /* open the selected shortcut */
-  thunar_shortcuts_view_open (view, FALSE);
+  thunar_shortcuts_view_open (view, OPEN_IN_VIEW);
 }
 
 
@@ -1056,6 +1082,12 @@ thunar_shortcuts_view_context_menu (ThunarShortcutsView *view,
   /* set the stock icon */
   image = gtk_image_new_from_stock (GTK_STOCK_OPEN, GTK_ICON_SIZE_MENU);
   gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
+  
+  /* append the "Open in New Tab" menu action */
+  item = gtk_image_menu_item_new_with_mnemonic (_("Open in New Tab"));
+  g_signal_connect_swapped (G_OBJECT (item), "activate", G_CALLBACK (thunar_shortcuts_view_open_in_new_tab_clicked), view);
+  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+  gtk_widget_show (item);
 
   /* append the "Open in New Window" menu action */
   item = gtk_image_menu_item_new_with_mnemonic (_("Open in New Window"));
@@ -1538,7 +1570,7 @@ static void
 thunar_shortcuts_view_open_clicked (ThunarShortcutsView *view)
 {
   _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_VIEW (view));
-  thunar_shortcuts_view_open (view, FALSE);
+  thunar_shortcuts_view_open (view, OPEN_IN_VIEW);
 }
 
 
@@ -1551,14 +1583,14 @@ thunar_shortcuts_view_poke_file_finish (ThunarBrowser *browser,
                                         gpointer       user_data)
 {
   ThunarApplication *application;
-  gboolean           new_window = GPOINTER_TO_UINT (user_data);
+  OpenTarget         open_in = GPOINTER_TO_UINT (user_data);
 
   _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_VIEW (browser));
   _thunar_return_if_fail (THUNAR_IS_FILE (target_file));
 
   if (error == NULL)
     {
-      if (new_window)
+      if (open_in == OPEN_IN_WINDOW)
         {
           /* open a new window for the target folder */
           application = thunar_application_get ();
@@ -1566,6 +1598,11 @@ thunar_shortcuts_view_poke_file_finish (ThunarBrowser *browser,
                                           gtk_widget_get_screen (GTK_WIDGET (browser)), NULL);
           g_object_unref (application);
         }
+      else if (open_in == OPEN_IN_TAB)
+        {
+          /* invoke the signal to change to open folder in a new tab */
+          g_signal_emit (browser, view_signals[SHORTCUT_ACTIVATED_TAB], 0, target_file);
+        }
       else if (thunar_file_check_loaded (target_file))
         {
           /* invoke the signal to change to that folder */
@@ -1616,7 +1653,6 @@ thunar_shortcuts_view_poke_device_finish (ThunarBrowser *browser,
                                           GError        *error,
                                           gpointer       user_data)
 {
-  gboolean      new_window = GPOINTER_TO_UINT (user_data);
   gchar        *device_name;
   GtkTreeModel *model;
   GtkTreeModel *child_model;
@@ -1628,7 +1664,7 @@ thunar_shortcuts_view_poke_device_finish (ThunarBrowser *browser,
     {
       thunar_browser_poke_file (browser, mount_point, GTK_WIDGET (browser),
                                 thunar_shortcuts_view_poke_file_finish,
-                                GUINT_TO_POINTER (new_window));
+                                user_data);
     }
   else
     {
@@ -1648,7 +1684,7 @@ thunar_shortcuts_view_poke_device_finish (ThunarBrowser *browser,
 
 static void
 thunar_shortcuts_view_open (ThunarShortcutsView *view,
-                            gboolean             new_window)
+                            OpenTarget           open_in)
 {
   GtkTreeSelection *selection;
   GtkTreeModel     *model;
@@ -1684,19 +1720,19 @@ thunar_shortcuts_view_open (ThunarShortcutsView *view,
 
           thunar_browser_poke_device (THUNAR_BROWSER (view), device, view,
                                       thunar_shortcuts_view_poke_device_finish,
-                                      GUINT_TO_POINTER (new_window));
+                                      GUINT_TO_POINTER (open_in));
         }
       else if (file != NULL)
         {
           thunar_browser_poke_file (THUNAR_BROWSER (view), file, view,
                                     thunar_shortcuts_view_poke_file_finish,
-                                    GUINT_TO_POINTER (new_window));
+                                    GUINT_TO_POINTER (open_in));
         }
       else if (location != NULL)
         {
           thunar_browser_poke_location (THUNAR_BROWSER (view), location, view,
                                         thunar_shortcuts_view_poke_location_finish,
-                                        GUINT_TO_POINTER (new_window));
+                                        GUINT_TO_POINTER (open_in));
         }
 
       if (file != NULL)
@@ -1716,7 +1752,16 @@ static void
 thunar_shortcuts_view_open_in_new_window_clicked (ThunarShortcutsView *view)
 {
   _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_VIEW (view));
-  thunar_shortcuts_view_open (view, TRUE);
+  thunar_shortcuts_view_open (view, OPEN_IN_WINDOW);
+}
+
+
+
+static void
+thunar_shortcuts_view_open_in_new_tab_clicked (ThunarShortcutsView *view)
+{
+  _thunar_return_if_fail (THUNAR_IS_SHORTCUTS_VIEW (view));
+  thunar_shortcuts_view_open (view, OPEN_IN_TAB);
 }
 
 
diff --git a/thunar/thunar-standard-view-ui.xml b/thunar/thunar-standard-view-ui.xml
index f79853b..0678924 100644
--- a/thunar/thunar-standard-view-ui.xml
+++ b/thunar/thunar-standard-view-ui.xml
@@ -40,6 +40,13 @@
         <menuitem action="restore" />
       </placeholder>
     </menu>
+    
+    <menu action="go-menu">
+      <placeholder name="placeholder-go-history-actions">
+        <menuitem action="back" />
+        <menuitem action="forward" />
+      </placeholder>
+    </menu>
   </menubar>
 
   <popup action="file-context-menu">
@@ -76,6 +83,13 @@
     <menuitem action="properties" />
   </popup>
 
+  <toolbar name="location-toolbar">
+    <placeholder name="placeholder-history-actions">
+      <toolitem action="back" />
+      <toolitem action="forward" />
+    </placeholder>
+  </toolbar>
+
 </ui>
 
 <!-- vi: set ts=2 sw=2 et ai nocindent syntax=xml: -->
diff --git a/thunar/thunar-standard-view.c b/thunar/thunar-standard-view.c
index 7f17cf0..325e985 100644
--- a/thunar/thunar-standard-view.c
+++ b/thunar/thunar-standard-view.c
@@ -49,6 +49,7 @@
 #include <thunar/thunar-standard-view.h>
 #include <thunar/thunar-standard-view-ui.h>
 #include <thunar/thunar-templates-action.h>
+#include <thunar/thunar-history.h>
 #include <thunar/thunar-text-renderer.h>
 #include <thunar/thunar-thumbnailer.h>
 
@@ -68,6 +69,8 @@ enum
   PROP_0,
   PROP_CURRENT_DIRECTORY,
   PROP_LOADING,
+  PROP_DISPLAY_NAME,
+  PROP_TOOLTIP_TEXT,
   PROP_SELECTED_FILES,
   PROP_SHOW_HIDDEN,
   PROP_STATUSBAR_TEXT,
@@ -158,6 +161,10 @@ static ThunarFile          *thunar_standard_view_get_drop_file              (Thu
 static void                 thunar_standard_view_merge_custom_actions       (ThunarStandardView       *standard_view,
                                                                              GList                    *selected_items);
 static void                 thunar_standard_view_update_statusbar_text      (ThunarStandardView       *standard_view);
+static void                 thunar_standard_view_current_directory_destroy  (ThunarFile               *current_directory,
+                                                                             ThunarStandardView       *standard_view);
+static void                 thunar_standard_view_current_directory_changed  (ThunarFile               *current_directory,
+                                                                             ThunarStandardView       *standard_view);
 static void                 thunar_standard_view_action_create_empty_file   (GtkAction                *action,
                                                                              ThunarStandardView       *standard_view);
 static void                 thunar_standard_view_action_create_folder       (GtkAction                *action,
@@ -280,6 +287,9 @@ static void                 thunar_standard_view_size_allocate              (Thu
 
 struct _ThunarStandardViewPrivate
 {
+  /* current directory of the view */
+  ThunarFile             *current_directory;
+
   GtkAction              *action_create_folder;
   GtkAction              *action_create_document;
   GtkAction              *action_properties;
@@ -293,19 +303,25 @@ struct _ThunarStandardViewPrivate
   GtkAction              *action_rename;
   GtkAction              *action_restore;
 
+  /* history of the current view */
+  ThunarHistory          *history;
+
   /* support for file manager extensions */
   ThunarxProviderFactory *provider_factory;
 
   /* zoom-level support */
   ThunarZoomLevel         zoom_level;
 
+  /* scroll_to_file support */
+  GHashTable             *scroll_to_files;
+
   /* custom menu actions support */
   GtkActionGroup         *custom_actions;
   gint                    custom_merge_id;
 
   /* right-click drag/popup support */
   GList                  *drag_g_file_list;
-  gint                    drag_scroll_timer_id;
+  guint                   drag_scroll_timer_id;
   gint                    drag_x;
   gint                    drag_y;
 
@@ -441,6 +457,32 @@ thunar_standard_view_class_init (ThunarStandardViewClass *klass)
                                                                                 FALSE,
                                                                                 EXO_PARAM_READWRITE)));
 
+  /**
+   * ThunarStandardView:display-name:
+   *
+   * Display name of the current directory, for label text
+   **/
+  g_object_class_install_property (gobject_class,
+                                   PROP_DISPLAY_NAME,
+                                   g_param_spec_string ("display-name",
+                                                        "display-name",
+                                                        "display-name",
+                                                        NULL,
+                                                        EXO_PARAM_READABLE));
+
+  /**
+   * ThunarStandardView:parse-name:
+   *
+   * Full parsed name of the current directory, for label tooltip
+   **/
+  g_object_class_install_property (gobject_class,
+                                   PROP_TOOLTIP_TEXT,
+                                   g_param_spec_string ("tooltip-text",
+                                                        "tooltip-text",
+                                                        "tooltip-text",
+                                                        NULL,
+                                                        EXO_PARAM_READABLE));
+
   /* override ThunarComponent's properties */
   g_object_class_override_property (gobject_class, PROP_SELECTED_FILES, "selected-files");
   g_object_class_override_property (gobject_class, PROP_UI_MANAGER, "ui-manager");
@@ -541,9 +583,9 @@ static void
 thunar_standard_view_init (ThunarStandardView *standard_view)
 {
   standard_view->priv = THUNAR_STANDARD_VIEW_GET_PRIVATE (standard_view);
-  standard_view->priv->drag_scroll_timer_id = -1;
 
-  standard_view->priv->selection_before_delete = NULL;
+  /* allocate the scroll_to_files mapping (directory GFile -> first visible child GFile) */
+  standard_view->priv->scroll_to_files = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal, g_object_unref, g_object_unref);
 
   /* grab a reference on the preferences */
   standard_view->preferences = thunar_preferences_get ();
@@ -593,6 +635,10 @@ thunar_standard_view_init (ThunarStandardView *standard_view)
   gtk_action_group_add_action (standard_view->action_group, standard_view->priv->action_create_document);
   g_object_unref (G_OBJECT (standard_view->priv->action_create_document));
 
+  /* setup the history support */
+  standard_view->priv->history = g_object_new (THUNAR_TYPE_HISTORY, "action-group", standard_view->action_group, NULL);
+  g_signal_connect_swapped (G_OBJECT (standard_view->priv->history), "change-directory", G_CALLBACK (thunar_navigator_change_directory), standard_view);
+
   /* setup the list model */
   standard_view->model = thunar_list_model_new ();
   g_signal_connect (G_OBJECT (standard_view->model), "row-deleted", G_CALLBACK (thunar_standard_view_row_deleted), standard_view);
@@ -723,12 +769,21 @@ thunar_standard_view_dispose (GObject *object)
     exo_binding_unbind (standard_view->loading_binding);
 
   /* be sure to cancel any pending drag autoscroll timer */
-  if (G_UNLIKELY (standard_view->priv->drag_scroll_timer_id >= 0))
+  if (G_UNLIKELY (standard_view->priv->drag_scroll_timer_id != 0))
     g_source_remove (standard_view->priv->drag_scroll_timer_id);
 
   /* reset the UI manager property */
   thunar_component_set_ui_manager (THUNAR_COMPONENT (standard_view), NULL);
 
+  /* disconnect from file */
+  if (standard_view->priv->current_directory != NULL)
+    {
+      g_signal_handlers_disconnect_matched (standard_view->priv->current_directory,
+                                            G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, standard_view);
+      g_object_unref (standard_view->priv->current_directory);
+      standard_view->priv->current_directory = NULL;
+    }
+
   (*G_OBJECT_CLASS (thunar_standard_view_parent_class)->dispose) (object);
 }
 
@@ -765,6 +820,9 @@ thunar_standard_view_finalize (GObject *object)
   /* release the drop path list (just in case the drag-leave wasn't fired before) */
   thunar_g_file_list_free (standard_view->priv->drop_file_list);
 
+  /* release the history */
+  g_object_unref (standard_view->priv->history);
+
   /* release the reference on the name renderer */
   g_object_unref (G_OBJECT (standard_view->name_renderer));
 
@@ -795,6 +853,9 @@ thunar_standard_view_finalize (GObject *object)
   /* free the statusbar text (if any) */
   g_free (standard_view->statusbar_text);
 
+  /* release the scroll_to_files hash table */
+  g_hash_table_destroy (standard_view->priv->scroll_to_files);
+
   (*G_OBJECT_CLASS (thunar_standard_view_parent_class)->finalize) (object);
 }
 
@@ -806,6 +867,8 @@ thunar_standard_view_get_property (GObject    *object,
                                    GValue     *value,
                                    GParamSpec *pspec)
 {
+  ThunarFile *current_directory;
+
   switch (prop_id)
     {
     case PROP_CURRENT_DIRECTORY:
@@ -816,6 +879,18 @@ thunar_standard_view_get_property (GObject    *object,
       g_value_set_boolean (value, thunar_view_get_loading (THUNAR_VIEW (object)));
       break;
 
+    case PROP_DISPLAY_NAME:
+      current_directory = thunar_navigator_get_current_directory (THUNAR_NAVIGATOR (object));
+      if (current_directory != NULL)
+        g_value_set_static_string (value, thunar_file_get_display_name (current_directory));
+      break;
+
+    case PROP_TOOLTIP_TEXT:
+      current_directory = thunar_navigator_get_current_directory (THUNAR_NAVIGATOR (object));
+      if (current_directory != NULL)
+        g_value_take_string (value, g_file_get_parse_name (thunar_file_get_file (current_directory)));
+      break;
+
     case PROP_SELECTED_FILES:
       g_value_set_boxed (value, thunar_component_get_selected_files (THUNAR_COMPONENT (object)));
       break;
@@ -1076,6 +1151,10 @@ thunar_standard_view_set_ui_manager (ThunarComponent *component,
   ThunarStandardView *standard_view = THUNAR_STANDARD_VIEW (component);
   GError             *error = NULL;
 
+  /* leave if nothing changed */
+  if (standard_view->ui_manager == ui_manager)
+    return;
+
   /* disconnect from the previous UI manager */
   if (G_LIKELY (standard_view->ui_manager != NULL))
     {
@@ -1103,6 +1182,9 @@ thunar_standard_view_set_ui_manager (ThunarComponent *component,
       /* unmerge our ui controls from the previous UI manager */
       gtk_ui_manager_remove_ui (standard_view->ui_manager, standard_view->ui_merge_id);
 
+      /* force update to remove all actions and proxies */
+      gtk_ui_manager_ensure_update (standard_view->ui_manager);
+
       /* drop the reference on the previous UI manager */
       g_object_unref (G_OBJECT (standard_view->ui_manager));
     }
@@ -1130,6 +1212,9 @@ thunar_standard_view_set_ui_manager (ThunarComponent *component,
 
       /* merge the ui controls from derived classes */
       (*THUNAR_STANDARD_VIEW_GET_CLASS (standard_view)->connect_ui_manager) (standard_view, ui_manager);
+
+      /* force update to avoid flickering */
+      gtk_ui_manager_ensure_update (standard_view->ui_manager);
     }
 
   /* let others know that we have a new manager */
@@ -1142,16 +1227,97 @@ static ThunarFile*
 thunar_standard_view_get_current_directory (ThunarNavigator *navigator)
 {
   ThunarStandardView *standard_view = THUNAR_STANDARD_VIEW (navigator);
-  ThunarFolder       *folder;
-
   _thunar_return_val_if_fail (THUNAR_IS_STANDARD_VIEW (standard_view), NULL);
+  return standard_view->priv->current_directory;
+}
 
-  /* try to determine the current folder from the model */
-  folder = thunar_list_model_get_folder (standard_view->model);
-  if (G_LIKELY (folder != NULL))
-    return thunar_folder_get_corresponding_file (folder);
 
-  return NULL;
+
+static void
+thunar_standard_view_scroll_position_save (ThunarStandardView *standard_view)
+{
+  ThunarFile    *first_file;
+  GtkAdjustment *vadjustment;
+  GtkAdjustment *hadjustment;
+  GFile         *gfile;
+
+  _thunar_return_if_fail (THUNAR_IS_STANDARD_VIEW (standard_view));
+
+  /* store the previous directory in the scroll hash table */
+  if (standard_view->priv->current_directory != NULL)
+    {
+      /* only stop the first file is the scroll bar is actually moved */
+      vadjustment = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (standard_view));
+      hadjustment = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (standard_view));
+      gfile = thunar_file_get_file (standard_view->priv->current_directory);
+
+      if (gtk_adjustment_get_value (vadjustment) == 0.0
+          && gtk_adjustment_get_value (hadjustment) == 0.0)
+        {
+          /* remove from the hash table, we already scroll to 0,0 */
+          g_hash_table_remove (standard_view->priv->scroll_to_files, gfile);
+        }
+      else if (thunar_view_get_visible_range (THUNAR_VIEW (standard_view), &first_file, NULL))
+        {
+          /* add the file to our internal mapping of directories to scroll files */
+          g_hash_table_replace (standard_view->priv->scroll_to_files,
+                                g_object_ref (gfile),
+                                g_object_ref (thunar_file_get_file (first_file)));
+          g_object_unref (first_file);
+        }
+    }
+}
+
+
+
+static void
+thunar_standard_view_restore_selection_from_history (ThunarStandardView *standard_view)
+{
+  GList       selected_files;
+  ThunarFile *selected_file;
+
+  _thunar_return_if_fail (THUNAR_IS_STANDARD_VIEW (standard_view));
+  _thunar_return_if_fail (THUNAR_IS_FILE (standard_view->priv->current_directory));
+
+  /* reset the selected files list */
+  selected_files.data = NULL;
+  selected_files.prev = NULL;
+  selected_files.next = NULL;
+
+  /* determine the next file in the history */
+  selected_file = thunar_history_peek_forward (standard_view->priv->history);
+  if (selected_file != NULL)
+    {
+      /* mark the file from history for selection if it is inside the new
+       * directory */
+      if (thunar_file_is_parent (standard_view->priv->current_directory, selected_file))
+        selected_files.data = selected_file;
+      else
+        g_object_unref (selected_file);
+    }
+
+  /* do the same with the previous file in the history */
+  if (selected_files.data == NULL)
+    {
+      selected_file = thunar_history_peek_back (standard_view->priv->history);
+      if (selected_file != NULL)
+        {
+          /* mark the file from history for selection if it is inside the
+           * new directory */
+          if (thunar_file_is_parent (standard_view->priv->current_directory, selected_file))
+            selected_files.data = selected_file;
+          else
+            g_object_unref (selected_file);
+        }
+    }
+
+  /* select the previous or next file from the history if it is inside the
+   * new current directory */
+  if (selected_files.data != NULL)
+    {
+      thunar_component_set_selected_files (THUNAR_COMPONENT (standard_view), &selected_files);
+      g_object_unref (G_OBJECT (selected_files.data));
+    }
 }
 
 
@@ -1167,6 +1333,10 @@ thunar_standard_view_set_current_directory (ThunarNavigator *navigator,
   _thunar_return_if_fail (THUNAR_IS_STANDARD_VIEW (standard_view));
   _thunar_return_if_fail (current_directory == NULL || THUNAR_IS_FILE (current_directory));
 
+  /* get the current directory */
+  if (standard_view->priv->current_directory == current_directory)
+    return;
+
   /* cancel any pending thumbnail sources and requests */
   thunar_standard_view_cancel_thumbnailing (standard_view);
 
@@ -1174,9 +1344,24 @@ thunar_standard_view_set_current_directory (ThunarNavigator *navigator,
   if (G_LIKELY (standard_view->loading_binding != NULL))
     exo_binding_unbind (standard_view->loading_binding);
 
+  /* store the current scroll position */
+  if (current_directory != NULL)
+    thunar_standard_view_scroll_position_save (standard_view);
+
+  /* release previous directory */
+  if (standard_view->priv->current_directory != NULL)
+    {
+      g_signal_handlers_disconnect_matched (standard_view->priv->current_directory,
+                                            G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, standard_view);
+      g_object_unref (standard_view->priv->current_directory);
+    }
+
   /* check if we want to reset the directory */
   if (G_UNLIKELY (current_directory == NULL))
     {
+      /* unset */
+      standard_view->priv->current_directory = NULL;
+
       /* resetting the folder for the model can take some time if the view has
        * to update the selection everytime (i.e. closing a window with a lot of
        * selected files), so we temporarily disconnect the model from the view.
@@ -1193,10 +1378,18 @@ thunar_standard_view_set_current_directory (ThunarNavigator *navigator,
       return;
     }
 
+  /* take ref on new directory */
+  standard_view->priv->current_directory = g_object_ref (current_directory);
+  g_signal_connect (G_OBJECT (current_directory), "destroy", G_CALLBACK (thunar_standard_view_current_directory_destroy), standard_view);
+  g_signal_connect (G_OBJECT (current_directory), "changed", G_CALLBACK (thunar_standard_view_current_directory_changed), standard_view);
+
   /* scroll to top-left when changing folder */
   gtk_adjustment_set_value (gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (standard_view)), 0.0);
   gtk_adjustment_set_value (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (standard_view)), 0.0);
 
+  /* store the directory in the history */
+  thunar_navigator_set_current_directory (THUNAR_NAVIGATOR (standard_view->priv->history), current_directory);
+
   /* We drop the model from the view as a simple optimization to speed up
    * the process of disconnecting the model data from the view.
    */
@@ -1236,6 +1429,13 @@ thunar_standard_view_set_current_directory (ThunarNavigator *navigator,
 
   /* notify all listeners about the new/old current directory */
   g_object_notify (G_OBJECT (standard_view), "current-directory");
+
+  /* update tab label and tooltip */
+  g_object_notify (G_OBJECT (standard_view), "display-name");
+  g_object_notify (G_OBJECT (standard_view), "tooltip-text");
+
+  /* restore the selection from the history */
+  thunar_standard_view_restore_selection_from_history (standard_view);
 }
 
 
@@ -1255,6 +1455,8 @@ thunar_standard_view_set_loading (ThunarStandardView *standard_view,
   ThunarFile *file;
   GList      *new_files_path_list;
   GList      *selected_files;
+  GFile      *first_file;
+  ThunarFile *current_directory;
 
   loading = !!loading;
 
@@ -1272,21 +1474,39 @@ thunar_standard_view_set_loading (ThunarStandardView *standard_view,
     g_signal_handler_unblock (standard_view->model, standard_view->priv->row_changed_id);
 
   /* check if we're done loading and have a scheduled scroll_to_file */
-  if (G_UNLIKELY (!loading && standard_view->priv->scroll_to_file != NULL))
+  if (G_UNLIKELY (!loading))
     {
-      /* remember and reset the scroll_to_file reference */
-      file = standard_view->priv->scroll_to_file;
-      standard_view->priv->scroll_to_file = NULL;
+      if (standard_view->priv->scroll_to_file != NULL)
+        {
+          /* remember and reset the scroll_to_file reference */
+          file = standard_view->priv->scroll_to_file;
+          standard_view->priv->scroll_to_file = NULL;
 
-      /* and try again */
-      thunar_view_scroll_to_file (THUNAR_VIEW (standard_view), file,
-                                  standard_view->priv->scroll_to_select,
-                                  standard_view->priv->scroll_to_use_align,
-                                  standard_view->priv->scroll_to_row_align,
-                                  standard_view->priv->scroll_to_col_align);
+          /* and try again */
+          thunar_view_scroll_to_file (THUNAR_VIEW (standard_view), file,
+                                      standard_view->priv->scroll_to_select,
+                                      standard_view->priv->scroll_to_use_align,
+                                      standard_view->priv->scroll_to_row_align,
+                                      standard_view->priv->scroll_to_col_align);
 
-      /* cleanup */
-      g_object_unref (G_OBJECT (file));
+          /* cleanup */
+          g_object_unref (G_OBJECT (file));
+        }
+      else
+        {
+          /* look for a first visible file in the hash table */
+          current_directory = thunar_navigator_get_current_directory (THUNAR_NAVIGATOR (standard_view));
+          if (G_LIKELY (current_directory != NULL))
+            {
+              first_file = g_hash_table_lookup (standard_view->priv->scroll_to_files, thunar_file_get_file (current_directory));
+              if (G_LIKELY (first_file != NULL))
+                {
+                  file = thunar_file_cache_lookup (first_file);
+                  if (G_LIKELY (file != NULL))
+                    thunar_view_scroll_to_file (THUNAR_VIEW (standard_view), file, FALSE, TRUE, 0.0f, 0.0f);
+                }
+            }
+        }
     }
 
   /* check if we have a path list from new_files pending */
@@ -1828,6 +2048,102 @@ thunar_standard_view_update_statusbar_text (ThunarStandardView *standard_view)
 
 
 static void
+thunar_standard_view_current_directory_destroy (ThunarFile         *current_directory,
+                                                ThunarStandardView *standard_view)
+{
+  ThunarFile *new_directory = NULL;
+  GFile      *path;
+  GFile      *tmp;
+  GError     *error = NULL;
+
+  _thunar_return_if_fail (THUNAR_IS_STANDARD_VIEW (standard_view));
+  _thunar_return_if_fail (THUNAR_IS_FILE (current_directory));
+  _thunar_return_if_fail (standard_view->priv->current_directory == current_directory);
+
+  /* determine the path of the current directory */
+  path = g_object_ref (thunar_file_get_file (current_directory));
+
+  /* try to find a parent directory that still exists */
+  while (new_directory == NULL)
+    {
+      /* check whether the current directory exists */
+      if (g_file_query_exists (path, NULL))
+        {
+          /* it does, try to load the file */
+          new_directory = thunar_file_get (path, NULL);
+
+          /* fall back to $HOME if loading the file failed */
+          if (new_directory == NULL)
+            break;
+        }
+      else
+        {
+          /* determine the parent of the directory */
+          tmp = g_file_get_parent (path);
+
+          /* if there's no parent this means that we've found no parent
+           * that still exists at all. Fall back to $HOME then */
+          if (tmp == NULL)
+            break;
+
+          /* free the old directory */
+          g_object_unref (path);
+
+          /* check the parent next */
+          path = tmp;
+        }
+    }
+
+  /* release last ref */
+  if (path != NULL)
+    g_object_unref (path);
+
+  if (new_directory == NULL)
+    {
+      /* fall-back to the home directory */
+      path = thunar_g_file_new_for_home ();
+      new_directory = thunar_file_get (path, &error);
+      g_object_unref (path);
+
+      if (G_UNLIKELY (new_directory == NULL))
+        {
+          /* display an error to the user */
+          thunar_dialogs_show_error (GTK_WIDGET (standard_view), error, _("Failed to open the home folder"));
+          g_error_free (error);
+        }
+    }
+
+  if (G_LIKELY (new_directory != NULL))
+    {
+      /* enter the new folder */
+      thunar_navigator_change_directory (THUNAR_NAVIGATOR (standard_view), new_directory);
+
+      /* if the view is not active, do this on our own */
+      thunar_navigator_set_current_directory (THUNAR_NAVIGATOR (standard_view), new_directory);
+
+      /* release the file reference */
+      g_object_unref (new_directory);
+    }
+}
+
+
+
+static void
+thunar_standard_view_current_directory_changed (ThunarFile         *current_directory,
+                                                ThunarStandardView *standard_view)
+{
+  _thunar_return_if_fail (THUNAR_IS_STANDARD_VIEW (standard_view));
+  _thunar_return_if_fail (THUNAR_IS_FILE (current_directory));
+  _thunar_return_if_fail (standard_view->priv->current_directory == current_directory);
+
+  /* update tab label and tooltip */
+  g_object_notify (G_OBJECT (standard_view), "display-name");
+  g_object_notify (G_OBJECT (standard_view), "tooltip-text");
+}
+
+
+
+static void
 thunar_standard_view_action_create_empty_file (GtkAction          *action,
                                                ThunarStandardView *standard_view)
 {
@@ -1952,7 +2268,7 @@ thunar_standard_view_action_create_template (GtkAction           *action,
 
           /* launch the operation */
           application = thunar_application_get ();
-          thunar_application_creat (application, GTK_WIDGET (standard_view), &target_path_list, 
+          thunar_application_creat (application, GTK_WIDGET (standard_view), &target_path_list,
                                     thunar_file_get_file (file),
                                     thunar_standard_view_new_files_closure (standard_view, NULL));
           g_object_unref (G_OBJECT (application));
@@ -2804,7 +3120,7 @@ thunar_standard_view_drag_leave (GtkWidget          *widget,
   g_object_set (G_OBJECT (standard_view->icon_renderer), "drop-file", NULL, NULL);
 
   /* stop any running drag autoscroll timer */
-  if (G_UNLIKELY (standard_view->priv->drag_scroll_timer_id >= 0))
+  if (G_UNLIKELY (standard_view->priv->drag_scroll_timer_id != 0))
     g_source_remove (standard_view->priv->drag_scroll_timer_id);
 
   /* disable the drop highlighting around the view */
@@ -2859,7 +3175,7 @@ thunar_standard_view_drag_motion (GtkWidget          *view,
     }
 
   /* start the drag autoscroll timer if not already running */
-  if (G_UNLIKELY (standard_view->priv->drag_scroll_timer_id < 0))
+  if (G_UNLIKELY (standard_view->priv->drag_scroll_timer_id == 0))
     {
       /* schedule the drag autoscroll timer */
       standard_view->priv->drag_scroll_timer_id = g_timeout_add_full (G_PRIORITY_LOW, 50, thunar_standard_view_drag_scroll_timer,
@@ -2943,7 +3259,7 @@ thunar_standard_view_drag_end (GtkWidget          *view,
                                ThunarStandardView *standard_view)
 {
   /* stop any running drag autoscroll timer */
-  if (G_UNLIKELY (standard_view->priv->drag_scroll_timer_id >= 0))
+  if (G_UNLIKELY (standard_view->priv->drag_scroll_timer_id != 0))
     g_source_remove (standard_view->priv->drag_scroll_timer_id);
 
   /* release the list of dragged URIs */
@@ -3194,7 +3510,7 @@ thunar_standard_view_drag_scroll_timer (gpointer user_data)
 static void
 thunar_standard_view_drag_scroll_timer_destroy (gpointer user_data)
 {
-  THUNAR_STANDARD_VIEW (user_data)->priv->drag_scroll_timer_id = -1;
+  THUNAR_STANDARD_VIEW (user_data)->priv->drag_scroll_timer_id = 0;
 }
 
 
@@ -3629,5 +3945,3 @@ thunar_standard_view_selection_changed (ThunarStandardView *standard_view)
   g_object_notify (G_OBJECT (standard_view), "selected-files");
 }
 
-
-
diff --git a/thunar/thunar-tree-pane.c b/thunar/thunar-tree-pane.c
index ac6e9d0..c28ea33 100644
--- a/thunar/thunar-tree-pane.c
+++ b/thunar/thunar-tree-pane.c
@@ -148,6 +148,7 @@ thunar_tree_pane_init (ThunarTreePane *tree_pane)
   exo_binding_new (G_OBJECT (tree_pane), "show-hidden", G_OBJECT (tree_pane->view), "show-hidden");
   exo_binding_new (G_OBJECT (tree_pane), "current-directory", G_OBJECT (tree_pane->view), "current-directory");
   g_signal_connect_swapped (G_OBJECT (tree_pane->view), "change-directory", G_CALLBACK (thunar_navigator_change_directory), tree_pane);
+  g_signal_connect_swapped (G_OBJECT (tree_pane->view), "open-new-tab", G_CALLBACK (thunar_navigator_open_new_tab), tree_pane);
   gtk_container_add (GTK_CONTAINER (tree_pane), tree_pane->view);
   gtk_widget_show (tree_pane->view);
 }
diff --git a/thunar/thunar-tree-view.c b/thunar/thunar-tree-view.c
index e5f8c57..5cdeaff 100644
--- a/thunar/thunar-tree-view.c
+++ b/thunar/thunar-tree-view.c
@@ -157,11 +157,13 @@ static void                     thunar_tree_view_mount_finish                 (T
                                                                                gpointer                 user_data);
 static void                     thunar_tree_view_mount                        (ThunarTreeView          *view,
                                                                                gboolean                 open_after_mounting,
-                                                                               gboolean                 open_in_new_window);
+                                                                               guint                    open_in);
 static void                     thunar_tree_view_action_open                  (ThunarTreeView          *view);
 static void                     thunar_tree_view_open_selection               (ThunarTreeView          *view);
 static void                     thunar_tree_view_action_open_in_new_window    (ThunarTreeView          *view);
+static void                     thunar_tree_view_action_open_in_new_tab       (ThunarTreeView          *view);
 static void                     thunar_tree_view_open_selection_in_new_window (ThunarTreeView          *view);
+static void                     thunar_tree_view_open_selection_in_new_tab    (ThunarTreeView          *view);
 static void                     thunar_tree_view_action_paste_into_folder     (ThunarTreeView          *view);
 static void                     thunar_tree_view_action_properties            (ThunarTreeView          *view);
 static GClosure                *thunar_tree_view_new_files_closure            (ThunarTreeView          *view);
@@ -185,7 +187,7 @@ static void                     thunar_tree_view_expand_timer_destroy         (g
 static ThunarTreeViewMountData *thunar_tree_view_mount_data_new               (ThunarTreeView          *view,
                                                                                GtkTreePath             *path,
                                                                                gboolean                 open_after_mounting,
-                                                                               gboolean                 open_in_new_window);
+                                                                               guint                    open_in);
 static void                     thunar_tree_view_mount_data_free              (ThunarTreeViewMountData *data);
 static gboolean                 thunar_tree_view_get_show_hidden              (ThunarTreeView          *view);
 static void                     thunar_tree_view_set_show_hidden              (ThunarTreeView          *view,
@@ -246,12 +248,19 @@ struct _ThunarTreeView
   gint                    expand_timer_id;
 };
 
+enum
+{
+  OPEN_IN_VIEW,
+  OPEN_IN_WINDOW,
+  OPEN_IN_TAB
+};
+
 struct _ThunarTreeViewMountData
 {
   ThunarTreeView *view;
   GtkTreePath    *path;
   gboolean        open_after_mounting;
-  gboolean        open_in_new_window;
+  guint           open_in;
 };
 
 
@@ -708,8 +717,9 @@ thunar_tree_view_button_press_event (GtkWidget      *widget,
               result = TRUE;
             }
         }
-      else if ((event->button == 1 || event->button == 2) && event->type == GDK_BUTTON_PRESS
-            && (event->state & gtk_accelerator_get_default_mod_mask ()) == 0)
+      else if ((event->button == 1 || event->button == 2)
+               && event->type == GDK_BUTTON_PRESS
+               && (event->state & gtk_accelerator_get_default_mod_mask ()) == 0)
         {
           /* remember the button as pressed and handled it in the release handler */
           view->pressed_button = event->button;
@@ -729,15 +739,24 @@ thunar_tree_view_button_release_event (GtkWidget      *widget,
                                        GdkEventButton *event)
 {
   ThunarTreeView *view = THUNAR_TREE_VIEW (widget);
+  gboolean        in_tab;
 
   /* check if we have an event matching the pressed button state */
   if (G_LIKELY (view->pressed_button == (gint) event->button))
     {
       /* check if we should simply open or open in new window */
       if (G_LIKELY (event->button == 1))
-        thunar_tree_view_action_open (view);
+        {
+          thunar_tree_view_action_open (view);
+        }
       else if (G_UNLIKELY (event->button == 2))
-        thunar_tree_view_action_open_in_new_window (view);
+        {
+          g_object_get (view->preferences, "misc-middle-click-in-tab", &in_tab, NULL);
+          if (in_tab)
+            thunar_tree_view_action_open_in_new_tab (view);
+          else
+            thunar_tree_view_action_open_in_new_window (view);
+        }
     }
 
   /* reset the pressed button state */
@@ -997,7 +1016,7 @@ thunar_tree_view_test_expand_row (GtkTreeView *tree_view,
           expandable = FALSE;
 
           /* allocate a mount data struct */
-          data = thunar_tree_view_mount_data_new (view, path, FALSE, FALSE);
+          data = thunar_tree_view_mount_data_new (view, path, FALSE, OPEN_IN_VIEW);
 
           /* allocate a GTK+ mount operation */
           window = gtk_widget_get_toplevel (GTK_WIDGET (view));
@@ -1101,6 +1120,13 @@ thunar_tree_view_context_menu (ThunarTreeView *view,
   /* set the stock icon */
   image = gtk_image_new_from_stock (GTK_STOCK_OPEN, GTK_ICON_SIZE_MENU);
   gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
+  
+  /* append the "Open in New Tab" menu action */
+  item = gtk_image_menu_item_new_with_mnemonic (_("Open in New Tab"));
+  g_signal_connect_swapped (G_OBJECT (item), "activate", G_CALLBACK (thunar_tree_view_action_open_in_new_tab), view);
+  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+  gtk_widget_set_sensitive (item, (file != NULL || device != NULL));
+  gtk_widget_show (item);
 
   /* append the "Open in New Window" menu action */
   item = gtk_image_menu_item_new_with_mnemonic (_("Open in New Window"));
@@ -1866,7 +1892,7 @@ static void
 thunar_tree_view_action_mount (ThunarTreeView *view)
 {
   _thunar_return_if_fail (THUNAR_IS_TREE_VIEW (view));
-  thunar_tree_view_mount (view, FALSE, FALSE);
+  thunar_tree_view_mount (view, FALSE, OPEN_IN_VIEW);
 }
 
 
@@ -1892,10 +1918,20 @@ thunar_tree_view_mount_finish (ThunarDevice *device,
     {
       if (G_LIKELY (data->open_after_mounting))
         {
-          if (data->open_in_new_window)
-            thunar_tree_view_open_selection_in_new_window (data->view);
-          else
-            thunar_tree_view_open_selection (data->view);
+          switch (data->open_in)
+            {
+            case OPEN_IN_WINDOW:
+              thunar_tree_view_open_selection_in_new_window (data->view);
+              break;
+            
+            case OPEN_IN_TAB:
+              thunar_tree_view_open_selection_in_new_tab (data->view);
+              break;
+            
+            default:
+              thunar_tree_view_open_selection (data->view);
+              break;
+            }
         }
       else if (data->path != NULL)
         {
@@ -1911,7 +1947,7 @@ thunar_tree_view_mount_finish (ThunarDevice *device,
 static void
 thunar_tree_view_mount (ThunarTreeView *view,
                         gboolean        open_after_mounting,
-                        gboolean        open_in_new_window)
+                        guint           open_in)
 {
   ThunarTreeViewMountData *data;
   GMountOperation         *mount_operation;
@@ -1928,8 +1964,7 @@ thunar_tree_view_mount (ThunarTreeView *view,
       if (!thunar_device_is_mounted (device))
         {
           /* allocate mount data */
-          data = thunar_tree_view_mount_data_new (view, NULL, open_after_mounting,
-                                                  open_in_new_window);
+          data = thunar_tree_view_mount_data_new (view, NULL, open_after_mounting, open_in);
 
           /* allocate a GTK+ mount operation */
           window = gtk_widget_get_toplevel (GTK_WIDGET (view));
@@ -1971,7 +2006,7 @@ thunar_tree_view_action_open (ThunarTreeView *view)
       if (thunar_device_is_mounted (device))
         thunar_tree_view_open_selection (view);
       else
-        thunar_tree_view_mount (view, TRUE, FALSE);
+        thunar_tree_view_mount (view, TRUE, OPEN_IN_TAB);
 
       g_object_unref (device);
     }
@@ -2020,7 +2055,7 @@ thunar_tree_view_action_open_in_new_window (ThunarTreeView *view)
       if (thunar_device_is_mounted (device))
         thunar_tree_view_open_selection_in_new_window (view);
       else
-        thunar_tree_view_mount (view, TRUE, FALSE);
+        thunar_tree_view_mount (view, TRUE, OPEN_IN_WINDOW);
 
       g_object_unref (device);
     }
@@ -2034,6 +2069,36 @@ thunar_tree_view_action_open_in_new_window (ThunarTreeView *view)
 
 
 static void
+thunar_tree_view_action_open_in_new_tab (ThunarTreeView *view)
+{
+  ThunarFile   *file;
+  ThunarDevice *device;
+
+  _thunar_return_if_fail (THUNAR_IS_TREE_VIEW (view));
+
+  /* determine the selected device and file */
+  device = thunar_tree_view_get_selected_device (view);
+  file = thunar_tree_view_get_selected_file (view);
+
+  if (device != NULL)
+    {
+      if (thunar_device_is_mounted (device))
+        thunar_tree_view_open_selection_in_new_tab (view);
+      else
+        thunar_tree_view_mount (view, TRUE, OPEN_IN_TAB);
+
+      g_object_unref (device);
+    }
+  else if (file != NULL)
+    {
+      thunar_tree_view_open_selection_in_new_tab (view);
+      g_object_unref (file);
+    }
+}
+
+
+
+static void
 thunar_tree_view_open_selection_in_new_window (ThunarTreeView *view)
 {
   ThunarApplication *application;
@@ -2057,6 +2122,25 @@ thunar_tree_view_open_selection_in_new_window (ThunarTreeView *view)
 
 
 static void
+thunar_tree_view_open_selection_in_new_tab (ThunarTreeView *view)
+{
+  ThunarFile *file;
+
+  _thunar_return_if_fail (THUNAR_IS_TREE_VIEW (view));
+
+  /* determine the selected file */
+  file = thunar_tree_view_get_selected_file (view);
+  if (G_LIKELY (file != NULL))
+    {
+      /* open a new tab for the selected folder */
+      thunar_navigator_open_new_tab (THUNAR_NAVIGATOR (view), file);
+      g_object_unref (file);
+    }
+}
+
+
+
+static void
 thunar_tree_view_action_paste_into_folder (ThunarTreeView *view)
 {
   ThunarFile *file;
@@ -2159,13 +2243,15 @@ thunar_tree_view_visible_func (ThunarTreeModel *model,
                                ThunarFile      *file,
                                gpointer         user_data)
 {
-  ThunarTreeView *view = THUNAR_TREE_VIEW (user_data);
+  ThunarTreeView *view;
   gboolean        visible = TRUE;
 
   _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE);
   _thunar_return_val_if_fail (THUNAR_IS_TREE_MODEL (model), FALSE);
+  _thunar_return_val_if_fail (THUNAR_IS_TREE_VIEW (user_data), FALSE);
 
   /* if show_hidden is TRUE, nothing is filtered */
+  view = THUNAR_TREE_VIEW (user_data);
   if (G_LIKELY (!view->show_hidden))
     {
       /* we display all non-hidden file and hidden files that are ancestors of the current directory */
@@ -2435,7 +2521,7 @@ static ThunarTreeViewMountData *
 thunar_tree_view_mount_data_new (ThunarTreeView *view,
                                  GtkTreePath    *path,
                                  gboolean        open_after_mounting,
-                                 gboolean        open_in_new_window)
+                                 guint           open_in)
 {
   ThunarTreeViewMountData *data;
 
@@ -2443,7 +2529,7 @@ thunar_tree_view_mount_data_new (ThunarTreeView *view,
   data->path = path == NULL ? NULL : gtk_tree_path_copy (path);
   data->view = g_object_ref (view);
   data->open_after_mounting = open_after_mounting;
-  data->open_in_new_window = open_in_new_window;
+  data->open_in = open_in;
 
   return data;
 }
diff --git a/thunar/thunar-window-ui.xml b/thunar/thunar-window-ui.xml
index 46e7a04..465c8a8 100644
--- a/thunar/thunar-window-ui.xml
+++ b/thunar/thunar-window-ui.xml
@@ -12,7 +12,9 @@
 
   <menubar name="main-menu">
     <menu action="file-menu">
-      <menuitem action="open-new-window" />
+      <menuitem action="new-tab" />
+      <menuitem action="new-window" />
+      <separator />
       <placeholder name="placeholder-create-actions" />
       <separator />
       <placeholder name="placeholder-launcher" />
@@ -26,8 +28,11 @@
       <separator />
       <menuitem action="empty-trash" />
       <separator />
+      <menuitem action="detach-tab" />
+      <separator />
       <menuitem action="close-all-windows" />
-      <menuitem action="close" />
+      <menuitem action="close-tab" />
+      <menuitem action="close-window" />
     </menu>
 
     <menu action="edit-menu">
@@ -70,8 +75,7 @@
 
     <menu action="go-menu">
       <menuitem action="open-parent" />
-      <menuitem action="back" />
-      <menuitem action="forward" />
+      <placeholder name="placeholder-go-history-actions" />
       <separator />
       <menuitem action="open-home" />
       <menuitem action="open-desktop" />
@@ -110,9 +114,16 @@
     <placeholder name="placeholder-file-actions" />
   </popup>
 
+  <popup action="tab-context-menu">
+    <menuitem action="new-tab" />
+    <separator />
+    <menuitem action="detach-tab" />
+    <separator />
+    <menuitem action="close-tab" />
+  </popup>
+
   <toolbar name="location-toolbar">
-    <toolitem action="back" />
-    <toolitem action="forward" />
+    <placeholder name="placeholder-history-actions" />
     <toolitem action="open-parent" />
     <toolitem action="open-home" />
   </toolbar>
diff --git a/thunar/thunar-window.c b/thunar/thunar-window.c
index 9dd7a26..1f6a5d0 100644
--- a/thunar/thunar-window.c
+++ b/thunar/thunar-window.c
@@ -3,18 +3,18 @@
  * Copyright (c) 2005-2007 Benedikt Meurer <benny at xfce.org>
  * Copyright (c) 2009-2011 Jannis Pohlmann <jannis at xfce.org>
  *
- * This program is free software; you can redistribute it and/or 
+ * 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 
+ * 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 
+ * 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, write to the Free 
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the Free
  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  * Boston, MA 02110-1301, USA.
  */
@@ -43,7 +43,6 @@
 #include <thunar/thunar-gio-extensions.h>
 #include <thunar/thunar-gobject-extensions.h>
 #include <thunar/thunar-gtk-extensions.h>
-#include <thunar/thunar-history.h>
 #include <thunar/thunar-icon-view.h>
 #include <thunar/thunar-launcher.h>
 #include <thunar/thunar-location-buttons.h>
@@ -114,6 +113,30 @@ static void     thunar_window_realize                     (GtkWidget
 static void     thunar_window_unrealize                   (GtkWidget              *widget);
 static gboolean thunar_window_configure_event             (GtkWidget              *widget,
                                                            GdkEventConfigure      *event);
+static void     thunar_window_notebook_switch_page        (GtkWidget              *notebook,
+                                                           GtkWidget              *page,
+                                                           guint                   page_num,
+                                                           ThunarWindow           *window);
+static void     thunar_window_notebook_page_added         (GtkWidget              *notebook,
+                                                           GtkWidget              *page,
+                                                           guint                   page_num,
+                                                           ThunarWindow           *window);
+static void     thunar_window_notebook_page_removed       (GtkWidget              *notebook,
+                                                           GtkWidget              *page,
+                                                           guint                   page_num,
+                                                           ThunarWindow           *window);
+static gboolean thunar_window_notebook_button_press_event (GtkWidget              *notebook,
+                                                           GdkEventButton         *event,
+                                                           ThunarWindow           *window);
+static gboolean thunar_window_notebook_popup_menu         (GtkWidget              *notebook,
+                                                           ThunarWindow           *window);
+static gpointer thunar_window_notebook_create_window      (GtkWidget              *notebook,
+                                                           GtkWidget              *page,
+                                                           gint                    x,
+                                                           gint                    y,
+                                                           ThunarWindow           *window);
+static void     thunar_window_notebook_insert             (ThunarWindow           *window,
+                                                           ThunarFile             *directory);
 static void     thunar_window_merge_custom_preferences    (ThunarWindow           *window);
 static void     thunar_window_merge_go_actions            (ThunarWindow           *window);
 static void     thunar_window_install_location_bar        (ThunarWindow           *window,
@@ -122,13 +145,19 @@ static void     thunar_window_install_sidepane            (ThunarWindow
                                                            GType                   type);
 static void     thunar_window_start_open_location         (ThunarWindow           *window,
                                                            const gchar            *initial_text);
+static void     thunar_window_action_open_new_tab         (GtkAction              *action,
+                                                           ThunarWindow           *window);
 static void     thunar_window_action_open_new_window      (GtkAction              *action,
                                                            ThunarWindow           *window);
 static void     thunar_window_action_empty_trash          (GtkAction              *action,
                                                            ThunarWindow           *window);
+static void     thunar_window_action_detach_tab           (GtkAction              *action,
+                                                           ThunarWindow           *window);
 static void     thunar_window_action_close_all_windows    (GtkAction              *action,
                                                            ThunarWindow           *window);
-static void     thunar_window_action_close                (GtkAction              *action,
+static void     thunar_window_action_close_tab            (GtkAction              *action,
+                                                           ThunarWindow           *window);
+static void     thunar_window_action_close_window         (GtkAction              *action,
                                                            ThunarWindow           *window);
 static void     thunar_window_action_preferences          (GtkAction              *action,
                                                            ThunarWindow           *window);
@@ -191,8 +220,6 @@ static void     thunar_window_action_show_hidden          (GtkToggleAction
                                                            ThunarWindow           *window);
 static void     thunar_window_current_directory_changed   (ThunarFile             *current_directory,
                                                            ThunarWindow           *window);
-static void     thunar_window_current_directory_destroy   (ThunarFile             *current_directory,
-                                                           ThunarWindow           *window);
 static void     thunar_window_connect_proxy               (GtkUIManager           *manager,
                                                            GtkAction              *action,
                                                            GtkWidget              *proxy,
@@ -272,14 +299,17 @@ struct _ThunarWindow
   GtkWidget              *paned;
   GtkWidget              *sidepane;
   GtkWidget              *view_box;
+  GtkWidget              *notebook;
   GtkWidget              *view;
   GtkWidget              *statusbar;
 
+  GType                   view_type;
+  GSList                 *view_bindings;
+
   /* support for two different styles of location bars */
   GtkWidget              *location_bar;
   GtkWidget              *location_toolbar;
 
-  ThunarHistory          *history;
   ThunarLauncher         *launcher;
 
   ThunarFile             *current_directory;
@@ -293,9 +323,6 @@ struct _ThunarWindow
   /* support to remember window geometry */
   gint                    save_geometry_timer_id;
 
-  /* scroll_to_file support */
-  GHashTable             *scroll_to_files;
-
   /* support to toggle side pane using F9,
    * see the toggle_sidepane() function.
    */
@@ -307,11 +334,14 @@ struct _ThunarWindow
 static GtkActionEntry action_entries[] =
 {
   { "file-menu", NULL, N_ ("_File"), NULL, },
-  { "open-new-window", NULL, N_ ("Open New _Window"), "<control>N", N_ ("Open a new Thunar window for the displayed location"), G_CALLBACK (thunar_window_action_open_new_window), },
+  { "new-tab", NULL, N_ ("New _Tab"), "<control>T", N_ ("Open a new tab for the displayed location"), G_CALLBACK (thunar_window_action_open_new_tab), },
+  { "new-window", NULL, N_ ("New _Window"), "<control>N", N_ ("Open a new Thunar window for the displayed location"), G_CALLBACK (thunar_window_action_open_new_window), },
   { "sendto-menu", NULL, N_ ("_Send To"), NULL, },
   { "empty-trash", NULL, N_ ("_Empty Trash"), NULL, N_ ("Delete all files and folders in the Trash"), G_CALLBACK (thunar_window_action_empty_trash), },
+  { "detach-tab", NULL, N_ ("Detac_h Tab"), NULL, N_ ("Open current folder in a new window"), G_CALLBACK (thunar_window_action_detach_tab), },
   { "close-all-windows", NULL, N_ ("Close _All Windows"), "<control><shift>W", N_ ("Close all Thunar windows"), G_CALLBACK (thunar_window_action_close_all_windows), },
-  { "close", GTK_STOCK_CLOSE, N_ ("_Close"), "<control>W", N_ ("Close this window"), G_CALLBACK (thunar_window_action_close), },
+  { "close-tab", GTK_STOCK_CLOSE, N_ ("C_lose Tab"), "<control>W", N_ ("Close this folder"), G_CALLBACK (thunar_window_action_close_tab), },
+  { "close-window", GTK_STOCK_QUIT, N_ ("_Close Window"), "<control>Q", N_ ("Close this window"), G_CALLBACK (thunar_window_action_close_window), },
   { "edit-menu", NULL, N_ ("_Edit"), NULL, },
   { "preferences", GTK_STOCK_PREFERENCES, N_ ("Pr_eferences..."), NULL, N_ ("Edit Thunars Preferences"), G_CALLBACK (thunar_window_action_preferences), },
   { "view-menu", NULL, N_ ("_View"), NULL, },
@@ -345,7 +375,7 @@ static const GtkToggleActionEntry toggle_action_entries[] =
   { "view-location-selector-pathbar", NULL, N_ ("_Pathbar Style"), NULL, N_ ("Modern approach with buttons that correspond to folders"), G_CALLBACK (thunar_window_action_pathbar_changed), FALSE, },
   { "view-location-selector-toolbar", NULL, N_ ("_Toolbar Style"), NULL, N_ ("Traditional approach with location bar and navigation buttons"), G_CALLBACK (thunar_window_action_toolbar_changed), FALSE, },
   { "view-side-pane-shortcuts", NULL, N_ ("_Shortcuts"), "<control>B", N_ ("Toggles the visibility of the shortcuts pane"), G_CALLBACK (thunar_window_action_shortcuts_changed), FALSE, },
-  { "view-side-pane-tree", NULL, N_ ("_Tree"), "<control>T", N_ ("Toggles the visibility of the tree pane"), G_CALLBACK (thunar_window_action_tree_changed), FALSE, },
+  { "view-side-pane-tree", NULL, N_ ("_Tree"), "<control>E", N_ ("Toggles the visibility of the tree pane"), G_CALLBACK (thunar_window_action_tree_changed), FALSE, },
   { "view-statusbar", NULL, N_ ("St_atusbar"), NULL, N_ ("Change the visibility of this window's statusbar"), G_CALLBACK (thunar_window_action_statusbar_changed), FALSE, },
   { "view-menubar", NULL, N_ ("_Menubar"), "<control>M", N_ ("Change the visibility of this window's menubar"), G_CALLBACK (thunar_window_action_menubar_changed), TRUE, },
 };
@@ -665,14 +695,14 @@ static void
 thunar_window_setup_user_dir_menu_entries (ThunarWindow *window)
 {
   static const gchar *callback_names[] = {
-    "open-desktop", 
-    "open-documents", 
-    "open-downloads", 
+    "open-desktop",
+    "open-documents",
+    "open-downloads",
     "open-music",
-    "open-pictures", 
-    "open-public", 
-    "open-templates", 
-    "open-videos", 
+    "open-pictures",
+    "open-public",
+    "open-templates",
+    "open-videos",
     NULL
   };
   GtkAction          *action;
@@ -751,6 +781,10 @@ thunar_window_init (ThunarWindow *window)
   gint            width;
   gint            height;
   gboolean        maximized;
+  GtkRcStyle     *style;
+
+  /* unset the view type */
+  window->view_type = G_TYPE_NONE;
 
   /* grab a reference on the provider factory */
   window->provider_factory = thunarx_provider_factory_get_default ();
@@ -758,9 +792,6 @@ thunar_window_init (ThunarWindow *window)
   /* grab a reference on the preferences */
   window->preferences = thunar_preferences_get ();
 
-  /* allocate the scroll_to_files mapping */
-  window->scroll_to_files = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal, g_object_unref, g_object_unref);
-
   /* connect to the volume monitor */
   window->device_monitor = thunar_device_monitor_get ();
   g_signal_connect (window->device_monitor, "device-pre-unmount", G_CALLBACK (thunar_window_device_pre_unmount), window);
@@ -790,11 +821,6 @@ thunar_window_init (ThunarWindow *window)
   g_object_get (G_OBJECT (window->preferences), "last-show-hidden", &show_hidden, NULL);
   gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), show_hidden);
 
-  /* setup the history support */
-  window->history = g_object_new (THUNAR_TYPE_HISTORY, "action-group", window->action_group, NULL);
-  g_signal_connect_swapped (G_OBJECT (window->history), "change-directory", G_CALLBACK (thunar_window_set_current_directory), window);
-  exo_binding_new (G_OBJECT (window), "current-directory", G_OBJECT (window->history), "current-directory");
-
   /* rename the user dir menu entries and hide the unexisting ones */
   thunar_window_setup_user_dir_menu_entries (window);
 
@@ -837,11 +863,12 @@ thunar_window_init (ThunarWindow *window)
   thunar_component_set_ui_manager (THUNAR_COMPONENT (window->launcher), window->ui_manager);
   exo_binding_new (G_OBJECT (window), "current-directory", G_OBJECT (window->launcher), "current-directory");
   g_signal_connect_swapped (G_OBJECT (window->launcher), "change-directory", G_CALLBACK (thunar_window_set_current_directory), window);
+  g_signal_connect_swapped (G_OBJECT (window->launcher), "open-new-tab", G_CALLBACK (thunar_window_notebook_insert), window);
 
   /* determine the default window size from the preferences */
   g_object_get (G_OBJECT (window->preferences), "last-window-width", &width, "last-window-height", &height, "last-window-maximized", &maximized, NULL);
   gtk_window_set_default_size (GTK_WINDOW (window), width, height);
-  
+
   /* restore the maxized state of the window */
   if (G_UNLIKELY (maximized))
     gtk_window_maximize (GTK_WINDOW (window));
@@ -912,7 +939,28 @@ thunar_window_init (ThunarWindow *window)
   gtk_paned_pack2 (GTK_PANED (window->paned), window->view_box, TRUE, FALSE);
   gtk_widget_show (window->view_box);
 
-  /* determine the selected locatin selector */
+  /* tabs */
+  window->notebook = gtk_notebook_new ();
+  gtk_table_attach (GTK_TABLE (window->view_box), window->notebook, 0, 1, 1, 2, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
+  g_signal_connect (G_OBJECT (window->notebook), "switch-page", G_CALLBACK (thunar_window_notebook_switch_page), window);
+  g_signal_connect (G_OBJECT (window->notebook), "page-added", G_CALLBACK (thunar_window_notebook_page_added), window);
+  g_signal_connect (G_OBJECT (window->notebook), "page-removed", G_CALLBACK (thunar_window_notebook_page_removed), window);
+  g_signal_connect_after (G_OBJECT (window->notebook), "button-press-event", G_CALLBACK (thunar_window_notebook_button_press_event), window);
+  g_signal_connect (G_OBJECT (window->notebook), "popup-menu", G_CALLBACK (thunar_window_notebook_popup_menu), window);
+  g_signal_connect (G_OBJECT (window->notebook), "create-window", G_CALLBACK (thunar_window_notebook_create_window), window);
+  gtk_notebook_set_show_border (GTK_NOTEBOOK (window->notebook), FALSE);
+  gtk_notebook_set_homogeneous_tabs (GTK_NOTEBOOK (window->notebook), TRUE);
+  gtk_container_set_border_width (GTK_CONTAINER (window->notebook), 0);
+  gtk_notebook_set_group_name (GTK_NOTEBOOK (window->notebook), "thunar-tabs");
+  gtk_widget_show (window->notebook);
+
+  /* drop the notebook borders */
+  style = gtk_rc_style_new ();
+  style->xthickness = style->ythickness = 0;
+  gtk_widget_modify_style (window->notebook, style);
+  g_object_unref (G_OBJECT (style));
+
+  /* determine the selected location selector */
   g_object_get (G_OBJECT (window->preferences), "last-location-bar", &type_name, NULL);
   if (exo_str_is_equal (type_name, g_type_name (THUNAR_TYPE_LOCATION_BUTTONS)))
     type = THUNAR_TYPE_LOCATION_BUTTONS;
@@ -944,29 +992,14 @@ thunar_window_init (ThunarWindow *window)
   action = gtk_action_group_get_action (window->action_group, "view-side-pane-tree");
   gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), (type == THUNAR_TYPE_TREE_PANE));
 
-  /* determine the default view */
-  g_object_get (G_OBJECT (window->preferences), "default-view", &type_name, NULL);
-  type = g_type_from_name (type_name);
-  g_free (type_name);
-
   /* check if we should display the statusbar by default */
   g_object_get (G_OBJECT (window->preferences), "last-statusbar-visible", &visible, NULL);
   action = gtk_action_group_get_action (window->action_group, "view-statusbar");
   gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), visible);
 
-  /* determine the last selected view if we don't have a valid default */
-  if (!g_type_is_a (type, THUNAR_TYPE_VIEW))
-    {
-      g_object_get (G_OBJECT (window->preferences), "last-view", &type_name, NULL);
-      type = g_type_from_name (type_name);
-      g_free (type_name);
-    }
-
-  /* activate the selected view */
+  /* connect signal */
   action = gtk_action_group_get_action (window->action_group, "view-as-icons");
-  gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), view_type2index (g_type_is_a (type, THUNAR_TYPE_VIEW) ? type : THUNAR_TYPE_ICON_VIEW));
   g_signal_connect (G_OBJECT (action), "changed", G_CALLBACK (thunar_window_action_view_changed), window);
-  thunar_window_action_view_changed (GTK_RADIO_ACTION (action), GTK_RADIO_ACTION (action), window);
 
   /* schedule asynchronous menu action merging */
   window->merge_idle_id = g_idle_add_full (G_PRIORITY_LOW + 20, thunar_window_merge_idle, window, thunar_window_merge_idle_destroy);
@@ -1029,7 +1062,6 @@ thunar_window_finalize (GObject *object)
   g_object_unref (window->action_group);
   g_object_unref (window->icon_factory);
   g_object_unref (window->launcher);
-  g_object_unref (window->history);
 
   /* release our reference on the provider factory */
   g_object_unref (window->provider_factory);
@@ -1037,9 +1069,6 @@ thunar_window_finalize (GObject *object)
   /* release the preferences reference */
   g_object_unref (window->preferences);
 
-  /* release the scroll_to_files hash table */
-  g_hash_table_destroy (window->scroll_to_files);
-
   (*G_OBJECT_CLASS (thunar_window_parent_class)->finalize) (object);
 }
 
@@ -1361,6 +1390,426 @@ thunar_window_configure_event (GtkWidget         *widget,
 
 
 static void
+thunar_window_binding_destroyed (gpointer data,
+                                 GObject  *binding)
+{
+  ThunarWindow *window = THUNAR_WINDOW (data);
+
+  if (window->view_bindings != NULL)
+    window->view_bindings = g_slist_remove (window->view_bindings, binding);
+}
+
+
+
+static void
+thunar_window_binding_create (ThunarWindow *window,
+                              gpointer src_object,
+                              const gchar *src_prop,
+                              gpointer dst_object,
+                              const gchar *dst_prop,
+                              GBindingFlags flags)
+{
+  GBinding *binding;
+
+  _thunar_return_if_fail (G_IS_OBJECT (src_object));
+  _thunar_return_if_fail (G_IS_OBJECT (dst_object));
+
+  binding = g_object_bind_property (G_OBJECT (src_object), src_prop,
+                                    G_OBJECT (dst_object), dst_prop,
+                                    flags);
+
+  g_object_weak_ref (G_OBJECT (binding), thunar_window_binding_destroyed, window);
+  window->view_bindings = g_slist_prepend (window->view_bindings, binding);
+}
+
+
+
+static void
+thunar_window_notebook_switch_page (GtkWidget    *notebook,
+                                    GtkWidget    *page,
+                                    guint         page_num,
+                                    ThunarWindow *window)
+{
+  GtkAction  *action;
+  GSList     *view_bindings;
+  ThunarFile *current_directory;
+
+  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
+  _thunar_return_if_fail (GTK_IS_NOTEBOOK (notebook));
+  _thunar_return_if_fail (THUNAR_IS_VIEW (page));
+  _thunar_return_if_fail (window->notebook == notebook);
+
+  /* leave if nothing changed */
+  if (window->view == page)
+    return;
+
+  if (G_LIKELY (window->view != NULL))
+    {
+      /* unregisters the actions from the ui */
+      thunar_component_set_ui_manager (THUNAR_COMPONENT (window->view), NULL);
+
+      /* unset view during switch */
+      window->view = NULL;
+    }
+
+  /* disconnect existing bindings */
+  view_bindings = window->view_bindings;
+  window->view_bindings = NULL;
+  g_slist_free_full (view_bindings, g_object_unref);
+
+  /* update the directory of the current window */
+  current_directory = thunar_navigator_get_current_directory (THUNAR_NAVIGATOR (page));
+  thunar_window_set_current_directory (window, current_directory);
+
+  /* activate the selected view */
+  action = gtk_action_group_get_action (window->action_group, "view-as-icons");
+  g_signal_handlers_block_by_func (action, thunar_window_action_view_changed, window);
+  gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), view_type2index (G_OBJECT_TYPE (page)));
+  g_signal_handlers_unblock_by_func (action, thunar_window_action_view_changed, window);
+
+  /* add stock bindings */
+  thunar_window_binding_create (window, window, "current-directory", page, "current-directory", G_BINDING_DEFAULT);
+  thunar_window_binding_create (window, window, "show-hidden", page, "show-hidden", G_BINDING_SYNC_CREATE);
+  thunar_window_binding_create (window, page, "loading", window->spinner, "active", G_BINDING_SYNC_CREATE);
+  thunar_window_binding_create (window, page, "selected-files", window->launcher, "selected-files", G_BINDING_SYNC_CREATE);
+  thunar_window_binding_create (window, page, "zoom-level", window, "zoom-level", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
+
+  /* connect to the location bar (if any) */
+  if (G_LIKELY (window->location_bar != NULL))
+    {
+      thunar_window_binding_create (window, page, "selected-files",
+                                    window->location_bar, "selected-files",
+                                    G_BINDING_SYNC_CREATE);
+    }
+
+  /* connect to the sidepane (if any) */
+  if (G_LIKELY (window->sidepane != NULL))
+    {
+      thunar_window_binding_create (window, page, "selected-files",
+                                    window->sidepane, "selected-files",
+                                    G_BINDING_SYNC_CREATE);
+    }
+
+  /* connect to the statusbar (if any) */
+  if (G_LIKELY (window->statusbar != NULL))
+    {
+      thunar_window_binding_create (window, page, "statusbar-text",
+                                    window->statusbar, "text",
+                                    G_BINDING_SYNC_CREATE);
+    }
+
+  /* activate new view */
+  window->view = page;
+
+  /* integrate the standard view action in the ui */
+  thunar_component_set_ui_manager (THUNAR_COMPONENT (page), window->ui_manager);
+
+  gtk_widget_grab_focus (page);
+}
+
+
+
+static void
+thunar_window_notebook_show_tabs (ThunarWindow *window)
+{
+  gint       n_pages;
+  gboolean   show_tabs = TRUE;
+  GtkAction *action;
+
+  /* check if tabs should be visible */
+  n_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook));
+  if (n_pages < 2)
+    {
+      g_object_get (G_OBJECT (window->preferences),
+                    "misc-always-show-tabs", &show_tabs, NULL);
+    }
+
+  /* update visibility */
+  gtk_notebook_set_show_tabs (GTK_NOTEBOOK (window->notebook), show_tabs);
+
+  /* visibility of the detach action */
+  action = gtk_action_group_get_action (window->action_group, "detach-tab");
+  gtk_action_set_visible (action, n_pages > 1);
+}
+
+
+
+static void
+thunar_window_notebook_page_added (GtkWidget    *notebook,
+                                   GtkWidget    *page,
+                                   guint         page_num,
+                                   ThunarWindow *window)
+{
+  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
+  _thunar_return_if_fail (GTK_IS_NOTEBOOK (notebook));
+  _thunar_return_if_fail (THUNAR_IS_VIEW (page));
+  _thunar_return_if_fail (window->notebook == notebook);
+
+  /* connect signals */
+  g_signal_connect (G_OBJECT (page), "notify::loading", G_CALLBACK (thunar_window_notify_loading), window);
+  g_signal_connect_swapped (G_OBJECT (page), "start-open-location", G_CALLBACK (thunar_window_start_open_location), window);
+  g_signal_connect_swapped (G_OBJECT (page), "change-directory", G_CALLBACK (thunar_window_set_current_directory), window);
+  g_signal_connect_swapped (G_OBJECT (page), "open-new-tab", G_CALLBACK (thunar_window_notebook_insert), window);
+
+  /* update tab visibility */
+  thunar_window_notebook_show_tabs (window);
+
+  /* set default type if not set yet */
+  if (window->view_type == G_TYPE_NONE)
+    window->view_type = G_OBJECT_TYPE (page);
+}
+
+
+
+static void
+thunar_window_notebook_page_removed (GtkWidget    *notebook,
+                                     GtkWidget    *page,
+                                     guint         page_num,
+                                     ThunarWindow *window)
+{
+  gint n_pages;
+
+  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
+  _thunar_return_if_fail (GTK_IS_NOTEBOOK (notebook));
+  _thunar_return_if_fail (THUNAR_IS_VIEW (page));
+  _thunar_return_if_fail (window->notebook == notebook);
+
+  /* drop connected signals */
+  g_signal_handlers_disconnect_matched (page, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, window);
+
+  /* remove from the ui */
+  thunar_component_set_ui_manager (THUNAR_COMPONENT (page), NULL);
+
+  n_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook));
+  if (n_pages == 0)
+    {
+      /* destroy the window */
+      gtk_widget_destroy (GTK_WIDGET (window));
+    }
+  else
+    {
+      /* update tab visibility */
+      thunar_window_notebook_show_tabs (window);
+    }
+}
+
+
+
+static void
+thunar_window_notebook_popup_menu_real (ThunarWindow *window,
+                                        guint32       timestamp,
+                                        gint          button)
+{
+  GtkWidget *menu;
+
+  /* run the menu on the view's screen (figuring out whether to use the file or the folder context menu) */
+  menu = gtk_ui_manager_get_widget (window->ui_manager, "/tab-context-menu");
+  thunar_gtk_menu_run (GTK_MENU (menu), GTK_WIDGET (window),
+                       NULL, NULL, button, timestamp);
+}
+
+
+
+static gboolean
+thunar_window_notebook_button_press_event (GtkWidget      *notebook,
+                                           GdkEventButton *event,
+                                           ThunarWindow   *window)
+{
+  gint           page_num = 0;
+  GtkWidget     *page;
+  GtkWidget     *label_box;
+  GtkAllocation  alloc;
+  gint           x, y;
+  gboolean       close_tab;
+
+  if ((event->button == 2 || event->button == 3)
+      && event->type == GDK_BUTTON_PRESS)
+    {
+      /* get real window coordinates */
+      gdk_window_get_position (event->window, &x, &y);
+      x += event->x;
+      y += event->y;
+
+      /* lookup the clicked tab */
+      while ((page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), page_num)) != NULL)
+        {
+          label_box = gtk_notebook_get_tab_label (GTK_NOTEBOOK (notebook), page);
+          gtk_widget_get_allocation (label_box, &alloc);
+
+          if (x >= alloc.x && x < alloc.x + alloc.width
+              && y >= alloc.y && y < alloc.y + alloc.height)
+            break;
+
+          page_num++;
+        }
+
+      /* leave if no tab could be found */
+      if (page == NULL)
+        return FALSE;
+
+      if (event->button == 2)
+        {
+          /* check if we should close the tab */
+          g_object_get (window->preferences, "misc-tab-close-middle-click", &close_tab, NULL);
+          if (close_tab)
+            gtk_widget_destroy (page);
+        }
+      else if (event->button == 3)
+        {
+          /* update the current tab before we show the menu */
+          gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), page_num);
+
+          /* show the tab menu */
+          thunar_window_notebook_popup_menu_real (window, event->time, event->button);
+        }
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+
+
+static gboolean
+thunar_window_notebook_popup_menu (GtkWidget    *notebook,
+                                   ThunarWindow *window)
+{
+  thunar_window_notebook_popup_menu_real (window, gtk_get_current_event_time (), 0);
+  return TRUE;
+}
+
+
+
+static gpointer
+thunar_window_notebook_create_window (GtkWidget    *notebook,
+                                      GtkWidget    *page,
+                                      gint          x,
+                                      gint          y,
+                                      ThunarWindow *window)
+{
+  GtkWidget         *new_window;
+  ThunarApplication *application;
+  gint               width, height;
+  gint               monitor_num;
+  GdkScreen         *screen;
+  GdkRectangle       geo;
+
+  _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), NULL);
+  _thunar_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
+  _thunar_return_val_if_fail (window->notebook == notebook, NULL);
+  _thunar_return_val_if_fail (THUNAR_IS_VIEW (page), NULL);
+
+  /* do nothing if this window has only 1 tab */
+  if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook)) < 2)
+    return NULL;
+
+  /* create new window */
+  application = thunar_application_get ();
+  screen = gtk_window_get_screen (GTK_WINDOW (window));
+  new_window = thunar_application_open_window (application, NULL, screen, NULL);
+  g_object_unref (application);
+
+  /* make sure the new window has the same size */
+  gtk_window_get_size (GTK_WINDOW (window), &width, &height);
+  gtk_window_resize (GTK_WINDOW (new_window), width, height);
+
+  /* move the window to the drop position */
+  if (x >= 0 && y >= 0)
+    {
+      /* get the monitor geometry */
+      monitor_num = gdk_screen_get_monitor_at_point (screen, x, y);
+      gdk_screen_get_monitor_geometry (screen, monitor_num, &geo);
+
+      /* calculate window position, but keep it on the current monitor */
+      x = CLAMP (x - width / 2, geo.x, geo.x + geo.width - width);
+      y = CLAMP (y - height / 2, geo.y, geo.y + geo.height - height);
+
+      /* move the window */
+      gtk_window_move (GTK_WINDOW (new_window), MAX (0, x), MAX (0, y));
+    }
+
+  /* insert page in new notebook */
+  return THUNAR_WINDOW (new_window)->notebook;
+}
+
+
+
+static void
+thunar_window_notebook_insert (ThunarWindow *window,
+                               ThunarFile   *directory)
+{
+  GtkWidget  *view;
+  gint        page_num;
+  GtkWidget  *label;
+  GtkWidget  *label_box;
+  GtkWidget  *button;
+  GtkWidget  *icon;
+  GtkRcStyle *style;
+
+  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
+  _thunar_return_if_fail (THUNAR_IS_FILE (directory));
+  _thunar_return_if_fail (window->view_type != G_TYPE_NONE);
+
+  /* leave if no directory is set */
+  if (directory == NULL)
+    return;
+
+  /* allocate and setup a new view */
+  view = g_object_new (window->view_type, "current-directory", directory, NULL);
+  gtk_widget_show (view);
+
+  label_box = gtk_hbox_new (FALSE, 0);
+
+  label = gtk_label_new (NULL);
+  exo_binding_new (G_OBJECT (view), "display-name", G_OBJECT (label), "label");
+  exo_binding_new (G_OBJECT (view), "tooltip-text", G_OBJECT (label), "tooltip-text");
+  gtk_widget_set_has_tooltip (label, TRUE);
+  gtk_misc_set_alignment (GTK_MISC (label), 0.0f, 0.5f);
+  gtk_misc_set_padding (GTK_MISC (label), 3, 3);
+  gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
+  gtk_label_set_single_line_mode (GTK_LABEL (label), TRUE);
+  gtk_box_pack_start (GTK_BOX (label_box), label, TRUE, TRUE, 0);
+  gtk_widget_show (label);
+
+  button = gtk_button_new ();
+  gtk_box_pack_start (GTK_BOX (label_box), button, FALSE, FALSE, 0);
+  gtk_widget_set_can_default (button, FALSE);
+  gtk_button_set_focus_on_click (GTK_BUTTON (button), FALSE);
+  gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
+  gtk_widget_set_tooltip_text (button, _("Close tab"));
+  g_signal_connect_swapped (G_OBJECT (button), "clicked", G_CALLBACK (gtk_widget_destroy), view);
+  gtk_widget_show (button);
+
+  /* make button a bit smaller */
+  style = gtk_rc_style_new ();
+  style->xthickness = style->ythickness = 0;
+  gtk_widget_modify_style (button, style);
+  g_object_unref (G_OBJECT (style));
+
+  icon = gtk_image_new_from_stock (GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
+  gtk_container_add (GTK_CONTAINER (button), icon);
+  gtk_widget_show (icon);
+
+  /* insert the new page */
+  page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (window->notebook));
+  page_num = gtk_notebook_insert_page (GTK_NOTEBOOK (window->notebook), view, label_box, page_num + 1);
+
+  /* switch to the new tab*/
+  gtk_notebook_set_current_page (GTK_NOTEBOOK (window->notebook), page_num);
+
+  /* set tab child properties */
+  gtk_container_child_set (GTK_CONTAINER (window->notebook), view, "tab-expand", TRUE, NULL);
+  gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (window->notebook), view, TRUE);
+  gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (window->notebook), view, TRUE);
+
+  /* take focus on the view */
+  gtk_widget_grab_focus (view);
+}
+
+
+
+static void
 thunar_window_install_location_bar (ThunarWindow *window,
                                     GType         type)
 {
@@ -1395,7 +1844,7 @@ thunar_window_install_location_bar (ThunarWindow *window,
 
       /* connect the location widget to the view (if any) */
       if (G_LIKELY (window->view != NULL))
-        exo_binding_new (G_OBJECT (window->view), "selected-files", G_OBJECT (window->location_bar), "selected-files");
+        thunar_window_binding_create (window, window->view, "selected-files", window->location_bar, "selected-files", G_BINDING_SYNC_CREATE);
 
       /* check if the location bar should be placed into a toolbar */
       if (!thunar_location_bar_is_standalone (THUNAR_LOCATION_BAR (window->location_bar)))
@@ -1457,12 +1906,13 @@ thunar_window_install_sidepane (ThunarWindow *window,
       exo_binding_new (G_OBJECT (window), "show-hidden", G_OBJECT (window->sidepane), "show-hidden");
       exo_binding_new (G_OBJECT (window), "current-directory", G_OBJECT (window->sidepane), "current-directory");
       g_signal_connect_swapped (G_OBJECT (window->sidepane), "change-directory", G_CALLBACK (thunar_window_set_current_directory), window);
+      g_signal_connect_swapped (G_OBJECT (window->sidepane), "open-new-tab", G_CALLBACK (thunar_window_notebook_insert), window);
       gtk_paned_pack1 (GTK_PANED (window->paned), window->sidepane, FALSE, FALSE);
       gtk_widget_show (window->sidepane);
 
       /* connect the side pane widget to the view (if any) */
       if (G_LIKELY (window->view != NULL))
-        exo_binding_new (G_OBJECT (window->view), "selected-files", G_OBJECT (window->sidepane), "selected-files");
+        thunar_window_binding_create (window, window->view, "selected-files", window->sidepane, "selected-files", G_BINDING_SYNC_CREATE);
     }
 
   /* remember the setting */
@@ -1570,7 +2020,7 @@ thunar_window_merge_go_actions (ThunarWindow *window)
   if (thunar_g_vfs_is_uri_scheme_supported ("network"))
     {
       /* create the network action */
-      action = gtk_action_new ("open-network", _("Network"), _("Browse the network"), 
+      action = gtk_action_new ("open-network", _("Network"), _("Browse the network"),
                                GTK_STOCK_NETWORK);
       g_signal_connect (action, "activate", G_CALLBACK (thunar_window_action_open_network), window);
 
@@ -1635,7 +2085,7 @@ thunar_window_poke_file_finish (ThunarBrowser *browser,
     }
   else
     {
-      thunar_dialogs_show_error (GTK_WIDGET (browser), error, 
+      thunar_dialogs_show_error (GTK_WIDGET (browser), error,
                                  _("Failed to open \"%s\""),
                                  thunar_file_get_display_name (file));
     }
@@ -1649,7 +2099,7 @@ thunar_window_start_open_location (ThunarWindow *window,
 {
   ThunarFile *selected_file;
   GtkWidget  *dialog;
-  
+
   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
 
   /* bring up the "Open Location"-dialog if the window has no location bar or the location bar
@@ -1662,9 +2112,9 @@ thunar_window_start_open_location (ThunarWindow *window,
       gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
       gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
       gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (window));
-      thunar_location_dialog_set_working_directory (THUNAR_LOCATION_DIALOG (dialog), 
+      thunar_location_dialog_set_working_directory (THUNAR_LOCATION_DIALOG (dialog),
                                                     thunar_window_get_current_directory (window));
-      thunar_location_dialog_set_selected_file (THUNAR_LOCATION_DIALOG (dialog), 
+      thunar_location_dialog_set_selected_file (THUNAR_LOCATION_DIALOG (dialog),
                                                 thunar_window_get_current_directory (window));
 
       /* setup the initial text (if any) */
@@ -1687,7 +2137,7 @@ thunar_window_start_open_location (ThunarWindow *window,
           selected_file = thunar_location_dialog_get_selected_file (THUNAR_LOCATION_DIALOG (dialog));
           if (selected_file != NULL)
             {
-              thunar_browser_poke_file (THUNAR_BROWSER (window), selected_file, window, 
+              thunar_browser_poke_file (THUNAR_BROWSER (window), selected_file, window,
                                         thunar_window_poke_file_finish, NULL);
             }
         }
@@ -1700,6 +2150,16 @@ thunar_window_start_open_location (ThunarWindow *window,
 
 
 static void
+thunar_window_action_open_new_tab (GtkAction    *action,
+                                   ThunarWindow *window)
+{
+  /* insert new tab with current directory as default */
+  thunar_window_notebook_insert (window, thunar_window_get_current_directory (window));
+}
+
+
+
+static void
 thunar_window_action_open_new_window (GtkAction    *action,
                                       ThunarWindow *window)
 {
@@ -1741,6 +2201,48 @@ thunar_window_action_empty_trash (GtkAction    *action,
 
 
 static void
+thunar_window_action_detach_tab (GtkAction    *action,
+                                 ThunarWindow *window)
+{
+  GtkWidget *notebook;
+  GtkWidget *label;
+  GtkWidget *view = window->view;
+
+  _thunar_return_if_fail (THUNAR_IS_VIEW (view));
+  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
+
+  /* create a new window */
+  notebook = thunar_window_notebook_create_window (window->notebook, view, -1, -1, window);
+  if (notebook == NULL)
+    return;
+
+  /* get the current label */
+  label = gtk_notebook_get_tab_label (GTK_NOTEBOOK (window->notebook), view);
+  _thunar_return_if_fail (GTK_IS_WIDGET (label));
+
+  /* ref object so they don't destroy when removed from the container */
+  g_object_ref (label);
+  g_object_ref (view);
+
+  /* remove view from the current notebook */
+  gtk_container_remove (GTK_CONTAINER (window->notebook), view);
+
+  /* insert in the new notebook */
+  gtk_notebook_insert_page (GTK_NOTEBOOK (notebook), view, label, 0);
+
+  /* set tab child properties */
+  gtk_container_child_set (GTK_CONTAINER (notebook), view, "tab-expand", TRUE, NULL);
+  gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (notebook), view, TRUE);
+  gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (notebook), view, TRUE);
+
+  /* release */
+  g_object_unref (label);
+  g_object_unref (view);
+}
+
+
+
+static void
 thunar_window_action_close_all_windows (GtkAction    *action,
                                         ThunarWindow *window)
 {
@@ -1759,8 +2261,18 @@ thunar_window_action_close_all_windows (GtkAction    *action,
 
 
 static void
-thunar_window_action_close (GtkAction    *action,
-                            ThunarWindow *window)
+thunar_window_action_close_tab (GtkAction    *action,
+                                ThunarWindow *window)
+{
+  if (window->view != NULL)
+    gtk_widget_destroy (window->view);
+}
+
+
+
+static void
+thunar_window_action_close_window (GtkAction    *action,
+                                   ThunarWindow *window)
 {
   gtk_widget_destroy (GTK_WIDGET (window));
 }
@@ -1779,7 +2291,7 @@ thunar_window_action_preferences (GtkAction    *action,
 
   /* allocate and display a preferences dialog */;
   dialog = thunar_preferences_dialog_new (GTK_WINDOW (window));
-  gtk_widget_show (dialog);  
+  gtk_widget_show (dialog);
 
   /* ...and let the application take care of it */
   application = thunar_application_get ();
@@ -1925,7 +2437,7 @@ thunar_window_action_statusbar_changed (GtkToggleAction *action,
 
   /* determine the new state of the action */
   active = gtk_toggle_action_get_active (action);
-  
+
   /* check if we should drop the statusbar */
   if (!active && window->statusbar != NULL)
     {
@@ -1942,7 +2454,7 @@ thunar_window_action_statusbar_changed (GtkToggleAction *action,
 
       /* connect to the view (if any) */
       if (G_LIKELY (window->view != NULL))
-        exo_binding_new (G_OBJECT (window->view), "statusbar-text", G_OBJECT (window->statusbar), "text");
+        thunar_window_binding_create (window, window->view, "statusbar-text", window->statusbar, "text", G_BINDING_SYNC_CREATE);
     }
 
   /* remember the setting */
@@ -2025,53 +2537,39 @@ thunar_window_action_view_changed (GtkRadioAction *action,
                                    ThunarWindow   *window)
 {
   ThunarFile *file = NULL;
-  GType       type;
+  ThunarFile *current_directory = NULL;
+  GtkWidget  *old_view;
 
   /* drop the previous view (if any) */
+  old_view = window->view;
   if (G_LIKELY (window->view != NULL))
     {
       /* get first visible file in the previous view */
       if (!thunar_view_get_visible_range (THUNAR_VIEW (window->view), &file, NULL))
         file = NULL;
 
-      /* destroy and disconnect the previous view */
-      gtk_widget_destroy (window->view);
+      /* store the active directory */
+      current_directory = thunar_navigator_get_current_directory (THUNAR_NAVIGATOR (window->view));
+      if (current_directory != NULL)
+        g_object_ref (current_directory);
 
       /* update the UI (else GtkUIManager will crash on merging) */
       gtk_ui_manager_ensure_update (window->ui_manager);
     }
 
   /* determine the new type of view */
-  type = view_index2type (gtk_radio_action_get_current_value (action));
+  window->view_type = view_index2type (gtk_radio_action_get_current_value (action));
+
+  /* always open a new directory */
+  if (current_directory == NULL && window->current_directory != NULL)
+    current_directory = g_object_ref (window->current_directory);
 
   /* allocate a new view of the requested type */
-  if (G_LIKELY (type != G_TYPE_NONE))
+  if (G_LIKELY (window->view_type != G_TYPE_NONE))
     {
-      /* allocate and setup a new view */
-      window->view = g_object_new (type, "ui-manager", window->ui_manager, NULL);
-      g_signal_connect (G_OBJECT (window->view), "notify::loading", G_CALLBACK (thunar_window_notify_loading), window);
-      g_signal_connect_swapped (G_OBJECT (window->view), "start-open-location", G_CALLBACK (thunar_window_start_open_location), window);
-      g_signal_connect_swapped (G_OBJECT (window->view), "change-directory", G_CALLBACK (thunar_window_set_current_directory), window);
-      exo_binding_new (G_OBJECT (window), "current-directory", G_OBJECT (window->view), "current-directory");
-      exo_binding_new (G_OBJECT (window), "show-hidden", G_OBJECT (window->view), "show-hidden");
-      exo_binding_new (G_OBJECT (window->view), "loading", G_OBJECT (window->spinner), "active");
-      exo_binding_new (G_OBJECT (window->view), "selected-files", G_OBJECT (window->launcher), "selected-files");
-      exo_mutual_binding_new (G_OBJECT (window->view), "zoom-level", G_OBJECT (window), "zoom-level");
-      gtk_table_attach (GTK_TABLE (window->view_box), window->view, 0, 1, 1, 2, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
-      gtk_widget_grab_focus (window->view);
-      gtk_widget_show (window->view);
-
-      /* connect to the location bar (if any) */
-      if (G_LIKELY (window->location_bar != NULL))
-        exo_binding_new (G_OBJECT (window->view), "selected-files", G_OBJECT (window->location_bar), "selected-files");
-
-      /* connect to the sidepane (if any) */
-      if (G_LIKELY (window->sidepane != NULL))
-        exo_binding_new (G_OBJECT (window->view), "selected-files", G_OBJECT (window->sidepane), "selected-files");
-
-      /* connect to the statusbar (if any) */
-      if (G_LIKELY (window->statusbar != NULL))
-        exo_binding_new (G_OBJECT (window->view), "statusbar-text", G_OBJECT (window->statusbar), "text");
+      /* create new page */
+      if (current_directory != NULL)
+        thunar_window_notebook_insert (window, current_directory);
 
       /* scroll to the previously visible file in the old view */
       if (G_UNLIKELY (file != NULL))
@@ -2083,13 +2581,19 @@ thunar_window_action_view_changed (GtkRadioAction *action,
       window->view = NULL;
     }
 
+  /* destroy the old view */
+  if (old_view != NULL)
+    gtk_widget_destroy (old_view);
+
   /* remember the setting */
   if (gtk_widget_get_visible (GTK_WIDGET (window)))
-    g_object_set (G_OBJECT (window->preferences), "last-view", g_type_name (type), NULL);
+    g_object_set (G_OBJECT (window->preferences), "last-view", g_type_name (window->view_type), NULL);
 
-  /* release the file reference */
+  /* release the file references */
   if (G_UNLIKELY (file != NULL))
     g_object_unref (G_OBJECT (file));
+  if (G_UNLIKELY (current_directory != NULL))
+    g_object_unref (G_OBJECT (current_directory));
 }
 
 
@@ -2598,74 +3102,6 @@ thunar_window_current_directory_changed (ThunarFile   *current_directory,
 
 
 static void
-thunar_window_current_directory_destroy (ThunarFile   *current_directory,
-                                         ThunarWindow *window)
-{
-  ThunarFile *new_directory = NULL;
-  GFile      *path;
-  GFile      *tmp;
-
-  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
-  _thunar_return_if_fail (THUNAR_IS_FILE (current_directory));
-  _thunar_return_if_fail (window->current_directory == current_directory);
-
-  /* determine the path of the current directory */
-  path = g_object_ref (thunar_file_get_file (current_directory));
-
-  /* try to find a parent directory that still exists */
-  while (new_directory == NULL)
-    {
-      /* check whether the current directory exists */
-      if (g_file_query_exists (path, NULL))
-        {
-          /* it does, try to load the file */
-          new_directory = thunar_file_get (path, NULL);
-
-          /* fall back to $HOME if loading the file failed */
-          if (new_directory == NULL)
-            break;
-        }
-      else
-        {
-          /* determine the parent of the directory */
-          tmp = g_file_get_parent (path);
-          
-          /* if there's no parent this means that we've found no parent
-           * that still exists at all. Fall back to $HOME then */
-          if (tmp == NULL)
-            break;
-
-          /* free the old directory */
-          g_object_unref (path);
-
-          /* check the parent next */
-          path = tmp;
-        }
-    }
-
-  /* make sure we don't leak */
-  if (path != NULL)
-    g_object_unref (path);
-
-  /* check if we have a new folder */
-  if (G_LIKELY (new_directory != NULL))
-    {
-      /* enter the new folder */
-      thunar_window_set_current_directory (window, new_directory);
-
-      /* release the file reference */
-      g_object_unref (new_directory);
-    }
-  else
-    {
-      /* enter the home folder */
-      thunar_window_action_open_home (NULL, window);
-    }
-}
-
-
-
-static void
 thunar_window_connect_proxy (GtkUIManager *manager,
                              GtkAction    *action,
                              GtkWidget    *proxy,
@@ -2763,9 +3199,9 @@ thunar_window_notify_loading (ThunarView   *view,
 
   _thunar_return_if_fail (THUNAR_IS_VIEW (view));
   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
-  _thunar_return_if_fail (THUNAR_VIEW (window->view) == view);
 
-  if (gtk_widget_get_realized (GTK_WIDGET (window)))
+  if (gtk_widget_get_realized (GTK_WIDGET (window))
+      && window->view == GTK_WIDGET (view))
     {
       /* setup the proper cursor */
       if (thunar_view_get_loading (view))
@@ -2964,7 +3400,7 @@ thunar_window_set_zoom_level (ThunarWindow   *window,
 /**
  * thunar_window_get_current_directory:
  * @window : a #ThunarWindow instance.
- * 
+ *
  * Queries the #ThunarFile instance, which represents the directory
  * currently displayed within @window. %NULL is returned if @window
  * is not currently associated with any directory.
@@ -2989,14 +3425,13 @@ void
 thunar_window_set_current_directory (ThunarWindow *window,
                                      ThunarFile   *current_directory)
 {
-  ThunarFile *file;
-  ThunarFile *selected_file;
-  GList       selected_files;
-  GFile      *gfile;
+  GType       type;
+  GtkAction  *action;
+  gchar      *type_name;
 
   _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
   _thunar_return_if_fail (current_directory == NULL || THUNAR_IS_FILE (current_directory));
-  
+
   /* check if we already display the requested directory */
   if (G_UNLIKELY (window->current_directory == current_directory))
     return;
@@ -3004,18 +3439,7 @@ thunar_window_set_current_directory (ThunarWindow *window,
   /* disconnect from the previously active directory */
   if (G_LIKELY (window->current_directory != NULL))
     {
-      /* determine the fist visible file in the previous directory */
-      if (window->view != NULL && thunar_view_get_visible_range (THUNAR_VIEW (window->view), &file, NULL))
-        {
-          /* add the file to our internal mapping of directories to scroll files */
-          g_hash_table_replace (window->scroll_to_files,
-                                g_object_ref (thunar_file_get_file (window->current_directory)),
-                                g_object_ref (thunar_file_get_file (file)));
-          g_object_unref (file);
-        }
-
       /* disconnect signals and release reference */
-      g_signal_handlers_disconnect_by_func (G_OBJECT (window->current_directory), thunar_window_current_directory_destroy, window);
       g_signal_handlers_disconnect_by_func (G_OBJECT (window->current_directory), thunar_window_current_directory_changed, window);
       g_object_unref (G_OBJECT (window->current_directory));
     }
@@ -3028,9 +3452,23 @@ thunar_window_set_current_directory (ThunarWindow *window,
     {
       /* take a reference on the file and connect the "changed"/"destroy" signals */
       g_signal_connect (G_OBJECT (current_directory), "changed", G_CALLBACK (thunar_window_current_directory_changed), window);
-      g_signal_connect (G_OBJECT (current_directory), "destroy", G_CALLBACK (thunar_window_current_directory_destroy), window);
       g_object_ref (G_OBJECT (current_directory));
-    
+
+      /* create a new view if the window is new */
+      if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook)) == 0)
+        {
+          /* determine the last selected view if we don't have a valid default */
+          g_object_get (G_OBJECT (window->preferences), "last-view", &type_name, NULL);
+          type = g_type_from_name (type_name);
+
+          /* activate the selected view */
+          action = gtk_action_group_get_action (window->action_group, "view-as-icons");
+          g_signal_handlers_block_by_func (action, thunar_window_action_view_changed, window);
+          gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), view_type2index (g_type_is_a (type, THUNAR_TYPE_VIEW) ? type : THUNAR_TYPE_ICON_VIEW));
+          thunar_window_action_view_changed (GTK_RADIO_ACTION (action), GTK_RADIO_ACTION (action), window);
+          g_signal_handlers_unblock_by_func (action, thunar_window_action_view_changed, window);
+        }
+
       /* update window icon and title */
       thunar_window_current_directory_changed (current_directory, window);
 
@@ -3040,7 +3478,8 @@ thunar_window_set_current_directory (ThunarWindow *window,
     }
 
   /* enable the 'Open new window' action if we have a valid directory */
-  thunar_gtk_action_group_set_action_sensitive (window->action_group, "open-new-window", (current_directory != NULL));
+  thunar_gtk_action_group_set_action_sensitive (window->action_group, "new-window", (current_directory != NULL));
+  thunar_gtk_action_group_set_action_sensitive (window->action_group, "new-tab", (current_directory != NULL));
 
   /* enable the 'Up' action if possible for the new directory */
   thunar_gtk_action_group_set_action_sensitive (window->action_group, "open-parent", (current_directory != NULL
@@ -3051,59 +3490,6 @@ thunar_window_set_current_directory (ThunarWindow *window,
    * state already while the folder view is loading.
    */
   g_object_notify (G_OBJECT (window), "current-directory");
-
-  /* check if we have a valid current directory */
-  if (G_LIKELY (window->current_directory != NULL))
-    {
-      /* check if we have a scroll_to_file for the new directory and scroll to the file */
-      gfile = g_hash_table_lookup (window->scroll_to_files, thunar_file_get_file (window->current_directory));
-      if (G_LIKELY (gfile != NULL))
-        {
-          file = thunar_file_cache_lookup (gfile);
-          if (G_LIKELY (file != NULL))
-            thunar_window_scroll_to_file (window, file, FALSE, TRUE, 0.1f, 0.1f);
-        }
-
-      /* reset the selected files list */
-      selected_files.data = NULL;
-      selected_files.prev = NULL;
-      selected_files.next = NULL;
-      
-      /* determine the next file in the history */
-      selected_file = thunar_history_peek_forward (window->history);
-      if (selected_file != NULL)
-        {
-          /* mark the file from history for selection if it is inside the new
-           * directory */
-          if (thunar_file_is_parent (window->current_directory, selected_file))
-            selected_files.data = selected_file;
-          else
-            g_object_unref (selected_file);
-        }
-
-      /* do the same with the previous file in the history */
-      if (selected_files.data == NULL)
-        {
-          selected_file = thunar_history_peek_back (window->history);
-          if (selected_file != NULL)
-            {
-              /* mark the file from history for selection if it is inside the 
-               * new directory */
-              if (thunar_file_is_parent (window->current_directory, selected_file))
-                selected_files.data = selected_file;
-              else
-                g_object_unref (selected_file);
-            }
-        }
-
-      /* select the previous or next file from the history if it is inside the
-       * new current directory */
-      if (selected_files.data != NULL)
-        {
-          thunar_component_set_selected_files (THUNAR_COMPONENT (window->view), &selected_files);
-          g_object_unref (G_OBJECT (selected_files.data));
-        }
-    }
 }
 
 


More information about the Xfce4-commits mailing list