[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