/* vi:set et ai sw=2 sts=2 ts=2: */ /*- * Copyright (c) 2005-2007 Benedikt Meurer * Copyright (c) 2009-2011 Jannis Pohlmann * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_LOCALE_H #include #endif #include "thunar/thunar-action-manager.h" #include "thunar/thunar-application.h" #include "thunar/thunar-browser.h" #include "thunar/thunar-clipboard-manager.h" #include "thunar/thunar-compact-view.h" #include "thunar/thunar-details-view.h" #include "thunar/thunar-device-monitor.h" #include "thunar/thunar-dialogs.h" #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-job-operation-history.h" #include "thunar/thunar-location-buttons.h" #include "thunar/thunar-location-entry.h" #include "thunar/thunar-marshal.h" #include "thunar/thunar-menu.h" #include "thunar/thunar-pango-extensions.h" #include "thunar/thunar-preferences-dialog.h" #include "thunar/thunar-preferences.h" #include "thunar/thunar-private.h" #include "thunar/thunar-shortcuts-pane.h" #include "thunar/thunar-statusbar.h" #include "thunar/thunar-thumbnailer.h" #include "thunar/thunar-toolbar-editor.h" #include "thunar/thunar-tree-pane.h" #include "thunar/thunar-util.h" #include "thunar/thunar-window.h" #include #include #include #define DEFAULT_LOCATION_BAR_MARGIN 5 /* Property identifiers */ enum { PROP_0, PROP_CURRENT_DIRECTORY, PROP_ZOOM_LEVEL, PROP_DIRECTORY_SPECIFIC_SETTINGS, }; /* Signal identifiers */ enum { BACK, RELOAD, TOGGLE_SIDEPANE, TOGGLE_MENUBAR, ZOOM_IN, ZOOM_OUT, ZOOM_RESET, TAB_CHANGE, LAST_SIGNAL, }; /* Trash infobar response ids */ enum { EMPTY, RESTORE }; struct _ThunarBookmark { GFile *g_file; gchar *name; }; typedef struct _ThunarBookmark ThunarBookmark; typedef struct { ThunarWindow *window; gchar *action_name; } UCAActivation; static void thunar_window_screen_changed (GtkWidget *widget, GdkScreen *old_screen, gpointer userdata); static void thunar_window_dispose (GObject *object); static void thunar_window_finalize (GObject *object); static gboolean thunar_window_delete (GtkWidget *widget, GdkEvent *event, gpointer data); static void thunar_window_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static void thunar_window_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static gboolean thunar_window_csd_update (ThunarWindow *window); static gboolean thunar_window_reload (ThunarWindow *window, gboolean reload_info); static gboolean thunar_window_toggle_sidepane (ThunarWindow *window); static gboolean thunar_window_zoom_in (ThunarWindow *window); static gboolean thunar_window_zoom_out (ThunarWindow *window); static gboolean thunar_window_zoom_reset (ThunarWindow *window); static gboolean thunar_window_tab_change (ThunarWindow *window, gint nth); static void thunar_window_realize (GtkWidget *widget); 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_update_title (GtkWidget *label); static GtkWidget * thunar_window_create_view (ThunarWindow *window, ThunarFile *directory, GType view_type); static void thunar_window_notebook_insert_page (ThunarWindow *window, gint position, GtkWidget *view); static void thunar_window_notebook_select_current_page (ThunarWindow *window); static GtkWidget * thunar_window_paned_notebooks_add (ThunarWindow *window); static void thunar_window_paned_notebooks_indicate_focus (ThunarWindow *window, GtkWidget *notebook); static gboolean thunar_window_split_view_is_active (ThunarWindow *window); static void thunar_window_update_location_bar_visible (ThunarWindow *window); static void thunar_window_install_sidepane (ThunarWindow *window, ThunarSidepaneType type); static void thunar_window_start_open_location (ThunarWindow *window, const gchar *initial_text); static void thunar_window_resume_search (ThunarWindow *window, const gchar *initial_text); static gint thunar_window_reset_view_type_idle (gpointer window_ptr); static gboolean thunar_window_action_open_new_tab (ThunarWindow *window, GtkWidget *menu_item); static gboolean thunar_window_action_open_new_window (ThunarWindow *window, GtkWidget *menu_item); static gboolean thunar_window_action_detach_tab (ThunarWindow *window, GtkWidget *menu_item); static gboolean thunar_window_action_close_all_windows (ThunarWindow *window, GtkWidget *menu_item); static gboolean thunar_window_action_close_tab (ThunarWindow *window, GtkWidget *menu_item); static gboolean thunar_window_action_close_window (ThunarWindow *window, GtkWidget *menu_item); static gboolean thunar_window_action_undo (ThunarWindow *window, GtkWidget *menu_item); static gboolean thunar_window_action_redo (ThunarWindow *window, GtkWidget *menu_item); static gboolean thunar_window_action_preferences (ThunarWindow *window, GtkWidget *menu_item); static gboolean thunar_window_action_reload (ThunarWindow *window, GtkWidget *menu_item); static gboolean thunar_window_action_toggle_split_view (ThunarWindow *window); static gboolean thunar_window_action_switch_next_tab (ThunarWindow *window); static gboolean thunar_window_action_switch_previous_tab (ThunarWindow *window); static gboolean thunar_window_action_locationbar_entry (ThunarWindow *window); static gboolean thunar_window_action_locationbar_buttons (ThunarWindow *window); static gboolean thunar_window_action_shortcuts_changed (ThunarWindow *window); static gboolean thunar_window_action_tree_changed (ThunarWindow *window); static gboolean thunar_window_action_image_preview (ThunarWindow *window); static gboolean thunar_window_action_statusbar_changed (ThunarWindow *window); static void thunar_window_action_menubar_update (ThunarWindow *window); static gboolean thunar_window_action_menubar_changed (ThunarWindow *window); static gboolean thunar_window_action_detailed_view (ThunarWindow *window); static gboolean thunar_window_action_icon_view (ThunarWindow *window); static gboolean thunar_window_action_compact_view (ThunarWindow *window); static gboolean thunar_window_action_show_toolbar_editor (ThunarWindow *window); static void thunar_window_replace_view (ThunarWindow *window, GtkWidget *view_to_replace, GType view_type); static void thunar_window_action_view_changed (ThunarWindow *window, GType view_type); static gboolean thunar_window_action_go_up (ThunarWindow *window); static gboolean thunar_window_action_back (ThunarWindow *window); static gboolean thunar_window_action_forward (ThunarWindow *window); static gboolean thunar_window_action_open_home (ThunarWindow *window); static gboolean thunar_window_action_open_desktop (ThunarWindow *window); static gboolean thunar_window_action_open_computer (ThunarWindow *window); static gboolean thunar_window_action_open_templates (ThunarWindow *window); static gboolean thunar_window_action_open_file_system (ThunarWindow *window); static gboolean thunar_window_action_open_recent (ThunarWindow *window); static gboolean thunar_window_action_open_trash (ThunarWindow *window); static gboolean thunar_window_action_open_network (ThunarWindow *window); static void thunar_window_action_open_bookmark (GFile *g_file); static gboolean thunar_window_action_open_location (ThunarWindow *window); static gboolean thunar_window_action_contents (ThunarWindow *window); static gboolean thunar_window_action_about (ThunarWindow *window); static gboolean thunar_window_action_show_hidden (ThunarWindow *window); static gboolean thunar_window_action_show_highlight (ThunarWindow *window); static gboolean thunar_window_propagate_key_event (GtkWindow *window, GdkEvent *key_event, gpointer user_data); static gboolean thunar_window_after_propagate_key_event (GtkWindow *window, GdkEvent *key_event, gpointer user_data); static gboolean thunar_window_action_menu (ThunarWindow *window); static gboolean thunar_window_action_open_file_menu (ThunarWindow *window); static void thunar_window_update_title (ThunarWindow *window); static void thunar_window_menu_item_selected (ThunarWindow *window, GtkWidget *menu_item); static void thunar_window_menu_item_deselected (ThunarWindow *window, GtkWidget *menu_item); static void thunar_window_notify_loading (ThunarView *view, GParamSpec *pspec, ThunarWindow *window); static void thunar_window_device_pre_unmount (ThunarDeviceMonitor *device_monitor, ThunarDevice *device, GFile *root_file, ThunarWindow *window); static void thunar_window_device_changed (ThunarDeviceMonitor *device_monitor, ThunarDevice *device, ThunarWindow *window); static gboolean thunar_window_save_paned (ThunarWindow *window); static gboolean thunar_window_save_paned_notebooks (ThunarWindow *window); static gboolean thunar_window_paned_notebooks_button_press_event (GtkWidget *paned, GdkEventButton *event); static void thunar_window_save_geometry_timer_destroy (gpointer user_data); static void thunar_window_set_zoom_level (ThunarWindow *window, ThunarZoomLevel zoom_level); static void thunar_window_update_window_icon (ThunarWindow *window); static void thunar_window_create_menu (ThunarWindow *window, ThunarWindowAction action, GCallback cb_update_menu, GtkWidget *menu); static void thunar_window_select_files (ThunarWindow *window, GList *files_to_select); static void thunar_window_update_file_menu (ThunarWindow *window, GtkWidget *menu); static void thunar_window_update_edit_menu (ThunarWindow *window, GtkWidget *menu); static void thunar_window_update_view_menu (ThunarWindow *window, GtkWidget *menu); static void thunar_window_update_go_menu (ThunarWindow *window, GtkWidget *menu); static void thunar_window_update_bookmarks_menu (ThunarWindow *window, GtkWidget *menu); static void thunar_window_update_help_menu (ThunarWindow *window, GtkWidget *menu); static void thunar_window_binding_create (ThunarWindow *window, gpointer src_object, const gchar *src_prop, gpointer dst_object, const gchar *dst_prop, GBindingFlags flags); static gboolean thunar_window_history_clicked (GtkWidget *button, GdkEventButton *event, ThunarWindow *window); static gboolean thunar_window_open_parent_clicked (GtkWidget *button, GdkEventButton *event, ThunarWindow *window); static gboolean thunar_window_open_home_clicked (GtkWidget *button, GdkEventButton *event, ThunarWindow *window); static gboolean thunar_window_toolbar_button_press_event (GtkWidget *toolbar, GdkEventButton *event, ThunarWindow *window); static gboolean thunar_window_button_press_event (GtkWidget *view, GdkEventButton *event, ThunarWindow *window); static void thunar_window_history_changed (ThunarWindow *window); static void thunar_window_update_bookmarks (ThunarWindow *window); static void thunar_window_free_bookmarks (ThunarWindow *window); static void thunar_window_menu_add_bookmarks (ThunarWindow *window, GtkMenuShell *view_menu); static gboolean thunar_window_check_uca_key_activation (ThunarWindow *window, GdkEventKey *key_event, gpointer user_data); static void thunar_window_set_directory_specific_settings (ThunarWindow *window, gboolean directory_specific_settings); static GType thunar_window_view_type_for_directory (ThunarWindow *window, ThunarFile *directory); static gboolean thunar_window_action_clear_directory_specific_settings (ThunarWindow *window); static void thunar_window_trash_infobar_clicked (GtkInfoBar *info_bar, gint response_id, ThunarWindow *window); static void thunar_window_update_embedded_image_preview (ThunarWindow *window); static void thunar_window_update_standalone_image_preview (ThunarWindow *window); static void thunar_window_selection_changed (ThunarWindow *window); static void thunar_window_finished_thumbnailing (ThunarWindow *window, ThunarThumbnailSize size, ThunarFile *file); static void thunar_window_recent_reload (GtkRecentManager *recent_manager, ThunarWindow *window); static void thunar_window_catfish_dialog_configure (GtkWidget *entry); static gboolean thunar_window_paned_notebooks_update_orientation (ThunarWindow *window); static void thunar_window_location_bar_create (ThunarWindow *window); static void thunar_window_location_toolbar_create (ThunarWindow *window); static void thunar_window_update_location_toolbar (ThunarWindow *window); static void thunar_window_update_location_toolbar_icons (ThunarWindow *window); static void thunar_window_location_toolbar_add_ucas (ThunarWindow *window); GtkWidget * thunar_window_location_toolbar_add_uca (ThunarWindow *window, GObject *thunarx_menu_item); static void thunar_window_location_toolbar_load_items (ThunarWindow *window); static void thunar_window_location_toolbar_load_last_order (ThunarWindow *window); static gboolean thunar_window_location_toolbar_load_visibility (ThunarWindow *window); static guint thunar_window_toolbar_item_count (ThunarWindow *window); static gchar * thunar_window_toolbar_get_icon_name (ThunarWindow *window, const gchar *icon_name); static GtkWidget * thunar_window_create_toolbar_item_from_action (ThunarWindow *window, ThunarWindowAction action, guint item_order); static GtkWidget * thunar_window_create_toolbar_toggle_item_from_action (ThunarWindow *window, ThunarWindowAction action, gboolean active, guint item_order); static GtkWidget * thunar_window_create_toolbar_radio_item_from_action (ThunarWindow *window, ThunarWindowAction action, gboolean active, GtkRadioToolButton *group, guint item_order); static GtkWidget * thunar_window_create_toolbar_view_switcher (ThunarWindow *window, guint item_order); static void thunar_window_view_switcher_update (ThunarWindow *window); static gboolean thunar_window_image_preview_mode_changed (ThunarWindow *window); static void image_preview_update (GtkWidget *parent, GtkAllocation *allocation, GtkWidget *image); struct _ThunarWindowClass { GtkWindowClass __parent__; /* internal action signals */ gboolean (*reload) (ThunarWindow *window, gboolean reload_info); gboolean (*zoom_in) (ThunarWindow *window); gboolean (*zoom_out) (ThunarWindow *window); gboolean (*zoom_reset) (ThunarWindow *window); gboolean (*tab_change) (ThunarWindow *window, gint idx); }; struct _ThunarWindow { GtkWindow __parent__; /* support for custom preferences actions */ ThunarxProviderFactory *provider_factory; GList *thunarx_preferences_providers; GFile *bookmark_file; GList *bookmarks; GFileMonitor *bookmark_monitor; ThunarClipboardManager *clipboard; ThunarPreferences *preferences; /* to be able to change folder on "device-pre-unmount" if required */ ThunarDeviceMonitor *device_monitor; GtkWidget *grid; GtkWidget *menubar; gboolean menubar_visible; GtkWidget *spinner; GtkWidget *paned; GtkWidget *paned_right; GtkWidget *sidepane; GtkWidget *sidepane_box; GtkWidget *sidepane_preview_image; GtkWidget *right_pane; GtkWidget *right_pane_box; GtkWidget *right_pane_grid; GtkWidget *right_pane_preview_image; GtkWidget *right_pane_image_label; GtkWidget *right_pane_size_label; GtkWidget *right_pane_size_value; GtkWidget *view_box; GtkWidget *trash_infobar; GtkWidget *trash_infobar_restore_button; GtkWidget *trash_infobar_empty_button; /* split view panes */ GtkWidget *paned_notebooks; GtkWidget *notebook_selected; GtkWidget *notebook_left; GtkWidget *notebook_right; GtkWidget *view; GtkWidget *statusbar; /* search */ GtkWidget *catfish_search_button; gchar *search_query; gboolean is_searching; gboolean ignore_next_search_update; GType view_type; GSList *view_bindings; guint reset_view_type_idle_id; /* support for two different styles of location bars */ GtkWidget *location_bar; GtkWidget *location_toolbar; GFileMonitor *uca_file_monitor; GFile *uca_file; /* we need to maintain pointers to be able to toggle sensitivity and activity */ GtkWidget *location_toolbar_item_menu; GtkWidget *location_toolbar_item_back; GtkWidget *location_toolbar_item_forward; GtkWidget *location_toolbar_item_parent; GtkWidget *location_toolbar_item_home; GtkWidget *location_toolbar_item_split_view; GtkWidget *location_toolbar_item_undo; GtkWidget *location_toolbar_item_redo; GtkWidget *location_toolbar_item_zoom_in; GtkWidget *location_toolbar_item_zoom_out; GtkWidget *location_toolbar_item_icon_view; GtkWidget *location_toolbar_item_detailed_view; GtkWidget *location_toolbar_item_compact_view; GtkWidget *location_toolbar_item_view_switcher; GtkWidget *location_toolbar_item_search; ThunarActionManager *action_mgr; gulong signal_handler_id_history_changed; ThunarFile *current_directory; GtkAccelGroup *accel_group; /* zoom-level support */ ThunarZoomLevel zoom_level; gboolean show_hidden; gboolean directory_specific_settings; /* support to remember window geometry */ guint save_geometry_timer_id; /* type of the sidepane */ ThunarSidepaneType sidepane_type; /* Image Preview thumbnail generation */ ThunarFile *preview_image_file; GdkPixbuf *preview_image_pixbuf; /* Reference to the global job operation history */ ThunarJobOperationHistory *job_operation_history; }; /* clang-format off */ static XfceGtkActionEntry thunar_window_action_entries[] = { { THUNAR_WINDOW_ACTION_FILE_MENU, "/ThunarWindow/file-menu", "", XFCE_GTK_MENU_ITEM, N_ ("_File"), NULL, NULL, NULL,}, { THUNAR_WINDOW_ACTION_NEW_TAB, "/ThunarWindow/new-tab", "t", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("New _Tab"), N_ ("Open a new tab for the displayed location"), "tab-new", G_CALLBACK (thunar_window_action_open_new_tab), }, { THUNAR_WINDOW_ACTION_NEW_WINDOW, "/ThunarWindow/new-window", "n", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("New _Window"), N_ ("Open a new Thunar window for the displayed location"), "window-new", G_CALLBACK (thunar_window_action_open_new_window), }, { THUNAR_WINDOW_ACTION_DETACH_TAB, "/ThunarWindow/detach-tab", "", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Detac_h Tab"), N_ ("Open current folder in a new window"), NULL, G_CALLBACK (thunar_window_action_detach_tab), }, { THUNAR_WINDOW_ACTION_CLOSE_TAB, "/ThunarWindow/close-tab", "w", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Close Ta_b"), N_ ("Close this folder"), "window-close", G_CALLBACK (thunar_window_action_close_tab), }, { THUNAR_WINDOW_ACTION_CLOSE_WINDOW, "/ThunarWindow/close-window", "q", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Close Window"), N_ ("Close this window"), "application-exit", G_CALLBACK (thunar_window_action_close_window), }, { THUNAR_WINDOW_ACTION_CLOSE_ALL_WINDOWS, "/ThunarWindow/close-all-windows", "w", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Close _All Windows"), N_ ("Close all Thunar windows"), NULL, G_CALLBACK (thunar_window_action_close_all_windows), }, { THUNAR_WINDOW_ACTION_EDIT_MENU, "/ThunarWindow/edit-menu", "", XFCE_GTK_MENU_ITEM, N_ ("_Edit"), NULL, NULL, NULL, }, { THUNAR_WINDOW_ACTION_UNDO, "/ThunarActionManager/undo", "Z", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Undo"), N_ ("Undo the latest operation"), "edit-undo", G_CALLBACK (thunar_window_action_undo), }, { THUNAR_WINDOW_ACTION_REDO, "/ThunarActionManager/redo", "Z", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Red_o"), N_ ("Redo the latest operation"), "edit-redo", G_CALLBACK (thunar_window_action_redo), }, { THUNAR_WINDOW_ACTION_PREFERENCES, "/ThunarWindow/preferences", "", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Pr_eferences..."), N_ ("Edit Thunar's Preferences"), "preferences-system", G_CALLBACK (thunar_window_action_preferences), }, { THUNAR_WINDOW_ACTION_VIEW_MENU, "/ThunarWindow/view-menu", "", XFCE_GTK_MENU_ITEM, N_ ("_View"), NULL, NULL, NULL, }, { THUNAR_WINDOW_ACTION_RELOAD, "/ThunarWindow/reload", "r", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Reload"), N_ ("Reload the current folder"), "view-refresh", G_CALLBACK (thunar_window_action_reload), }, { THUNAR_WINDOW_ACTION_RELOAD_ALT_1, "/ThunarWindow/reload-alt-1", "F5", XFCE_GTK_IMAGE_MENU_ITEM, NULL, NULL, NULL, G_CALLBACK (thunar_window_action_reload), }, { THUNAR_WINDOW_ACTION_RELOAD_ALT_2, "/ThunarWindow/reload-alt-2", "Reload", XFCE_GTK_IMAGE_MENU_ITEM, NULL, NULL, NULL, G_CALLBACK (thunar_window_action_reload), }, { THUNAR_WINDOW_ACTION_VIEW_SPLIT, "/ThunarWindow/toggle-split-view", "F3", XFCE_GTK_CHECK_MENU_ITEM, N_ ("S_plit View"), N_ ("Open/Close Split View"), "view-dual", G_CALLBACK (thunar_window_action_toggle_split_view), }, { THUNAR_WINDOW_ACTION_SWITCH_FOCUSED_SPLIT_VIEW_PANE, "/ThunarWindow/switch-focused-split-view-pane", "", XFCE_GTK_MENU_ITEM, N_ ("Switch Focused Split View Pane"), NULL, NULL, G_CALLBACK (thunar_window_paned_notebooks_switch), }, { THUNAR_WINDOW_ACTION_VIEW_LOCATION_SELECTOR_MENU, "/ThunarWindow/view-location-selector-menu", "", XFCE_GTK_MENU_ITEM, N_ ("Locatio_n Selector"), NULL, NULL, NULL, }, { THUNAR_WINDOW_ACTION_VIEW_LOCATION_SELECTOR_ENTRY, "/ThunarWindow/view-location-selector-entry", "", XFCE_GTK_CHECK_MENU_ITEM, N_ ("_Text Style"), N_ ("Traditional text box showing the current path"), NULL, G_CALLBACK (thunar_window_action_locationbar_entry), }, { THUNAR_WINDOW_ACTION_VIEW_LOCATION_SELECTOR_BUTTONS, "/ThunarWindow/view-location-selector-buttons", "", XFCE_GTK_CHECK_MENU_ITEM, N_ ("_Buttons Style"), N_ ("Modern approach with buttons that correspond to folders"), NULL, G_CALLBACK (thunar_window_action_locationbar_buttons),}, { THUNAR_WINDOW_ACTION_VIEW_SIDE_PANE_MENU, "/ThunarWindow/view-side-pane-menu", "", XFCE_GTK_MENU_ITEM, N_ ("_Side Pane"), NULL, NULL, NULL, }, { THUNAR_WINDOW_ACTION_VIEW_SIDE_PANE_SHORTCUTS, "/ThunarWindow/view-side-pane-shortcuts", "b", XFCE_GTK_CHECK_MENU_ITEM, N_ ("_Shortcuts"), N_ ("Toggles the visibility of the shortcuts pane"), NULL, G_CALLBACK (thunar_window_action_shortcuts_changed), }, { THUNAR_WINDOW_ACTION_VIEW_SIDE_PANE_TREE, "/ThunarWindow/view-side-pane-tree", "e", XFCE_GTK_CHECK_MENU_ITEM, N_ ("_Tree"), N_ ("Toggles the visibility of the tree pane"), NULL, G_CALLBACK (thunar_window_action_tree_changed), }, { THUNAR_WINDOW_ACTION_TOGGLE_SIDE_PANE, "/ThunarWindow/toggle-side-pane", "F9", XFCE_GTK_MENU_ITEM, NULL, NULL, NULL, G_CALLBACK (thunar_window_toggle_sidepane), }, { THUNAR_WINDOW_ACTION_TOGGLE_IMAGE_PREVIEW, "/ThunarWindow/toggle-image-preview", "", XFCE_GTK_CHECK_MENU_ITEM, N_ ("_Image Preview"), N_ ("Change the visibility of this window's image preview"), NULL, G_CALLBACK (thunar_window_action_image_preview), }, { THUNAR_WINDOW_ACTION_VIEW_STATUSBAR, "/ThunarWindow/view-statusbar", "", XFCE_GTK_CHECK_MENU_ITEM, N_ ("St_atusbar"), N_ ("Change the visibility of this window's statusbar"), NULL, G_CALLBACK (thunar_window_action_statusbar_changed), }, { THUNAR_WINDOW_ACTION_VIEW_MENUBAR, "/ThunarWindow/view-menubar", "m", XFCE_GTK_CHECK_MENU_ITEM, N_ ("_Menubar"), N_ ("Change the visibility of this window's menubar"), "open-menu", G_CALLBACK (thunar_window_action_menubar_changed), }, { THUNAR_WINDOW_ACTION_CONFIGURE_TOOLBAR, "/ThunarWindow/view-configure-toolbar", "", XFCE_GTK_MENU_ITEM , N_ ("Configure _Toolbar..."), N_ ("Configure the toolbar"), NULL, G_CALLBACK (thunar_window_action_show_toolbar_editor),}, { THUNAR_WINDOW_ACTION_CLEAR_DIRECTORY_SPECIFIC_SETTINGS,"/ThunarWindow/clear-directory-specific-settings","", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Cl_ear Saved Folder View Settings"), N_ ("Delete saved view settings for this folder"), NULL, G_CALLBACK (thunar_window_action_clear_directory_specific_settings), }, { THUNAR_WINDOW_ACTION_SHOW_HIDDEN, "/ThunarWindow/show-hidden", "h", XFCE_GTK_CHECK_MENU_ITEM, N_ ("Show _Hidden Files"), N_ ("Toggles the display of hidden files in the current window"), NULL, G_CALLBACK (thunar_window_action_show_hidden), }, { THUNAR_WINDOW_ACTION_SHOW_HIGHLIGHT, "/ThunarWindow/show-highlight", "", XFCE_GTK_CHECK_MENU_ITEM, N_ ("Show _File Highlight"), N_ ("Toggles the display of file highlight which can be configured in the file specific property dialog"), NULL,G_CALLBACK (thunar_window_action_show_highlight), }, { THUNAR_WINDOW_ACTION_ZOOM_IN, "/ThunarWindow/zoom-in", "plus", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Zoom I_n"), N_ ("Show the contents in more detail"), "zoom-in", G_CALLBACK (thunar_window_zoom_in), }, { THUNAR_WINDOW_ACTION_ZOOM_IN_ALT_1, "/ThunarWindow/zoom-in-alt1", "KP_Add", XFCE_GTK_IMAGE_MENU_ITEM, NULL, NULL, NULL, G_CALLBACK (thunar_window_zoom_in), }, { THUNAR_WINDOW_ACTION_ZOOM_IN_ALT_2, "/ThunarWindow/zoom-in-alt2", "equal", XFCE_GTK_IMAGE_MENU_ITEM, NULL, NULL, NULL, G_CALLBACK (thunar_window_zoom_in), }, { THUNAR_WINDOW_ACTION_ZOOM_OUT, "/ThunarWindow/zoom-out", "minus", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Zoom _Out"), N_ ("Show the contents in less detail"), "zoom-out", G_CALLBACK (thunar_window_zoom_out), }, { THUNAR_WINDOW_ACTION_ZOOM_OUT_ALT, "/ThunarWindow/zoom-out-alt", "KP_Subtract", XFCE_GTK_IMAGE_MENU_ITEM, NULL, NULL, NULL, G_CALLBACK (thunar_window_zoom_out), }, { THUNAR_WINDOW_ACTION_ZOOM_RESET, "/ThunarWindow/zoom-reset", "0", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Normal Si_ze"), N_ ("Show the contents at the normal size"), "zoom-original", G_CALLBACK (thunar_window_zoom_reset), }, { THUNAR_WINDOW_ACTION_ZOOM_RESET_ALT, "/ThunarWindow/zoom-reset-alt", "KP_0", XFCE_GTK_IMAGE_MENU_ITEM, NULL, NULL, NULL, G_CALLBACK (thunar_window_zoom_reset), }, { THUNAR_WINDOW_ACTION_VIEW_AS_ICONS, "/ThunarWindow/view-as-icons", "1", XFCE_GTK_RADIO_MENU_ITEM, N_ ("_Icon View"), N_ ("Display folder content in an icon view"), "view-grid", G_CALLBACK (thunar_window_action_icon_view), }, { THUNAR_WINDOW_ACTION_VIEW_AS_DETAILED_LIST, "/ThunarWindow/view-as-detailed-list", "2", XFCE_GTK_RADIO_MENU_ITEM, N_ ("_List View"), N_ ("Display folder content in a detailed list view"), "view-list", G_CALLBACK (thunar_window_action_detailed_view), }, { THUNAR_WINDOW_ACTION_VIEW_AS_COMPACT_LIST, "/ThunarWindow/view-as-compact-list", "3", XFCE_GTK_RADIO_MENU_ITEM, N_ ("_Compact View"), N_ ("Display folder content in a compact list view"), "view-compact", G_CALLBACK (thunar_window_action_compact_view), }, { THUNAR_WINDOW_ACTION_GO_MENU, "/ThunarWindow/go-menu", "", XFCE_GTK_MENU_ITEM, N_ ("_Go"), NULL, NULL, NULL }, { THUNAR_WINDOW_ACTION_OPEN_FILE_SYSTEM, "/ThunarWindow/open-file-system", "", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("F_ile System"), N_ ("Browse the file system"), "drive-harddisk", G_CALLBACK (thunar_window_action_open_file_system), }, { THUNAR_WINDOW_ACTION_OPEN_HOME, "/ThunarWindow/open-home", "Home", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Home"), N_ ("Go to the home folder"), "go-home", G_CALLBACK (thunar_window_action_open_home), }, { THUNAR_WINDOW_ACTION_OPEN_DESKTOP, "/ThunarWindow/open-desktop", "", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Desktop"), N_ ("Go to the desktop folder"), "user-desktop", G_CALLBACK (thunar_window_action_open_desktop), }, { THUNAR_WINDOW_ACTION_OPEN_COMPUTER, "/ThunarWindow/open-computer", "", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Computer"), N_ ("Browse all local and remote disks and folders accessible from this computer"), "computer", G_CALLBACK (thunar_window_action_open_computer), }, { THUNAR_WINDOW_ACTION_OPEN_RECENT, "/ThunarWindow/open-recent", "", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Recent"), N_ ("Display recently used files"), "document-open-recent", G_CALLBACK (thunar_window_action_open_recent), }, { THUNAR_WINDOW_ACTION_OPEN_TRASH, "/ThunarWindow/open-trash", "", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Trash"), N_ ("Display the contents of the trash can"), NULL, G_CALLBACK (thunar_window_action_open_trash), }, { THUNAR_WINDOW_ACTION_OPEN_PARENT, "/ThunarWindow/open-parent", "Up", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Open _Parent"), N_ ("Open the parent folder"), "go-up", G_CALLBACK (thunar_window_action_go_up), }, { THUNAR_WINDOW_ACTION_OPEN_LOCATION, "/ThunarWindow/open-location", "l", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Open Location..."), N_ ("Specify a location to open"), NULL, G_CALLBACK (thunar_window_action_open_location), }, { THUNAR_WINDOW_ACTION_OPEN_LOCATION_ALT, "/ThunarWindow/open-location-alt", "d", XFCE_GTK_MENU_ITEM, NULL, NULL, NULL, G_CALLBACK (thunar_window_action_open_location), }, { THUNAR_WINDOW_ACTION_OPEN_TEMPLATES, "/ThunarWindow/open-templates", "", XFCE_GTK_IMAGE_MENU_ITEM, N_("T_emplates"), N_ ("Go to the templates folder"), "text-x-generic-template", G_CALLBACK (thunar_window_action_open_templates), }, { THUNAR_WINDOW_ACTION_OPEN_NETWORK, "/ThunarWindow/open-network", "", XFCE_GTK_IMAGE_MENU_ITEM, N_("Browse _Network"), N_ ("Browse local network connections"), "network-workgroup", G_CALLBACK (thunar_window_action_open_network), }, { THUNAR_WINDOW_ACTION_BOOKMARKS_MENU, "/ThunarWindow/bookmarks-menu", "", XFCE_GTK_MENU_ITEM, N_ ("_Bookmarks"), NULL, NULL, NULL }, { THUNAR_WINDOW_ACTION_HELP_MENU, "/ThunarWindow/contents/help-menu", "", XFCE_GTK_MENU_ITEM , N_ ("_Help"), NULL, NULL, NULL}, { THUNAR_WINDOW_ACTION_CONTENTS, "/ThunarWindow/contents", "F1", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Contents"), N_ ("Display Thunar user manual"), "help-browser", G_CALLBACK (thunar_window_action_contents), }, { THUNAR_WINDOW_ACTION_ABOUT, "/ThunarWindow/about", "", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_About"), N_ ("Display information about Thunar"), "help-about", G_CALLBACK (thunar_window_action_about), }, { THUNAR_WINDOW_ACTION_BACK, "/ThunarStandardView/back", "Left", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Back"), N_ ("Go to the previous visited folder"), "go-previous", G_CALLBACK (thunar_window_action_back), }, { THUNAR_WINDOW_ACTION_BACK_ALT_1, "/ThunarStandardView/back-alt1", "BackSpace", XFCE_GTK_IMAGE_MENU_ITEM, NULL, NULL, NULL, G_CALLBACK (thunar_window_action_back), }, { THUNAR_WINDOW_ACTION_BACK_ALT_2, "/ThunarStandardView/back-alt2", "Back", XFCE_GTK_IMAGE_MENU_ITEM, NULL, NULL, NULL, G_CALLBACK (thunar_window_action_back), }, { THUNAR_WINDOW_ACTION_FORWARD, "/ThunarStandardView/forward", "Right", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Forward"), N_ ("Go to the next visited folder"), "go-next", G_CALLBACK (thunar_window_action_forward), }, { THUNAR_WINDOW_ACTION_FORWARD_ALT, "/ThunarStandardView/forward-alt", "Forward", XFCE_GTK_IMAGE_MENU_ITEM, NULL, NULL, NULL, G_CALLBACK (thunar_window_action_forward), }, { THUNAR_WINDOW_ACTION_SWITCH_PREV_TAB, "/ThunarWindow/switch-previous-tab", "Page_Up", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Previous Tab"), N_ ("Switch to Previous Tab"), "go-previous", G_CALLBACK (thunar_window_action_switch_previous_tab), }, { THUNAR_WINDOW_ACTION_SWITCH_PREV_TAB_ALT, "/ThunarWindow/switch-previous-tab-alt", "ISO_Left_Tab", XFCE_GTK_IMAGE_MENU_ITEM, NULL, NULL, NULL, G_CALLBACK (thunar_window_action_switch_previous_tab), }, { THUNAR_WINDOW_ACTION_SWITCH_NEXT_TAB, "/ThunarWindow/switch-next-tab", "Page_Down", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Next Tab"), N_ ("Switch to Next Tab"), "go-next", G_CALLBACK (thunar_window_action_switch_next_tab), }, { THUNAR_WINDOW_ACTION_SWITCH_NEXT_TAB_ALT, "/ThunarWindow/switch-next-tab-alt", "Tab", XFCE_GTK_IMAGE_MENU_ITEM, NULL, NULL, NULL, G_CALLBACK (thunar_window_action_switch_next_tab), }, { THUNAR_WINDOW_ACTION_SEARCH, "/ThunarWindow/search", "f", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Search for Files..."), N_ ("Search for a specific file in the current folder and Recent"), "system-search", G_CALLBACK (thunar_window_action_search), }, { THUNAR_WINDOW_ACTION_SEARCH_ALT, "/ThunarWindow/search-alt", "Search", XFCE_GTK_IMAGE_MENU_ITEM, NULL, NULL, NULL, G_CALLBACK (thunar_window_action_search), }, { THUNAR_WINDOW_ACTION_CANCEL_SEARCH, "/ThunarWindow/cancel-search", "Escape", XFCE_GTK_MENU_ITEM, N_ ("Cancel search for files"),NULL, "", G_CALLBACK (thunar_window_action_cancel_search), }, { THUNAR_WINDOW_ACTION_MENU, "/Thunarwindow/menu", "", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Menu"), N_ ("Show the menu"), "open-menu", G_CALLBACK (thunar_window_action_menu), }, { 0, "/ThunarWindow/open-file-menu", "F10", 0, NULL, NULL, NULL, G_CALLBACK (thunar_window_action_open_file_menu), }, }; /* clang-format on */ #define get_action_entry(id) xfce_gtk_get_action_entry_by_id (thunar_window_action_entries, G_N_ELEMENTS (thunar_window_action_entries), id) static guint window_signals[LAST_SIGNAL]; G_DEFINE_TYPE_WITH_CODE (ThunarWindow, thunar_window, GTK_TYPE_WINDOW, G_IMPLEMENT_INTERFACE (THUNAR_TYPE_BROWSER, NULL)) static void thunar_window_class_init (ThunarWindowClass *klass) { GtkWidgetClass *gtkwidget_class; GtkBindingSet *binding_set; GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS (klass); gobject_class->dispose = thunar_window_dispose; gobject_class->finalize = thunar_window_finalize; gobject_class->get_property = thunar_window_get_property; gobject_class->set_property = thunar_window_set_property; gtkwidget_class = GTK_WIDGET_CLASS (klass); gtkwidget_class->realize = thunar_window_realize; gtkwidget_class->unrealize = thunar_window_unrealize; gtkwidget_class->configure_event = thunar_window_configure_event; klass->reload = thunar_window_reload; klass->zoom_in = thunar_window_zoom_in; klass->zoom_out = thunar_window_zoom_out; klass->zoom_reset = thunar_window_zoom_reset; klass->tab_change = thunar_window_tab_change; xfce_gtk_translate_action_entries (thunar_window_action_entries, G_N_ELEMENTS (thunar_window_action_entries)); /** * ThunarWindow:current-directory: * * The directory currently displayed within this #ThunarWindow * or %NULL. **/ g_object_class_install_property (gobject_class, PROP_CURRENT_DIRECTORY, g_param_spec_object ("current-directory", "current-directory", "current-directory", THUNAR_TYPE_FILE, EXO_PARAM_READWRITE)); /** * ThunarWindow:zoom-level: * * The #ThunarZoomLevel applied to the #ThunarView currently * shown within this window. **/ g_object_class_install_property (gobject_class, PROP_ZOOM_LEVEL, g_param_spec_enum ("zoom-level", "zoom-level", "zoom-level", THUNAR_TYPE_ZOOM_LEVEL, THUNAR_ZOOM_LEVEL_100_PERCENT, EXO_PARAM_READWRITE)); /** * ThunarWindow:directory-specific-settings: * * Whether to use directory specific settings. **/ g_object_class_install_property (gobject_class, PROP_DIRECTORY_SPECIFIC_SETTINGS, g_param_spec_boolean ("directory-specific-settings", "directory-specific-settings", "directory-specific-settings", FALSE, EXO_PARAM_READWRITE)); /** * ThunarWindow::reload: * @window : a #ThunarWindow instance. * * Emitted whenever the user requests to reload the contents * of the currently displayed folder. **/ window_signals[RELOAD] = g_signal_new (I_ ("reload"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (ThunarWindowClass, reload), g_signal_accumulator_true_handled, NULL, _thunar_marshal_BOOLEAN__BOOLEAN, G_TYPE_BOOLEAN, 1, G_TYPE_BOOLEAN); /** * ThunarWindow::zoom-in: * @window : a #ThunarWindow instance. * * Emitted whenever the user requests to zoom in. This * is an internal signal used to bind the action to keys. **/ window_signals[ZOOM_IN] = g_signal_new (I_ ("zoom-in"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (ThunarWindowClass, zoom_in), g_signal_accumulator_true_handled, NULL, _thunar_marshal_BOOLEAN__VOID, G_TYPE_BOOLEAN, 0); /** * ThunarWindow::zoom-out: * @window : a #ThunarWindow instance. * * Emitted whenever the user requests to zoom out. This * is an internal signal used to bind the action to keys. **/ window_signals[ZOOM_OUT] = g_signal_new (I_ ("zoom-out"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (ThunarWindowClass, zoom_out), g_signal_accumulator_true_handled, NULL, _thunar_marshal_BOOLEAN__VOID, G_TYPE_BOOLEAN, 0); /** * ThunarWindow::zoom-reset: * @window : a #ThunarWindow instance. * * Emitted whenever the user requests reset the zoom level. * This is an internal signal used to bind the action to keys. **/ window_signals[ZOOM_RESET] = g_signal_new (I_ ("zoom-reset"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (ThunarWindowClass, zoom_reset), g_signal_accumulator_true_handled, NULL, _thunar_marshal_BOOLEAN__VOID, G_TYPE_BOOLEAN, 0); /** * ThunarWindow::tab-change: * @window : a #ThunarWindow instance. * @idx : tab index, * * Emitted whenever the user uses a Alt+N combination to * switch tabs. **/ window_signals[TAB_CHANGE] = g_signal_new (I_ ("tab-change"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (ThunarWindowClass, tab_change), g_signal_accumulator_true_handled, NULL, _thunar_marshal_BOOLEAN__INT, G_TYPE_BOOLEAN, 1, G_TYPE_INT); /* setup the key bindings for the windows */ binding_set = gtk_binding_set_by_class (klass); /* setup the key bindings for Alt+N */ for (guint i = 0; i < 10; i++) { gtk_binding_entry_add_signal (binding_set, GDK_KEY_0 + i, GDK_MOD1_MASK, "tab-change", 1, G_TYPE_UINT, i - 1); } } static void thunar_window_paned_notebooks_destroy (GtkWidget *paned_notebooks, GtkWidget *widget, ThunarWindow *window) { if (window->notebook_left) { gtk_widget_destroy (window->notebook_left); window->notebook_left = NULL; } if (window->notebook_right) { gtk_widget_destroy (window->notebook_right); window->notebook_right = NULL; } } static void thunar_window_init (ThunarWindow *window) { GtkWidget *label; GtkWidget *infobar; GtkWidget *item; GtkWidget *event_box; gboolean last_menubar_visible; ThunarSidepaneType last_side_pane; gchar *uca_path; gchar *catfish_path; gint last_separator_position; gint last_window_width; gint last_window_height; gboolean last_window_maximized; gboolean last_statusbar_visible; gboolean last_image_preview_visible; ThunarImagePreviewMode misc_image_preview_mode; gint max_paned_position; GtkStyleContext *context; gboolean misc_use_csd; /* unset the view type */ window->view_type = G_TYPE_NONE; /* grab a reference on the provider factory and load the providers */ window->provider_factory = thunarx_provider_factory_get_default (); window->thunarx_preferences_providers = thunarx_provider_factory_list_providers (window->provider_factory, THUNARX_TYPE_PREFERENCES_PROVIDER); /* grab a reference on the preferences */ window->preferences = thunar_preferences_get (); window->accel_group = gtk_accel_group_new (); xfce_gtk_accel_map_add_entries (thunar_window_action_entries, G_N_ELEMENTS (thunar_window_action_entries)); xfce_gtk_accel_group_connect_action_entries (window->accel_group, thunar_window_action_entries, G_N_ELEMENTS (thunar_window_action_entries), window); gtk_window_add_accel_group (GTK_WINDOW (window), window->accel_group); /* get all properties for init */ g_object_get (G_OBJECT (window->preferences), "last-show-hidden", &window->show_hidden, "last-window-width", &last_window_width, "last-window-height", &last_window_height, "last-window-maximized", &last_window_maximized, "last-menubar-visible", &last_menubar_visible, "last-separator-position", &last_separator_position, "last-side-pane", &last_side_pane, "last-statusbar-visible", &last_statusbar_visible, "last-image-preview-visible", &last_image_preview_visible, "misc-image-preview-mode", &misc_image_preview_mode, "misc-use-csd", &misc_use_csd, NULL); /* update the visual on screen_changed events */ g_signal_connect (window, "screen-changed", G_CALLBACK (thunar_window_screen_changed), NULL); /* invoke the thunar_window_screen_changed function to initially set the best possible visual */ thunar_window_screen_changed (GTK_WIDGET (window), NULL, NULL); /* set up a handler to confirm exit when there are multiple tabs open */ g_signal_connect (window, "delete-event", G_CALLBACK (thunar_window_delete), NULL); /* 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); g_signal_connect (window->device_monitor, "device-removed", G_CALLBACK (thunar_window_device_changed), window); g_signal_connect (window->device_monitor, "device-changed", G_CALLBACK (thunar_window_device_changed), window); /* catch key events before accelerators get processed */ g_signal_connect (window, "key-press-event", G_CALLBACK (thunar_window_propagate_key_event), NULL); g_signal_connect (window, "key-release-event", G_CALLBACK (thunar_window_propagate_key_event), NULL); g_signal_connect_after (window, "key-release-event", G_CALLBACK (thunar_window_after_propagate_key_event), NULL); window->action_mgr = g_object_new (THUNAR_TYPE_ACTION_MANAGER, "widget", GTK_WIDGET (window), NULL); g_object_bind_property (G_OBJECT (window), "current-directory", G_OBJECT (window->action_mgr), "current-directory", G_BINDING_SYNC_CREATE); g_signal_connect_swapped (G_OBJECT (window->action_mgr), "change-directory", G_CALLBACK (thunar_window_set_current_directory), window); g_signal_connect_swapped (G_OBJECT (window->action_mgr), "open-new-tab", G_CALLBACK (thunar_window_notebook_open_new_tab), window); g_signal_connect_swapped (G_OBJECT (window->action_mgr), "new-files-created", G_CALLBACK (thunar_window_show_and_select_files), window); thunar_action_manager_append_accelerators (window->action_mgr, window->accel_group); /* determine the default window size from the preferences */ gtk_window_set_default_size (GTK_WINDOW (window), last_window_width, last_window_height); /* restore the maximized state of the window */ if (G_UNLIKELY (last_window_maximized)) gtk_window_maximize (GTK_WINDOW (window)); /* add thunar style class for easier theming */ context = gtk_widget_get_style_context (GTK_WIDGET (window)); gtk_style_context_add_class (context, "thunar"); window->grid = gtk_grid_new (); gtk_container_add (GTK_CONTAINER (window), window->grid); gtk_widget_show (window->grid); /* build the menubar */ window->menubar = gtk_menu_bar_new (); thunar_window_create_menu (window, THUNAR_WINDOW_ACTION_FILE_MENU, G_CALLBACK (thunar_window_update_file_menu), window->menubar); thunar_window_create_menu (window, THUNAR_WINDOW_ACTION_EDIT_MENU, G_CALLBACK (thunar_window_update_edit_menu), window->menubar); thunar_window_create_menu (window, THUNAR_WINDOW_ACTION_VIEW_MENU, G_CALLBACK (thunar_window_update_view_menu), window->menubar); thunar_window_create_menu (window, THUNAR_WINDOW_ACTION_GO_MENU, G_CALLBACK (thunar_window_update_go_menu), window->menubar); thunar_window_create_menu (window, THUNAR_WINDOW_ACTION_BOOKMARKS_MENU, G_CALLBACK (thunar_window_update_bookmarks_menu), window->menubar); thunar_window_create_menu (window, THUNAR_WINDOW_ACTION_HELP_MENU, G_CALLBACK (thunar_window_update_help_menu), window->menubar); gtk_widget_show_all (window->menubar); window->menubar_visible = last_menubar_visible; if (last_menubar_visible == FALSE) gtk_widget_hide (window->menubar); gtk_widget_set_hexpand (window->menubar, TRUE); /* append the menu item for the spinner */ item = gtk_menu_item_new (); gtk_widget_set_sensitive (GTK_WIDGET (item), FALSE); g_object_set (G_OBJECT (item), "right-justified", TRUE, NULL); gtk_menu_shell_append (GTK_MENU_SHELL (window->menubar), item); gtk_widget_show (item); /* Required if F10 is pushed while the menu is hidden */ g_signal_connect_swapped (G_OBJECT (window->menubar), "deactivate", G_CALLBACK (thunar_window_action_menubar_update), window); /* place the spinner into the menu item */ window->spinner = gtk_spinner_new (); gtk_container_add (GTK_CONTAINER (item), window->spinner); gtk_widget_set_visible (GTK_WIDGET (window->spinner), TRUE); /* check if we need to add the root warning */ if (G_UNLIKELY (geteuid () == 0)) { /* add the bar for the root warning */ infobar = gtk_info_bar_new (); gtk_info_bar_set_message_type (GTK_INFO_BAR (infobar), GTK_MESSAGE_WARNING); gtk_widget_set_hexpand (infobar, TRUE); gtk_grid_attach (GTK_GRID (window->grid), infobar, 0, 2, 1, 1); gtk_widget_show (infobar); /* add the label with the root warning */ label = gtk_label_new (_("Warning: you are using the root account. You may harm your system.")); gtk_container_add (GTK_CONTAINER (gtk_info_bar_get_content_area (GTK_INFO_BAR (infobar))), label); gtk_widget_show (label); } /* main paned widget */ window->paned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL); gtk_container_set_border_width (GTK_CONTAINER (window->paned), 0); gtk_widget_set_hexpand (window->paned, TRUE); gtk_widget_set_vexpand (window->paned, TRUE); gtk_grid_attach (GTK_GRID (window->grid), window->paned, 0, 4, 1, 1); gtk_widget_show (window->paned); /* left sidepane - container */ window->sidepane_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_paned_pack1 (GTK_PANED (window->paned), window->sidepane_box, FALSE, FALSE); gtk_widget_show (window->sidepane_box); /* left sidepane - preview */ window->sidepane_preview_image = gtk_image_new_from_file (""); gtk_widget_set_margin_top (window->sidepane_preview_image, 10); gtk_widget_set_margin_bottom (window->sidepane_preview_image, 10); gtk_box_pack_end (GTK_BOX (window->sidepane_box), window->sidepane_preview_image, FALSE, TRUE, 0); if (last_image_preview_visible == TRUE && misc_image_preview_mode == THUNAR_IMAGE_PREVIEW_MODE_EMBEDDED) gtk_widget_show (window->sidepane_preview_image); g_signal_connect (G_OBJECT (window->sidepane_box), "size-allocate", G_CALLBACK (image_preview_update), window->sidepane_preview_image); /* determine the last separator position and apply it to the paned view */ gtk_paned_set_position (GTK_PANED (window->paned), last_separator_position); g_signal_connect_swapped (window->paned, "accept-position", G_CALLBACK (thunar_window_save_paned), window); g_signal_connect_swapped (window->paned, "button-release-event", G_CALLBACK (thunar_window_save_paned), window); /* nested paned widget */ window->paned_right = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL); gtk_container_set_border_width (GTK_CONTAINER (window->paned_right), 0); gtk_widget_set_hexpand (window->paned_right, TRUE); gtk_widget_set_vexpand (window->paned_right, TRUE); gtk_paned_pack2 (GTK_PANED (window->paned), window->paned_right, TRUE, FALSE); gtk_widget_show (window->paned_right); /* right sidepane */ window->right_pane = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (window->right_pane), GTK_SHADOW_IN); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (window->right_pane), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_paned_pack2 (GTK_PANED (window->paned_right), window->right_pane, TRUE, FALSE); gtk_widget_show (window->right_pane); gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (window->right_pane)), "preview-pane"); /* right sidepane - container */ window->right_pane_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10); gtk_widget_set_margin_bottom (window->right_pane_box, 10); gtk_container_add (GTK_CONTAINER (window->right_pane), window->right_pane_box); /* right sidepane - preview */ window->right_pane_preview_image = gtk_image_new_from_file (""); gtk_widget_set_size_request (window->right_pane_preview_image, 276, -1); /* large thumbnail size + 20 */ gtk_box_set_center_widget (GTK_BOX (window->right_pane_box), window->right_pane_preview_image); /* right sidepane - text */ window->right_pane_grid = gtk_grid_new (); gtk_widget_set_halign (window->right_pane_grid, GTK_ALIGN_CENTER); gtk_widget_set_vexpand (window->right_pane_grid, TRUE); gtk_widget_set_hexpand (window->right_pane_grid, TRUE); gtk_box_pack_end (GTK_BOX (window->right_pane_box), window->right_pane_grid, FALSE, TRUE, 0); window->right_pane_image_label = gtk_label_new (""); gtk_label_set_ellipsize (GTK_LABEL (window->right_pane_image_label), PANGO_ELLIPSIZE_END); gtk_widget_set_margin_start (window->right_pane_image_label, 10); gtk_widget_set_margin_end (window->right_pane_image_label, 10); gtk_grid_attach (GTK_GRID (window->right_pane_grid), window->right_pane_image_label, 0, 1, 2, 1); window->right_pane_size_label = gtk_label_new (_("Size: ")); gtk_label_set_xalign (GTK_LABEL (window->right_pane_size_label), 1.0); gtk_grid_attach (GTK_GRID (window->right_pane_grid), window->right_pane_size_label, 0, 2, 1, 1); window->right_pane_size_value = gtk_label_new (""); gtk_label_set_xalign (GTK_LABEL (window->right_pane_size_value), 0.0); gtk_grid_attach (GTK_GRID (window->right_pane_grid), window->right_pane_size_value, 1, 2, 1, 1); gtk_widget_show_all (window->right_pane_box); g_signal_connect (G_OBJECT (window->right_pane_box), "size-allocate", G_CALLBACK (image_preview_update), window->right_pane_preview_image); /* right sidepane - visibility */ if (last_image_preview_visible == FALSE || misc_image_preview_mode == THUNAR_IMAGE_PREVIEW_MODE_EMBEDDED) gtk_widget_hide (window->right_pane); g_signal_connect_swapped (window->preferences, "notify::misc-image-preview-mode", G_CALLBACK (thunar_window_image_preview_mode_changed), window); window->preview_image_pixbuf = NULL; window->preview_image_file = NULL; /* split view: Create panes where the two notebooks */ window->paned_notebooks = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL); g_signal_connect_swapped (window->preferences, "notify::misc-vertical-split-pane", G_CALLBACK (thunar_window_paned_notebooks_update_orientation), window); thunar_window_paned_notebooks_update_orientation (window); window->view_box = gtk_grid_new (); gtk_paned_pack1 (GTK_PANED (window->paned_right), window->view_box, TRUE, FALSE); gtk_widget_show (window->view_box); gtk_widget_add_events (window->paned_notebooks, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_BUTTON_PRESS_MASK); gtk_grid_attach (GTK_GRID (window->view_box), window->paned_notebooks, 0, 0, 1, 1); gtk_widget_show (window->paned_notebooks); g_object_get (window->paned_right, "max-position", &max_paned_position, NULL); gtk_paned_set_position (GTK_PANED (window->paned_right), max_paned_position); /* close notebooks on window-remove signal because later on window property pointers are broken */ g_signal_connect (G_OBJECT (window), "remove", G_CALLBACK (thunar_window_paned_notebooks_destroy), window); /* add first notebook and select it */ window->notebook_selected = thunar_window_paned_notebooks_add (window); /* get a reference of the global job operation history */ window->job_operation_history = thunar_job_operation_history_get_default (); /* add location toolbar */ window->location_toolbar = NULL; thunar_window_location_toolbar_create (window); /* Create client-side decoration if needed and add menubar and toolbar */ if (misc_use_csd) { GtkWidget *header_bar = gtk_header_bar_new (); gtk_header_bar_set_show_close_button (GTK_HEADER_BAR (header_bar), TRUE); gtk_window_set_titlebar (GTK_WINDOW (window), header_bar); thunar_window_csd_update (window); gtk_widget_show (header_bar); } else { gtk_grid_attach (GTK_GRID (window->grid), window->menubar, 0, 0, 1, 1); gtk_grid_attach (GTK_GRID (window->grid), window->location_toolbar, 0, 1, 1, 1); } /* setup setting the location bar visibility on-demand */ g_signal_connect_swapped (G_OBJECT (window->preferences), "notify::last-location-bar", G_CALLBACK (thunar_window_update_location_bar_visible), window); thunar_window_update_location_bar_visible (window); /* update the location toolbar when symbolic icons setting is toggled */ g_signal_connect_swapped (G_OBJECT (window->preferences), "notify::misc-symbolic-icons-in-toolbar", G_CALLBACK (thunar_window_update_location_toolbar_icons), window); /* update the location toolbar when custom actions are changed */ uca_path = xfce_resource_save_location (XFCE_RESOURCE_CONFIG, "Thunar/uca.xml", TRUE); window->uca_file = g_file_new_for_path (uca_path); window->uca_file_monitor = g_file_monitor_file (window->uca_file, G_FILE_MONITOR_WATCH_MOVES, NULL, NULL); if (G_LIKELY (window->uca_file_monitor != NULL)) g_signal_connect_swapped (window->uca_file_monitor, "changed", G_CALLBACK (thunar_window_update_location_toolbar), window); g_free (uca_path); /* the UCA shortcuts need to be checked 'by hand', since we dont want to permanently keep menu items for them */ g_signal_connect (window, "key-press-event", G_CALLBACK (thunar_window_check_uca_key_activation), NULL); /* handle the "back" and "forward" buttons */ g_signal_connect (window, "button-press-event", G_CALLBACK (thunar_window_button_press_event), window); window->signal_handler_id_history_changed = 0; /* set the selected side pane */ thunar_window_install_sidepane (window, last_side_pane); /* ensure that all the view types are registered */ g_type_ensure (THUNAR_TYPE_ICON_VIEW); g_type_ensure (THUNAR_TYPE_DETAILS_VIEW); g_type_ensure (THUNAR_TYPE_COMPACT_VIEW); /* update window icon whenever preferences change */ g_signal_connect_swapped (G_OBJECT (window->preferences), "notify::misc-change-window-icon", G_CALLBACK (thunar_window_update_window_icon), window); /* synchronise the "directory-specific-settings" property with the global "misc-directory-specific-settings" property */ g_object_bind_property (G_OBJECT (window->preferences), "misc-directory-specific-settings", G_OBJECT (window), "directory-specific-settings", G_BINDING_SYNC_CREATE); /* setup the `Show More...` button that appears at the bottom of the view after a search is completed */ catfish_path = g_find_program_in_path ("catfish"); if (catfish_path != NULL) { /* TRANSLATORS: `Catfish' is a software package, please don't translate it. */ window->catfish_search_button = gtk_button_new_with_label (_("Search with Catfish...")); gtk_grid_attach (GTK_GRID (window->view_box), window->catfish_search_button, 0, 1, 1, 1); g_signal_connect_swapped (window->catfish_search_button, "clicked", G_CALLBACK (thunar_window_catfish_dialog_configure), window); gtk_widget_hide (window->catfish_search_button); g_free (catfish_path); } else window->catfish_search_button = NULL; /* setup the trash infobar */ window->trash_infobar = gtk_info_bar_new (); gtk_grid_attach (GTK_GRID (window->view_box), window->trash_infobar, 0, 2, 1, 1); window->trash_infobar_restore_button = gtk_info_bar_add_button (GTK_INFO_BAR (window->trash_infobar), _("Restore Selected Items"), RESTORE); gtk_widget_set_sensitive (window->trash_infobar_restore_button, FALSE); window->trash_infobar_empty_button = gtk_info_bar_add_button (GTK_INFO_BAR (window->trash_infobar), _("Empty Trash"), EMPTY); g_signal_connect (window->trash_infobar, "response", G_CALLBACK (thunar_window_trash_infobar_clicked), G_OBJECT (window)); /* setup a new statusbar */ event_box = gtk_event_box_new (); window->statusbar = thunar_statusbar_new (); thunar_statusbar_append_accelerators (THUNAR_STATUSBAR (window->statusbar), window->accel_group); gtk_widget_set_hexpand (window->statusbar, TRUE); gtk_container_add (GTK_CONTAINER (event_box), window->statusbar); gtk_grid_attach (GTK_GRID (window->view_box), event_box, 0, 3, 1, 1); if (last_statusbar_visible) gtk_widget_show (window->statusbar); gtk_widget_show (event_box); thunar_statusbar_setup_event (THUNAR_STATUSBAR (window->statusbar), event_box); if (G_LIKELY (window->view != NULL)) thunar_window_binding_create (window, THUNAR_STANDARD_VIEW (window->view), "statusbar-text", window->statusbar, "text", G_BINDING_SYNC_CREATE); /* load the bookmarks file and monitor */ window->bookmarks = NULL; window->bookmark_file = thunar_g_file_new_for_bookmarks (); window->bookmark_monitor = g_file_monitor_file (window->bookmark_file, G_FILE_MONITOR_NONE, NULL, NULL); if (G_LIKELY (window->bookmark_monitor != NULL)) g_signal_connect_swapped (window->bookmark_monitor, "changed", G_CALLBACK (thunar_window_update_bookmarks), window); /* initial load of the bookmarks */ thunar_window_update_bookmarks (window); /* update recent */ g_signal_connect (G_OBJECT (gtk_recent_manager_get_default ()), "changed", G_CALLBACK (thunar_window_recent_reload), window); window->search_query = NULL; window->reset_view_type_idle_id = 0; } static void thunar_window_screen_changed (GtkWidget *widget, GdkScreen *old_screen, gpointer userdata) { GdkScreen *screen = gdk_screen_get_default (); GdkVisual *visual = gdk_screen_get_rgba_visual (screen); if (visual == NULL || !gdk_screen_is_composited (screen)) visual = gdk_screen_get_system_visual (screen); gtk_widget_set_visual (GTK_WIDGET (widget), visual); } static void hash_table_entry_show_and_select_files (gpointer key, gpointer list, gpointer application) { ThunarFile *original_dir = NULL; GList *window_list = NULL; _thunar_return_if_fail (key != NULL); _thunar_return_if_fail (list != NULL); _thunar_return_if_fail (application != NULL); /* open directory */ original_dir = thunar_file_get_for_uri (key, NULL); thunar_application_open_window (application, original_dir, NULL, NULL, FALSE); /* select files */ window_list = thunar_application_get_windows (application); /* this will be the topmost Window */ thunar_window_select_files (THUNAR_WINDOW (g_list_last (window_list)->data), list); /* free memory */ g_list_free (window_list); g_object_unref (original_dir); } /** * thunar_window_show_and_select_files: * @window : a #ThunarWindow instance. * @files_to_select : a list of #GFiles * * Visually selects the files, given by the list. If the files are being restored from the trash folder * new tabs are opened and then the files are selected. **/ void thunar_window_show_and_select_files (ThunarWindow *window, GList *files_to_select) { gboolean restore_and_show_in_progress; ThunarFile *first_file; _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); restore_and_show_in_progress = thunar_file_is_trash (window->current_directory) && thunar_g_file_is_trashed (files_to_select->data) == FALSE; if (restore_and_show_in_progress) { thunar_window_open_files_in_location (window, files_to_select); } else { thunar_window_select_files (window, files_to_select); } /* scroll to first file */ if (files_to_select != NULL) { first_file = thunar_file_get (files_to_select->data, NULL); thunar_view_scroll_to_file (THUNAR_VIEW (window->view), first_file, FALSE, TRUE, 0.1f, 0.1f); g_object_unref (first_file); } } void thunar_window_open_files_in_location (ThunarWindow *window, GList *files_to_select) { ThunarApplication *application; GHashTable *restore_show_table; /* > */ gchar *original_uri; GFile *original_dir_file; gchar *original_dir_path; _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); /* prepare hashtable */ restore_show_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (void (*) (void *)) thunar_g_list_free_full); for (GList *lp = files_to_select; lp != NULL; lp = lp->next) { original_dir_file = g_file_get_parent (lp->data); original_uri = g_file_get_uri (lp->data); original_dir_path = g_file_get_uri (original_dir_file); if (g_hash_table_contains (restore_show_table, original_dir_path) == FALSE) { GList *list = g_list_prepend (NULL, g_file_new_for_commandline_arg (original_uri)); g_hash_table_insert (restore_show_table, original_dir_path, list); } else { GList *list = g_hash_table_lookup (restore_show_table, original_dir_path); list = g_list_append (list, g_file_new_for_commandline_arg (original_uri)); g_free (original_dir_path); } g_free (original_uri); g_object_unref (original_dir_file); } /* open tabs and show files */ application = thunar_application_get (); g_hash_table_foreach (restore_show_table, hash_table_entry_show_and_select_files, application); /* free memory */ g_hash_table_destroy (restore_show_table); g_object_unref (application); } /** * thunar_window_select_files: * @window : a #ThunarWindow instance. * @files_to_select : a list of #GFiles * * Visually selects the files, given by the list **/ static void thunar_window_select_files (ThunarWindow *window, GList *files_to_select) { GList *thunar_files = NULL; ThunarFolder *thunar_folder; /* If possible, reload the current directory to make sure new files got added to the view */ thunar_folder = thunar_folder_get_for_file (window->current_directory); if (thunar_folder != NULL) { thunar_folder_reload (thunar_folder, FALSE); g_object_unref (thunar_folder); } for (GList *lp = files_to_select; lp != NULL; lp = lp->next) thunar_files = g_list_append (thunar_files, thunar_file_get (G_FILE (lp->data), NULL)); if (thunar_files != NULL) thunar_view_set_selected_files (THUNAR_VIEW (window->view), thunar_files); g_list_free_full (thunar_files, g_object_unref); } static void thunar_window_create_menu (ThunarWindow *window, ThunarWindowAction action, GCallback cb_update_menu, GtkWidget *menu) { GtkWidget *item; GtkWidget *submenu; _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); item = xfce_gtk_menu_item_new_from_action_entry (get_action_entry (action), G_OBJECT (window), GTK_MENU_SHELL (menu)); submenu = g_object_new (THUNAR_TYPE_MENU, "menu-type", THUNAR_MENU_TYPE_WINDOW, "action_mgr", window->action_mgr, NULL); gtk_menu_set_accel_group (GTK_MENU (submenu), window->accel_group); gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), GTK_WIDGET (submenu)); g_signal_connect_swapped (G_OBJECT (submenu), "show", G_CALLBACK (cb_update_menu), window); } static void thunar_window_update_file_menu (ThunarWindow *window, GtkWidget *menu) { GtkWidget *item; _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); thunar_gtk_menu_clean (GTK_MENU (menu)); xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_NEW_TAB), G_OBJECT (window), GTK_MENU_SHELL (menu)); xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_NEW_WINDOW), G_OBJECT (window), GTK_MENU_SHELL (menu)); xfce_gtk_menu_append_separator (GTK_MENU_SHELL (menu)); thunar_menu_add_sections (THUNAR_MENU (menu), THUNAR_MENU_SECTION_OPEN | THUNAR_MENU_SECTION_SENDTO | THUNAR_MENU_SECTION_CREATE_NEW_FILES | THUNAR_MENU_SECTION_EMPTY_TRASH | THUNAR_MENU_SECTION_CUSTOM_ACTIONS | THUNAR_MENU_SECTION_PROPERTIES); xfce_gtk_menu_append_separator (GTK_MENU_SHELL (menu)); item = xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_DETACH_TAB), G_OBJECT (window), GTK_MENU_SHELL (menu)); gtk_widget_set_sensitive (item, gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook_selected)) > 1); xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_CLOSE_ALL_WINDOWS), G_OBJECT (window), GTK_MENU_SHELL (menu)); xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_CLOSE_TAB), G_OBJECT (window), GTK_MENU_SHELL (menu)); xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_CLOSE_WINDOW), G_OBJECT (window), GTK_MENU_SHELL (menu)); gtk_widget_show_all (GTK_WIDGET (menu)); thunar_window_redirect_menu_tooltips_to_statusbar (window, GTK_MENU (menu)); } static void thunar_window_update_edit_menu (ThunarWindow *window, GtkWidget *menu) { GtkWidget *gtk_menu_item; GList *thunarx_menu_items; GList *pp, *lp; const XfceGtkActionEntry *action_entry; gchar *action_tooltip; _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); thunar_gtk_menu_clean (GTK_MENU (menu)); action_entry = get_action_entry (THUNAR_WINDOW_ACTION_UNDO); action_tooltip = thunar_job_operation_history_get_undo_text (); gtk_menu_item = xfce_gtk_image_menu_item_new_from_icon_name (action_entry->menu_item_label_text, action_tooltip, action_entry->accel_path, action_entry->callback, G_OBJECT (window), action_entry->menu_item_icon_name, GTK_MENU_SHELL (menu)); g_free (action_tooltip); gtk_widget_set_sensitive (gtk_menu_item, thunar_job_operation_history_can_undo ()); action_entry = get_action_entry (THUNAR_WINDOW_ACTION_REDO); action_tooltip = thunar_job_operation_history_get_redo_text (); gtk_menu_item = xfce_gtk_image_menu_item_new_from_icon_name (action_entry->menu_item_label_text, action_tooltip, action_entry->accel_path, action_entry->callback, G_OBJECT (window), action_entry->menu_item_icon_name, GTK_MENU_SHELL (menu)); g_free (action_tooltip); gtk_widget_set_sensitive (gtk_menu_item, thunar_job_operation_history_can_redo ()); xfce_gtk_menu_append_separator (GTK_MENU_SHELL (menu)); thunar_menu_add_sections (THUNAR_MENU (menu), THUNAR_MENU_SECTION_CUT | THUNAR_MENU_SECTION_COPY_PASTE | THUNAR_MENU_SECTION_TRASH_DELETE); if (window->view != NULL) { thunar_standard_view_append_menu_item (THUNAR_STANDARD_VIEW (window->view), GTK_MENU (menu), THUNAR_STANDARD_VIEW_ACTION_SELECT_ALL_FILES); thunar_standard_view_append_menu_item (THUNAR_STANDARD_VIEW (window->view), GTK_MENU (menu), THUNAR_STANDARD_VIEW_ACTION_SELECT_BY_PATTERN); thunar_standard_view_append_menu_item (THUNAR_STANDARD_VIEW (window->view), GTK_MENU (menu), THUNAR_STANDARD_VIEW_ACTION_INVERT_SELECTION); thunar_standard_view_append_menu_item (THUNAR_STANDARD_VIEW (window->view), GTK_MENU (menu), THUNAR_STANDARD_VIEW_ACTION_UNSELECT_ALL_FILES); } xfce_gtk_menu_append_separator (GTK_MENU_SHELL (menu)); thunar_menu_add_sections (THUNAR_MENU (menu), THUNAR_MENU_SECTION_DUPLICATE | THUNAR_MENU_SECTION_MAKELINK | THUNAR_MENU_SECTION_RENAME | THUNAR_MENU_SECTION_RESTORE | THUNAR_MENU_SECTION_REMOVE_FROM_RECENT); /* determine the available preferences providers */ if (G_LIKELY (window->thunarx_preferences_providers != NULL)) { /* add menu items from all providers */ for (pp = window->thunarx_preferences_providers; pp != NULL; pp = pp->next) { /* determine the available menu items for the provider */ thunarx_menu_items = thunarx_preferences_provider_get_menu_items (THUNARX_PREFERENCES_PROVIDER (pp->data), GTK_WIDGET (window)); for (lp = thunarx_menu_items; lp != NULL; lp = lp->next) { gtk_menu_item = thunar_gtk_menu_thunarx_menu_item_new (lp->data, GTK_MENU_SHELL (menu)); /* each thunarx_menu_item will be destroyed together with its related gtk_menu_item */ g_signal_connect_swapped (G_OBJECT (gtk_menu_item), "destroy", G_CALLBACK (g_object_unref), lp->data); } /* release the list */ g_list_free (thunarx_menu_items); } } xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_PREFERENCES), G_OBJECT (window), GTK_MENU_SHELL (menu)); gtk_widget_show_all (GTK_WIDGET (menu)); thunar_window_redirect_menu_tooltips_to_statusbar (window, GTK_MENU (menu)); } static void thunar_window_update_view_menu (ThunarWindow *window, GtkWidget *menu) { GtkWidget *item; GtkWidget *sub_items; gchar *last_location_bar; gboolean image_preview_visible; gboolean highlight_enabled; _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); thunar_gtk_menu_clean (GTK_MENU (menu)); xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_RELOAD), G_OBJECT (window), GTK_MENU_SHELL (menu)); xfce_gtk_menu_append_separator (GTK_MENU_SHELL (menu)); xfce_gtk_toggle_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_VIEW_SPLIT), G_OBJECT (window), thunar_window_split_view_is_active (window), GTK_MENU_SHELL (menu)); xfce_gtk_menu_append_separator (GTK_MENU_SHELL (menu)); item = xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_VIEW_LOCATION_SELECTOR_MENU), G_OBJECT (window), GTK_MENU_SHELL (menu)); sub_items = gtk_menu_new (); gtk_menu_set_accel_group (GTK_MENU (sub_items), window->accel_group); g_object_get (window->preferences, "last-location-bar", &last_location_bar, "last-image-preview-visible", &image_preview_visible, NULL); xfce_gtk_toggle_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_VIEW_LOCATION_SELECTOR_BUTTONS), G_OBJECT (window), (g_strcmp0 (last_location_bar, g_type_name (THUNAR_TYPE_LOCATION_BUTTONS)) == 0), GTK_MENU_SHELL (sub_items)); xfce_gtk_toggle_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_VIEW_LOCATION_SELECTOR_ENTRY), G_OBJECT (window), (g_strcmp0 (last_location_bar, g_type_name (THUNAR_TYPE_LOCATION_ENTRY)) == 0), GTK_MENU_SHELL (sub_items)); g_free (last_location_bar); gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), GTK_WIDGET (sub_items)); item = xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_VIEW_SIDE_PANE_MENU), G_OBJECT (window), GTK_MENU_SHELL (menu)); sub_items = gtk_menu_new (); gtk_menu_set_accel_group (GTK_MENU (sub_items), window->accel_group); xfce_gtk_toggle_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_VIEW_SIDE_PANE_SHORTCUTS), G_OBJECT (window), thunar_window_has_shortcut_sidepane (window), GTK_MENU_SHELL (sub_items)); xfce_gtk_toggle_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_VIEW_SIDE_PANE_TREE), G_OBJECT (window), thunar_window_has_tree_view_sidepane (window), GTK_MENU_SHELL (sub_items)); xfce_gtk_menu_append_separator (GTK_MENU_SHELL (sub_items)); xfce_gtk_toggle_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_TOGGLE_IMAGE_PREVIEW), G_OBJECT (window), image_preview_visible, GTK_MENU_SHELL (sub_items)); gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), GTK_WIDGET (sub_items)); xfce_gtk_toggle_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_VIEW_STATUSBAR), G_OBJECT (window), gtk_widget_get_visible (window->statusbar), GTK_MENU_SHELL (menu)); xfce_gtk_toggle_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_VIEW_MENUBAR), G_OBJECT (window), window->menubar_visible, GTK_MENU_SHELL (menu)); xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_CONFIGURE_TOOLBAR), G_OBJECT (window), GTK_MENU_SHELL (menu)); xfce_gtk_menu_append_separator (GTK_MENU_SHELL (menu)); if (window->directory_specific_settings) { item = xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_CLEAR_DIRECTORY_SPECIFIC_SETTINGS), G_OBJECT (window), GTK_MENU_SHELL (menu)); gtk_widget_set_sensitive (item, thunar_file_has_directory_specific_settings (window->current_directory)); } xfce_gtk_toggle_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_SHOW_HIDDEN), G_OBJECT (window), window->show_hidden, GTK_MENU_SHELL (menu)); if (thunar_g_vfs_metadata_is_supported ()) { g_object_get (G_OBJECT (window->preferences), "misc-highlighting-enabled", &highlight_enabled, NULL); xfce_gtk_toggle_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_SHOW_HIGHLIGHT), G_OBJECT (window), highlight_enabled, GTK_MENU_SHELL (menu)); } xfce_gtk_menu_append_separator (GTK_MENU_SHELL (menu)); if (window->view != NULL) thunar_standard_view_append_menu_items (THUNAR_STANDARD_VIEW (window->view), GTK_MENU (menu), window->accel_group); xfce_gtk_menu_append_separator (GTK_MENU_SHELL (menu)); thunar_window_append_menu_item (window, GTK_MENU_SHELL (menu), THUNAR_WINDOW_ACTION_ZOOM_IN); thunar_window_append_menu_item (window, GTK_MENU_SHELL (menu), THUNAR_WINDOW_ACTION_ZOOM_OUT); thunar_window_append_menu_item (window, GTK_MENU_SHELL (menu), THUNAR_WINDOW_ACTION_ZOOM_RESET); xfce_gtk_menu_append_separator (GTK_MENU_SHELL (menu)); item = xfce_gtk_toggle_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_VIEW_AS_ICONS), G_OBJECT (window), window->view_type == THUNAR_TYPE_ICON_VIEW, GTK_MENU_SHELL (menu)); if (window->is_searching == TRUE) gtk_widget_set_sensitive (item, FALSE); xfce_gtk_toggle_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_VIEW_AS_DETAILED_LIST), G_OBJECT (window), window->view_type == THUNAR_TYPE_DETAILS_VIEW, GTK_MENU_SHELL (menu)); item = xfce_gtk_toggle_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_VIEW_AS_COMPACT_LIST), G_OBJECT (window), window->view_type == THUNAR_TYPE_COMPACT_VIEW, GTK_MENU_SHELL (menu)); if (window->is_searching == TRUE) gtk_widget_set_sensitive (item, FALSE); gtk_widget_show_all (GTK_WIDGET (menu)); thunar_window_redirect_menu_tooltips_to_statusbar (window, GTK_MENU (menu)); } static void thunar_window_update_go_menu (ThunarWindow *window, GtkWidget *menu) { gchar *icon_name; const XfceGtkActionEntry *action_entry; ThunarHistory *history = NULL; GtkWidget *item; _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); if (window->view != NULL) history = thunar_standard_view_get_history (THUNAR_STANDARD_VIEW (window->view)); thunar_gtk_menu_clean (GTK_MENU (menu)); item = xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_OPEN_PARENT), G_OBJECT (window), GTK_MENU_SHELL (menu)); gtk_widget_set_sensitive (item, !thunar_g_file_is_root (thunar_file_get_file (window->current_directory))); item = xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_BACK), G_OBJECT (window), GTK_MENU_SHELL (menu)); if (history != NULL) gtk_widget_set_sensitive (item, thunar_history_has_back (history)); item = xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_FORWARD), G_OBJECT (window), GTK_MENU_SHELL (menu)); if (history != NULL) gtk_widget_set_sensitive (item, thunar_history_has_forward (history)); xfce_gtk_menu_append_separator (GTK_MENU_SHELL (menu)); xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_OPEN_COMPUTER), G_OBJECT (window), GTK_MENU_SHELL (menu)); xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_OPEN_HOME), G_OBJECT (window), GTK_MENU_SHELL (menu)); xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_OPEN_DESKTOP), G_OBJECT (window), GTK_MENU_SHELL (menu)); if (thunar_g_vfs_is_uri_scheme_supported ("recent")) xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_OPEN_RECENT), G_OBJECT (window), GTK_MENU_SHELL (menu)); if (thunar_g_vfs_is_uri_scheme_supported ("trash")) { GFile *gfile; ThunarFile *trash_folder; /* try to connect to the trash bin */ gfile = thunar_g_file_new_for_trash (); if (gfile != NULL) { trash_folder = thunar_file_get (gfile, NULL); if (trash_folder != NULL) { action_entry = get_action_entry (THUNAR_WINDOW_ACTION_OPEN_TRASH); if (action_entry != NULL) { if (thunar_file_get_item_count (trash_folder) > 0) icon_name = "user-trash-full"; else icon_name = "user-trash"; xfce_gtk_image_menu_item_new_from_icon_name (action_entry->menu_item_label_text, action_entry->menu_item_tooltip_text, action_entry->accel_path, action_entry->callback, G_OBJECT (window), icon_name, GTK_MENU_SHELL (menu)); } g_object_unref (trash_folder); } g_object_unref (gfile); } } xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_OPEN_TEMPLATES), G_OBJECT (window), GTK_MENU_SHELL (menu)); xfce_gtk_menu_append_separator (GTK_MENU_SHELL (menu)); xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_OPEN_FILE_SYSTEM), G_OBJECT (window), GTK_MENU_SHELL (menu)); xfce_gtk_menu_append_separator (GTK_MENU_SHELL (menu)); xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_OPEN_NETWORK), G_OBJECT (window), GTK_MENU_SHELL (menu)); xfce_gtk_menu_append_separator (GTK_MENU_SHELL (menu)); xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_OPEN_LOCATION), G_OBJECT (window), GTK_MENU_SHELL (menu)); xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_SEARCH), G_OBJECT (window), GTK_MENU_SHELL (menu)); gtk_widget_show_all (GTK_WIDGET (menu)); thunar_window_redirect_menu_tooltips_to_statusbar (window, GTK_MENU (menu)); } static void thunar_window_update_bookmarks_menu (ThunarWindow *window, GtkWidget *menu) { _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); thunar_gtk_menu_clean (GTK_MENU (menu)); thunar_action_manager_append_menu_item (window->action_mgr, GTK_MENU_SHELL (menu), THUNAR_ACTION_MANAGER_ACTION_SENDTO_SHORTCUTS, FALSE); xfce_gtk_menu_append_separator (GTK_MENU_SHELL (menu)); thunar_window_menu_add_bookmarks (window, GTK_MENU_SHELL (menu)); gtk_widget_show_all (GTK_WIDGET (menu)); thunar_window_redirect_menu_tooltips_to_statusbar (window, GTK_MENU (menu)); } static void thunar_window_update_help_menu (ThunarWindow *window, GtkWidget *menu) { _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); thunar_gtk_menu_clean (GTK_MENU (menu)); xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_CONTENTS), G_OBJECT (window), GTK_MENU_SHELL (menu)); xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_ABOUT), G_OBJECT (window), GTK_MENU_SHELL (menu)); gtk_widget_show_all (GTK_WIDGET (menu)); thunar_window_redirect_menu_tooltips_to_statusbar (window, GTK_MENU (menu)); } static void thunar_window_dispose (GObject *object) { ThunarWindow *window = THUNAR_WINDOW (object); /* indicate that history items are out of use */ window->location_toolbar_item_back = NULL; window->location_toolbar_item_forward = NULL; if (window->accel_group != NULL) { gtk_accel_group_disconnect (window->accel_group, NULL); gtk_window_remove_accel_group (GTK_WINDOW (window), window->accel_group); g_object_unref (window->accel_group); window->accel_group = NULL; } /* destroy the save geometry timer source */ if (G_UNLIKELY (window->save_geometry_timer_id != 0)) g_source_remove (window->save_geometry_timer_id); /* disconnect from the current-directory */ thunar_window_set_current_directory (window, NULL); (*G_OBJECT_CLASS (thunar_window_parent_class)->dispose) (object); } static void thunar_window_finalize (GObject *object) { ThunarWindow *window = THUNAR_WINDOW (object); thunar_window_free_bookmarks (window); g_list_free_full (window->thunarx_preferences_providers, g_object_unref); g_free (window->search_query); /* Disconnect from preview file */ if (window->preview_image_file != NULL) { g_signal_handlers_disconnect_by_data (window->preview_image_file, window); g_object_unref (window->preview_image_file); window->preview_image_file = NULL; } /* clear image preview pixbuf */ if (window->preview_image_pixbuf != NULL) { g_object_unref (window->preview_image_pixbuf); window->preview_image_pixbuf = NULL; } /* disconnect from the volume monitor */ g_signal_handlers_disconnect_by_data (window->device_monitor, window); g_object_unref (window->device_monitor); g_signal_handlers_disconnect_by_data (window->action_mgr, window); g_object_unref (window->action_mgr); if (window->bookmark_file != NULL) g_object_unref (window->bookmark_file); if (window->bookmark_monitor != NULL) { g_file_monitor_cancel (window->bookmark_monitor); g_object_unref (window->bookmark_monitor); } /* detach from the file monitor */ if (window->uca_file_monitor != NULL) { g_file_monitor_cancel (window->uca_file_monitor); g_object_unref (window->uca_file_monitor); g_object_unref (window->uca_file); } /* release our reference on the provider factory */ g_object_unref (window->provider_factory); /* release the preferences reference */ g_signal_handlers_disconnect_by_data (window->preferences, window); g_object_unref (window->preferences); /* disconnect signal from GtkRecentManager */ g_signal_handlers_disconnect_by_data (G_OBJECT (gtk_recent_manager_get_default ()), window); g_object_unref (window->job_operation_history); (*G_OBJECT_CLASS (thunar_window_parent_class)->finalize) (object); } static gboolean thunar_window_delete (GtkWidget *widget, GdkEvent *event, gpointer data) { gboolean confirm_close_multiple_tabs, do_not_ask_again, restore_tabs; gint response, n_tabs, n_tabsl = 0, n_tabsr = 0; gint current_page_left = 0, current_page_right = 0; ThunarWindow *window = THUNAR_WINDOW (widget); gchar **tab_uris_left; gchar **tab_uris_right; _thunar_return_val_if_fail (THUNAR_IS_WINDOW (widget), FALSE); if (window->is_searching == TRUE) thunar_window_action_cancel_search (window); if (window->reset_view_type_idle_id != 0) { thunar_window_reset_view_type_idle (window); g_source_remove (window->reset_view_type_idle_id); } if (window->notebook_left) n_tabsl = gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook_left)); if (window->notebook_right) n_tabsr = gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook_right)); n_tabs = n_tabsl + n_tabsr; /* save open tabs */ g_object_get (G_OBJECT (window->preferences), "last-restore-tabs", &restore_tabs, NULL); if (restore_tabs) { tab_uris_left = g_new0 (gchar *, n_tabsl + 1); for (int i = 0; i < n_tabsl; i++) { ThunarNavigator *view = THUNAR_NAVIGATOR (gtk_notebook_get_nth_page (GTK_NOTEBOOK (window->notebook_left), i)); gchar *uri = g_file_get_uri (thunar_file_get_file (thunar_navigator_get_current_directory (view))); tab_uris_left[i] = g_strdup (uri); g_free (uri); } tab_uris_right = g_new0 (gchar *, n_tabsr + 1); for (int i = 0; i < n_tabsr; i++) { ThunarNavigator *view = THUNAR_NAVIGATOR (gtk_notebook_get_nth_page (GTK_NOTEBOOK (window->notebook_right), i)); gchar *uri = g_file_get_uri (thunar_file_get_file (thunar_navigator_get_current_directory (view))); tab_uris_right[i] = g_strdup (uri); g_free (uri); } if (window->notebook_left) current_page_left = gtk_notebook_get_current_page (GTK_NOTEBOOK (window->notebook_left)); if (window->notebook_right) current_page_right = gtk_notebook_get_current_page (GTK_NOTEBOOK (window->notebook_right)); g_object_set (G_OBJECT (window->preferences), "last-tabs-left", tab_uris_left, NULL); g_object_set (G_OBJECT (window->preferences), "last-tabs-right", tab_uris_right, NULL); if (current_page_left > -1) g_object_set (G_OBJECT (window->preferences), "last-focused-tab-left", current_page_left, NULL); if (current_page_right > -1) g_object_set (G_OBJECT (window->preferences), "last-focused-tab-right", current_page_right, NULL); g_strfreev (tab_uris_left); g_strfreev (tab_uris_right); } /* if we don't have muliple tabs in one of the notebooks then just exit */ if (thunar_window_split_view_is_active (window)) { if (n_tabs < 3) return FALSE; } else { if (n_tabs < 2) return FALSE; } /* check if the user has disabled confirmation of closing multiple tabs, and just exit if so */ g_object_get (G_OBJECT (window->preferences), "misc-confirm-close-multiple-tabs", &confirm_close_multiple_tabs, NULL); if (!confirm_close_multiple_tabs) return FALSE; /* ask the user for confirmation */ do_not_ask_again = FALSE; response = xfce_dialog_confirm_close_tabs (GTK_WINDOW (widget), n_tabs, TRUE, &do_not_ask_again); /* if the user requested not to be asked again, store this preference */ if (response != GTK_RESPONSE_CANCEL && do_not_ask_again) g_object_set (G_OBJECT (window->preferences), "misc-confirm-close-multiple-tabs", FALSE, NULL); if (response == GTK_RESPONSE_YES) return FALSE; /* close active tab in active notebook */ if (response == GTK_RESPONSE_CLOSE) gtk_notebook_remove_page (GTK_NOTEBOOK (window->notebook_selected), gtk_notebook_get_current_page (GTK_NOTEBOOK (window->notebook_selected))); return TRUE; } static void thunar_window_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { ThunarWindow *window = THUNAR_WINDOW (object); switch (prop_id) { case PROP_CURRENT_DIRECTORY: g_value_set_object (value, thunar_window_get_current_directory (window)); break; case PROP_ZOOM_LEVEL: g_value_set_enum (value, window->zoom_level); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void thunar_window_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { ThunarWindow *window = THUNAR_WINDOW (object); switch (prop_id) { case PROP_CURRENT_DIRECTORY: thunar_window_set_current_directory (window, g_value_get_object (value)); break; case PROP_ZOOM_LEVEL: thunar_window_set_zoom_level (window, g_value_get_enum (value)); break; case PROP_DIRECTORY_SPECIFIC_SETTINGS: thunar_window_set_directory_specific_settings (window, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static gboolean thunar_window_csd_update (ThunarWindow *window) { GtkWidget *header_bar, *in_header_bar, *below_header_bar, *grid_child; _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); header_bar = gtk_window_get_titlebar (GTK_WINDOW (window)); if (header_bar == NULL) return FALSE; g_object_ref (window->menubar); g_object_ref (window->location_toolbar); /* The widget on top of the grid is either the menubar or the toolbar */ grid_child = gtk_grid_get_child_at (GTK_GRID (window->grid), 0, 0); if (GTK_IS_WIDGET (grid_child)) gtk_container_remove (GTK_CONTAINER (window->grid), grid_child); gtk_header_bar_set_custom_title (GTK_HEADER_BAR (header_bar), NULL); if (window->menubar_visible) { in_header_bar = window->menubar; below_header_bar = window->location_toolbar; /* restore default location bar margins */ gtk_widget_set_margin_start (window->location_bar, DEFAULT_LOCATION_BAR_MARGIN); gtk_widget_set_margin_end (window->location_bar, DEFAULT_LOCATION_BAR_MARGIN); } else { in_header_bar = window->location_toolbar; below_header_bar = window->menubar; /* add extra space around the location bar to function as window drag area */ gtk_widget_set_margin_start (window->location_bar, 15); gtk_widget_set_margin_end (window->location_bar, 15); } gtk_header_bar_set_custom_title (GTK_HEADER_BAR (header_bar), in_header_bar); gtk_grid_attach (GTK_GRID (window->grid), below_header_bar, 0, 0, 1, 1); g_object_unref (window->menubar); g_object_unref (window->location_toolbar); return TRUE; } static gboolean thunar_window_reload (ThunarWindow *window, gboolean reload_info) { _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); /* force the view to reload */ if (G_LIKELY (window->view != NULL)) { thunar_view_reload (THUNAR_VIEW (window->view), reload_info); return TRUE; } return FALSE; } /** * thunar_window_has_shortcut_sidepane: * @window : a #ThunarWindow instance. * * Return value: True, if this window is running a shortcut sidepane **/ gboolean thunar_window_has_shortcut_sidepane (ThunarWindow *window) { _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); /* check if a side pane is currently active */ if (G_LIKELY (window->sidepane != NULL)) return G_OBJECT_TYPE (window->sidepane) == THUNAR_TYPE_SHORTCUTS_PANE; return FALSE; } /** * thunar_window_has_tree_view_sidepane: * @window : a #ThunarWindow instance. * * Return value: True, if this window is running a tree_view sidepane **/ gboolean thunar_window_has_tree_view_sidepane (ThunarWindow *window) { _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); /* check if a side pane is currently active */ if (G_LIKELY (window->sidepane != NULL)) return G_OBJECT_TYPE (window->sidepane) == THUNAR_TYPE_TREE_PANE; return FALSE; } /** * thunar_window_get_sidepane: * @window : a #ThunarWindow instance. * * Return value: (transfer none): The #ThunarSidePane of this window, or NULL if not available **/ GtkWidget * thunar_window_get_sidepane (ThunarWindow *window) { _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); return GTK_WIDGET (window->sidepane); } static gboolean thunar_window_toggle_sidepane (ThunarWindow *window) { _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); /* invert the sidepane type hidden status */ switch (window->sidepane_type) { case THUNAR_SIDEPANE_TYPE_HIDDEN_SHORTCUTS: thunar_window_install_sidepane (window, THUNAR_SIDEPANE_TYPE_SHORTCUTS); break; case THUNAR_SIDEPANE_TYPE_SHORTCUTS: thunar_window_install_sidepane (window, THUNAR_SIDEPANE_TYPE_HIDDEN_SHORTCUTS); break; case THUNAR_SIDEPANE_TYPE_HIDDEN_TREE: thunar_window_install_sidepane (window, THUNAR_SIDEPANE_TYPE_TREE); break; case THUNAR_SIDEPANE_TYPE_TREE: thunar_window_install_sidepane (window, THUNAR_SIDEPANE_TYPE_HIDDEN_TREE); break; } return TRUE; } static gboolean thunar_window_zoom_in (ThunarWindow *window) { _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); /* check if we can still zoom in */ if (G_LIKELY (window->zoom_level < THUNAR_ZOOM_N_LEVELS - 1)) thunar_window_set_zoom_level (window, window->zoom_level + 1); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_window_zoom_out (ThunarWindow *window) { _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); /* check if we can still zoom out */ if (G_LIKELY (window->zoom_level > 0)) thunar_window_set_zoom_level (window, window->zoom_level - 1); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_window_zoom_reset (ThunarWindow *window) { _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); /* tell the view to reset it's zoom level */ if (G_LIKELY (window->view != NULL)) { thunar_view_reset_zoom_level (THUNAR_VIEW (window->view)); return TRUE; } return TRUE; } static gboolean thunar_window_tab_change (ThunarWindow *window, gint nth) { _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); /* Alt+0 is 10th tab */ thunar_window_notebook_set_current_tab (window, nth == -1 ? 9 : nth); return TRUE; } static gboolean thunar_window_action_switch_next_tab (ThunarWindow *window) { gint current_page; gint new_page; gint pages; _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); current_page = gtk_notebook_get_current_page (GTK_NOTEBOOK (window->notebook_selected)); pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook_selected)); new_page = (current_page + 1) % pages; thunar_window_notebook_set_current_tab (window, new_page); return TRUE; } static gboolean thunar_window_action_switch_previous_tab (ThunarWindow *window) { gint current_page; gint new_page; gint pages; _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); current_page = gtk_notebook_get_current_page (GTK_NOTEBOOK (window->notebook_selected)); pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook_selected)); new_page = (current_page - 1) % pages; thunar_window_notebook_set_current_tab (window, new_page); return TRUE; } static void thunar_window_clipboard_manager_changed (GtkWidget *widget) { ThunarWindow *window = THUNAR_WINDOW (widget); /* check if the content actually can be pasted into thunar, * in order to do not redraw the view if just some text is copied. */ if (thunar_clipboard_manager_get_can_paste (window->clipboard) && G_LIKELY (window->view != NULL)) thunar_standard_view_queue_redraw (THUNAR_STANDARD_VIEW (window->view)); } static void thunar_window_realize (GtkWidget *widget) { ThunarWindow *window = THUNAR_WINDOW (widget); /* let the GtkWidget class perform the realize operation */ (*GTK_WIDGET_CLASS (thunar_window_parent_class)->realize) (widget); /* connect to the clipboard manager of the new display and be sure to redraw the window * whenever the clipboard contents change to make sure we always display up2date state. */ window->clipboard = thunar_clipboard_manager_get_for_display (gtk_widget_get_display (widget)); g_signal_connect_swapped (G_OBJECT (window->clipboard), "changed", G_CALLBACK (thunar_window_clipboard_manager_changed), widget); } static void thunar_window_unrealize (GtkWidget *widget) { ThunarWindow *window = THUNAR_WINDOW (widget); /* disconnect from the clipboard manager */ g_signal_handlers_disconnect_by_func (G_OBJECT (window->clipboard), thunar_window_clipboard_manager_changed, widget); /* let the GtkWidget class unrealize the window */ (*GTK_WIDGET_CLASS (thunar_window_parent_class)->unrealize) (widget); /* drop the reference on the clipboard manager, we do this after letting the GtkWidget class * unrealise the window to prevent the clipboard being disposed during the unrealize */ g_object_unref (G_OBJECT (window->clipboard)); } static gboolean thunar_window_configure_event (GtkWidget *widget, GdkEventConfigure *event) { ThunarWindow *window = THUNAR_WINDOW (widget); GtkAllocation widget_allocation; gtk_widget_get_allocation (widget, &widget_allocation); /* check if we have a new dimension here */ if (widget_allocation.width != event->width || widget_allocation.height != event->height) { /* drop any previous timer source */ if (window->save_geometry_timer_id != 0) g_source_remove (window->save_geometry_timer_id); /* check if we should schedule another save timer */ if (gtk_widget_get_visible (widget)) { /* save the geometry one second after the last configure event */ window->save_geometry_timer_id = g_timeout_add_seconds_full (G_PRIORITY_LOW, 1, thunar_util_save_geometry_timer, window, thunar_window_save_geometry_timer_destroy); } } /* let Gtk+ handle the configure event */ return (*GTK_WIDGET_CLASS (thunar_window_parent_class)->configure_event) (widget, event); } 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_switch_current_view (ThunarWindow *window, GtkWidget *new_view) { GSList *view_bindings; ThunarFile *current_directory; ThunarHistory *history; gchar *search_query; _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); _thunar_return_if_fail (THUNAR_IS_VIEW (new_view)); if (window->view == new_view) return; if (G_LIKELY (window->view != NULL)) { /* Use accelerators only on the current active view */ g_object_set (G_OBJECT (window->view), "accel-group", NULL, NULL); /* disconnect from previous history */ if (window->signal_handler_id_history_changed != 0) { history = thunar_standard_view_get_history (THUNAR_STANDARD_VIEW (window->view)); g_signal_handler_disconnect (history, window->signal_handler_id_history_changed); window->signal_handler_id_history_changed = 0; } g_signal_handlers_disconnect_by_func (window->view, thunar_window_selection_changed, window); /* 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); /* exit search mode (if the view has no ongoing search operation) */ search_query = thunar_standard_view_get_search_query (THUNAR_STANDARD_VIEW (new_view)); if (search_query == NULL && window->search_query != NULL) thunar_window_action_cancel_search (window); /* update the directory of the current window */ current_directory = thunar_navigator_get_current_directory (THUNAR_NAVIGATOR (new_view)); thunar_window_set_current_directory (window, current_directory); /* add stock bindings */ thunar_window_binding_create (window, window, "current-directory", new_view, "current-directory", G_BINDING_DEFAULT); thunar_window_binding_create (window, new_view, "loading", window->spinner, "active", G_BINDING_SYNC_CREATE); thunar_window_binding_create (window, new_view, "searching", window->spinner, "active", G_BINDING_SYNC_CREATE); thunar_window_binding_create (window, new_view, "search-mode-active", window->location_toolbar_item_icon_view, "sensitive", G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN); thunar_window_binding_create (window, new_view, "search-mode-active", window->location_toolbar_item_compact_view, "sensitive", G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN); thunar_window_binding_create (window, new_view, "search-mode-active", window->location_toolbar_item_view_switcher, "sensitive", G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN); thunar_window_binding_create (window, new_view, "selected-files", window->action_mgr, "selected-files", G_BINDING_SYNC_CREATE); thunar_window_binding_create (window, new_view, "zoom-level", window, "zoom-level", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); /* connect to the sidepane (if any) */ if (G_LIKELY (window->sidepane != NULL)) { thunar_window_binding_create (window, new_view, "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, THUNAR_STANDARD_VIEW (new_view), "statusbar-text", window->statusbar, "text", G_BINDING_SYNC_CREATE); } /* activate new view */ window->view = new_view; window->view_type = G_TYPE_FROM_INSTANCE (new_view); /* before we can set which view button should be active we need to block the signals first */ g_signal_handlers_block_by_func (window->location_toolbar_item_detailed_view, get_action_entry (THUNAR_WINDOW_ACTION_VIEW_AS_DETAILED_LIST)->callback, window); g_signal_handlers_block_by_func (window->location_toolbar_item_compact_view, get_action_entry (THUNAR_WINDOW_ACTION_VIEW_AS_COMPACT_LIST)->callback, window); g_signal_handlers_block_by_func (window->location_toolbar_item_icon_view, get_action_entry (THUNAR_WINDOW_ACTION_VIEW_AS_ICONS)->callback, window); if (window->view_type == THUNAR_TYPE_DETAILS_VIEW) gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (window->location_toolbar_item_detailed_view), TRUE); else if (window->view_type == THUNAR_TYPE_COMPACT_VIEW) gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (window->location_toolbar_item_compact_view), TRUE); else if (window->view_type == THUNAR_TYPE_ICON_VIEW) gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (window->location_toolbar_item_icon_view), TRUE); g_signal_handlers_unblock_by_func (window->location_toolbar_item_detailed_view, get_action_entry (THUNAR_WINDOW_ACTION_VIEW_AS_DETAILED_LIST)->callback, window); g_signal_handlers_unblock_by_func (window->location_toolbar_item_compact_view, get_action_entry (THUNAR_WINDOW_ACTION_VIEW_AS_COMPACT_LIST)->callback, window); g_signal_handlers_unblock_by_func (window->location_toolbar_item_icon_view, get_action_entry (THUNAR_WINDOW_ACTION_VIEW_AS_ICONS)->callback, window); thunar_window_view_switcher_update (window); /* connect accelerators for the view, we need to do this after window->view has been set, * see thunar_window_reconnect_accelerators and thunar_standard_view_connect_accelerators */ g_object_set (G_OBJECT (window->view), "accel-group", window->accel_group, NULL); g_signal_connect_swapped (G_OBJECT (window->view), "notify::selected-files", G_CALLBACK (thunar_window_selection_changed), window); /* remember the last view type if directory specific settings are not enabled */ if (!window->directory_specific_settings && !window->is_searching && window->view_type != G_TYPE_NONE) g_object_set (G_OBJECT (window->preferences), "last-view", g_type_name (window->view_type), NULL); /* connect to the new history */ history = thunar_standard_view_get_history (THUNAR_STANDARD_VIEW (window->view)); if (history != NULL) { window->signal_handler_id_history_changed = g_signal_connect_swapped (G_OBJECT (history), "history-changed", G_CALLBACK (thunar_window_history_changed), window); thunar_window_history_changed (window); } /* Set trash infobar's `empty trash` button sensitivity, if required */ if (thunar_file_is_trash (window->current_directory)) gtk_widget_set_sensitive (window->trash_infobar_empty_button, thunar_file_get_item_count (window->current_directory) > 0); /* if the view has an ongoing search operation, take that into account */ if (search_query != NULL) { gchar *str = g_strjoin (NULL, thunar_util_get_search_prefix (), search_query, NULL); thunar_window_resume_search (window, str); g_free (str); } /* switch to the new view */ thunar_window_notebook_set_current_tab (window, gtk_notebook_page_num (GTK_NOTEBOOK (window->notebook_selected), window->view)); /* take focus on the new view */ gtk_widget_grab_focus (window->view); } static void thunar_window_notebook_switch_page (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)); /* leave if nothing changed or tab from other split-view is selected as * thunar_window_notebook_select_current_page() is going to take care of that */ if ((window->view == page) || (window->notebook_selected != notebook)) return; /* switch ti the new view (will as well focus the new page) */ thunar_window_switch_current_view (window, page); } static void thunar_window_notebook_show_tabs (ThunarWindow *window) { gboolean always_show_tabs; _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); _thunar_return_if_fail (window->notebook_left || window->notebook_right); g_object_get (G_OBJECT (window->preferences), "misc-always-show-tabs", &always_show_tabs, NULL); /* check both notebooks, maybe not the selected one get clicked */ if (window->notebook_left) { gtk_notebook_set_show_tabs (GTK_NOTEBOOK (window->notebook_left), gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook_left)) > 1 || always_show_tabs); } if (window->notebook_right) { gtk_notebook_set_show_tabs (GTK_NOTEBOOK (window->notebook_right), gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook_right)) > 1 || always_show_tabs); } } static void thunar_window_history_changed (ThunarWindow *window) { ThunarHistory *history; _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); if (window->view == NULL) return; history = thunar_standard_view_get_history (THUNAR_STANDARD_VIEW (window->view)); if (history == NULL) return; if (window->location_toolbar_item_back != NULL) gtk_widget_set_sensitive (window->location_toolbar_item_back, thunar_history_has_back (history)); if (window->location_toolbar_item_forward != NULL) gtk_widget_set_sensitive (window->location_toolbar_item_forward, thunar_history_has_forward (history)); } 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_selected == 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_open_new_tab), 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_left == notebook || window->notebook_right == notebook); /* drop connected signals */ g_signal_handlers_disconnect_by_data (page, window); /* skip selecting another page when the window is being destroyed */ if (gtk_widget_in_destruction (GTK_WIDGET (window))) return; n_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook)); if (n_pages == 0) { if (thunar_window_split_view_is_active (window)) { /* select the other notebook if the current gets closed */ if (notebook == window->notebook_selected) thunar_window_paned_notebooks_switch (window); thunar_window_action_toggle_split_view (window); } else { /* destroy the window */ gtk_widget_destroy (GTK_WIDGET (window)); } } else { /* page from the other notebook was removed */ if (notebook != window->notebook_selected) thunar_window_paned_notebooks_switch (window); else /* this page removed -> select next page */ thunar_window_notebook_select_current_page (window); /* update tab visibility */ thunar_window_notebook_show_tabs (window); } } 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; /* switch focus to parent notebook */ if (window->notebook_selected != notebook) thunar_window_paned_notebooks_switch (window); /* do not forward double-click events to the parent widget "paned_notebooks" * to avoid resetting the split view separator when the clicks occurred on a tab */ if (event->button == 1 && event->type == GDK_2BUTTON_PRESS) return TRUE; 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 (notebook, window); } return TRUE; } return FALSE; } static gboolean thunar_window_notebook_popup_menu (GtkWidget *notebook, ThunarWindow *window) { GtkWidget *menu; menu = gtk_menu_new (); gtk_menu_set_accel_group (GTK_MENU (menu), window->accel_group); xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_NEW_TAB), G_OBJECT (window), GTK_MENU_SHELL (menu)); xfce_gtk_menu_append_separator (GTK_MENU_SHELL (menu)); xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_DETACH_TAB), G_OBJECT (window), GTK_MENU_SHELL (menu)); xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_SWITCH_PREV_TAB), G_OBJECT (window), GTK_MENU_SHELL (menu)); xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_SWITCH_NEXT_TAB), G_OBJECT (window), GTK_MENU_SHELL (menu)); xfce_gtk_menu_append_separator (GTK_MENU_SHELL (menu)); xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_CLOSE_TAB), G_OBJECT (window), GTK_MENU_SHELL (menu)); gtk_widget_show_all (menu); thunar_gtk_menu_run (GTK_MENU (menu)); 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; GdkMonitor *monitor; 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_selected == 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, TRUE); 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 = gdk_display_get_monitor_at_point (gdk_display_get_default (), x, y); gdk_monitor_get_geometry (monitor, &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_selected; } static void thunar_window_notebook_update_title (GtkWidget *label) { ThunarWindow *window; GtkWidget *view; GBinding *binding; gboolean show_full_path; window = g_object_get_data (G_OBJECT (label), "window"); view = g_object_get_data (G_OBJECT (label), "view"); binding = g_object_get_data (G_OBJECT (label), "binding"); _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); /* set tab title according to window preferences */ g_object_get (G_OBJECT (window->preferences), "misc-full-path-in-tab-title", &show_full_path, NULL); if (binding != NULL) g_binding_unbind (binding); if (show_full_path) { binding = g_object_bind_property (G_OBJECT (view), "full-parsed-path", G_OBJECT (label), "label", G_BINDING_SYNC_CREATE); gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_START); } else { binding = g_object_bind_property (G_OBJECT (view), "display-name", G_OBJECT (label), "label", G_BINDING_SYNC_CREATE); gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END); } g_object_set_data (G_OBJECT (label), "binding", binding); } static GtkWidget * thunar_window_create_view (ThunarWindow *window, ThunarFile *directory, GType view_type) { ThunarColumn sort_column; GtkSortType sort_order; ThunarHistory *history = NULL; GtkWidget *view; _thunar_return_val_if_fail (THUNAR_IS_FILE (directory), NULL); _thunar_return_val_if_fail (view_type != G_TYPE_NONE, NULL); /* If there is already an active view, inherit settings and history from that */ if (window->view == NULL) { g_object_get (G_OBJECT (window->preferences), "last-sort-column", &sort_column, "last-sort-order", &sort_order, NULL); } else { g_object_get (window->view, "sort-column", &sort_column, "sort-order", &sort_order, NULL); history = thunar_standard_view_copy_history (THUNAR_STANDARD_VIEW (window->view)); } /* allocate and setup a new view */ view = g_object_new (view_type, "current-directory", directory, "sort-column-default", sort_column, "sort-order-default", sort_order, NULL); thunar_view_set_show_hidden (THUNAR_VIEW (view), window->show_hidden); /* set the history of the view if a history is provided */ if (history != NULL) thunar_standard_view_set_history (THUNAR_STANDARD_VIEW (view), history); return view; } static void thunar_window_notebook_insert_page (ThunarWindow *window, gint position, GtkWidget *view) { GtkWidget *label; GtkWidget *label_box; GtkWidget *button; GtkWidget *spinner; GtkWidget *icon; _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); label_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); label = gtk_label_new (NULL); g_object_set_data (G_OBJECT (label), "window", window); g_object_set_data (G_OBJECT (label), "view", view); g_object_set_data (G_OBJECT (label), "binding", NULL); thunar_window_notebook_update_title (label); g_signal_connect_object (window->preferences, "notify::misc-full-path-in-tab-title", G_CALLBACK (thunar_window_notebook_update_title), label, G_CONNECT_SWAPPED); g_object_bind_property (G_OBJECT (view), "full-parsed-path", G_OBJECT (label), "tooltip-text", G_BINDING_SYNC_CREATE); gtk_widget_set_has_tooltip (label, TRUE); gtk_label_set_xalign (GTK_LABEL (label), 0.0f); gtk_widget_set_margin_start (GTK_WIDGET (label), 3); gtk_widget_set_margin_end (GTK_WIDGET (label), 3); gtk_widget_set_margin_top (GTK_WIDGET (label), 3); gtk_widget_set_margin_bottom (GTK_WIDGET (label), 3); 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); spinner = gtk_spinner_new (); gtk_box_pack_start (GTK_BOX (label_box), spinner, FALSE, FALSE, 0); gtk_widget_show (spinner); g_object_bind_property (G_OBJECT (spinner), "active", G_OBJECT (spinner), "visible", G_BINDING_SYNC_CREATE); g_object_bind_property (G_OBJECT (view), "searching", G_OBJECT (spinner), "active", G_BINDING_SYNC_CREATE); button = gtk_button_new (); gtk_box_pack_start (GTK_BOX (label_box), button, FALSE, FALSE, 0); gtk_widget_set_can_default (button, FALSE); gtk_widget_set_focus_on_click (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); icon = gtk_image_new_from_icon_name ("window-close-symbolic", GTK_ICON_SIZE_MENU); gtk_container_add (GTK_CONTAINER (button), icon); gtk_widget_show (icon); /* insert the new page */ gtk_notebook_insert_page (GTK_NOTEBOOK (window->notebook_selected), view, label_box, position); /* set tab child properties */ gtk_container_child_set (GTK_CONTAINER (window->notebook_selected), view, "tab-expand", TRUE, NULL); gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (window->notebook_selected), view, TRUE); gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (window->notebook_selected), view, TRUE); gtk_widget_show (view); } static void thunar_window_notebook_select_current_page (ThunarWindow *window) { gint current_page_n; GtkWidget *current_page; _thunar_return_if_fail (window->notebook_selected != NULL); current_page_n = gtk_notebook_get_current_page (GTK_NOTEBOOK (window->notebook_selected)); current_page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (window->notebook_selected), current_page_n); thunar_window_notebook_switch_page (window->notebook_selected, current_page, current_page_n, window); } static GtkWidget * thunar_window_paned_notebooks_add (ThunarWindow *window) { GtkWidget *notebook; _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), NULL); _thunar_return_val_if_fail (!thunar_window_split_view_is_active (window), NULL); notebook = gtk_notebook_new (); gtk_widget_set_hexpand (notebook, TRUE); gtk_widget_set_vexpand (notebook, TRUE); g_signal_connect (G_OBJECT (notebook), "switch-page", G_CALLBACK (thunar_window_notebook_switch_page), window); g_signal_connect (G_OBJECT (notebook), "page-added", G_CALLBACK (thunar_window_notebook_page_added), window); g_signal_connect (G_OBJECT (notebook), "page-removed", G_CALLBACK (thunar_window_notebook_page_removed), window); g_signal_connect (G_OBJECT (notebook), "button-press-event", G_CALLBACK (thunar_window_notebook_button_press_event), window); g_signal_connect (G_OBJECT (notebook), "popup-menu", G_CALLBACK (thunar_window_notebook_popup_menu), window); g_signal_connect (G_OBJECT (notebook), "create-window", G_CALLBACK (thunar_window_notebook_create_window), window); gtk_notebook_set_show_border (GTK_NOTEBOOK (notebook), FALSE); gtk_notebook_set_scrollable (GTK_NOTEBOOK (notebook), TRUE); gtk_container_set_border_width (GTK_CONTAINER (notebook), 0); gtk_notebook_set_group_name (GTK_NOTEBOOK (notebook), "thunar-tabs"); gtk_widget_show (notebook); if (window->notebook_left == NULL) { gtk_paned_pack1 (GTK_PANED (window->paned_notebooks), notebook, TRUE, FALSE); window->notebook_left = notebook; } else if (window->notebook_right == NULL) { gtk_paned_pack2 (GTK_PANED (window->paned_notebooks), notebook, TRUE, FALSE); window->notebook_right = notebook; } return notebook; } void thunar_window_paned_notebooks_switch (ThunarWindow *window) { GtkWidget *new_curr_notebook = NULL; _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); if (!thunar_window_split_view_is_active (window)) return; if (window->notebook_selected == window->notebook_left) new_curr_notebook = window->notebook_right; else if (window->notebook_selected == window->notebook_right) new_curr_notebook = window->notebook_left; if (new_curr_notebook) { thunar_window_paned_notebooks_indicate_focus (window, new_curr_notebook); /* select and activate selected notebook */ window->notebook_selected = new_curr_notebook; thunar_window_notebook_select_current_page (window); } } void thunar_window_focus_view (ThunarWindow *window, GtkWidget *view) { GtkWidget *selected_notebook; _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); if (!thunar_window_split_view_is_active (window)) return; selected_notebook = gtk_widget_get_ancestor (view, GTK_TYPE_NOTEBOOK); if (selected_notebook == window->notebook_selected) return; thunar_window_paned_notebooks_switch (window); } static void thunar_window_paned_notebooks_indicate_focus (ThunarWindow *window, GtkWidget *notebook) { _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); _thunar_return_if_fail (GTK_IS_NOTEBOOK (notebook)); _thunar_return_if_fail (thunar_window_split_view_is_active (window)); /* add style class to inactive pane */ gtk_style_context_remove_class (gtk_widget_get_style_context (notebook), "split-view-inactive-pane"); if (notebook == window->notebook_left) gtk_style_context_add_class (gtk_widget_get_style_context (window->notebook_right), "split-view-inactive-pane"); if (notebook == window->notebook_right) gtk_style_context_add_class (gtk_widget_get_style_context (window->notebook_left), "split-view-inactive-pane"); gtk_widget_grab_focus (notebook); } static gboolean thunar_window_split_view_is_active (ThunarWindow *window) { _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); return (window->notebook_left && window->notebook_right); } static gboolean thunar_window_paned_notebooks_update_orientation (ThunarWindow *window) { gboolean vertical_split_panes; _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); g_object_get (G_OBJECT (window->preferences), "misc-vertical-split-pane", &vertical_split_panes, NULL); if (vertical_split_panes) gtk_orientable_set_orientation (GTK_ORIENTABLE (window->paned_notebooks), GTK_ORIENTATION_VERTICAL); else gtk_orientable_set_orientation (GTK_ORIENTABLE (window->paned_notebooks), GTK_ORIENTATION_HORIZONTAL); return TRUE; } void thunar_window_notebook_add_new_tab (ThunarWindow *window, ThunarFile *directory, ThunarNewTabBehavior behavior) { ThunarHistory *history = NULL; GtkWidget *view; gint page_num; GType view_type; gboolean switch_to_new_tab; if (thunar_file_is_directory (directory) == FALSE) { char *uri = thunar_file_dup_uri (directory); g_warning ("Skipping to add tab. The passed URI is not a directory: %s", uri); g_free (uri); return; } /* find the correct view type */ view_type = thunar_window_view_type_for_directory (window, directory); /* insert the new view */ page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (window->notebook_selected)); view = thunar_window_create_view (window, directory, view_type); /* history is updated only on 'change-directory' signal. */ /* For inserting a new tab, we need to update it manually */ history = thunar_standard_view_get_history (THUNAR_STANDARD_VIEW (view)); if (G_LIKELY (history)) thunar_history_add (history, directory); thunar_window_notebook_insert_page (window, page_num + 1, view); /* switch to the new view */ g_object_get (G_OBJECT (window->preferences), "misc-switch-to-new-tab", &switch_to_new_tab, NULL); if ((behavior == THUNAR_NEW_TAB_BEHAVIOR_FOLLOW_PREFERENCE && switch_to_new_tab == TRUE) || behavior == THUNAR_NEW_TAB_BEHAVIOR_SWITCH) { page_num = gtk_notebook_page_num (GTK_NOTEBOOK (window->notebook_selected), view); thunar_window_notebook_set_current_tab (window, page_num); } /* take focus on the new view */ gtk_widget_grab_focus (view); } void thunar_window_notebook_open_new_tab (ThunarWindow *window, ThunarFile *directory) { thunar_window_notebook_add_new_tab (window, directory, THUNAR_NEW_TAB_BEHAVIOR_FOLLOW_PREFERENCE); } /** * thunar_window_notebook_toggle_split_view: * @window : a #ThunarWindow instance. * * Toggles the split-view functionality for @window. **/ void thunar_window_notebook_toggle_split_view (ThunarWindow *window) { thunar_window_action_toggle_split_view (window); } /** * thunar_window_notebook_remove_tab: * @window : a #ThunarWindow instance. * @tab : the page index as a #gint. * * Removes @tab page from the currently selected notebook. **/ void thunar_window_notebook_remove_tab (ThunarWindow *window, gint tab) { gtk_notebook_remove_page (GTK_NOTEBOOK (window->notebook_selected), tab); } /** * thunar_window_notebook_set_current_tab: * @window : a #ThunarWindow instance. * @tab : the page index as a #gint. * * Switches to the @tab page in the currently selected notebook. **/ void thunar_window_notebook_set_current_tab (ThunarWindow *window, gint tab) { gtk_notebook_set_current_page (GTK_NOTEBOOK (window->notebook_selected), tab); } void thunar_window_update_directories (ThunarWindow *window, ThunarFile *old_directory, ThunarFile *new_directory) { GtkWidget *view; ThunarFile *directory; gint n; gint n_pages; gint active_page; _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); _thunar_return_if_fail (THUNAR_IS_FILE (old_directory)); _thunar_return_if_fail (THUNAR_IS_FILE (new_directory)); n_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook_selected)); if (G_UNLIKELY (n_pages == 0)) return; active_page = gtk_notebook_get_current_page (GTK_NOTEBOOK (window->notebook_selected)); for (n = 0; n < n_pages; n++) { /* get the view */ view = gtk_notebook_get_nth_page (GTK_NOTEBOOK (window->notebook_selected), n); if (!THUNAR_IS_NAVIGATOR (view)) continue; /* get the directory of the view */ directory = thunar_navigator_get_current_directory (THUNAR_NAVIGATOR (view)); if (!THUNAR_IS_FILE (directory)) continue; /* if it matches the old directory, change to the new one */ if (directory == old_directory) { if (n == active_page) thunar_navigator_change_directory (THUNAR_NAVIGATOR (view), new_directory); else thunar_navigator_set_current_directory (THUNAR_NAVIGATOR (view), new_directory); } } } static void thunar_window_update_location_bar_visible (ThunarWindow *window) { gchar *last_location_bar = NULL; g_object_get (window->preferences, "last-location-bar", &last_location_bar, NULL); if (g_strcmp0 (last_location_bar, g_type_name (G_TYPE_NONE)) == 0) { gtk_widget_hide (window->location_toolbar); if (window->view != NULL) gtk_widget_grab_focus (window->view); } else gtk_widget_show (window->location_toolbar); g_free (last_location_bar); } static void thunar_window_update_window_icon (ThunarWindow *window) { gboolean change_window_icon; GtkIconTheme *icon_theme; const gchar *icon_name = "folder"; g_object_get (window->preferences, "misc-change-window-icon", &change_window_icon, NULL); if (change_window_icon) { icon_theme = gtk_icon_theme_get_for_screen (gtk_window_get_screen (GTK_WINDOW (window))); icon_name = thunar_file_get_icon_name (window->current_directory, THUNAR_FILE_ICON_STATE_DEFAULT, icon_theme); } gtk_window_set_icon_name (GTK_WINDOW (window), icon_name); } static void thunar_window_install_sidepane (ThunarWindow *window, ThunarSidepaneType type) { GtkStyleContext *context; _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); /* drop the previous side pane (if any) */ if (G_UNLIKELY (window->sidepane != NULL)) { gtk_widget_destroy (window->sidepane); window->sidepane = NULL; } /* check if we have a new sidepane widget */ if (G_LIKELY (type == THUNAR_SIDEPANE_TYPE_SHORTCUTS || type == THUNAR_SIDEPANE_TYPE_TREE)) { /* allocate the new side pane widget */ if (type == THUNAR_SIDEPANE_TYPE_SHORTCUTS) window->sidepane = g_object_new (THUNAR_TYPE_SHORTCUTS_PANE, NULL); else window->sidepane = g_object_new (THUNAR_TYPE_TREE_PANE, NULL); gtk_widget_set_size_request (window->sidepane, 0, -1); g_object_bind_property (G_OBJECT (window), "current-directory", G_OBJECT (window->sidepane), "current-directory", G_BINDING_SYNC_CREATE); 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_open_new_tab), window); context = gtk_widget_get_style_context (window->sidepane); gtk_style_context_add_class (context, "sidebar"); gtk_box_pack_start (GTK_BOX (window->sidepane_box), window->sidepane, TRUE, TRUE, 0); gtk_widget_show (window->sidepane); gtk_widget_show (window->sidepane_box); /* connect the side pane widget to the view (if any) */ if (G_LIKELY (window->view != NULL)) thunar_window_binding_create (window, window->view, "selected-files", window->sidepane, "selected-files", G_BINDING_SYNC_CREATE); /* apply show_hidden config to tree pane */ if (type == THUNAR_SIDEPANE_TYPE_TREE) thunar_side_pane_set_show_hidden (THUNAR_SIDE_PANE (window->sidepane), window->show_hidden); } else gtk_widget_hide (window->sidepane_box); /* remember the setting */ window->sidepane_type = type; if (gtk_widget_get_visible (GTK_WIDGET (window))) g_object_set (G_OBJECT (window->preferences), "last-side-pane", type, NULL); } static gchar * thunar_window_bookmark_get_accel_path (GFile *bookmark_file) { GChecksum *checksum; gchar *uri; gchar *accel_path; const gchar *unique_name; _thunar_return_val_if_fail (G_IS_FILE (bookmark_file), NULL); /* create unique id based on the uri */ uri = g_file_get_uri (bookmark_file); checksum = g_checksum_new (G_CHECKSUM_MD5); g_checksum_update (checksum, (const guchar *) uri, strlen (uri)); unique_name = g_checksum_get_string (checksum); accel_path = g_strconcat ("/ThunarBookmarks/", unique_name, NULL); g_free (uri); g_checksum_free (checksum); return accel_path; } static void thunar_window_menu_add_bookmarks (ThunarWindow *window, GtkMenuShell *view_menu) { GList *lp; ThunarBookmark *bookmark; ThunarFile *thunar_file; gchar *parse_name; gchar *accel_path; gchar *tooltip; gchar *name; GtkIconTheme *icon_theme; const gchar *icon_name; _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); for (lp = window->bookmarks; lp != NULL; lp = lp->next) { bookmark = lp->data; name = g_strdup (bookmark->name); accel_path = thunar_window_bookmark_get_accel_path (bookmark->g_file); parse_name = g_file_get_parse_name (bookmark->g_file); tooltip = g_strdup_printf (_("Open the location \"%s\""), parse_name); g_free (parse_name); if (g_file_has_uri_scheme (bookmark->g_file, "file")) { thunar_file = thunar_file_get (bookmark->g_file, NULL); if (name == NULL) { if (thunar_file != NULL) name = g_strdup (thunar_file_get_display_name (thunar_file)); else name = g_file_get_basename (bookmark->g_file); } icon_theme = gtk_icon_theme_get_for_screen (gtk_window_get_screen (GTK_WINDOW (window))); icon_name = thunar_file == NULL ? "folder" : thunar_file_get_icon_name (thunar_file, THUNAR_FILE_ICON_STATE_DEFAULT, icon_theme); if (thunar_file != NULL) g_object_unref (thunar_file); } else { if (name == NULL) name = thunar_g_file_get_display_name_remote (bookmark->g_file); icon_name = "folder-remote"; } xfce_gtk_image_menu_item_new_from_icon_name (name, tooltip, accel_path, G_CALLBACK (thunar_window_action_open_bookmark), G_OBJECT (bookmark->g_file), icon_name, view_menu); g_free (name); g_free (tooltip); g_free (accel_path); } } static ThunarBookmark * thunar_window_bookmark_add (ThunarWindow *window, GFile *g_file, const gchar *name) { ThunarBookmark *bookmark; bookmark = g_slice_new0 (ThunarBookmark); bookmark->g_file = g_object_ref (g_file); bookmark->name = g_strdup (name); window->bookmarks = g_list_append (window->bookmarks, bookmark); return bookmark; } static void thunar_window_free_bookmarks (ThunarWindow *window) { GList *lp; ThunarBookmark *bookmark; for (lp = window->bookmarks; lp != NULL; lp = lp->next) { bookmark = lp->data; g_object_unref (bookmark->g_file); g_free (bookmark->name); g_slice_free (ThunarBookmark, lp->data); } g_list_free (window->bookmarks); window->bookmarks = NULL; } static void thunar_window_update_bookmark (GFile *g_file, const gchar *name, gint line_num, gpointer user_data) { ThunarWindow *window = THUNAR_WINDOW (user_data); gchar *accel_path; XfceGtkActionEntry entry[1]; _thunar_return_if_fail (G_IS_FILE (g_file)); _thunar_return_if_fail (name == NULL || g_utf8_validate (name, -1, NULL)); _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); /* Add the bookmark to our internal list of bookmarks */ thunar_window_bookmark_add (window, g_file, name); /* Add ref to window to each g_file, will be needed in callback */ g_object_set_data_full (G_OBJECT (g_file), I_ ("thunar-window"), window, NULL); /* Build a minimal XfceGtkActionEntry in order to be able to use the methods below */ accel_path = thunar_window_bookmark_get_accel_path (g_file); entry[0].accel_path = accel_path; entry[0].callback = G_CALLBACK (thunar_window_action_open_bookmark); entry[0].default_accelerator = ""; /* Add entry, so that the bookmark can loaded/saved to acceels.scm (will be skipped if already available)*/ xfce_gtk_accel_map_add_entries (entry, G_N_ELEMENTS (entry)); /* Link action with callback */ xfce_gtk_accel_group_disconnect_action_entries (window->accel_group, entry, G_N_ELEMENTS (entry)); xfce_gtk_accel_group_connect_action_entries (window->accel_group, entry, G_N_ELEMENTS (entry), g_file); g_free (accel_path); } static void thunar_window_update_bookmarks (ThunarWindow *window) { _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); thunar_window_free_bookmarks (window); /* re-create our internal bookmarks according to the bookmark file */ thunar_util_load_bookmarks (window->bookmark_file, thunar_window_update_bookmark, window); } static void thunar_window_start_open_location (ThunarWindow *window, const gchar *initial_text) { _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); /* setup a search if required */ if (initial_text != NULL && thunar_util_is_a_search_query (initial_text) == TRUE) { GType view_type; window->is_searching = TRUE; /* workaround the slowness of ExoIconView */ view_type = window->view_type; thunar_window_action_detailed_view (window); thunar_standard_view_save_view_type (THUNAR_STANDARD_VIEW (window->view), view_type); /* save it in the new view */ /* end of workaround */ /* temporary show the location toolbar, even if it is normally hidden */ gtk_widget_show (window->location_toolbar); thunar_location_bar_request_entry (THUNAR_LOCATION_BAR (window->location_bar), initial_text, FALSE); thunar_window_update_search (window); thunar_action_manager_set_searching (window->action_mgr, TRUE); /* the check is useless as long as the workaround is in place */ if (THUNAR_IS_DETAILS_VIEW (window->view)) thunar_details_view_set_location_column_visible (THUNAR_DETAILS_VIEW (window->view), TRUE); } else /* location edit */ { gchar *last_location_bar = NULL; gboolean temporary_till_focus_lost = FALSE; /* If the style is already 'location entry', we dont need to care about 'focus-lost' */ g_object_get (window->preferences, "last-location-bar", &last_location_bar, NULL); if (g_strcmp0 (last_location_bar, g_type_name (THUNAR_TYPE_LOCATION_ENTRY)) != 0) temporary_till_focus_lost = TRUE; g_free (last_location_bar); thunar_window_action_cancel_search (window); /* temporary show the location toolbar, even if it is normally hidden */ gtk_widget_show (window->location_toolbar); thunar_location_bar_request_entry (THUNAR_LOCATION_BAR (window->location_bar), initial_text, temporary_till_focus_lost); } } static void thunar_window_resume_search (ThunarWindow *window, const gchar *initial_text) { _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); /* when setting up the location entry do not resent the search query to the standard view, there is a search ongoing */ window->ignore_next_search_update = TRUE; /* continue searching */ window->is_searching = TRUE; /* temporary show the location toolbar, even if it is normally hidden */ gtk_widget_show (window->location_toolbar); thunar_location_bar_request_entry (THUNAR_LOCATION_BAR (window->location_bar), initial_text, FALSE); /* change to search UI and options */ g_free (window->search_query); window->search_query = thunar_location_bar_get_search_query (THUNAR_LOCATION_BAR (window->location_bar)); if (window->catfish_search_button != NULL) gtk_widget_show (window->catfish_search_button); thunar_action_manager_set_searching (window->action_mgr, TRUE); /* the check is useless as long as the workaround is in place */ if (THUNAR_IS_DETAILS_VIEW (window->view)) thunar_details_view_set_location_column_visible (THUNAR_DETAILS_VIEW (window->view), TRUE); g_signal_handlers_block_by_func (G_OBJECT (window->location_toolbar_item_search), thunar_window_action_search, window); gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (window->location_toolbar_item_search), TRUE); g_signal_handlers_unblock_by_func (G_OBJECT (window->location_toolbar_item_search), thunar_window_action_search, window); } void thunar_window_update_search (ThunarWindow *window) { if (window->ignore_next_search_update == TRUE) { window->ignore_next_search_update = FALSE; return; } g_free (window->search_query); window->search_query = thunar_location_bar_get_search_query (THUNAR_LOCATION_BAR (window->location_bar)); thunar_standard_view_set_searching (THUNAR_STANDARD_VIEW (window->view), window->search_query); if (window->search_query != NULL && g_strcmp0 (window->search_query, "") != 0 && window->catfish_search_button != NULL) gtk_widget_show (window->catfish_search_button); else if (window->catfish_search_button != NULL) gtk_widget_hide (window->catfish_search_button); } static gint thunar_window_reset_view_type_idle (gpointer window_ptr) { ThunarWindow *window = window_ptr; /* null check for the same reason as thunar_standard_view_set_searching */ if (window->view != NULL) { if (thunar_standard_view_get_saved_view_type (THUNAR_STANDARD_VIEW (window->view)) != 0) thunar_window_action_view_changed (window, thunar_standard_view_get_saved_view_type (THUNAR_STANDARD_VIEW (window->view))); thunar_standard_view_save_view_type (THUNAR_STANDARD_VIEW (window->view), 0); } return G_SOURCE_REMOVE; } static void thunar_window_reset_view_type_idle_destroyed (gpointer data) { _thunar_return_if_fail (THUNAR_IS_WINDOW (data)); THUNAR_WINDOW (data)->reset_view_type_idle_id = 0; } gboolean thunar_window_action_cancel_search (ThunarWindow *window) { ThunarApplication *application; _thunar_return_val_if_fail (THUNAR_IS_LOCATION_BAR (window->location_bar), FALSE); _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); if (window->is_searching == FALSE) return FALSE; thunar_location_bar_cancel_search (THUNAR_LOCATION_BAR (window->location_bar)); thunar_standard_view_set_searching (THUNAR_STANDARD_VIEW (window->view), NULL); thunar_action_manager_set_searching (window->action_mgr, FALSE); if (window->catfish_search_button != NULL) gtk_widget_hide (window->catfish_search_button); g_free (window->search_query); window->search_query = NULL; if (THUNAR_IS_DETAILS_VIEW (window->view)) { gboolean is_recent = thunar_file_is_recent (window->current_directory); thunar_details_view_set_recency_column_visible (THUNAR_DETAILS_VIEW (window->view), is_recent); thunar_details_view_set_location_column_visible (THUNAR_DETAILS_VIEW (window->view), is_recent); } window->is_searching = FALSE; if (window->reset_view_type_idle_id == 0) { window->reset_view_type_idle_id = g_idle_add_full (G_PRIORITY_LOW, thunar_window_reset_view_type_idle, window, thunar_window_reset_view_type_idle_destroyed); } g_signal_handlers_block_by_func (G_OBJECT (window->location_toolbar_item_search), thunar_window_action_search, window); gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (window->location_toolbar_item_search), FALSE); g_signal_handlers_unblock_by_func (G_OBJECT (window->location_toolbar_item_search), thunar_window_action_search, window); /* bring back the original location bar style (relevant if the bar is hidden) */ thunar_window_update_location_bar_visible (window); /* tidy up memory after a search */ application = thunar_application_get (); thunar_application_malloc_trim_on_idle (application); g_object_unref (application); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_window_action_open_new_tab (ThunarWindow *window, GtkWidget *menu_item) { /* open new tab with current directory as default */ thunar_window_notebook_add_new_tab (window, thunar_window_get_current_directory (window), THUNAR_NEW_TAB_BEHAVIOR_SWITCH); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_window_action_open_new_window (ThunarWindow *window, GtkWidget *menu_item) { ThunarApplication *application; ThunarHistory *history; ThunarWindow *new_window; ThunarFile *start_file; /* popup a new window */ application = thunar_application_get (); new_window = THUNAR_WINDOW (thunar_application_open_window (application, window->current_directory, gtk_widget_get_screen (GTK_WIDGET (window)), NULL, TRUE)); g_object_unref (G_OBJECT (application)); /* if we have no origin view we are done */ if (window->view == NULL) return TRUE; /* let the view of the new window inherit the history of the origin view */ history = thunar_standard_view_copy_history (THUNAR_STANDARD_VIEW (window->view)); if (history != NULL) { thunar_standard_view_set_history (THUNAR_STANDARD_VIEW (new_window->view), history); thunar_window_history_changed (new_window); /* connect the new window to the new history */ new_window->signal_handler_id_history_changed = g_signal_connect_swapped (G_OBJECT (history), "history-changed", G_CALLBACK (thunar_window_history_changed), new_window); } /* determine the first visible file in the current window */ if (thunar_view_get_visible_range (THUNAR_VIEW (window->view), &start_file, NULL)) { /* scroll the new window to the same file */ thunar_view_scroll_to_file (THUNAR_VIEW (new_window->view), start_file, FALSE, TRUE, 0.1f, 0.1f); /* release the file reference */ g_object_unref (G_OBJECT (start_file)); } /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_window_action_detach_tab (ThunarWindow *window, GtkWidget *menu_item) { GtkWidget *notebook; GtkWidget *label; GtkWidget *view = window->view; _thunar_return_val_if_fail (THUNAR_IS_VIEW (view), FALSE); _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); /* create a new window */ notebook = thunar_window_notebook_create_window (window->notebook_selected, view, -1, -1, window); if (notebook == NULL) return TRUE; /* get the current label */ label = gtk_notebook_get_tab_label (GTK_NOTEBOOK (window->notebook_selected), view); _thunar_return_val_if_fail (GTK_IS_WIDGET (label), FALSE); /* 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_selected), 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); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_window_action_close_all_windows (ThunarWindow *window, GtkWidget *menu_item) { ThunarApplication *application; GList *windows; /* query the list of currently open windows */ application = thunar_application_get (); windows = thunar_application_get_windows (application); g_object_unref (G_OBJECT (application)); /* destroy all open windows */ g_list_free_full (windows, (GDestroyNotify) gtk_widget_destroy); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_window_action_close_tab (ThunarWindow *window, GtkWidget *menu_item) { gboolean response; if (thunar_window_split_view_is_active (window)) { if (window->view != NULL) gtk_widget_destroy (window->view); } else { if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook_selected)) == 1) { response = thunar_window_delete (GTK_WIDGET (window), NULL, NULL); if (response == FALSE) gtk_widget_destroy (GTK_WIDGET (window)); } else if (window->view != NULL) gtk_widget_destroy (window->view); } /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_window_action_close_window (ThunarWindow *window, GtkWidget *menu_item) { gboolean response; response = thunar_window_delete (GTK_WIDGET (window), NULL, NULL); if (response == FALSE) gtk_widget_destroy (GTK_WIDGET (window)); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_window_action_undo (ThunarWindow *window, GtkWidget *menu_item) { thunar_job_operation_history_undo (GTK_WINDOW (window)); return TRUE; /* return value required in case of shortcut activation, in order to signal that the accel key got handled */ } static gboolean thunar_window_action_redo (ThunarWindow *window, GtkWidget *menu_item) { thunar_job_operation_history_redo (GTK_WINDOW (window)); return TRUE; /* return value required in case of shortcut activation, in order to signal that the accel key got handled */ } static gboolean thunar_window_action_preferences (ThunarWindow *window, GtkWidget *menu_item) { GtkWidget *dialog; ThunarApplication *application; _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); /* allocate and display a preferences dialog */; dialog = thunar_preferences_dialog_new (GTK_WINDOW (window)); gtk_widget_show (dialog); /* ...and let the application take care of it */ application = thunar_application_get (); thunar_application_take_window (application, GTK_WINDOW (dialog)); g_object_unref (G_OBJECT (application)); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_window_action_reload (ThunarWindow *window, GtkWidget *menu_item) { gboolean result; _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); /* force the view to reload */ g_signal_emit (G_OBJECT (window), window_signals[RELOAD], 0, TRUE, &result); /* update the location bar to show the current directory */ if (window->location_bar != NULL) g_object_notify (G_OBJECT (window->location_bar), "current-directory"); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_window_action_toggle_split_view (ThunarWindow *window) { ThunarFile *directory; gint page_num, last_splitview_separator_position; GType view_type; GtkWidget *view; _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); _thunar_return_val_if_fail (window->view_type != G_TYPE_NONE, FALSE); if (thunar_window_split_view_is_active (window)) { GtkWidget *notebook_to_close = window->notebook_selected == window->notebook_left ? window->notebook_right : window->notebook_left; gint tabs_to_close = gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook_to_close)); if (tabs_to_close > 1) { gboolean confirm_close_multiple_tabs; g_object_get (G_OBJECT (window->preferences), "misc-confirm-close-multiple-tabs", &confirm_close_multiple_tabs, NULL); if (confirm_close_multiple_tabs && thunar_dialog_confirm_close_split_pane_tabs (GTK_WINDOW (window)) == GTK_RESPONSE_CANCEL) return TRUE; } gtk_widget_destroy (notebook_to_close); if (window->notebook_selected == window->notebook_left) window->notebook_right = NULL; else if (window->notebook_selected == window->notebook_right) window->notebook_left = NULL; gtk_notebook_set_show_border (GTK_NOTEBOOK (window->notebook_selected), FALSE); g_signal_handlers_disconnect_by_func (window->paned_notebooks, thunar_window_save_paned_notebooks, window); g_signal_handlers_disconnect_by_func (window->paned_notebooks, thunar_window_paned_notebooks_button_press_event, NULL); } else { window->notebook_selected = thunar_window_paned_notebooks_add (window); directory = thunar_window_get_current_directory (window); /* find the correct view type */ view_type = thunar_window_view_type_for_directory (window, directory); /* insert the new view */ page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (window->notebook_selected)); view = thunar_window_create_view (window, directory, view_type); thunar_window_notebook_insert_page (window, page_num + 1, view); /* restore the last separator position */ g_object_get (G_OBJECT (window->preferences), "last-splitview-separator-position", &last_splitview_separator_position, NULL); if (last_splitview_separator_position <= 0) { /* prevent notebook expand on tab creation */ last_splitview_separator_position = thunar_gtk_orientable_get_center_pos (GTK_ORIENTABLE (window->paned_notebooks)); } gtk_paned_set_position (GTK_PANED (window->paned_notebooks), last_splitview_separator_position); /* keep focus on the first notebook */ thunar_window_paned_notebooks_switch (window); g_signal_connect_swapped (window->paned_notebooks, "accept-position", G_CALLBACK (thunar_window_save_paned_notebooks), window); g_signal_connect_swapped (window->paned_notebooks, "button-release-event", G_CALLBACK (thunar_window_save_paned_notebooks), window); g_signal_connect (window->paned_notebooks, "button-press-event", G_CALLBACK (thunar_window_paned_notebooks_button_press_event), NULL); } if (thunar_window_split_view_is_active (window) != gtk_toggle_tool_button_get_active (GTK_TOGGLE_TOOL_BUTTON (window->location_toolbar_item_split_view))) { g_signal_handlers_block_by_func (window->location_toolbar_item_split_view, get_action_entry (THUNAR_WINDOW_ACTION_VIEW_SPLIT)->callback, window); gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (window->location_toolbar_item_split_view), thunar_window_split_view_is_active (window)); g_signal_handlers_unblock_by_func (window->location_toolbar_item_split_view, get_action_entry (THUNAR_WINDOW_ACTION_VIEW_SPLIT)->callback, window); } /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_window_action_locationbar_entry (ThunarWindow *window) { gchar *last_location_bar; gboolean entry_checked; _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); g_object_get (window->preferences, "last-location-bar", &last_location_bar, NULL); entry_checked = (g_strcmp0 (last_location_bar, g_type_name (THUNAR_TYPE_LOCATION_ENTRY)) == 0); g_free (last_location_bar); thunar_window_action_cancel_search (window); if (entry_checked) g_object_set (window->preferences, "last-location-bar", g_type_name (G_TYPE_NONE), NULL); else g_object_set (window->preferences, "last-location-bar", g_type_name (THUNAR_TYPE_LOCATION_ENTRY), NULL); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_window_action_locationbar_buttons (ThunarWindow *window) { gchar *last_location_bar; gboolean buttons_checked; _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); g_object_get (window->preferences, "last-location-bar", &last_location_bar, NULL); buttons_checked = (g_strcmp0 (last_location_bar, g_type_name (THUNAR_TYPE_LOCATION_BUTTONS)) == 0); g_free (last_location_bar); thunar_window_action_cancel_search (window); if (buttons_checked) g_object_set (window->preferences, "last-location-bar", g_type_name (G_TYPE_NONE), NULL); else g_object_set (window->preferences, "last-location-bar", g_type_name (THUNAR_TYPE_LOCATION_BUTTONS), NULL); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_window_action_shortcuts_changed (ThunarWindow *window) { _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); if (thunar_window_has_shortcut_sidepane (window)) thunar_window_install_sidepane (window, THUNAR_SIDEPANE_TYPE_HIDDEN_SHORTCUTS); else thunar_window_install_sidepane (window, THUNAR_SIDEPANE_TYPE_SHORTCUTS); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_window_action_tree_changed (ThunarWindow *window) { _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); if (thunar_window_has_tree_view_sidepane (window)) thunar_window_install_sidepane (window, THUNAR_SIDEPANE_TYPE_HIDDEN_TREE); else thunar_window_install_sidepane (window, THUNAR_SIDEPANE_TYPE_TREE); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_window_action_image_preview (ThunarWindow *window) { ThunarImagePreviewMode misc_image_preview_mode; gboolean image_preview_visible; _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); g_object_get (window->preferences, "misc-image-preview-mode", &misc_image_preview_mode, "last-image-preview-visible", &image_preview_visible, NULL); if (misc_image_preview_mode == THUNAR_IMAGE_PREVIEW_MODE_EMBEDDED) { gtk_widget_set_visible (window->sidepane_preview_image, !image_preview_visible); gtk_widget_set_visible (window->right_pane, FALSE); } else { gtk_widget_set_visible (window->sidepane_preview_image, FALSE); gtk_widget_set_visible (window->right_pane, !image_preview_visible); } g_object_set (G_OBJECT (window->preferences), "last-image-preview-visible", !image_preview_visible, NULL); /* to directly trigger a preview, in case an image currently is selected */ thunar_window_selection_changed (window); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } gboolean thunar_window_image_preview_mode_changed (ThunarWindow *window) { ThunarImagePreviewMode misc_image_preview_mode; gboolean last_image_preview_visible; _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); g_object_get (window->preferences, "last-image-preview-visible", &last_image_preview_visible, "misc-image-preview-mode", &misc_image_preview_mode, NULL); gtk_widget_set_visible (window->sidepane_preview_image, last_image_preview_visible && misc_image_preview_mode == THUNAR_IMAGE_PREVIEW_MODE_EMBEDDED); gtk_widget_set_visible (window->right_pane, last_image_preview_visible && misc_image_preview_mode == THUNAR_IMAGE_PREVIEW_MODE_STANDALONE); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static void image_preview_update (GtkWidget *parent, GtkAllocation *allocation, GtkWidget *image) { ThunarWindow *window = THUNAR_WINDOW (gtk_widget_get_toplevel (parent)); GdkPixbuf *scaled_preview; cairo_surface_t *surface; gint new_size; gint scale_factor; _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); /* there is no image to preview */ if (window->preview_image_pixbuf == NULL) return; if (allocation != NULL) { new_size = allocation->width < allocation->height ? allocation->width - 50 : allocation->height - 50; } else { GtkAllocation alloc; gtk_widget_get_allocation (parent, &alloc); if (alloc.width - 50 <= 0) /* the widget doesn't have any allocated space */ return; new_size = alloc.width < alloc.height ? alloc.width - 50 : alloc.height - 50; } scale_factor = gtk_widget_get_scale_factor (parent); scaled_preview = exo_gdk_pixbuf_scale_ratio (window->preview_image_pixbuf, new_size * scale_factor); surface = gdk_cairo_surface_create_from_pixbuf (scaled_preview, scale_factor, gtk_widget_get_window (parent)); gtk_image_set_from_surface (GTK_IMAGE (image), surface); g_object_unref (G_OBJECT (scaled_preview)); cairo_surface_destroy (surface); } static gboolean thunar_window_action_statusbar_changed (ThunarWindow *window) { gboolean statusbar_visible; _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); statusbar_visible = gtk_widget_get_visible (window->statusbar); gtk_widget_set_visible (window->statusbar, !statusbar_visible); g_object_set (G_OBJECT (window->preferences), "last-statusbar-visible", !statusbar_visible, NULL); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static void thunar_window_action_menubar_update (ThunarWindow *window) { _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); gtk_widget_set_visible (window->menubar, window->menubar_visible); } static gboolean thunar_window_action_menubar_changed (ThunarWindow *window) { _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); /* Dont rely on 'gtk_widget_set_visible', it will be wrong when the menubar is accessed via F10 */ window->menubar_visible = !window->menubar_visible; gtk_widget_set_visible (window->menubar, window->menubar_visible); gtk_widget_set_visible (window->location_toolbar_item_menu, !window->menubar_visible); g_object_set (G_OBJECT (window->preferences), "last-menubar-visible", window->menubar_visible, NULL); thunar_window_csd_update (window); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_window_action_show_toolbar_editor (ThunarWindow *window) { thunar_show_toolbar_editor (GTK_WIDGET (window), window->location_toolbar); return TRUE; } static gboolean thunar_window_action_clear_directory_specific_settings (ThunarWindow *window) { GType view_type; gboolean result; /* clear the settings */ thunar_file_clear_directory_specific_settings (window->current_directory); /* get the correct view type for the current directory */ view_type = thunar_window_view_type_for_directory (window, window->current_directory); /* force the view to reload so that any changes to the settings are applied */ g_signal_emit (G_OBJECT (window), window_signals[RELOAD], 0, TRUE, &result); /* replace the active view with a new one of the correct type */ thunar_window_replace_view (window, window->view, view_type); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_window_action_detailed_view (ThunarWindow *window) { thunar_window_action_view_changed (window, THUNAR_TYPE_DETAILS_VIEW); thunar_details_view_set_date_deleted_column_visible (THUNAR_DETAILS_VIEW (window->view), thunar_file_is_trash (window->current_directory)); thunar_details_view_set_recency_column_visible (THUNAR_DETAILS_VIEW (window->view), thunar_file_is_recent (window->current_directory)); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_window_action_icon_view (ThunarWindow *window) { if (window->is_searching == FALSE) thunar_window_action_view_changed (window, THUNAR_TYPE_ICON_VIEW); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_window_action_compact_view (ThunarWindow *window) { if (window->is_searching == FALSE) thunar_window_action_view_changed (window, THUNAR_TYPE_COMPACT_VIEW); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static void thunar_window_replace_view (ThunarWindow *window, GtkWidget *view_to_replace, GType view_type) { ThunarFile *file = NULL; ThunarFile *current_directory = NULL; GtkWidget *new_view; gint page_num; _thunar_return_if_fail (view_type != G_TYPE_NONE); /* if the view already has the correct type then just return */ if (view_to_replace != NULL && G_TYPE_FROM_INSTANCE (view_to_replace) == view_type) return; /* save some settings from the old view for the new view */ if (view_to_replace != NULL) { /* get first visible file in the old view */ if (!thunar_view_get_visible_range (THUNAR_VIEW (view_to_replace), &file, NULL)) file = NULL; /* store the active directory from the old view */ current_directory = thunar_navigator_get_current_directory (THUNAR_NAVIGATOR (view_to_replace)); if (current_directory != NULL) g_object_ref (current_directory); /* cancel any ongoing search in the old view */ if (thunar_standard_view_get_search_query (THUNAR_STANDARD_VIEW (view_to_replace)) != NULL) thunar_window_action_cancel_search (window); } /* if we have not got a current directory from the old view, use the window's current directory */ if (current_directory == NULL && window->current_directory != NULL) current_directory = g_object_ref (window->current_directory); _thunar_assert (current_directory != NULL); /* find where to insert the new view */ if (view_to_replace != NULL) page_num = gtk_notebook_page_num (GTK_NOTEBOOK (window->notebook_selected), view_to_replace); else page_num = -1; /* create and insert the new view */ new_view = thunar_window_create_view (window, current_directory, view_type); thunar_window_notebook_insert_page (window, page_num + 1, new_view); /* use same selection than in the previous view */ if (view_to_replace != NULL && new_view != NULL) thunar_standard_view_transfer_selection (THUNAR_STANDARD_VIEW (new_view), THUNAR_STANDARD_VIEW (view_to_replace)); /* is the view we are replacing the active view? * (note that this will be true if both view_to_replace and window->view are NULL) */ if (view_to_replace == window->view) thunar_window_switch_current_view (window, new_view); /* scroll to the previously visible file in the old view */ if (G_UNLIKELY (file != NULL)) thunar_view_scroll_to_file (THUNAR_VIEW (new_view), file, FALSE, TRUE, 0.0f, 0.0f); /* Remove the old page */ if (view_to_replace != NULL) gtk_notebook_remove_page (GTK_NOTEBOOK (window->notebook_selected), page_num); /* unref the old view */ /* 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)); } static void thunar_window_action_view_changed (ThunarWindow *window, GType view_type) { thunar_window_replace_view (window, window->view, view_type); thunar_window_view_switcher_update (window); /* if directory specific settings are enabled, save the view type for this directory */ if (window->directory_specific_settings && !window->is_searching) thunar_file_set_metadata_setting (window->current_directory, "thunar-view-type", g_type_name (view_type), TRUE); } static gboolean thunar_window_action_go_up (ThunarWindow *window) { ThunarFile *parent; GError *error = NULL; parent = thunar_file_get_parent (window->current_directory, &error); if (G_LIKELY (parent != NULL)) { thunar_window_set_current_directory (window, parent); g_object_unref (G_OBJECT (parent)); } else { /* the root folder '/' has no parent. In this special case we do not need a dialog */ if (error->code != G_FILE_ERROR_NOENT) { thunar_dialogs_show_error (GTK_WIDGET (window), error, _("Failed to open parent folder")); } g_error_free (error); } /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_window_action_back (ThunarWindow *window) { ThunarHistory *history; _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); history = thunar_standard_view_get_history (THUNAR_STANDARD_VIEW (window->view)); thunar_history_action_back (history); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_window_action_forward (ThunarWindow *window) { ThunarHistory *history; _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); history = thunar_standard_view_get_history (THUNAR_STANDARD_VIEW (window->view)); thunar_history_action_forward (history); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_window_action_open_home (ThunarWindow *window) { GFile *home; ThunarFile *home_file; GError *error = NULL; _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); /* determine the path to the home directory */ home = thunar_g_file_new_for_home (); /* determine the file for the home directory */ home_file = thunar_file_get (home, &error); if (G_UNLIKELY (home_file == NULL)) { /* display an error to the user */ thunar_dialogs_show_error (GTK_WIDGET (window), error, _("Failed to open the home folder")); g_error_free (error); } else { /* open the home folder */ thunar_window_set_current_directory (window, home_file); g_object_unref (G_OBJECT (home_file)); } /* release our reference on the home path */ g_object_unref (home); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_window_open_user_folder (ThunarWindow *window, GUserDirectory thunar_user_dir, const gchar *default_name) { ThunarFile *user_file = NULL; gboolean result = FALSE; GError *error = NULL; GFile *home_dir; GFile *user_dir; const gchar *path; gint response; GtkWidget *dialog; gchar *parse_name; path = g_get_user_special_dir (thunar_user_dir); home_dir = thunar_g_file_new_for_home (); /* check if there is an entry in user-dirs.dirs */ if (G_LIKELY (path != NULL)) { user_dir = g_file_new_for_path (path); /* if equal to home, leave */ if (g_file_equal (user_dir, home_dir)) goto is_homedir; } else { /* build a name */ user_dir = g_file_resolve_relative_path (home_dir, default_name); } /* try to load the user dir */ user_file = thunar_file_get (user_dir, NULL); /* check if the directory exists */ if (G_UNLIKELY (user_file == NULL || !thunar_file_exists (user_file))) { /* release the instance if it does not exist */ if (user_file != NULL) { g_object_unref (user_file); user_file = NULL; } /* ask the user to create the directory */ parse_name = g_file_get_parse_name (user_dir); dialog = gtk_message_dialog_new (GTK_WINDOW (window), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, _("The directory \"%s\" does not exist. Do you want to create it?"), parse_name); gtk_window_set_title (GTK_WINDOW (dialog), _("Create directory")); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_YES); response = gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); g_free (parse_name); if (response == GTK_RESPONSE_YES && g_file_make_directory_with_parents (user_dir, NULL, &error)) { /* try again */ user_file = thunar_file_get (user_dir, &error); } } if (G_LIKELY (user_file != NULL)) { /* open the folder */ thunar_window_set_current_directory (window, user_file); g_object_unref (G_OBJECT (user_file)); result = TRUE; } else if (error != NULL) { parse_name = g_file_get_parse_name (user_dir); thunar_dialogs_show_error (GTK_WIDGET (window), error, _("Failed to open directory \"%s\""), parse_name); g_free (parse_name); g_error_free (error); } is_homedir: g_object_unref (user_dir); g_object_unref (home_dir); return result; } static gboolean thunar_window_action_open_desktop (ThunarWindow *window) { _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); thunar_window_open_user_folder (window, G_USER_DIRECTORY_DESKTOP, "Desktop"); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_window_action_open_computer (ThunarWindow *window) { GFile *computer; ThunarFile *computer_file; GError *error = NULL; _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); /* determine the computer location */ computer = thunar_g_file_new_for_computer (); /* determine the file for this location */ computer_file = thunar_file_get (computer, &error); if (G_UNLIKELY (computer_file == NULL)) { /* display an error to the user */ thunar_dialogs_show_error (GTK_WIDGET (window), error, _("Failed to browse the computer")); g_error_free (error); } else { /* open the computer location */ thunar_window_set_current_directory (window, computer_file); g_object_unref (G_OBJECT (computer_file)); } /* release our reference on the location itself */ g_object_unref (computer); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_window_action_open_templates (ThunarWindow *window) { GtkWidget *dialog; GtkWidget *button; GtkWidget *label; GtkWidget *image; GtkWidget *hbox; GtkWidget *vbox; gboolean show_about_templates; gboolean success; _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); success = thunar_window_open_user_folder (window, G_USER_DIRECTORY_TEMPLATES, "Templates"); /* check whether we should display the "About Templates" dialog */ g_object_get (G_OBJECT (window->preferences), "misc-show-about-templates", &show_about_templates, NULL); if (G_UNLIKELY (show_about_templates && success)) { /* display the "About Templates" dialog */ dialog = gtk_dialog_new_with_buttons (_("About Templates"), GTK_WINDOW (window), GTK_DIALOG_DESTROY_WITH_PARENT, _("_OK"), GTK_RESPONSE_OK, NULL); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); gtk_container_set_border_width (GTK_CONTAINER (hbox), 8); gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), hbox, TRUE, TRUE, 0); gtk_widget_show (hbox); image = gtk_image_new_from_icon_name ("dialog-information", GTK_ICON_SIZE_DIALOG); gtk_widget_set_halign (image, GTK_ALIGN_CENTER); gtk_widget_set_valign (image, GTK_ALIGN_START); gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0); gtk_widget_show (image); vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 18); gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); gtk_widget_show (vbox); label = gtk_label_new (_("All files in this folder will appear in the \"Create Document\" menu.")); gtk_label_set_xalign (GTK_LABEL (label), 0.0f); gtk_label_set_attributes (GTK_LABEL (label), thunar_pango_attr_list_big_bold ()); gtk_label_set_line_wrap (GTK_LABEL (label), FALSE); gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); gtk_widget_show (label); label = gtk_label_new (_("If you frequently create certain kinds " " of documents, make a copy of one and put it in this " "folder. Thunar will add an entry for this document in the" " \"Create Document\" menu.\n\n" "You can then select the entry from the \"Create Document\" " "menu and a copy of the document will be created in the " "directory you are viewing.")); gtk_label_set_xalign (GTK_LABEL (label), 0.0f); gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0); gtk_widget_show (label); button = gtk_check_button_new_with_mnemonic (_("Do _not display this message again")); g_object_bind_property (G_OBJECT (window->preferences), "misc-show-about-templates", G_OBJECT (button), "active", G_BINDING_INVERT_BOOLEAN | G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); gtk_widget_show (button); gtk_window_set_default_size (GTK_WINDOW (dialog), 600, -1); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); } /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_window_action_open_file_system (ThunarWindow *window) { GFile *root; ThunarFile *root_file; GError *error = NULL; _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); /* determine the path to the root directory */ root = thunar_g_file_new_for_root (); /* determine the file for the root directory */ root_file = thunar_file_get (root, &error); if (G_UNLIKELY (root_file == NULL)) { /* display an error to the user */ thunar_dialogs_show_error (GTK_WIDGET (window), error, _("Failed to open the file system root folder")); g_error_free (error); } else { /* open the root folder */ thunar_window_set_current_directory (window, root_file); g_object_unref (G_OBJECT (root_file)); } /* release our reference on the home path */ g_object_unref (root); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_window_action_open_recent (ThunarWindow *window) { GFile *recent; ThunarFile *recent_file; GError *error = NULL; _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); /* determine the path to `Recent` */ recent = thunar_g_file_new_for_recent (); /* determine the file for `Recent` */ recent_file = thunar_file_get (recent, &error); if (G_UNLIKELY (recent_file == NULL)) { /* display an error to the user */ thunar_dialogs_show_error (GTK_WIDGET (window), error, _("Failed to display `Recent`")); g_error_free (error); } else { /* open the `Recent` folder */ thunar_window_set_current_directory (window, recent_file); g_object_unref (G_OBJECT (recent_file)); } /* release our reference on the `Recent` path */ g_object_unref (recent); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_window_action_open_trash (ThunarWindow *window) { GFile *trash_bin; ThunarFile *trash_bin_file; GError *error = NULL; _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); /* determine the path to the trash bin */ trash_bin = thunar_g_file_new_for_trash (); /* determine the file for the trash bin */ trash_bin_file = thunar_file_get (trash_bin, &error); if (G_UNLIKELY (trash_bin_file == NULL)) { /* display an error to the user */ thunar_dialogs_show_error (GTK_WIDGET (window), error, _("Failed to display the contents of the trash can")); g_error_free (error); } else { /* open the trash folder */ thunar_window_set_current_directory (window, trash_bin_file); g_object_unref (G_OBJECT (trash_bin_file)); } /* release our reference on the trash bin path */ g_object_unref (trash_bin); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_window_action_open_network (ThunarWindow *window) { ThunarFile *network_file; GError *error = NULL; GFile *network; _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); /* determine the network root location */ network = thunar_g_file_new_for_network (); /* determine the file for this location */ network_file = thunar_file_get (network, &error); if (G_UNLIKELY (network_file == NULL)) { /* display an error to the user */ thunar_dialogs_show_error (GTK_WIDGET (window), error, _("Failed to browse the network")); g_error_free (error); } else { /* open the network root location */ thunar_window_set_current_directory (window, network_file); g_object_unref (G_OBJECT (network_file)); } /* release our reference on the location itself */ g_object_unref (network); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_window_check_uca_key_activation (ThunarWindow *window, GdkEventKey *key_event, gpointer user_data) { if (thunar_action_manager_check_uca_key_activation (window->action_mgr, key_event)) return GDK_EVENT_STOP; return GDK_EVENT_PROPAGATE; } static gboolean thunar_window_propagate_key_event (GtkWindow *window, GdkEvent *key_event, gpointer user_data) { GtkWidget *focused_widget; ThunarWindow *thunar_window = THUNAR_WINDOW (window); _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), GDK_EVENT_PROPAGATE); focused_widget = gtk_window_get_focus (window); /* Turn the accelerator priority around globally, * so that the focused widget always gets the accels first. * Implementing this cleanly while maintaining some wanted accels * (like Ctrl+N and exo accels) is a lot of work. So we resort to * only priorize GtkEditable, because that is the easiest way to * fix the right-ahead problem. */ if (focused_widget != NULL && GTK_IS_EDITABLE (focused_widget)) return gtk_window_propagate_key_event (window, (GdkEventKey *) key_event); /* GTK ignores the Tab accelerator by default, handle it manually */ if (xfce_gtk_handle_tab_accels ((GdkEventKey *) key_event, thunar_window->accel_group, thunar_window, thunar_window_action_entries, THUNAR_WINDOW_N_ACTIONS) == TRUE) return TRUE; /* ThunarActionManager doesn't handle it own shortcuts, so ThunarWindow will handle any Tab-accelerated actions */ if (xfce_gtk_handle_tab_accels ((GdkEventKey *) key_event, thunar_window->accel_group, thunar_window->action_mgr, thunar_action_manager_get_action_entries (), THUNAR_ACTION_MANAGER_N_ACTIONS) == TRUE) return TRUE; /* ThunarStatusbar doesn't handle it own shortcuts, so ThunarWindow will handle any Tab-accelerated actions */ if (xfce_gtk_handle_tab_accels ((GdkEventKey *) key_event, thunar_window->accel_group, thunar_window->statusbar, thunar_statusbar_get_action_entries (), THUNAR_STATUS_BAR_N_ACTIONS) == TRUE) return TRUE; return GDK_EVENT_PROPAGATE; } static gboolean thunar_window_after_propagate_key_event (GtkWindow *window, GdkEvent *key_event, gpointer user_data) { GtkWidget *focused_widget; ThunarWindow *thunar_window = THUNAR_WINDOW (window); _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), GDK_EVENT_PROPAGATE); focused_widget = gtk_window_get_focus (window); /* After 'tab' was preassed, we might need to update the selected notebook */ if (thunar_window_split_view_is_active (thunar_window)) { if (thunar_window->notebook_left != NULL && gtk_widget_is_ancestor (focused_widget, thunar_window->notebook_left)) { thunar_window->notebook_selected = thunar_window->notebook_left; thunar_window_notebook_select_current_page (thunar_window); } if (thunar_window->notebook_right != NULL && gtk_widget_is_ancestor (focused_widget, thunar_window->notebook_right)) { thunar_window->notebook_selected = thunar_window->notebook_right; thunar_window_notebook_select_current_page (thunar_window); } } return GDK_EVENT_PROPAGATE; } static void thunar_window_action_open_bookmark (GFile *g_file) { ThunarWindow *window; window = g_object_get_data (G_OBJECT (g_file), I_ ("thunar-window")); g_object_set (G_OBJECT (window->action_mgr), "selected-location", g_file, NULL); thunar_action_manager_activate_selected_files (window->action_mgr, THUNAR_ACTION_MANAGER_CHANGE_DIRECTORY, NULL); } static gboolean thunar_window_action_open_location (ThunarWindow *window) { /* just use the "start-open-location" callback */ thunar_window_start_open_location (window, NULL); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_window_action_contents (ThunarWindow *window) { /* display the documentation index */ xfce_dialog_show_help (GTK_WINDOW (window), "thunar", NULL, NULL); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_window_action_about (ThunarWindow *window) { /* just popup the about dialog */ thunar_dialogs_show_about (GTK_WINDOW (window), PACKAGE_NAME, _("Thunar is a fast and easy to use file manager\n" "for the Xfce Desktop Environment.")); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_window_action_show_hidden (ThunarWindow *window) { _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); window->show_hidden = !window->show_hidden; gtk_container_foreach (GTK_CONTAINER (window->notebook_selected), (GtkCallback) (void (*) (void)) thunar_view_set_show_hidden, GINT_TO_POINTER (window->show_hidden)); if (G_LIKELY (window->sidepane != NULL)) thunar_side_pane_set_show_hidden (THUNAR_SIDE_PANE (window->sidepane), window->show_hidden); g_object_set (G_OBJECT (window->preferences), "last-show-hidden", window->show_hidden, NULL); /* restart any active search */ if (G_UNLIKELY (window->is_searching)) thunar_window_update_search (window); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_window_action_show_highlight (ThunarWindow *window) { gboolean highlight_enabled; _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); g_object_get (G_OBJECT (window->preferences), "misc-highlighting-enabled", &highlight_enabled, NULL); g_object_set (G_OBJECT (window->preferences), "misc-highlighting-enabled", !highlight_enabled, NULL); /* refresh the view to refresh the cell renderer drawings */ thunar_window_action_reload (window, NULL); return TRUE; } gboolean thunar_window_action_search (ThunarWindow *window) { _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); if (window->is_searching == FALSE) { /* initiate search */ thunar_window_start_open_location (window, thunar_util_get_search_prefix ()); g_signal_handlers_block_by_func (G_OBJECT (window->location_toolbar_item_search), thunar_window_action_search, window); gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (window->location_toolbar_item_search), TRUE); g_signal_handlers_unblock_by_func (G_OBJECT (window->location_toolbar_item_search), thunar_window_action_search, window); } else thunar_window_action_cancel_search (window); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_window_action_menu_deactivate (ThunarWindow *window, GtkWidget *menu) { _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); _thunar_return_val_if_fail (GTK_IS_WIDGET (menu), FALSE); /* toggle off the toolbar button */ g_signal_handlers_block_by_func (window->location_toolbar_item_menu, get_action_entry (THUNAR_WINDOW_ACTION_MENU)->callback, window); gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (window->location_toolbar_item_menu), FALSE); g_signal_handlers_unblock_by_func (window->location_toolbar_item_menu, get_action_entry (THUNAR_WINDOW_ACTION_MENU)->callback, window); /* release the menu reference */ g_object_ref_sink (G_OBJECT (menu)); g_object_unref (G_OBJECT (menu)); return TRUE; } static gboolean thunar_window_action_menu (ThunarWindow *window) { GtkWidget *menu; _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); /* build the menu */ menu = gtk_menu_new (); thunar_window_create_menu (window, THUNAR_WINDOW_ACTION_FILE_MENU, G_CALLBACK (thunar_window_update_file_menu), menu); thunar_window_create_menu (window, THUNAR_WINDOW_ACTION_EDIT_MENU, G_CALLBACK (thunar_window_update_edit_menu), menu); thunar_window_create_menu (window, THUNAR_WINDOW_ACTION_VIEW_MENU, G_CALLBACK (thunar_window_update_view_menu), menu); thunar_window_create_menu (window, THUNAR_WINDOW_ACTION_GO_MENU, G_CALLBACK (thunar_window_update_go_menu), menu); thunar_window_create_menu (window, THUNAR_WINDOW_ACTION_BOOKMARKS_MENU, G_CALLBACK (thunar_window_update_bookmarks_menu), menu); thunar_window_create_menu (window, THUNAR_WINDOW_ACTION_HELP_MENU, G_CALLBACK (thunar_window_update_help_menu), menu); gtk_widget_show_all (menu); g_signal_connect_swapped (G_OBJECT (menu), "deactivate", G_CALLBACK (thunar_window_action_menu_deactivate), window); /* show the menu below its toolbar button */ gtk_menu_popup_at_widget (GTK_MENU (menu), window->location_toolbar_item_menu, GDK_GRAVITY_SOUTH_WEST, GDK_GRAVITY_NORTH_WEST, NULL); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_window_action_open_file_menu (ThunarWindow *window) { gboolean ret; GList *children; _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); /* In case the menubar is hidden, we make it visible (e.g. when F10 is pressed) */ gtk_widget_set_visible (window->menubar, TRUE); children = gtk_container_get_children (GTK_CONTAINER (window->menubar)); g_signal_emit_by_name (children->data, "button-press-event", NULL, &ret); g_list_free (children); gtk_menu_shell_select_first (GTK_MENU_SHELL (window->menubar), TRUE); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static void thunar_window_update_title (ThunarWindow *window) { ThunarWindowTitleStyle window_title_style; gchar *title; gchar *parse_name = NULL; const gchar *name; _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); /* get name of directory or full path */ g_object_get (G_OBJECT (window->preferences), "misc-window-title-style", &window_title_style, NULL); if (G_UNLIKELY (window_title_style == THUNAR_WINDOW_TITLE_STYLE_FULL_PATH_WITH_THUNAR_SUFFIX || window_title_style == THUNAR_WINDOW_TITLE_STYLE_FULL_PATH_WITHOUT_THUNAR_SUFFIX)) name = parse_name = g_file_get_parse_name (thunar_file_get_file (window->current_directory)); else name = thunar_file_get_display_name (window->current_directory); /* set window title */ if (G_UNLIKELY (window_title_style == THUNAR_WINDOW_TITLE_STYLE_FOLDER_NAME_WITHOUT_THUNAR_SUFFIX || window_title_style == THUNAR_WINDOW_TITLE_STYLE_FULL_PATH_WITHOUT_THUNAR_SUFFIX)) title = g_strdup_printf ("%s", name); else title = g_strdup_printf ("%s - %s", name, "Thunar"); gtk_window_set_title (GTK_WINDOW (window), title); g_free (title); g_free (parse_name); } static void thunar_window_menu_item_selected (ThunarWindow *window, GtkWidget *menu_item) { gchar *tooltip; guint id; _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); /* we can only display tooltips if we have a statusbar */ if (G_LIKELY (window->statusbar != NULL)) { tooltip = gtk_widget_get_tooltip_text (menu_item); if (G_LIKELY (tooltip != NULL)) { /* push to the statusbar */ id = gtk_statusbar_get_context_id (GTK_STATUSBAR (window->statusbar), "Menu tooltip"); gtk_statusbar_push (GTK_STATUSBAR (window->statusbar), id, tooltip); g_free (tooltip); } } } static void thunar_window_menu_item_deselected (ThunarWindow *window, GtkWidget *menu_item) { guint id; _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); /* we can only undisplay tooltips if we have a statusbar */ if (G_LIKELY (window->statusbar != NULL)) { /* drop the last tooltip from the statusbar */ id = gtk_statusbar_get_context_id (GTK_STATUSBAR (window->statusbar), "Menu tooltip"); gtk_statusbar_pop (GTK_STATUSBAR (window->statusbar), id); } } static void thunar_window_notify_loading (ThunarView *view, GParamSpec *pspec, ThunarWindow *window) { GdkCursor *cursor; _thunar_return_if_fail (THUNAR_IS_VIEW (view)); _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); if (gtk_widget_get_realized (GTK_WIDGET (window)) && window->view == GTK_WIDGET (view)) { /* setup the proper cursor */ if (thunar_view_get_loading (view)) { cursor = gdk_cursor_new_for_display (gtk_widget_get_display (GTK_WIDGET (view)), GDK_WATCH); gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (window)), cursor); g_object_unref (cursor); } else { gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (window)), NULL); } /* Set trash infobar's `empty trash` button sensitivity, if required */ if (thunar_file_is_trash (window->current_directory)) gtk_widget_set_sensitive (window->trash_infobar_empty_button, thunar_file_get_item_count (window->current_directory) > 0); } } static void thunar_window_device_pre_unmount (ThunarDeviceMonitor *device_monitor, ThunarDevice *device, GFile *root_file, ThunarWindow *window) { _thunar_return_if_fail (THUNAR_IS_DEVICE_MONITOR (device_monitor)); _thunar_return_if_fail (window->device_monitor == device_monitor); _thunar_return_if_fail (THUNAR_IS_DEVICE (device)); _thunar_return_if_fail (G_IS_FILE (root_file)); _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); /* nothing to do if we don't have a current directory */ if (G_UNLIKELY (window->current_directory == NULL)) return; /* check if the file is the current directory or an ancestor of the current directory */ if (g_file_equal (thunar_file_get_file (window->current_directory), root_file) || thunar_file_is_gfile_ancestor (window->current_directory, root_file)) { /* change to the home folder */ thunar_window_action_open_home (window); } } static void thunar_window_device_changed (ThunarDeviceMonitor *device_monitor, ThunarDevice *device, ThunarWindow *window) { GFile *root_file; _thunar_return_if_fail (THUNAR_IS_DEVICE_MONITOR (device_monitor)); _thunar_return_if_fail (window->device_monitor == device_monitor); _thunar_return_if_fail (THUNAR_IS_DEVICE (device)); _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); if (thunar_device_is_mounted (device)) return; root_file = thunar_device_get_root (device); if (root_file != NULL) { thunar_window_device_pre_unmount (device_monitor, device, root_file, window); g_object_unref (root_file); } } static gboolean thunar_window_save_paned (ThunarWindow *window) { _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); g_object_set (G_OBJECT (window->preferences), "last-separator-position", gtk_paned_get_position (GTK_PANED (window->paned)), NULL); /* for button release event */ return FALSE; } static gboolean thunar_window_save_paned_notebooks (ThunarWindow *window) { _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); /* save the separator position, use -1 (= unset) for 'center position' */ g_object_set (G_OBJECT (window->preferences), "last-splitview-separator-position", gtk_paned_get_position (GTK_PANED (window->paned_notebooks)) == thunar_gtk_orientable_get_center_pos (GTK_ORIENTABLE (window->paned_notebooks)) ? -1 : gtk_paned_get_position (GTK_PANED (window->paned_notebooks)), NULL); /* for button release event */ return FALSE; } static gboolean thunar_window_paned_notebooks_button_press_event (GtkWidget *paned, GdkEventButton *event) { gint center_pos; _thunar_return_val_if_fail (GTK_IS_WIDGET (paned), FALSE); /* reset the separator position on double click */ if (event->button == 1 && event->type == GDK_2BUTTON_PRESS) { /* calculate the position manually because `gtk_paned_set_position (paned, -1)` * does not divide the panes equally when tabs are created or removed */ center_pos = thunar_gtk_orientable_get_center_pos (GTK_ORIENTABLE (paned)); gtk_paned_set_position (GTK_PANED (paned), center_pos); return TRUE; } return FALSE; } static void thunar_window_save_geometry_timer_destroy (gpointer user_data) { THUNAR_WINDOW (user_data)->save_geometry_timer_id = 0; } /** * thunar_window_set_zoom_level: * @window : a #ThunarWindow instance. * @zoom_level : the new zoom level for @window. * * Sets the zoom level for @window to @zoom_level. **/ void thunar_window_set_zoom_level (ThunarWindow *window, ThunarZoomLevel zoom_level) { _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); _thunar_return_if_fail (zoom_level < THUNAR_ZOOM_N_LEVELS); /* check if we have a new zoom level */ if (G_LIKELY (window->zoom_level != zoom_level)) { /* remember the new zoom level */ window->zoom_level = zoom_level; /* notify listeners */ g_object_notify (G_OBJECT (window), "zoom-level"); } /* check if we can still zoom in and set the sensitivity of the button */ gtk_widget_set_sensitive (window->location_toolbar_item_zoom_in, (window->zoom_level < THUNAR_ZOOM_N_LEVELS - 1)); /* check if we can still zoom out and set the sensitivity of the button */ gtk_widget_set_sensitive (window->location_toolbar_item_zoom_out, (window->zoom_level > 0)); } /** * thunar_window_set_directory_specific_settings: * @window : a #ThunarWindow instance. * @directory_specific_settings : whether to use directory specific settings in @window. * * Toggles the use of directory specific settings in @window according to @directory_specific_settings. **/ void thunar_window_set_directory_specific_settings (ThunarWindow *window, gboolean directory_specific_settings) { GList *tabs, *lp; ThunarFile *directory; GType view_type; gchar *type_name; _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); /* reset to the default view type if we are turning directory specific settings off */ if (!directory_specific_settings && window->directory_specific_settings) { /* determine the default view type */ g_object_get (G_OBJECT (window->preferences), "default-view", &type_name, NULL); view_type = g_type_from_name (type_name); g_free (type_name); /* set the last view type */ if (!g_type_is_a (view_type, G_TYPE_NONE) && !g_type_is_a (view_type, G_TYPE_INVALID) && !window->is_searching) g_object_set (G_OBJECT (window->preferences), "last-view", g_type_name (view_type), NULL); } /* save the setting */ window->directory_specific_settings = directory_specific_settings; /* get all of the window's tabs */ tabs = gtk_container_get_children (GTK_CONTAINER (window->notebook_selected)); /* replace each tab with a tab of the correct view type */ for (lp = tabs; lp != NULL; lp = lp->next) { if (!THUNAR_IS_STANDARD_VIEW (lp->data)) continue; directory = thunar_navigator_get_current_directory (lp->data); if (!THUNAR_IS_FILE (directory)) continue; /* find the correct view type for the new view */ view_type = thunar_window_view_type_for_directory (window, directory); /* replace the old view with a new one */ thunar_window_replace_view (window, lp->data, view_type); } g_list_free (tabs); } /** * 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. * * Return value: the directory currently displayed within @window or %NULL. **/ ThunarFile * thunar_window_get_current_directory (ThunarWindow *window) { _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), NULL); return window->current_directory; } /** * thunar_window_set_current_directory: * @window : a #ThunarWindow instance. * @current_directory : the new directory or %NULL. **/ void thunar_window_set_current_directory (ThunarWindow *window, ThunarFile *current_directory) { gboolean is_trash; gboolean is_recent; GType type; gchar *type_name; gint num_pages; _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; /* disconnect from the previously active directory */ if (G_LIKELY (window->current_directory != NULL)) { /* release reference */ g_object_unref (G_OBJECT (window->current_directory)); window->current_directory = NULL; } /* not much to do in this case */ if (current_directory == NULL) return; /* take a reference on the file */ g_object_ref (G_OBJECT (current_directory)); window->current_directory = current_directory; num_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook_selected)); /* if the window is new, get the default-view type and set it as the last-view type (if it is a valid type) * so that it will be used as the initial view type for directories with no saved directory specific view type */ if (num_pages == 0) { /* determine the default view type */ g_object_get (G_OBJECT (window->preferences), "default-view", &type_name, NULL); type = g_type_from_name (type_name); g_free (type_name); /* set the last view type to the default view type if there is a default view type */ if (!g_type_is_a (type, G_TYPE_NONE) && !g_type_is_a (type, G_TYPE_INVALID) && !window->is_searching) g_object_set (G_OBJECT (window->preferences), "last-view", g_type_name (type), NULL); } type = thunar_window_view_type_for_directory (window, current_directory); if (num_pages == 0) /* create a new view if the window is new */ { GtkWidget *new_view; new_view = thunar_window_create_view (window, current_directory, type); thunar_window_notebook_insert_page (window, 0, new_view); } thunar_window_update_title (window); thunar_window_update_window_icon (window); if (G_LIKELY (window->view != NULL)) { /* grab the focus to the main view */ gtk_widget_grab_focus (window->view); } thunar_window_history_changed (window); gtk_widget_set_sensitive (window->location_toolbar_item_parent, !thunar_g_file_is_root (thunar_file_get_file (current_directory))); /* * tell everybody that we have a new "current-directory", * we do this first so other widgets display the new * state already while the folder view is loading. */ g_object_notify (G_OBJECT (window), "current-directory"); /* change the view type if necessary */ if (window->view != NULL && window->view_type != type) thunar_window_replace_view (window, window->view, type); is_trash = thunar_file_is_trash (current_directory); is_recent = thunar_file_is_recent (current_directory); if (is_trash) gtk_widget_show (window->trash_infobar); else gtk_widget_hide (window->trash_infobar); if (THUNAR_IS_DETAILS_VIEW (window->view) == FALSE) return; /* show/hide date_deleted column/sortBy in the trash directory */ thunar_details_view_set_date_deleted_column_visible (THUNAR_DETAILS_VIEW (window->view), is_trash); thunar_details_view_set_recency_column_visible (THUNAR_DETAILS_VIEW (window->view), is_recent); thunar_details_view_set_location_column_visible (THUNAR_DETAILS_VIEW (window->view), is_recent); } GList * thunar_window_get_directories (ThunarWindow *window, gint *active_page) { gint n; gint n_pages; GList *uris = NULL; GtkWidget *view; ThunarFile *directory; _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), NULL); n_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook_selected)); if (G_UNLIKELY (n_pages == 0)) return NULL; for (n = 0; n < n_pages; n++) { /* get the view */ view = gtk_notebook_get_nth_page (GTK_NOTEBOOK (window->notebook_selected), n); if (THUNAR_IS_NAVIGATOR (view) == FALSE) continue; /* get the directory of the view */ directory = thunar_navigator_get_current_directory (THUNAR_NAVIGATOR (view)); if (THUNAR_IS_FILE (directory) == FALSE) continue; uris = g_list_append (uris, thunar_file_dup_uri (directory)); } /* selected tab */ if (active_page != NULL) *active_page = gtk_notebook_get_current_page (GTK_NOTEBOOK (window->notebook_selected)); return uris; } gboolean thunar_window_set_directories (ThunarWindow *window, gchar **uris, gint active_page) { ThunarFile *directory; guint n; _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); _thunar_return_val_if_fail (uris != NULL, FALSE); for (n = 0; uris[n] != NULL; n++) { /* check if the string looks like an uri */ if (!g_uri_is_valid (uris[n], G_URI_FLAGS_NONE, NULL)) continue; /* get the file for the uri */ directory = thunar_file_get_for_uri (uris[n], NULL); if (G_UNLIKELY (directory == NULL)) continue; /* open the directory in a new notebook */ if (thunar_file_is_directory (directory)) { if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook_selected)) == 0) thunar_window_set_current_directory (window, directory); else thunar_window_notebook_open_new_tab (window, directory); } g_object_unref (G_OBJECT (directory)); } /* select the page */ thunar_window_notebook_set_current_tab (window, active_page); /* we succeeded if new pages have been opened */ return gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->notebook_selected)) > 0; } /** * thunar_window_get_action_entry: * @window : Instance of a #ThunarWindow * @action : #ThunarWindowAction for which the #XfceGtkActionEntry is requested * * returns a reference to the requested #XfceGtkActionEntry * * Return value: (transfer none): The reference to the #XfceGtkActionEntry **/ const XfceGtkActionEntry * thunar_window_get_action_entry (ThunarWindow *window, ThunarWindowAction action) { return get_action_entry (action); } /** * thunar_window_append_menu_item: * @window : Instance of a #ThunarWindow * @menu : #GtkMenuShell to which the item should be added * @action : #ThunarWindowAction to select which item should be added * * Adds the selected, widget specific #GtkMenuItem to the passed #GtkMenuShell **/ void thunar_window_append_menu_item (ThunarWindow *window, GtkMenuShell *menu, ThunarWindowAction action) { GtkWidget *item; _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); item = xfce_gtk_menu_item_new_from_action_entry (get_action_entry (action), G_OBJECT (window), menu); if (action == THUNAR_WINDOW_ACTION_ZOOM_IN) gtk_widget_set_sensitive (item, G_LIKELY (window->zoom_level < THUNAR_ZOOM_N_LEVELS - 1)); if (action == THUNAR_WINDOW_ACTION_ZOOM_OUT) gtk_widget_set_sensitive (item, G_LIKELY (window->zoom_level > 0)); } /** * thunar_window_get_action_manager: * @window : a #ThunarWindow instance. * * Return value: (transfer none): The single #ThunarActionManager of this #ThunarWindow **/ ThunarActionManager * thunar_window_get_action_manager (ThunarWindow *window) { _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), NULL); return window->action_mgr; } static void thunar_window_redirect_menu_tooltips_to_statusbar_recursive (GtkWidget *menu_item, ThunarWindow *window) { GtkWidget *submenu; if (GTK_IS_MENU_ITEM (menu_item)) { submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (menu_item)); if (submenu != NULL) gtk_container_foreach (GTK_CONTAINER (submenu), (GtkCallback) (void (*) (void)) thunar_window_redirect_menu_tooltips_to_statusbar_recursive, window); /* this disables to show the tooltip on hover */ gtk_widget_set_has_tooltip (menu_item, FALSE); /* These method will put the tooltip on the statusbar */ g_signal_connect_swapped (G_OBJECT (menu_item), "select", G_CALLBACK (thunar_window_menu_item_selected), window); g_signal_connect_swapped (G_OBJECT (menu_item), "deselect", G_CALLBACK (thunar_window_menu_item_deselected), window); } } /** * thunar_window_redirect_menu_tooltips_to_statusbar: * @window : a #ThunarWindow instance. * @menu : #GtkMenu for which all tooltips should be shown in the statusbar * * All tooltips of the provided #GtkMenu and any submenu will not be shown directly any more. * Instead they will be shown in the status bar of the passed #ThunarWindow **/ void thunar_window_redirect_menu_tooltips_to_statusbar (ThunarWindow *window, GtkMenu *menu) { _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); _thunar_return_if_fail (GTK_IS_MENU (menu)); gtk_container_foreach (GTK_CONTAINER (menu), (GtkCallback) (void (*) (void)) thunar_window_redirect_menu_tooltips_to_statusbar_recursive, window); } static gboolean thunar_window_button_press_event (GtkWidget *view, GdkEventButton *event, ThunarWindow *window) { const XfceGtkActionEntry *action_entry; _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); if (event->type == GDK_BUTTON_PRESS) { if (G_UNLIKELY (event->button == 8)) { action_entry = get_action_entry (THUNAR_WINDOW_ACTION_BACK); ((void (*) (GtkWindow *)) action_entry->callback) (GTK_WINDOW (window)); return GDK_EVENT_STOP; } if (G_UNLIKELY (event->button == 9)) { action_entry = get_action_entry (THUNAR_WINDOW_ACTION_FORWARD); ((void (*) (GtkWindow *)) action_entry->callback) (GTK_WINDOW (window)); return GDK_EVENT_STOP; } } return GDK_EVENT_PROPAGATE; } static gboolean thunar_window_history_clicked (GtkWidget *button, GdkEventButton *event, ThunarWindow *window) { ThunarHistory *history = NULL; ThunarFile *directory = NULL; gboolean open_in_tab; _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); history = thunar_standard_view_get_history (THUNAR_STANDARD_VIEW (window->view)); if (event->button == 3) { if (button == window->location_toolbar_item_back) thunar_history_show_menu (history, THUNAR_HISTORY_MENU_BACK, button); else if (button == window->location_toolbar_item_forward) thunar_history_show_menu (history, THUNAR_HISTORY_MENU_FORWARD, button); else g_warning ("This button is not able to spawn a history menu"); return TRUE; } else if (event->button == 2) { /* middle click to open a new tab/window */ g_object_get (window->preferences, "misc-middle-click-in-tab", &open_in_tab, NULL); if (button == window->location_toolbar_item_back) directory = thunar_history_peek_back (history); else if (button == window->location_toolbar_item_forward) directory = thunar_history_peek_forward (history); if (directory == NULL) return FALSE; if (open_in_tab) thunar_window_notebook_open_new_tab (window, directory); else { ThunarApplication *application = thunar_application_get (); thunar_application_open_window (application, directory, NULL, NULL, TRUE); g_object_unref (G_OBJECT (application)); } g_object_unref (directory); return TRUE; } return FALSE; } static gboolean thunar_window_open_parent_clicked (GtkWidget *button, GdkEventButton *event, ThunarWindow *window) { ThunarFile *directory = NULL; gboolean open_in_tab; _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); g_object_get (window->preferences, "misc-middle-click-in-tab", &open_in_tab, NULL); if (event->button == 2) { /* middle click to open a new tab/window */ directory = thunar_file_get_parent (window->current_directory, NULL); if (G_LIKELY (directory == NULL)) return FALSE; if (open_in_tab) thunar_window_notebook_open_new_tab (window, directory); else { ThunarApplication *application = thunar_application_get (); thunar_application_open_window (application, directory, NULL, NULL, TRUE); g_object_unref (G_OBJECT (application)); } g_object_unref (directory); return TRUE; } return FALSE; } static gboolean thunar_window_open_home_clicked (GtkWidget *button, GdkEventButton *event, ThunarWindow *window) { ThunarFile *directory = NULL; gint page_num; gboolean open_in_tab; _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); g_object_get (window->preferences, "misc-middle-click-in-tab", &open_in_tab, NULL); if (event->button == 2) { /* switch to the new tab, go to the home directory, return to the old tab */ if (open_in_tab) { page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (window->notebook_selected)); thunar_window_notebook_add_new_tab (window, window->current_directory, THUNAR_NEW_TAB_BEHAVIOR_SWITCH); thunar_window_action_open_home (window); thunar_window_notebook_set_current_tab (window, page_num); } else { ThunarApplication *application = thunar_application_get (); ThunarWindow *newWindow = THUNAR_WINDOW (thunar_application_open_window (application, directory, NULL, NULL, TRUE)); thunar_window_action_open_home (newWindow); g_object_unref (G_OBJECT (application)); } return TRUE; } return FALSE; } static gboolean thunar_window_toolbar_button_press_event (GtkWidget *toolbar, GdkEventButton *event, ThunarWindow *window) { GtkWidget *menu; _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), FALSE); if (event->button == 3) { menu = gtk_menu_new (); xfce_gtk_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_CONFIGURE_TOOLBAR), G_OBJECT (window), GTK_MENU_SHELL (menu)); xfce_gtk_toggle_menu_item_new_from_action_entry (get_action_entry (THUNAR_WINDOW_ACTION_VIEW_MENUBAR), G_OBJECT (window), window->menubar_visible, GTK_MENU_SHELL (menu)); gtk_widget_show_all (menu); /* run the menu (takes over the floating of menu) */ thunar_gtk_menu_run (GTK_MENU (menu)); return TRUE; } return FALSE; } /** * thunar_window_view_type_for_directory: * @window : a #ThunarWindow instance. * @directory : #ThunarFile representing the directory * * Return value: the #GType representing the view type which * @window would use to display @directory. **/ GType thunar_window_view_type_for_directory (ThunarWindow *window, ThunarFile *directory) { GType type = G_TYPE_NONE; gchar *type_name; _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), G_TYPE_NONE); _thunar_return_val_if_fail (THUNAR_IS_FILE (directory), G_TYPE_NONE); /* if the directory has a saved view type and directory specific view types are enabled, we use it */ if (window->directory_specific_settings) { gchar *dir_spec_type_name; dir_spec_type_name = thunar_file_get_metadata_setting (directory, "thunar-view-type"); if (dir_spec_type_name != NULL) type = g_type_from_name (dir_spec_type_name); g_free (dir_spec_type_name); } /* if there is no saved view type for the directory or directory specific view types are not enabled, * we use the last view type */ if (g_type_is_a (type, G_TYPE_NONE) || g_type_is_a (type, G_TYPE_INVALID)) { /* determine the last view type */ g_object_get (G_OBJECT (window->preferences), "last-view", &type_name, NULL); type = g_type_from_name (type_name); g_free (type_name); } /* fallback view type, in case nothing was set */ if (g_type_is_a (type, G_TYPE_NONE) || g_type_is_a (type, G_TYPE_INVALID)) type = THUNAR_TYPE_ICON_VIEW; return type; } static void thunar_window_trash_infobar_clicked (GtkInfoBar *info_bar, gint response_id, ThunarWindow *window) { switch (response_id) { case EMPTY: thunar_action_manager_action_empty_trash (window->action_mgr); break; case RESTORE: thunar_action_manager_action_restore (window->action_mgr); break; default: g_return_if_reached (); } } static void thunar_window_update_embedded_image_preview (ThunarWindow *window) { ThunarImagePreviewMode misc_image_preview_mode; gboolean last_image_preview_visible; g_object_get (G_OBJECT (window->preferences), "last-image-preview-visible", &last_image_preview_visible, "misc-image-preview-mode", &misc_image_preview_mode, NULL); if (window->preview_image_pixbuf != NULL) { image_preview_update (window->sidepane_box, NULL, window->sidepane_preview_image); if (last_image_preview_visible == TRUE && misc_image_preview_mode == THUNAR_IMAGE_PREVIEW_MODE_EMBEDDED) gtk_widget_show (window->sidepane_preview_image); else gtk_widget_hide (window->sidepane_preview_image); } else gtk_widget_hide (window->sidepane_preview_image); } static void thunar_window_update_standalone_image_preview (ThunarWindow *window) { GList *selected_files = thunar_view_get_selected_files (THUNAR_VIEW (window->view)); gboolean file_size_binary; g_object_get (G_OBJECT (window->preferences), "misc-file_size_binary", &file_size_binary, NULL); if (window->preview_image_pixbuf != NULL) { const gchar *display_name = thunar_file_get_display_name (selected_files->data); gchar *file_size = thunar_file_get_size_string_formatted (selected_files->data, file_size_binary); image_preview_update (window->right_pane, NULL, window->right_pane_preview_image); if (display_name != NULL) gtk_label_set_text (GTK_LABEL (window->right_pane_image_label), display_name); gtk_widget_show (window->right_pane_size_label); gtk_label_set_text (GTK_LABEL (window->right_pane_size_value), file_size); g_free (file_size); } else { gtk_image_clear (GTK_IMAGE (window->right_pane_preview_image)); gtk_label_set_text (GTK_LABEL (window->right_pane_image_label), _("Select an image to preview")); gtk_widget_hide (window->right_pane_size_label); gtk_label_set_text (GTK_LABEL (window->right_pane_size_value), ""); } } static void thunar_window_preview_file_destroyed (ThunarWindow *window) { if (window->preview_image_file != NULL) { g_signal_handlers_disconnect_by_data (window->preview_image_file, window); g_object_unref (window->preview_image_file); window->preview_image_file = NULL; } } /** * thunar_window_selection_changed: * @window : a #ThunarWindow instance. * * Used to set the `sensitive` value of the `Restore` button in the trash infobar and to * update the image previews. **/ static void thunar_window_selection_changed (ThunarWindow *window) { GList *selected_files = thunar_view_get_selected_files (THUNAR_VIEW (window->view)); gboolean last_image_preview_visible; /* butttons specific to the Trash location */ if (g_list_length (selected_files) > 0) gtk_widget_set_sensitive (window->trash_infobar_restore_button, TRUE); else gtk_widget_set_sensitive (window->trash_infobar_restore_button, FALSE); /* Disconnect from previous file */ if (window->preview_image_file != NULL) { g_signal_handlers_disconnect_by_data (window->preview_image_file, window); g_object_unref (window->preview_image_file); window->preview_image_file = NULL; } /* clear image previews */ if (window->preview_image_pixbuf != NULL) { g_object_unref (window->preview_image_pixbuf); window->preview_image_pixbuf = NULL; } /* only request new preview thumbnails if the user wants image previews */ g_object_get (G_OBJECT (window->preferences), "last-image-preview-visible", &last_image_preview_visible, NULL); /* get or request a thumbnail */ if (last_image_preview_visible == TRUE) { if (g_list_length (selected_files) >= 1) { ThunarFileThumbState state; window->preview_image_file = g_object_ref (selected_files->data); g_signal_connect_swapped (G_OBJECT (window->preview_image_file), "thumbnail-updated", G_CALLBACK (thunar_window_finished_thumbnailing), window); g_signal_connect_swapped (G_OBJECT (window->preview_image_file), "destroy", G_CALLBACK (thunar_window_preview_file_destroyed), window); state = thunar_file_get_thumb_state (window->preview_image_file, THUNAR_THUMBNAIL_SIZE_XX_LARGE); if (state == THUNAR_FILE_THUMB_STATE_UNKNOWN) thunar_file_request_thumbnail (window->preview_image_file, THUNAR_THUMBNAIL_SIZE_XX_LARGE); else if (state == THUNAR_FILE_THUMB_STATE_READY) { const gchar *thumbnail_path = thunar_file_get_thumbnail_path (window->preview_image_file, THUNAR_THUMBNAIL_SIZE_XX_LARGE); if (thumbnail_path != NULL) window->preview_image_pixbuf = gdk_pixbuf_new_from_file (thumbnail_path, NULL); } } thunar_window_update_embedded_image_preview (window); thunar_window_update_standalone_image_preview (window); } } static void thunar_window_finished_thumbnailing (ThunarWindow *window, ThunarThumbnailSize size, ThunarFile *file) { _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); if (file == window->preview_image_file && size == THUNAR_THUMBNAIL_SIZE_XX_LARGE) { /* there is no guarantee that the thumbnail will exist, the type of the selected file might be unsupported by the thumbnailer */ const gchar *path = thunar_file_get_thumbnail_path (file, THUNAR_THUMBNAIL_SIZE_XX_LARGE); if (path == NULL) return; window->preview_image_pixbuf = gdk_pixbuf_new_from_file (path, NULL); thunar_window_update_embedded_image_preview (window); thunar_window_update_standalone_image_preview (window); } } static void thunar_window_recent_reload (GtkRecentManager *recent_manager, ThunarWindow *window) { _thunar_return_if_fail (window != NULL); _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); if (thunar_file_is_in_recent (window->current_directory)) thunar_window_action_reload (window, NULL); } static void thunar_window_catfish_dialog_configure (GtkWidget *entry) { GError *err = NULL; gchar *argv[4]; GdkScreen *screen; char *display = NULL; /* prepare the argument vector */ argv[0] = (gchar *) "catfish"; argv[1] = THUNAR_WINDOW (entry)->search_query; argv[2] = (gchar *) "--start"; argv[3] = NULL; screen = gtk_widget_get_screen (entry); if (screen != NULL) display = g_strdup (gdk_display_get_name (gdk_screen_get_display (screen))); /* invoke the configuration interface of Catfish */ if (!g_spawn_async (NULL, argv, NULL, G_SPAWN_SEARCH_PATH, thunar_setup_display_cb, display, NULL, &err)) { thunar_dialogs_show_error (entry, err, _("Failed to launch search with Catfish")); g_error_free (err); } g_free (display); } void thunar_window_update_statusbar (ThunarWindow *window) { thunar_standard_view_update_statusbar_text (THUNAR_STANDARD_VIEW (window->view)); } XfceGtkActionEntry * thunar_window_get_action_entries (void) { return thunar_window_action_entries; } /** * thunar_window_reconnect_accelerators: * @window : a #ThunarWindow instance. * * Used to recreate the accelerator group when the accelerator map changes. This way the open windows can use the * updated shortcuts. **/ void thunar_window_reconnect_accelerators (ThunarWindow *window) { /* the window has not been properly initialized yet */ if (window->accel_group == NULL) return; /* delete previous accel_group */ gtk_accel_group_disconnect (window->accel_group, NULL); gtk_window_remove_accel_group (GTK_WINDOW (window), window->accel_group); g_object_unref (window->accel_group); /* create new accel_group */ window->accel_group = gtk_accel_group_new (); xfce_gtk_accel_map_add_entries (thunar_window_action_entries, G_N_ELEMENTS (thunar_window_action_entries)); xfce_gtk_accel_group_connect_action_entries (window->accel_group, thunar_window_action_entries, G_N_ELEMENTS (thunar_window_action_entries), window); thunar_action_manager_append_accelerators (window->action_mgr, window->accel_group); thunar_statusbar_append_accelerators (THUNAR_STATUSBAR (window->statusbar), window->accel_group); thunar_window_update_bookmarks (window); gtk_window_add_accel_group (GTK_WINDOW (window), window->accel_group); /* update page accelarators */ if (window->view != NULL) g_object_set (G_OBJECT (window->view), "accel-group", window->accel_group, NULL); } static void uca_activation_callback_free (gpointer data, GClosure *closure) { g_free (((UCAActivation *) data)->action_name); g_slice_free (UCAActivation, data); } static void _thunar_window_check_activate_toolbar_uca_for_menu_items (GList *thunarx_menu_items, const gchar *action_name) { GList *lp_item; gchar *name; ThunarxMenu *submenu; for (lp_item = thunarx_menu_items; lp_item != NULL; lp_item = lp_item->next) { g_object_get (G_OBJECT (lp_item->data), "name", &name, "menu", &submenu, NULL); if (submenu != NULL) { /* if this menu-item is a folder, recursivly traverse it */ GList *thunarx_submenu_items = thunarx_menu_get_items (submenu); if (thunarx_submenu_items != NULL) { _thunar_window_check_activate_toolbar_uca_for_menu_items (thunarx_submenu_items, action_name); thunarx_menu_item_list_free (thunarx_submenu_items); } g_object_unref (submenu); } else { if (g_strcmp0 (action_name, name) == 0) thunarx_menu_item_activate (lp_item->data); } g_free (name); } } static void thunar_window_check_activate_toolbar_uca (UCAActivation *data) { ThunarWindow *window = data->window; gchar *action_name = data->action_name; ThunarxProviderFactory *provider_factory; GList *providers; GList *thunarx_menu_items = NULL; GList *lp_provider; /* load the menu providers from the provider factory */ provider_factory = thunarx_provider_factory_get_default (); providers = thunarx_provider_factory_list_providers (provider_factory, THUNARX_TYPE_MENU_PROVIDER); g_object_unref (provider_factory); if (G_UNLIKELY (providers == NULL)) return; /* load the menu items offered by the menu providers */ for (lp_provider = providers; lp_provider != NULL; lp_provider = lp_provider->next) { thunarx_menu_items = thunarx_menu_provider_get_folder_menu_items (lp_provider->data, GTK_WIDGET (window), THUNARX_FILE_INFO (window->current_directory)); _thunar_window_check_activate_toolbar_uca_for_menu_items (thunarx_menu_items, action_name); g_list_free_full (thunarx_menu_items, g_object_unref); } g_list_free_full (providers, g_object_unref); } GtkWidget * thunar_window_location_toolbar_add_uca (ThunarWindow *window, GObject *thunarx_menu_item) { gchar *name, *label_text, *tooltip_text, *icon_name; GtkWidget *image = NULL; GIcon *icon = NULL; GtkToolItem *tool_item; UCAActivation *data; g_return_val_if_fail (THUNARX_IS_MENU_ITEM (thunarx_menu_item), NULL); g_return_val_if_fail (THUNAR_IS_WINDOW (window), NULL); g_object_get (G_OBJECT (thunarx_menu_item), "name", &name, "label", &label_text, "tooltip", &tooltip_text, "icon", &icon_name, NULL); if (icon_name != NULL) icon = g_icon_new_for_string (icon_name, NULL); if (icon != NULL) image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_MENU); if (image == NULL) image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_LARGE_TOOLBAR); tool_item = gtk_tool_button_new (image, label_text); gtk_widget_set_tooltip_text (GTK_WIDGET (tool_item), tooltip_text); data = g_slice_new0 (UCAActivation); data->action_name = g_strdup (name); data->window = window; g_signal_connect_data (G_OBJECT (tool_item), "clicked", G_CALLBACK (thunar_window_check_activate_toolbar_uca), data, uca_activation_callback_free, G_CONNECT_SWAPPED); gtk_toolbar_insert (GTK_TOOLBAR (window->location_toolbar), tool_item, -1); g_free (name); g_free (label_text); g_free (tooltip_text); g_free (icon_name); if (icon != NULL) g_object_unref (icon); return GTK_WIDGET (tool_item); } static gchar * thunar_window_toolbar_get_icon_name (ThunarWindow *window, const gchar *icon_name) { gboolean use_symbolic_icons; if (icon_name == NULL) return NULL; g_object_get (G_OBJECT (window->preferences), "misc-symbolic-icons-in-toolbar", &use_symbolic_icons, NULL); /* create symbolic icon name */ if (use_symbolic_icons && !g_str_has_suffix (icon_name, "-symbolic")) return g_strjoin (NULL, icon_name, "-symbolic", NULL); /* create regular icon name */ if (!use_symbolic_icons && g_str_has_suffix (icon_name, "-symbolic")) return g_strndup (icon_name, strlen (icon_name) - 9); return g_strdup (icon_name); } static GtkWidget * thunar_window_create_toolbar_item_from_action (ThunarWindow *window, ThunarWindowAction action, guint item_order) { const XfceGtkActionEntry *entry = get_action_entry (action); GtkWidget *toolbar_item; GtkWidget *image; gchar *icon_name; toolbar_item = xfce_gtk_tool_button_new_from_action_entry (entry, G_OBJECT (window), GTK_TOOLBAR (window->location_toolbar)); /* update icon */ icon_name = thunar_window_toolbar_get_icon_name (window, entry->menu_item_icon_name); image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_LARGE_TOOLBAR); gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (toolbar_item), image); gtk_widget_show (image); /* update label to handle mnemonics in the overflow menu */ gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (toolbar_item), gtk_label_new_with_mnemonic (entry->menu_item_label_text)); g_object_set_data_full (G_OBJECT (toolbar_item), "id", thunar_util_accel_path_to_id (entry->accel_path), g_free); g_object_set_data_full (G_OBJECT (toolbar_item), "label", g_strdup (entry->menu_item_label_text), g_free); g_object_set_data_full (G_OBJECT (toolbar_item), "icon", g_strdup (icon_name), g_free); thunar_g_object_set_guint_data (G_OBJECT (toolbar_item), "default-order", item_order); g_free (icon_name); return toolbar_item; } static GtkWidget * thunar_window_create_toolbar_toggle_item_from_action (ThunarWindow *window, ThunarWindowAction action, gboolean active, guint item_order) { const XfceGtkActionEntry *entry = get_action_entry (action); GtkWidget *toolbar_item; GtkWidget *image; gchar *icon_name; toolbar_item = xfce_gtk_toggle_tool_button_new_from_action_entry (entry, G_OBJECT (window), active, GTK_TOOLBAR (window->location_toolbar)); /* update icon */ icon_name = thunar_window_toolbar_get_icon_name (window, entry->menu_item_icon_name); image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_LARGE_TOOLBAR); gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (toolbar_item), image); gtk_widget_show (image); /* update label to handle mnemonics in the overflow menu */ gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (toolbar_item), gtk_label_new_with_mnemonic (entry->menu_item_label_text)); g_object_set_data_full (G_OBJECT (toolbar_item), "id", thunar_util_accel_path_to_id (entry->accel_path), g_free); g_object_set_data_full (G_OBJECT (toolbar_item), "label", g_strdup (entry->menu_item_label_text), g_free); g_object_set_data_full (G_OBJECT (toolbar_item), "icon", g_strdup (icon_name), g_free); thunar_g_object_set_guint_data (G_OBJECT (toolbar_item), "default-order", item_order); g_free (icon_name); return toolbar_item; } static GtkWidget * thunar_window_create_toolbar_radio_item_from_action (ThunarWindow *window, ThunarWindowAction action, gboolean active, GtkRadioToolButton *group, guint item_order) { const XfceGtkActionEntry *entry = get_action_entry (action); GtkToolItem *toolbar_item; GtkWidget *image; gchar *icon_name; if (group == NULL) toolbar_item = gtk_radio_tool_button_new (NULL); else toolbar_item = gtk_radio_tool_button_new_from_widget (group); icon_name = thunar_window_toolbar_get_icon_name (window, entry->menu_item_icon_name); image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_LARGE_TOOLBAR); gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (toolbar_item), image); gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (toolbar_item), gtk_label_new_with_mnemonic (entry->menu_item_label_text)); gtk_widget_set_tooltip_text (GTK_WIDGET (toolbar_item), entry->menu_item_tooltip_text); gtk_toolbar_insert (GTK_TOOLBAR (window->location_toolbar), toolbar_item, -1); gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (toolbar_item), active); /* Note: set up "toggled" signal handler after all buttons inside the radio button group have been created */ g_object_set_data_full (G_OBJECT (toolbar_item), "id", thunar_util_accel_path_to_id (entry->accel_path), g_free); g_object_set_data_full (G_OBJECT (toolbar_item), "label", g_strdup (entry->menu_item_label_text), g_free); g_object_set_data_full (G_OBJECT (toolbar_item), "icon", g_strdup (icon_name), g_free); thunar_g_object_set_guint_data (G_OBJECT (toolbar_item), "default-order", item_order); g_free (icon_name); return GTK_WIDGET (toolbar_item); } static GtkWidget * thunar_window_create_toolbar_view_switcher (ThunarWindow *window, guint item_order) { GtkToolItem *toolbar_item; GtkWidget *menu_item; GtkWidget *menu_button; GtkWidget *image; GtkWidget *box; GtkWidget *arrow; toolbar_item = gtk_tool_item_new (); gtk_widget_set_tooltip_markup (GTK_WIDGET (toolbar_item), _("Change the active view type")); gtk_toolbar_insert (GTK_TOOLBAR (window->location_toolbar), toolbar_item, -1); g_object_set_data_full (G_OBJECT (toolbar_item), "id", g_strdup ("view-switcher"), g_free); g_object_set_data_full (G_OBJECT (toolbar_item), "label", g_strdup (_("View Switcher")), g_free); g_object_set_data_full (G_OBJECT (toolbar_item), "icon", g_strdup ("view-grid"), g_free); thunar_g_object_set_guint_data (G_OBJECT (toolbar_item), "default-order", item_order++); menu_button = gtk_menu_button_new (); /* remove menu_button arrow and add box to hold icon and arrow */ gtk_container_remove (GTK_CONTAINER (menu_button), gtk_bin_get_child (GTK_BIN (menu_button))); /* create layout of view switcher */ box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 1); image = gtk_image_new (); G_GNUC_BEGIN_IGNORE_DEPRECATIONS arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE); G_GNUC_END_IGNORE_DEPRECATIONS gtk_box_pack_start (GTK_BOX (box), image, TRUE, TRUE, 1); gtk_box_pack_end (GTK_BOX (box), arrow, FALSE, TRUE, 1); gtk_container_add (GTK_CONTAINER (menu_button), box); gtk_widget_show_all (box); gtk_container_add (GTK_CONTAINER (toolbar_item), menu_button); /* add a proxy menu item for the view switcher to be represent in the overflow menu */ menu_item = gtk_menu_item_new_with_label (_("View Switcher")); gtk_tool_item_set_proxy_menu_item (GTK_TOOL_ITEM (toolbar_item), "view-switcher-menu-id", menu_item); gtk_widget_set_sensitive (menu_item, FALSE); return GTK_WIDGET (toolbar_item); } static void thunar_window_view_switcher_update (ThunarWindow *window) { GtkToolItem *toolbar_item; GtkWidget *menu_button; GtkWidget *box; GtkWidget *image; GtkWidget *view_switcher_menu; GtkWidget *view_switcher_item; gchar *icon_name; XfceGtkActionEntry action_entry; GList *children; toolbar_item = GTK_TOOL_ITEM (window->location_toolbar_item_view_switcher); menu_button = gtk_bin_get_child (GTK_BIN (toolbar_item)); box = gtk_bin_get_child (GTK_BIN (menu_button)); children = gtk_container_get_children (GTK_CONTAINER (box)); image = g_list_nth_data (children, 0); view_switcher_menu = gtk_menu_new (); gtk_widget_set_halign (view_switcher_menu, GTK_ALIGN_CENTER); action_entry = *(get_action_entry (THUNAR_WINDOW_ACTION_VIEW_AS_ICONS)); action_entry.menu_item_type = XFCE_GTK_IMAGE_MENU_ITEM; icon_name = thunar_window_toolbar_get_icon_name (window, "view-grid"); action_entry.menu_item_icon_name = icon_name; view_switcher_item = xfce_gtk_menu_item_new_from_action_entry (&action_entry, G_OBJECT (window), GTK_MENU_SHELL (view_switcher_menu)); gtk_widget_set_tooltip_markup (view_switcher_item, action_entry.menu_item_tooltip_text); gtk_widget_show (view_switcher_item); if (window->view_type == THUNAR_TYPE_ICON_VIEW) { gtk_widget_set_sensitive (view_switcher_item, FALSE); gtk_image_set_from_icon_name (GTK_IMAGE (image), icon_name, gtk_tool_item_get_icon_size (toolbar_item)); } g_free (icon_name); action_entry = *(get_action_entry (THUNAR_WINDOW_ACTION_VIEW_AS_DETAILED_LIST)); action_entry.menu_item_type = XFCE_GTK_IMAGE_MENU_ITEM; icon_name = thunar_window_toolbar_get_icon_name (window, "view-list"); action_entry.menu_item_icon_name = icon_name; view_switcher_item = xfce_gtk_menu_item_new_from_action_entry (&action_entry, G_OBJECT (window), GTK_MENU_SHELL (view_switcher_menu)); gtk_widget_set_tooltip_markup (view_switcher_item, action_entry.menu_item_tooltip_text); gtk_widget_show (view_switcher_item); if (window->view_type == THUNAR_TYPE_DETAILS_VIEW) { gtk_widget_set_sensitive (view_switcher_item, FALSE); gtk_image_set_from_icon_name (GTK_IMAGE (image), icon_name, gtk_tool_item_get_icon_size (toolbar_item)); } g_free (icon_name); action_entry = *(get_action_entry (THUNAR_WINDOW_ACTION_VIEW_AS_COMPACT_LIST)); action_entry.menu_item_type = XFCE_GTK_IMAGE_MENU_ITEM; icon_name = thunar_window_toolbar_get_icon_name (window, "view-compact"); action_entry.menu_item_icon_name = icon_name; view_switcher_item = xfce_gtk_menu_item_new_from_action_entry (&action_entry, G_OBJECT (window), GTK_MENU_SHELL (view_switcher_menu)); gtk_widget_set_tooltip_markup (view_switcher_item, action_entry.menu_item_tooltip_text); gtk_widget_show (view_switcher_item); if (window->view_type == THUNAR_TYPE_COMPACT_VIEW) { gtk_widget_set_sensitive (view_switcher_item, FALSE); gtk_image_set_from_icon_name (GTK_IMAGE (image), icon_name, gtk_tool_item_get_icon_size (toolbar_item)); } g_free (icon_name); gtk_menu_button_set_popup (GTK_MENU_BUTTON (menu_button), view_switcher_menu); g_list_free (children); } static void thunar_window_location_bar_create (ThunarWindow *window) { /* allocate the new location bar widget */ window->location_bar = thunar_location_bar_new (); gtk_widget_set_margin_start (window->location_bar, DEFAULT_LOCATION_BAR_MARGIN); gtk_widget_set_margin_end (window->location_bar, DEFAULT_LOCATION_BAR_MARGIN); g_object_bind_property (G_OBJECT (window), "current-directory", G_OBJECT (window->location_bar), "current-directory", G_BINDING_SYNC_CREATE); g_signal_connect_swapped (G_OBJECT (window->location_bar), "change-directory", G_CALLBACK (thunar_window_set_current_directory), window); g_signal_connect_swapped (G_OBJECT (window->location_bar), "open-new-tab", G_CALLBACK (thunar_window_notebook_open_new_tab), window); g_signal_connect_swapped (G_OBJECT (window->location_bar), "entry-done", G_CALLBACK (thunar_window_update_location_bar_visible), window); gtk_widget_show (window->location_bar); } static void thunar_window_location_toolbar_create (ThunarWindow *window) { GtkToolItem *tool_item; GtkWidget *menu_item; guint item_order = 0; gboolean small_icons; g_object_get (G_OBJECT (window->preferences), "misc-small-toolbar-icons", &small_icons, NULL); /* create the location bar */ thunar_window_location_bar_create (window); /* setup the toolbar for the location bar */ window->location_toolbar = gtk_toolbar_new (); gtk_toolbar_set_style (GTK_TOOLBAR (window->location_toolbar), GTK_TOOLBAR_ICONS); gtk_toolbar_set_icon_size (GTK_TOOLBAR (window->location_toolbar), small_icons ? GTK_ICON_SIZE_SMALL_TOOLBAR : GTK_ICON_SIZE_LARGE_TOOLBAR); gtk_widget_set_hexpand (window->location_toolbar, TRUE); g_signal_connect (G_OBJECT (window->location_toolbar), "button-press-event", G_CALLBACK (thunar_window_toolbar_button_press_event), window); /* add toolbar items */ window->location_toolbar_item_menu = thunar_window_create_toolbar_toggle_item_from_action (window, THUNAR_WINDOW_ACTION_MENU, FALSE, item_order++); window->location_toolbar_item_back = thunar_window_create_toolbar_item_from_action (window, THUNAR_WINDOW_ACTION_BACK, item_order++); window->location_toolbar_item_forward = thunar_window_create_toolbar_item_from_action (window, THUNAR_WINDOW_ACTION_FORWARD, item_order++); window->location_toolbar_item_parent = thunar_window_create_toolbar_item_from_action (window, THUNAR_WINDOW_ACTION_OPEN_PARENT, item_order++); window->location_toolbar_item_home = thunar_window_create_toolbar_item_from_action (window, THUNAR_WINDOW_ACTION_OPEN_HOME, item_order++); thunar_window_create_toolbar_item_from_action (window, THUNAR_WINDOW_ACTION_NEW_TAB, item_order++); thunar_window_create_toolbar_item_from_action (window, THUNAR_WINDOW_ACTION_NEW_WINDOW, item_order++); window->location_toolbar_item_split_view = thunar_window_create_toolbar_toggle_item_from_action (window, THUNAR_WINDOW_ACTION_VIEW_SPLIT, thunar_window_split_view_is_active (window), item_order++); window->location_toolbar_item_undo = thunar_window_create_toolbar_item_from_action (window, THUNAR_WINDOW_ACTION_UNDO, item_order++); window->location_toolbar_item_redo = thunar_window_create_toolbar_item_from_action (window, THUNAR_WINDOW_ACTION_REDO, item_order++); window->location_toolbar_item_zoom_out = thunar_window_create_toolbar_item_from_action (window, THUNAR_WINDOW_ACTION_ZOOM_OUT, item_order++); window->location_toolbar_item_zoom_in = thunar_window_create_toolbar_item_from_action (window, THUNAR_WINDOW_ACTION_ZOOM_IN, item_order++); thunar_window_create_toolbar_item_from_action (window, THUNAR_WINDOW_ACTION_ZOOM_RESET, item_order++); window->location_toolbar_item_icon_view = thunar_window_create_toolbar_radio_item_from_action (window, THUNAR_WINDOW_ACTION_VIEW_AS_ICONS, window->view_type == THUNAR_TYPE_ICON_VIEW, NULL, item_order++); window->location_toolbar_item_detailed_view = thunar_window_create_toolbar_radio_item_from_action (window, THUNAR_WINDOW_ACTION_VIEW_AS_DETAILED_LIST, window->view_type == THUNAR_TYPE_DETAILS_VIEW, GTK_RADIO_TOOL_BUTTON (window->location_toolbar_item_icon_view), item_order++); window->location_toolbar_item_compact_view = thunar_window_create_toolbar_radio_item_from_action (window, THUNAR_WINDOW_ACTION_VIEW_AS_COMPACT_LIST, window->view_type == THUNAR_TYPE_COMPACT_VIEW, GTK_RADIO_TOOL_BUTTON (window->location_toolbar_item_icon_view), item_order++); window->location_toolbar_item_view_switcher = thunar_window_create_toolbar_view_switcher (window, item_order++); g_signal_connect (window->location_toolbar_item_back, "button-press-event", G_CALLBACK (thunar_window_history_clicked), window); g_signal_connect (window->location_toolbar_item_forward, "button-press-event", G_CALLBACK (thunar_window_history_clicked), window); g_signal_connect (window->location_toolbar_item_parent, "button-press-event", G_CALLBACK (thunar_window_open_parent_clicked), window); g_signal_connect (window->location_toolbar_item_home, "button-press-event", G_CALLBACK (thunar_window_open_home_clicked), window); g_object_bind_property (window->job_operation_history, "can-undo", window->location_toolbar_item_undo, "sensitive", G_BINDING_SYNC_CREATE); g_object_bind_property (window->job_operation_history, "can-redo", window->location_toolbar_item_redo, "sensitive", G_BINDING_SYNC_CREATE); g_signal_connect_swapped (window->location_toolbar_item_icon_view, "toggled", get_action_entry (THUNAR_WINDOW_ACTION_VIEW_AS_ICONS)->callback, window); g_signal_connect_swapped (window->location_toolbar_item_detailed_view, "toggled", get_action_entry (THUNAR_WINDOW_ACTION_VIEW_AS_DETAILED_LIST)->callback, window); g_signal_connect_swapped (window->location_toolbar_item_compact_view, "toggled", get_action_entry (THUNAR_WINDOW_ACTION_VIEW_AS_COMPACT_LIST)->callback, window); thunar_window_view_switcher_update (window); /* add the location bar to the toolbar */ tool_item = gtk_tool_item_new (); gtk_tool_item_set_expand (tool_item, TRUE); gtk_toolbar_insert (GTK_TOOLBAR (window->location_toolbar), tool_item, -1); g_object_set_data_full (G_OBJECT (tool_item), "id", g_strdup ("location-bar"), g_free); g_object_set_data_full (G_OBJECT (tool_item), "label", g_strdup (_("Location Bar")), g_free); g_object_set_data_full (G_OBJECT (tool_item), "icon", g_strdup (""), g_free); thunar_g_object_set_guint_data (G_OBJECT (tool_item), "default-order", item_order++); /* add a proxy menu item for the location bar to represent the bar in the overflow menu */ menu_item = gtk_menu_item_new_with_label (_("Location Bar")); gtk_tool_item_set_proxy_menu_item (tool_item, "location-toolbar-menu-id", menu_item); gtk_widget_set_sensitive (GTK_WIDGET (menu_item), FALSE); /* add remaining toolbar items */ thunar_window_create_toolbar_item_from_action (window, THUNAR_WINDOW_ACTION_RELOAD, item_order++); window->location_toolbar_item_search = thunar_window_create_toolbar_toggle_item_from_action (window, THUNAR_WINDOW_ACTION_SEARCH, window->is_searching, item_order++); /* add custom actions to the toolbar */ thunar_window_location_toolbar_add_ucas (window); /* display the toolbar */ gtk_widget_show_all (window->location_toolbar); /* only show the menu button when the menubar is hidden */ gtk_widget_set_visible (window->location_toolbar_item_menu, !window->menubar_visible); /* add the location bar itself after gtk_widget_show_all to not mess with the visibility of the location buttons */ gtk_container_add (GTK_CONTAINER (tool_item), window->location_bar); /* load the correct order and visibility of items in the toolbar */ thunar_window_location_toolbar_load_items (window); } static void thunar_window_update_location_toolbar (ThunarWindow *window) { gtk_widget_destroy (window->location_toolbar); thunar_window_location_toolbar_create (window); if (gtk_window_get_titlebar (GTK_WINDOW (window)) == NULL) gtk_grid_attach (GTK_GRID (window->grid), window->location_toolbar, 0, 1, 1, 1); thunar_window_csd_update (window); } static void thunar_window_update_location_toolbar_icons (ThunarWindow *window) { GtkWidget *parent; GList *toolbar_items; GList *lp; toolbar_items = gtk_container_get_children (GTK_CONTAINER (window->location_toolbar)); for (lp = toolbar_items; lp != NULL; lp = lp->next) { GtkWidget *item = lp->data; gchar *icon = g_object_get_data (G_OBJECT (item), "icon"); gchar *id = g_object_get_data (G_OBJECT (item), "id"); /* skip custom actions */ if (g_str_has_prefix (id, "uca-action")) continue; if (GTK_IS_TOOL_BUTTON (item)) { GtkWidget *image; gchar *icon_name; /* update icon */ icon_name = thunar_window_toolbar_get_icon_name (window, icon); image = gtk_image_new_from_icon_name (icon_name, gtk_tool_item_get_icon_size (GTK_TOOL_ITEM (item))); gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (item), image); gtk_widget_show (image); g_object_set_data_full (G_OBJECT (item), "icon", g_strdup (icon_name), g_free); g_free (icon_name); } } /* get the toolbar item containing the location bar */ parent = gtk_widget_get_parent (window->location_bar); if (parent != NULL) { /* rebuild the location bar */ if (window->location_bar != NULL) gtk_widget_destroy (window->location_bar); thunar_window_location_bar_create (window); gtk_container_add (GTK_CONTAINER (parent), window->location_bar); } thunar_window_view_switcher_update (window); g_list_free (toolbar_items); } static void _thunar_window_location_toolbar_add_ucas_menu_items (ThunarWindow *window, GList *thunarx_menu_items, guint *item_count) { GList *lp_item; gchar *name, *label_text, *icon_name; ThunarxMenu *submenu; for (lp_item = thunarx_menu_items; lp_item != NULL; lp_item = lp_item->next) { g_object_get (G_OBJECT (lp_item->data), "name", &name, "label", &label_text, "icon", &icon_name, "menu", &submenu, NULL); if (submenu != NULL) { /* if this menu-item is a folder, recursivly traverse it */ GList *thunarx_submenu_items = thunarx_menu_get_items (submenu); if (thunarx_submenu_items != NULL) { _thunar_window_location_toolbar_add_ucas_menu_items (window, thunarx_submenu_items, item_count); thunarx_menu_item_list_free (thunarx_submenu_items); } g_object_unref (submenu); } else { if (g_str_has_prefix (name, "uca-action") == TRUE) { GtkWidget *toolbar_item; guint *item_order; toolbar_item = thunar_window_location_toolbar_add_uca (window, lp_item->data); g_object_set_data_full (G_OBJECT (toolbar_item), "id", g_strdup (name), g_free); g_object_set_data_full (G_OBJECT (toolbar_item), "label", g_strdup (label_text), g_free); g_object_set_data_full (G_OBJECT (toolbar_item), "icon", g_strdup (icon_name), g_free); item_order = g_malloc (sizeof (gint)); *item_order = (*item_count)++; g_object_set_data_full (G_OBJECT (toolbar_item), "default-order", item_order, g_free); } } g_free (name); g_free (label_text); g_free (icon_name); } } static void thunar_window_location_toolbar_add_ucas (ThunarWindow *window) { ThunarxProviderFactory *provider_factory; ThunarFile *home_folder; GFile *home_gfile; GList *providers; GList *thunarx_menu_items = NULL; GList *lp_provider; GList *toolbar_container_children; guint item_count; /* determine the file for the home directory */ home_gfile = thunar_g_file_new_for_home (); home_folder = thunar_file_get (home_gfile, NULL); g_object_unref (home_gfile); if (home_folder == NULL) return; /* get number of items in the toolbar */ toolbar_container_children = gtk_container_get_children (GTK_CONTAINER (window->location_toolbar)); item_count = g_list_length (toolbar_container_children); g_list_free (toolbar_container_children); /* load the menu providers from the provider factory */ provider_factory = thunarx_provider_factory_get_default (); providers = thunarx_provider_factory_list_providers (provider_factory, THUNARX_TYPE_MENU_PROVIDER); g_object_unref (provider_factory); if (G_UNLIKELY (providers != NULL)) { /* load the menu items offered by the menu providers */ for (lp_provider = providers; lp_provider != NULL; lp_provider = lp_provider->next) { thunarx_menu_items = thunarx_menu_provider_get_folder_menu_items (lp_provider->data, GTK_WIDGET (window), THUNARX_FILE_INFO (home_folder)); _thunar_window_location_toolbar_add_ucas_menu_items (window, thunarx_menu_items, &item_count); g_list_free_full (thunarx_menu_items, g_object_unref); } g_list_free_full (providers, g_object_unref); } g_object_unref (home_folder); } static void thunar_window_location_toolbar_load_items (ThunarWindow *window) { GList *toolbar_items; gchar **items; guint items_length; gchar *tmp; /* read and migrate old settings */ // TODO: drop this code block and the called functions // after the 4.20 release, or later if desired if (!thunar_preferences_has_property (window->preferences, "/last-toolbar-items") && thunar_preferences_has_property (window->preferences, "/last-toolbar-item-order")) { /* load the correct order of items in the toolbar */ thunar_window_location_toolbar_load_last_order (window); /* load the correct visibility of items in the toolbar */ thunar_window_location_toolbar_load_visibility (window); /* save configuration */ thunar_save_toolbar_configuration (window->location_toolbar); return; } if (thunar_window_toolbar_item_count (window) == 0) return; /* get all toolbar items */ toolbar_items = gtk_container_get_children (GTK_CONTAINER (window->location_toolbar)); /* determine the order from the preferences */ g_object_get (G_OBJECT (window->preferences), "last-toolbar-items", &tmp, NULL); items = g_strsplit (tmp, ",", -1); items_length = g_strv_length (items); g_free (tmp); /* now rearrange the toolbar items according to the saved order */ for (guint i = 0; i < items_length; i++) { GList *lp; gchar **item_data = g_strsplit (items[i], ":", -1); /* id:visible */ /* find matching toolbar item in the list */ for (lp = toolbar_items; lp != NULL; lp = lp->next) { GtkWidget *item = lp->data; gchar *id = g_object_get_data (G_OBJECT (item), "id"); /* update the toolbar item */ if (g_strcmp0 (item_data[0], id) == 0) { gboolean hidden; /* set its position */ g_object_ref (item); gtk_container_remove (GTK_CONTAINER (window->location_toolbar), item); gtk_toolbar_insert (GTK_TOOLBAR (window->location_toolbar), GTK_TOOL_ITEM (item), i); g_object_unref (item); /* set its visibility */ hidden = (g_strcmp0 (item_data[1], "0") == 0); if (hidden) thunar_window_toolbar_toggle_item_visibility (window, i); /* remove it from the list */ toolbar_items = g_list_remove (toolbar_items, item); break; } } g_strfreev (item_data); } /* hide remaining toolbar items which are not present in the saved order */ g_list_foreach (toolbar_items, (GFunc) (void (*) (void)) gtk_widget_hide, NULL); g_list_free (toolbar_items); g_strfreev (items); } /** * thunar_window_location_toolbar_load_last_order: * @window : a #ThunarWindow instance. * * Load the order of toolbar items stored in `last-toolbar-button-order`. **/ static void thunar_window_location_toolbar_load_last_order (ThunarWindow *window) { gchar **item_order; guint item_order_length; gchar *tmp; guint item_count = thunar_window_toolbar_item_count (window); guint target_order[item_count]; /* item_order converted to guint and without invalid entries (i.e. entries >= item_count */ guint current_order[item_count]; /* determine the column order from the preferences */ g_object_get (G_OBJECT (window->preferences), "last-toolbar-item-order", &tmp, NULL); item_order = g_strsplit (tmp, ",", -1); item_order_length = g_strv_length (item_order); g_free (tmp); /* restore the default toolbar item order from version 4.18 to make this work */ if (item_count > 0) { GList *toolbar_items = gtk_container_get_children (GTK_CONTAINER (window->location_toolbar)); GList *lp; gchar *old_default_order[17] = { "menu", "back", "forward", "open-parent", "open-home", "undo", "redo", "zoom-in", "zoom-out", "zoom-reset", "view-as-icons", "view-as-detailed-list", "view-as-compact-list", "toggle-split-view", "location-bar", "reload", "search" }; guint uca_count = 0; /* custom actions count */ guint uca_index = 17; /* custom actions will be added after the default items */ guint new_index; /* toolbar items added after 4.18 will be appended */ for (lp = toolbar_items; lp != NULL; lp = lp->next) { gchar *id = g_object_get_data (G_OBJECT (lp->data), "id"); if (g_str_has_prefix (id, "uca-action")) uca_count++; } new_index = uca_index + uca_count; for (lp = toolbar_items; lp != NULL; lp = lp->next) { gchar *id = g_object_get_data (G_OBJECT (lp->data), "id"); guint *pos = g_object_get_data (G_OBJECT (lp->data), "default-order"); guint i = 0; for (; i < 17; i++) { if (g_strcmp0 (old_default_order[i], id) == 0) break; } if (i < 17) current_order[*pos] = i; /* old default item */ else if (g_str_has_prefix (id, "uca-action")) current_order[*pos] = uca_index++; /* custom action */ else current_order[*pos] = new_index++; /* new toolbar item */ } g_list_free (toolbar_items); } for (guint i = 0; i < item_count; i++) target_order[i] = i; /* convert strings to guints for convenience */ for (guint i = 0, j = 0; i < item_order_length; i++) { guint64 n; if (g_ascii_string_to_unsigned (item_order[i], 10, 0, UINT_MAX, &n, NULL) == FALSE) g_error ("Invalid entry in \"last-toolbar-button-order\""); /* the entry is invalid, it is likely that a custom action was removed and the preference hasn't been updated */ if (n >= item_count) continue; target_order[j] = n; j++; } /* now rearrange the toolbar items, the goal is to make the current_order like the target_order */ for (guint i = 0; i < item_count; i++) { guint x = target_order[i]; for (guint j = i; j < item_count; j++) { guint y = current_order[j]; if (x == y && i != j) { /* swap the positions of the toolbar items */ thunar_window_toolbar_swap_items (window, i, j); y = current_order[i]; current_order[i] = target_order[i]; current_order[j] = y; break; } } } /* release the column order */ g_strfreev (item_order); } /** * thunar_window_location_toolbar_load_visibility: * @window : a #ThunarWindow instance. * * Load the visibility of toolbar items. This should run after thunar_window_location_toolbar_load_last_order because * it depends on the the saved order instead of the default. * * returns FALSE so it can be used as an idle function **/ static gboolean thunar_window_location_toolbar_load_visibility (ThunarWindow *window) { gchar **item_visibility; guint item_visibility_length; gchar *item_visibility_string; guint item_count = thunar_window_toolbar_item_count (window); guint target_order[item_count]; /* determine the column order from the preferences */ g_object_get (G_OBJECT (window->preferences), "last-toolbar-visible-buttons", &item_visibility_string, NULL); item_visibility = g_strsplit (item_visibility_string, ",", -1); item_visibility_length = g_strv_length (item_visibility); g_free (item_visibility_string); for (guint i = 0; i < item_count; i++) target_order[i] = 0; /* default to invisible */ /* convert strings to guints for convenience */ for (guint i = 0, j = 0; i < item_visibility_length; i++) { guint64 n; if (g_ascii_string_to_unsigned (item_visibility[i], 10, 0, UINT_MAX, &n, NULL) == FALSE) g_error ("Invalid entry in \"last-toolbar-visible-buttons\""); target_order[j] = n; j++; } for (guint i = 0; i < item_count; i++) { guint visible = target_order[i]; if (visible == 0) thunar_window_toolbar_toggle_item_visibility (window, i); } /* release the column order */ g_strfreev (item_visibility); return FALSE; } static guint thunar_window_toolbar_item_count (ThunarWindow *window) { GList *toolbar_items; guint count = 0; _thunar_return_val_if_fail (THUNAR_IS_WINDOW (window), count); if (window->location_toolbar == NULL) return count; toolbar_items = gtk_container_get_children (GTK_CONTAINER (window->location_toolbar)); count = g_list_length (toolbar_items); g_list_free (toolbar_items); return count; } void thunar_window_toolbar_toggle_item_visibility (ThunarWindow *window, gint index) { GList *toolbar_items, *lp; _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); _thunar_return_if_fail (index >= 0); if (window->location_toolbar == NULL) return; toolbar_items = gtk_container_get_children (GTK_CONTAINER (window->location_toolbar)); lp = toolbar_items; for (gint i = 0; lp != NULL; lp = lp->next, i++) { GtkWidget *item = lp->data; /* visibility of this item is only controlled by 'window->menubar_visible' */ if (item == window->location_toolbar_item_menu) continue; if (index == i) { gtk_widget_set_visible (item, !gtk_widget_is_visible (item)); break; } } g_list_free (toolbar_items); } void thunar_window_toolbar_swap_items (ThunarWindow *window, gint index_a, gint index_b) { GList *toolbar_items, *lp; GtkWidget *item_a = NULL; GtkWidget *item_b = NULL; _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); _thunar_return_if_fail (index_a >= 0); _thunar_return_if_fail (index_b >= 0); if (window->location_toolbar == NULL) return; toolbar_items = gtk_container_get_children (GTK_CONTAINER (window->location_toolbar)); lp = toolbar_items; for (gint i = 0; lp != NULL; lp = lp->next, i++) { if (index_a == i) item_a = lp->data; if (index_b == i) item_b = lp->data; } if (item_a == NULL || item_b == NULL) { g_error ("Unable to swap toolbar items.\n"); return; } g_object_ref (item_a); gtk_container_remove (GTK_CONTAINER (window->location_toolbar), item_a); gtk_toolbar_insert (GTK_TOOLBAR (window->location_toolbar), GTK_TOOL_ITEM (item_a), index_b); g_object_unref (item_a); g_object_ref (item_b); gtk_container_remove (GTK_CONTAINER (window->location_toolbar), item_b); gtk_toolbar_insert (GTK_TOOLBAR (window->location_toolbar), GTK_TOOL_ITEM (item_b), index_a); g_object_unref (item_b); g_list_free (toolbar_items); } /** * thunar_window_queue_redraw: * @window : a #ThunarWindow instance. * * Method to trigger a redraw of the window **/ void thunar_window_queue_redraw (ThunarWindow *window) { _thunar_return_if_fail (THUNAR_IS_WINDOW (window)); if (G_LIKELY (window->view != NULL)) thunar_standard_view_queue_redraw (THUNAR_STANDARD_VIEW (window->view)); // TODO: Redraw as well all other parts of the window }