/* vi:set et ai sw=2 sts=2 ts=2: */ /*- * Copyright (c) 2005-2006 Benedikt Meurer * Copyright (c) 2009 Jannis Pohlmann * Copyright (c) 2020 Alexander Schwinn * * 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., 59 Temple * Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_MEMORY_H #include #endif #ifdef HAVE_STRING_H #include #endif #include "thunar/thunar-action-manager.h" #include "thunar/thunar-application.h" #include "thunar/thunar-browser.h" #include "thunar/thunar-chooser-dialog.h" #include "thunar/thunar-clipboard-manager.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-icon-factory.h" #include "thunar/thunar-io-scan-directory.h" #include "thunar/thunar-preferences.h" #include "thunar/thunar-private.h" #include "thunar/thunar-properties-dialog.h" #include "thunar/thunar-renamer-dialog.h" #include "thunar/thunar-sendto-model.h" #include "thunar/thunar-shortcuts-pane.h" #include "thunar/thunar-simple-job.h" #include "thunar/thunar-tree-view.h" #include "thunar/thunar-util.h" #include "thunar/thunar-window.h" #include #include /** * SECTION:thunar-action-manager * @Short_description: Manages creation and execution of menu-item * @Title: ThunarActionManager * * The #ThunarActionManager class manages the creation and execution of menu-item which are used by multiple menus. * The management is done in a central way to prevent code duplication on various places. * XfceGtkActionEntry is used in order to define a list of the managed items and ease the setup of single items. * * #ThunarActionManager implements the #ThunarNavigator interface in order to use the "open in new tab" and "change directory" service. * It as well tracks the current directory via #ThunarNavigator. * * #ThunarActionManager implements the #ThunarComponent interface in order to track the currently selected files. * Based on to the current selection (and some other criteria), some menu items will not be shown, or will be insensitive. * * Files which are opened via #ThunarActionManager are poked first in order to e.g do missing mount operations. * * As well menu-item related services, like activation of selected files and opening tabs/new windows, * are provided by #ThunarActionManager. * * It is required to keep an instance of #ThunarActionManager open, in order to listen to accellerators which target * menu-items managed by #ThunarActionManager. * Typically a single instance of #ThunarActionManager is provided by each #ThunarWindow. */ typedef struct _ThunarActionManagerPokeData ThunarActionManagerPokeData; /* Signal identifiers */ enum { DEVICE_OPERATION_STARTED, DEVICE_OPERATION_FINISHED, NEW_FILES_CREATED, LAST_SIGNAL, }; /* Property identifiers */ enum { PROP_0, PROP_CURRENT_DIRECTORY, PROP_SELECTED_FILES, PROP_WIDGET, PROP_SELECTED_DEVICE, PROP_SELECTED_LOCATION, N_PROPERTIES }; static void thunar_action_manager_component_init (ThunarComponentIface *iface); static void thunar_action_manager_navigator_init (ThunarNavigatorIface *iface); static void thunar_action_manager_dispose (GObject *object); static void thunar_action_manager_finalize (GObject *object); static void thunar_action_manager_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static void thunar_action_manager_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static ThunarFile * thunar_action_manager_get_current_directory (ThunarNavigator *navigator); static void thunar_action_manager_set_current_directory (ThunarNavigator *navigator, ThunarFile *current_directory); static void thunar_action_manager_set_selected_files (ThunarComponent *component, GList *selected_files); static void thunar_action_manager_execute_files (ThunarActionManager *action_mgr, GList *files, gboolean in_terminal); static void thunar_action_manager_open_files (ThunarActionManager *action_mgr, GList *files, GAppInfo *application_to_use); static void thunar_action_manager_open_paths (GAppInfo *app_info, GList *file_list, ThunarActionManager *action_mgr); static void thunar_action_manager_open_windows (ThunarActionManager *action_mgr, GList *directories); static void thunar_action_manager_poke (ThunarActionManager *action_mgr, GAppInfo *application_to_use, ThunarActionManagerFolderOpenAction folder_open_action); static void thunar_action_manager_poke_device_finish (ThunarBrowser *browser, ThunarDevice *volume, ThunarFile *mount_point, GError *error, gpointer user_data, gboolean cancelled); static void thunar_action_manager_poke_location_finish (ThunarBrowser *browser, GFile *location, ThunarFile *file, ThunarFile *target_file, GError *error, gpointer user_data); static void thunar_action_manager_poke_files_finish (ThunarBrowser *browser, ThunarFile *file, ThunarFile *target_file, GError *error, gpointer user_data); static ThunarActionManagerPokeData * thunar_action_manager_poke_data_new (GList *files_to_poke, GAppInfo *application_to_use, ThunarActionManagerFolderOpenAction folder_open_action, GFile *location_to_poke, ThunarDevice *device_to_poke); static void thunar_action_manager_poke_data_free (ThunarActionManagerPokeData *data); static void thunar_action_manager_widget_destroyed (ThunarActionManager *action_mgr, GtkWidget *widget); static gboolean thunar_action_manager_action_open (ThunarActionManager *action_mgr); static gboolean thunar_action_manager_action_open_in_new_tabs (ThunarActionManager *action_mgr); static gboolean thunar_action_manager_action_open_in_new_windows (ThunarActionManager *action_mgr); static gboolean thunar_action_manager_action_open_location (ThunarActionManager *action_mgr); static gboolean thunar_action_manager_action_open_with_other (ThunarActionManager *action_mgr); static gboolean thunar_action_manager_action_set_default_app (ThunarActionManager *action_mgr); static gboolean thunar_action_manager_action_sendto_desktop (ThunarActionManager *action_mgr); static gboolean thunar_action_manager_action_properties (ThunarActionManager *action_mgr); static gboolean thunar_action_manager_action_sendto_device (ThunarActionManager *action_mgr, GObject *object); static gboolean thunar_action_manager_action_add_shortcuts (ThunarActionManager *action_mgr); static gboolean thunar_action_manager_action_make_link (ThunarActionManager *action_mgr); static gboolean thunar_action_manager_action_duplicate (ThunarActionManager *action_mgr); static gboolean thunar_action_manager_action_rename (ThunarActionManager *action_mgr); static void thunar_action_manager_action_move_to_trash (ThunarActionManager *action_mgr); static gboolean thunar_action_manager_action_delete (ThunarActionManager *action_mgr); static gboolean thunar_action_manager_action_trash_delete (ThunarActionManager *action_mgr); static gboolean thunar_action_manager_action_remove_from_recent (ThunarActionManager *action_mgr); static gboolean thunar_action_manager_action_cut (ThunarActionManager *action_mgr); static gboolean thunar_action_manager_action_copy (ThunarActionManager *action_mgr); static gboolean thunar_action_manager_action_paste (ThunarActionManager *action_mgr); static gboolean thunar_action_manager_action_paste_into_folder (ThunarActionManager *action_mgr); static void thunar_action_manager_action_edit_launcher (ThunarActionManager *action_mgr); static void thunar_action_manager_sendto_device (ThunarActionManager *action_mgr, ThunarDevice *device); static void thunar_action_manager_sendto_mount_finish (ThunarDevice *device, const GError *error, gpointer user_data); static GtkWidget * thunar_action_manager_build_sendto_submenu (ThunarActionManager *action_mgr); static gboolean thunar_action_manager_menu_item_activated (ThunarActionManager *action_mgr, GtkWidget *menu_item); static gboolean thunar_action_manager_action_create_folder (ThunarActionManager *action_mgr); static gboolean thunar_action_manager_action_create_document (ThunarActionManager *action_mgr, GtkWidget *menu_item); static GtkWidget * thunar_action_manager_create_document_submenu_new (ThunarActionManager *action_mgr); static void thunar_action_manager_new_files_created (ThunarActionManager *action_mgr, GList *new_thunar_files); struct _ThunarActionManagerClass { GObjectClass __parent__; }; struct _ThunarActionManager { GObject __parent__; ThunarFile *current_directory; GList *files_to_process; /* List of thunar-files to work with */ ThunarDevice *device_to_process; /* Device to work with */ GFile *location_to_process; /* Location to work with (might be not reachable) */ gint n_files_to_process; gint n_directories_to_process; gint n_regulars_to_process; gboolean files_to_process_trashable; gboolean files_are_selected; gboolean files_are_all_executable; gboolean single_directory_to_process; ThunarFile *single_folder; ThunarFile *parent_folder; /* closure invoked whenever action manager creates new files (create, paste, rename, etc) */ GClosure *new_files_created_closure; ThunarPreferences *preferences; /* Parent widget which holds the instance of the action manager */ GtkWidget *widget; /* TRUE if the active view is displaying search results or actively searching for files */ gboolean is_searching; }; static GQuark thunar_action_manager_appinfo_quark; static GQuark thunar_action_manager_device_quark; static GQuark thunar_action_manager_file_quark; static guint action_manager_signals[LAST_SIGNAL]; struct _ThunarActionManagerPokeData { GList *files_to_poke; /* List of thunar-files */ GList *files_poked; /* List of thunar-files */ GFile *location_to_poke; ThunarDevice *device_to_poke; GAppInfo *application_to_use; ThunarActionManagerFolderOpenAction folder_open_action; }; static GParamSpec *action_manager_props[N_PROPERTIES] = { NULL, }; /* clang-format off */ static XfceGtkActionEntry thunar_action_manager_action_entries[] = { { THUNAR_ACTION_MANAGER_ACTION_OPEN, "/ThunarActionManager/open", "O", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Open"), NULL, "document-open", G_CALLBACK (thunar_action_manager_action_open), }, { THUNAR_ACTION_MANAGER_ACTION_EXECUTE, "/ThunarActionManager/execute", "", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Execute"), NULL, "system-run", G_CALLBACK (thunar_action_manager_action_open), }, { THUNAR_ACTION_MANAGER_ACTION_EDIT_LAUNCHER, NULL, "", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Edit _Launcher"), N_ ("Edit the selected launcher"), "gtk-edit", G_CALLBACK (thunar_action_manager_action_edit_launcher), }, { THUNAR_ACTION_MANAGER_ACTION_OPEN_IN_TAB, "/ThunarActionManager/open-in-new-tab", "P", XFCE_GTK_MENU_ITEM, N_ ("Open in new _Tab"), NULL, NULL, G_CALLBACK (thunar_action_manager_action_open_in_new_tabs), }, { THUNAR_ACTION_MANAGER_ACTION_OPEN_IN_WINDOW, "/ThunarActionManager/open-in-new-window", "O", XFCE_GTK_MENU_ITEM, N_ ("Open in new _Window"), NULL, NULL, G_CALLBACK (thunar_action_manager_action_open_in_new_windows), }, { THUNAR_ACTION_MANAGER_ACTION_OPEN_LOCATION, "/ThunarActionManager/open-location", "", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Open Item _Location"), N_ ("Navigate to the folder in which the selected file is located"), "go-jump", G_CALLBACK (thunar_action_manager_action_open_location), }, { THUNAR_ACTION_MANAGER_ACTION_OPEN_WITH_OTHER, "/ThunarActionManager/open-with-other", "", XFCE_GTK_MENU_ITEM, N_ ("Ope_n With Other Application..."), N_ ("Choose another application with which to open the selected file"), NULL, G_CALLBACK (thunar_action_manager_action_open_with_other), }, { THUNAR_ACTION_MANAGER_ACTION_SET_DEFAULT_APP, "/ThunarStandardView/set-default-app", "", XFCE_GTK_MENU_ITEM, N_ ("Set Defa_ult Application..."), N_ ("Choose an application which should be used by default to open the selected file"), NULL, G_CALLBACK (thunar_action_manager_action_set_default_app), }, /* For backward compatibility the old accel paths are re-used. Currently not possible to automatically migrate to new accel paths. */ /* Waiting for https://gitlab.gnome.org/GNOME/gtk/issues/2375 to be able to fix that */ {THUNAR_ACTION_MANAGER_ACTION_SENDTO_MENU, "/ThunarWindow/sendto-menu", "", XFCE_GTK_MENU_ITEM, N_ ("_Send To"), NULL, NULL, NULL, }, {THUNAR_ACTION_MANAGER_ACTION_SENDTO_SHORTCUTS, "/ThunarShortcutsPane/sendto-shortcuts", "D", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Add Bookmark"), N_ ("Create bookmarks for all selected folders. If nothing is selected, the current folder is bookmarked."), "bookmark-new", G_CALLBACK (thunar_action_manager_action_add_shortcuts), }, {THUNAR_ACTION_MANAGER_ACTION_SENDTO_DESKTOP, "/ThunarActionManager/sendto-desktop", "", XFCE_GTK_MENU_ITEM, N_ ("Send to _Desktop"), NULL, "user-desktop", G_CALLBACK (thunar_action_manager_action_sendto_desktop), }, {THUNAR_ACTION_MANAGER_ACTION_PROPERTIES, "/ThunarStandardView/properties", "Return", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Properties..."), N_ ("View the properties of the selected file"), "document-properties", G_CALLBACK (thunar_action_manager_action_properties), }, {THUNAR_ACTION_MANAGER_ACTION_MAKE_LINK, "/ThunarStandardView/make-link", "", XFCE_GTK_MENU_ITEM, N_ ("Ma_ke Link"), NULL, NULL, G_CALLBACK (thunar_action_manager_action_make_link), }, {THUNAR_ACTION_MANAGER_ACTION_DUPLICATE, "/ThunarStandardView/duplicate", "", XFCE_GTK_MENU_ITEM, N_ ("Dup_licate"), NULL, NULL, G_CALLBACK (thunar_action_manager_action_duplicate), }, {THUNAR_ACTION_MANAGER_ACTION_RENAME, "/ThunarStandardView/rename", "F2", XFCE_GTK_MENU_ITEM, N_ ("_Rename..."), NULL, NULL, G_CALLBACK (thunar_action_manager_action_rename), }, {THUNAR_ACTION_MANAGER_ACTION_EMPTY_TRASH, "/ThunarWindow/empty-trash", "", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Empty Trash"), N_ ("Delete all files and folders in the Trash"), NULL, G_CALLBACK (thunar_action_manager_action_empty_trash), }, {THUNAR_ACTION_MANAGER_ACTION_REMOVE_FROM_RECENT, "/ThunarWindow/remove-from-recent", "", XFCE_GTK_MENU_ITEM, N_ ("_Remove from Recent"), N_ ("Remove the selected files from Recent"), NULL, G_CALLBACK (thunar_action_manager_action_remove_from_recent), }, {THUNAR_ACTION_MANAGER_ACTION_CREATE_FOLDER, "/ThunarStandardView/create-folder", "N", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Create _Folder..."), N_ ("Create an empty folder within the current folder"), "folder-new", G_CALLBACK (thunar_action_manager_action_create_folder), }, {THUNAR_ACTION_MANAGER_ACTION_CREATE_DOCUMENT, "/ThunarStandardView/create-document", "", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Create _Document"), N_ ("Create a new document from a template"), "document-new", G_CALLBACK (NULL), }, {THUNAR_ACTION_MANAGER_ACTION_RESTORE, "/ThunarActionManager/restore", "", XFCE_GTK_MENU_ITEM, N_ ("_Restore"), NULL, NULL, G_CALLBACK (thunar_action_manager_action_restore), }, { THUNAR_ACTION_MANAGER_ACTION_RESTORE_SHOW, "/ThunarActionManager/restore-show", "", XFCE_GTK_MENU_ITEM, N_ ("Restore and S_how"), NULL, NULL, G_CALLBACK (thunar_action_manager_action_restore_and_show), }, {THUNAR_ACTION_MANAGER_ACTION_MOVE_TO_TRASH, "/ThunarActionManager/move-to-trash", "", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Mo_ve to Trash"), NULL, "user-trash", G_CALLBACK (thunar_action_manager_action_trash_delete), }, {THUNAR_ACTION_MANAGER_ACTION_TRASH_DELETE, "/ThunarActionManager/trash-delete", "Delete", XFCE_GTK_IMAGE_MENU_ITEM, NULL, NULL, NULL, G_CALLBACK (thunar_action_manager_action_trash_delete), }, {THUNAR_ACTION_MANAGER_ACTION_TRASH_DELETE_ALT, "/ThunarActionManager/trash-delete-2", "KP_Delete", XFCE_GTK_IMAGE_MENU_ITEM, NULL, NULL, NULL, G_CALLBACK (thunar_action_manager_action_trash_delete), }, {THUNAR_ACTION_MANAGER_ACTION_DELETE, "/ThunarActionManager/delete", "", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Delete"), NULL, "edit-delete", G_CALLBACK (thunar_action_manager_action_delete), }, {THUNAR_ACTION_MANAGER_ACTION_DELETE_ALT_1, "/ThunarActionManager/delete-2", "Delete", XFCE_GTK_IMAGE_MENU_ITEM, NULL, NULL, NULL, G_CALLBACK (thunar_action_manager_action_delete), }, {THUNAR_ACTION_MANAGER_ACTION_DELETE_ALT_2, "/ThunarActionManager/delete-3", "KP_Delete", XFCE_GTK_IMAGE_MENU_ITEM, NULL, NULL, NULL, G_CALLBACK (thunar_action_manager_action_delete), }, { THUNAR_ACTION_MANAGER_ACTION_PASTE, "/ThunarActionManager/paste", "V", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Paste"), N_ ("Move or copy files previously selected by a Cut or Copy command"), "edit-paste", G_CALLBACK (thunar_action_manager_action_paste), }, { THUNAR_ACTION_MANAGER_ACTION_PASTE_ALT, "/ThunarActionManager/paste-2", "Insert", XFCE_GTK_IMAGE_MENU_ITEM, NULL, NULL, NULL, G_CALLBACK (thunar_action_manager_action_paste), }, { THUNAR_ACTION_MANAGER_ACTION_PASTE_INTO_FOLDER,NULL, "", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Paste Into Folder"), N_ ("Move or copy files previously selected by a Cut or Copy command into the selected folder"), "edit-paste", G_CALLBACK (thunar_action_manager_action_paste_into_folder), }, { THUNAR_ACTION_MANAGER_ACTION_COPY, "/ThunarActionManager/copy", "C", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Copy"), NULL, "edit-copy", G_CALLBACK (thunar_action_manager_action_copy), }, { THUNAR_ACTION_MANAGER_ACTION_COPY_ALT, "/ThunarActionManager/copy-2", "Insert", XFCE_GTK_IMAGE_MENU_ITEM, NULL, NULL, NULL, G_CALLBACK (thunar_action_manager_action_copy), }, { THUNAR_ACTION_MANAGER_ACTION_CUT, "/ThunarActionManager/cut", "X", XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Cu_t"), NULL, "edit-cut", G_CALLBACK (thunar_action_manager_action_cut), }, { THUNAR_ACTION_MANAGER_ACTION_CUT_ALT, "/ThunarActionManager/cut-2", "", XFCE_GTK_IMAGE_MENU_ITEM, NULL, NULL, NULL, G_CALLBACK (thunar_action_manager_action_cut), }, { THUNAR_ACTION_MANAGER_ACTION_MOUNT, NULL, "", XFCE_GTK_MENU_ITEM, N_ ("_Mount"), N_ ("Mount the selected device"), NULL, G_CALLBACK (thunar_action_manager_action_mount), }, { THUNAR_ACTION_MANAGER_ACTION_UNMOUNT, NULL, "", XFCE_GTK_MENU_ITEM, N_ ("_Unmount"), N_ ("Unmount the selected device"), NULL, G_CALLBACK (thunar_action_manager_action_unmount), }, { THUNAR_ACTION_MANAGER_ACTION_EJECT, NULL, "", XFCE_GTK_MENU_ITEM, N_ ("_Eject"), N_ ("Eject the selected device"), NULL, G_CALLBACK (thunar_action_manager_action_eject), }, }; /* clang-format on */ #define get_action_entry(id) xfce_gtk_get_action_entry_by_id (thunar_action_manager_action_entries, G_N_ELEMENTS (thunar_action_manager_action_entries), id) G_DEFINE_TYPE_WITH_CODE (ThunarActionManager, thunar_action_manager, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (THUNAR_TYPE_BROWSER, NULL) G_IMPLEMENT_INTERFACE (THUNAR_TYPE_NAVIGATOR, thunar_action_manager_navigator_init) G_IMPLEMENT_INTERFACE (THUNAR_TYPE_COMPONENT, thunar_action_manager_component_init)) static void thunar_action_manager_class_init (ThunarActionManagerClass *klass) { GObjectClass *gobject_class; gpointer g_iface; /* determine all used quarks */ thunar_action_manager_appinfo_quark = g_quark_from_static_string ("thunar-action-manager-appinfo"); thunar_action_manager_device_quark = g_quark_from_static_string ("thunar-action-manager-device"); thunar_action_manager_file_quark = g_quark_from_static_string ("thunar-action-manager-file"); xfce_gtk_translate_action_entries (thunar_action_manager_action_entries, G_N_ELEMENTS (thunar_action_manager_action_entries)); gobject_class = G_OBJECT_CLASS (klass); gobject_class->dispose = thunar_action_manager_dispose; gobject_class->finalize = thunar_action_manager_finalize; gobject_class->get_property = thunar_action_manager_get_property; gobject_class->set_property = thunar_action_manager_set_property; /** * ThunarActionManager::device-operation-started: * @action_mgr : a #ThunarActionManager * @device : the #ThunarDevice on which the operation was finished * * This signal is emitted by the @action_mgr right after the device operation (mount/unmount/eject) is started **/ action_manager_signals[DEVICE_OPERATION_STARTED] = g_signal_new (I_ ("device-operation-started"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, THUNAR_TYPE_DEVICE); /** * ThunarActionManager::device-operation-finished: * @action_mgr : a #ThunarActionManager * @device : the #ThunarDevice on which the operation was finished * * This signal is emitted by the @action_mgr right after the device operation (mount/unmount/eject) is finished **/ action_manager_signals[DEVICE_OPERATION_FINISHED] = g_signal_new (I_ ("device-operation-finished"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, THUNAR_TYPE_DEVICE); /** * ThunarActionManager::new-files-created: * @action_mgr : a #ThunarActionManager * @files : a GList of #ThunarFiles which were created * * This signal is emitted by the @action_mgr whenever new files were created (e.g. via "rename", "create" or "paste") **/ action_manager_signals[NEW_FILES_CREATED] = g_signal_new (I_ ("new-files-created"), G_TYPE_FROM_CLASS (klass), G_SIGNAL_NO_HOOKS, 0, NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, G_TYPE_POINTER); /** * ThunarActionManager:widget: * * The #GtkWidget with which this action manager is associated. **/ action_manager_props[PROP_WIDGET] = g_param_spec_object ("widget", "widget", "widget", GTK_TYPE_WIDGET, EXO_PARAM_WRITABLE); /** * ThunarActionManager:select-device: * * The #ThunarDevice which currently is selected (or NULL if no #ThunarDevice is selected) **/ action_manager_props[PROP_SELECTED_DEVICE] = g_param_spec_pointer ("selected-device", "selected-device", "selected-device", G_PARAM_WRITABLE); /** * ThunarActionManager:select-device: * * The #GFile which currently is selected (or NULL if no #GFile is selected) **/ action_manager_props[PROP_SELECTED_LOCATION] = g_param_spec_pointer ("selected-location", "selected-location", "selected-location", G_PARAM_WRITABLE); /* Override ThunarNavigator's properties */ g_iface = g_type_default_interface_peek (THUNAR_TYPE_NAVIGATOR); action_manager_props[PROP_CURRENT_DIRECTORY] = g_param_spec_override ("current-directory", g_object_interface_find_property (g_iface, "current-directory")); /* Override ThunarComponent's properties */ g_iface = g_type_default_interface_peek (THUNAR_TYPE_COMPONENT); action_manager_props[PROP_SELECTED_FILES] = g_param_spec_override ("selected-files", g_object_interface_find_property (g_iface, "selected-files")); /* install properties */ g_object_class_install_properties (gobject_class, N_PROPERTIES, action_manager_props); } static void thunar_action_manager_component_init (ThunarComponentIface *iface) { iface->get_selected_files = NULL; iface->set_selected_files = thunar_action_manager_set_selected_files; } static void thunar_action_manager_navigator_init (ThunarNavigatorIface *iface) { iface->get_current_directory = thunar_action_manager_get_current_directory; iface->set_current_directory = thunar_action_manager_set_current_directory; } static void thunar_action_manager_init (ThunarActionManager *action_mgr) { action_mgr->files_to_process = NULL; action_mgr->device_to_process = NULL; action_mgr->location_to_process = NULL; action_mgr->parent_folder = NULL; /* grab a reference on the preferences */ action_mgr->preferences = thunar_preferences_get (); /* initialize the new_files_created_closure */ action_mgr->new_files_created_closure = g_cclosure_new_swap (G_CALLBACK (thunar_action_manager_new_files_created), action_mgr, NULL); g_closure_ref (action_mgr->new_files_created_closure); g_closure_sink (action_mgr->new_files_created_closure); action_mgr->is_searching = FALSE; } static void thunar_action_manager_dispose (GObject *object) { ThunarActionManager *action_mgr = THUNAR_ACTION_MANAGER (object); /* reset our properties */ thunar_navigator_set_current_directory (THUNAR_NAVIGATOR (action_mgr), NULL); thunar_action_manager_set_widget (THUNAR_ACTION_MANAGER (action_mgr), NULL); /* unref all members */ if (action_mgr->files_to_process != NULL) thunar_g_list_free_full (action_mgr->files_to_process); action_mgr->files_to_process = NULL; if (action_mgr->device_to_process != NULL) g_object_unref (action_mgr->device_to_process); action_mgr->device_to_process = NULL; if (action_mgr->location_to_process != NULL) g_object_unref (action_mgr->location_to_process); action_mgr->location_to_process = NULL; if (action_mgr->parent_folder != NULL) g_object_unref (action_mgr->parent_folder); action_mgr->parent_folder = NULL; (*G_OBJECT_CLASS (thunar_action_manager_parent_class)->dispose) (object); } static void thunar_action_manager_finalize (GObject *object) { ThunarActionManager *action_mgr = THUNAR_ACTION_MANAGER (object); g_closure_invalidate (action_mgr->new_files_created_closure); g_closure_unref (action_mgr->new_files_created_closure); /* release the preferences reference */ g_object_unref (action_mgr->preferences); (*G_OBJECT_CLASS (thunar_action_manager_parent_class)->finalize) (object); } static void thunar_action_manager_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { switch (prop_id) { case PROP_CURRENT_DIRECTORY: g_value_set_object (value, thunar_navigator_get_current_directory (THUNAR_NAVIGATOR (object))); break; case PROP_SELECTED_FILES: g_value_set_boxed (value, thunar_component_get_selected_files (THUNAR_COMPONENT (object))); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void thunar_action_manager_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { ThunarActionManager *action_mgr = THUNAR_ACTION_MANAGER (object); switch (prop_id) { case PROP_CURRENT_DIRECTORY: thunar_navigator_set_current_directory (THUNAR_NAVIGATOR (object), g_value_get_object (value)); break; case PROP_SELECTED_FILES: thunar_action_manager_set_selection (action_mgr, g_value_get_boxed (value), NULL, NULL); break; case PROP_WIDGET: thunar_action_manager_set_widget (action_mgr, g_value_get_object (value)); break; case PROP_SELECTED_DEVICE: thunar_action_manager_set_selection (action_mgr, NULL, g_value_get_pointer (value), NULL); break; case PROP_SELECTED_LOCATION: thunar_action_manager_set_selection (action_mgr, NULL, NULL, g_value_get_pointer (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static ThunarFile * thunar_action_manager_get_current_directory (ThunarNavigator *navigator) { return THUNAR_ACTION_MANAGER (navigator)->current_directory; } static void thunar_action_manager_set_current_directory (ThunarNavigator *navigator, ThunarFile *current_directory) { ThunarActionManager *action_mgr = THUNAR_ACTION_MANAGER (navigator); /* disconnect from the previous directory */ if (G_LIKELY (action_mgr->current_directory != NULL)) g_object_unref (G_OBJECT (action_mgr->current_directory)); /* activate the new directory */ action_mgr->current_directory = current_directory; /* connect to the new directory */ if (G_LIKELY (current_directory != NULL)) { g_object_ref (G_OBJECT (current_directory)); /* update files_to_process if not initialized yet */ if (action_mgr->files_to_process == NULL) thunar_action_manager_set_selected_files (THUNAR_COMPONENT (navigator), NULL); } /* notify listeners */ g_object_notify_by_pspec (G_OBJECT (action_mgr), action_manager_props[PROP_CURRENT_DIRECTORY]); } static void thunar_action_manager_set_selected_files (ThunarComponent *component, GList *selected_files) { ThunarActionManager *action_mgr = THUNAR_ACTION_MANAGER (component); GList *lp; /* That happens at startup for some reason */ if (action_mgr->current_directory == NULL) return; /* disconnect from the previous files to process */ if (action_mgr->files_to_process != NULL) thunar_g_list_free_full (action_mgr->files_to_process); action_mgr->files_to_process = NULL; /* notify listeners */ g_object_notify_by_pspec (G_OBJECT (action_mgr), action_manager_props[PROP_SELECTED_FILES]); /* unref previous parent, if any */ if (action_mgr->parent_folder != NULL) g_object_unref (action_mgr->parent_folder); action_mgr->parent_folder = NULL; action_mgr->files_are_selected = TRUE; if (selected_files == NULL || g_list_length (selected_files) == 0) action_mgr->files_are_selected = FALSE; action_mgr->files_to_process_trashable = TRUE; action_mgr->n_files_to_process = 0; action_mgr->n_directories_to_process = 0; action_mgr->n_regulars_to_process = 0; action_mgr->files_are_all_executable = TRUE; action_mgr->single_directory_to_process = FALSE; action_mgr->single_folder = NULL; /* if nothing is selected, the current directory is the folder to use for all menus */ if (action_mgr->files_are_selected) action_mgr->files_to_process = thunar_g_list_copy_deep (selected_files); else action_mgr->files_to_process = g_list_append (action_mgr->files_to_process, g_object_ref (action_mgr->current_directory)); /* determine the number of files/directories/executables */ for (lp = action_mgr->files_to_process; lp != NULL; lp = lp->next, ++action_mgr->n_files_to_process) { if (thunar_file_is_directory (lp->data) || thunar_file_is_shortcut (lp->data) || thunar_file_is_mountable (lp->data)) { ++action_mgr->n_directories_to_process; action_mgr->files_are_all_executable = FALSE; } else { if (action_mgr->files_are_all_executable && !thunar_file_can_execute (lp->data, NULL) && !thunar_file_is_desktop_file (lp->data)) action_mgr->files_are_all_executable = FALSE; ++action_mgr->n_regulars_to_process; } if (!thunar_file_can_be_trashed (lp->data)) action_mgr->files_to_process_trashable = FALSE; } action_mgr->single_directory_to_process = (action_mgr->n_directories_to_process == 1 && action_mgr->n_files_to_process == 1); if (action_mgr->single_directory_to_process) { /* grab the folder of the first selected item */ action_mgr->single_folder = THUNAR_FILE (action_mgr->files_to_process->data); } if (action_mgr->files_to_process != NULL) { /* just grab the folder of the first selected item */ action_mgr->parent_folder = thunar_file_get_parent (THUNAR_FILE (action_mgr->files_to_process->data), NULL); } } /** * thunar_action_manager_set_widget: * @action_mgr : a #ThunarActionManager. * @widget : a #GtkWidget or %NULL. * * Associates @action_mgr with @widget. **/ void thunar_action_manager_set_widget (ThunarActionManager *action_mgr, GtkWidget *widget) { _thunar_return_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr)); _thunar_return_if_fail (widget == NULL || GTK_IS_WIDGET (widget)); /* disconnect from the previous widget */ if (G_UNLIKELY (action_mgr->widget != NULL)) { g_signal_handlers_disconnect_by_func (G_OBJECT (action_mgr->widget), thunar_action_manager_widget_destroyed, action_mgr); g_object_unref (G_OBJECT (action_mgr->widget)); } action_mgr->widget = widget; /* connect to the new widget */ if (G_LIKELY (widget != NULL)) { g_object_ref (G_OBJECT (widget)); g_signal_connect_swapped (G_OBJECT (widget), "destroy", G_CALLBACK (thunar_action_manager_widget_destroyed), action_mgr); } /* notify listeners */ g_object_notify_by_pspec (G_OBJECT (action_mgr), action_manager_props[PROP_WIDGET]); } static gboolean thunar_action_manager_menu_item_activated (ThunarActionManager *action_mgr, GtkWidget *menu_item) { GAppInfo *app_info; _thunar_return_val_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr), FALSE); if (G_UNLIKELY (action_mgr->files_to_process == NULL)) return TRUE; /* if we have a mime handler associated with the menu_item, we pass it to the action_mgr (g_object_get_qdata will return NULL otherwise)*/ app_info = g_object_get_qdata (G_OBJECT (menu_item), thunar_action_manager_appinfo_quark); thunar_action_manager_activate_selected_files (action_mgr, THUNAR_ACTION_MANAGER_CHANGE_DIRECTORY, app_info); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } /** * thunar_action_manager_activate_selected_files: * @action_mgr : a #ThunarActionManager instance * @action : the #ThunarActionManagerFolderOpenAction to use, if there are folders among the selected files * @app_info : a #GAppInfo instance * * Will try to open all selected files with the provided #GAppInfo **/ void thunar_action_manager_activate_selected_files (ThunarActionManager *action_mgr, ThunarActionManagerFolderOpenAction action, GAppInfo *app_info) { _thunar_return_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr)); thunar_action_manager_poke (action_mgr, app_info, action); } static void thunar_action_manager_execute_files (ThunarActionManager *action_mgr, GList *files, gboolean in_terminal) { GError *error = NULL; GFile *working_directory; GList *lp; /* execute all selected files */ for (lp = files; lp != NULL; lp = lp->next) { ThunarFile *file = lp->data; working_directory = thunar_file_get_file (action_mgr->current_directory); if (!thunar_file_execute (lp->data, working_directory, action_mgr->widget, in_terminal, NULL, NULL, &error)) { /* display an error message to the user */ if (g_strcmp0 (thunar_file_get_display_name (file), thunar_file_get_basename (file)) != 0) thunar_dialogs_show_error (action_mgr->widget, error, _("Failed to execute file \"%s\" (%s)"), thunar_file_get_display_name (lp->data), thunar_file_get_basename (lp->data)); else thunar_dialogs_show_error (action_mgr->widget, error, _("Failed to execute file \"%s\""), thunar_file_get_display_name (lp->data)); g_error_free (error); break; } else { /* add executed file to `recent:///` */ thunar_file_add_to_recent (file); } } } static guint thunar_action_manager_g_app_info_hash (gconstpointer app_info) { return 0; } static void thunar_action_manager_open_files (ThunarActionManager *action_mgr, GList *files, GAppInfo *application_to_use) { GHashTable *applications; GAppInfo *app_info; GList *lp; /* allocate a hash table to associate applications to URIs. since GIO allocates * new GAppInfo objects every time, g_direct_hash does not work. we therefore use * a fake hash function to always hit the collision list of the hash table and * avoid storing multiple equal GAppInfos by means of g_app_info_equal(). */ applications = g_hash_table_new_full (thunar_action_manager_g_app_info_hash, (GEqualFunc) g_app_info_equal, (GDestroyNotify) g_object_unref, (GDestroyNotify) thunar_g_list_free_full); for (lp = files; lp != NULL; lp = lp->next) { /* Because we created the hash_table with g_hash_table_new_full * g_object_unref on each hash_table key and value will be called by g_hash_table_destroy */ if (application_to_use) { app_info = g_app_info_dup (application_to_use); /* Foreign data needs to be set explicitly to the new app_info */ if (g_object_get_data (G_OBJECT (application_to_use), "skip-app-info-update") != NULL) g_object_set_data (G_OBJECT (app_info), "skip-app-info-update", GUINT_TO_POINTER (1)); } else { /* determine the default application for the MIME type */ app_info = thunar_file_get_default_handler (lp->data); } /* check if we have an application here */ if (G_LIKELY (app_info != NULL)) { /* check if we have that application already */ /* Not possibly to check via g_hash_table_lookup directly, since that will only compare pointers */ GList *keys = g_hash_table_get_keys (applications); GList *file_list = NULL; for (GList *lp_keys = keys; lp_keys != NULL; lp_keys = lp_keys->next) { if (thunar_g_app_info_equal (lp_keys->data, app_info)) { /* Reuse the existing appinfo instead of adding the new one to the list*/ g_object_unref (app_info); app_info = g_object_ref (lp_keys->data); file_list = g_hash_table_lookup (applications, app_info); /* take a copy of the list as the old one will be dropped by the insert */ file_list = thunar_g_list_copy_deep (file_list); } } g_list_free (keys); /* append our new URI to the list */ file_list = thunar_g_list_append_deep (file_list, thunar_file_get_file (lp->data)); /* (re)insert the URI list for the application */ g_hash_table_insert (applications, app_info, file_list); } else { /* display a chooser dialog for the file and stop */ thunar_show_chooser_dialog (action_mgr->widget, lp->data, TRUE, TRUE); break; } } /* run all collected applications */ g_hash_table_foreach (applications, (GHFunc) thunar_action_manager_open_paths, action_mgr); /* drop the applications hash table */ g_hash_table_destroy (applications); } static void thunar_action_manager_open_paths (GAppInfo *app_info, GList *path_list, ThunarActionManager *action_mgr) { GdkAppLaunchContext *context; GdkScreen *screen; GError *error = NULL; GFile *working_directory = NULL; GList *lp; gchar *message; gchar *name; guint n; /* determine the screen on which to launch the application */ screen = gtk_widget_get_screen (action_mgr->widget); /* create launch context */ context = gdk_display_get_app_launch_context (gdk_screen_get_display (screen)); gdk_app_launch_context_set_screen (context, screen); gdk_app_launch_context_set_timestamp (context, gtk_get_current_event_time ()); gdk_app_launch_context_set_icon (context, g_app_info_get_icon (app_info)); /* determine the working directory */ if (action_mgr->current_directory != NULL) working_directory = thunar_file_get_file (action_mgr->current_directory); /* try to execute the application with the given URIs */ if (!thunar_g_app_info_launch (app_info, working_directory, path_list, G_APP_LAUNCH_CONTEXT (context), &error)) { /* figure out the appropriate error message */ n = g_list_length (path_list); if (G_LIKELY (n == 1)) { /* we can give a precise error message here */ name = g_filename_display_name (g_file_get_basename (path_list->data)); message = g_strdup_printf (_("Failed to open file \"%s\""), name); g_free (name); } else { /* we can just tell that n files failed to open */ message = g_strdup_printf (ngettext ("Failed to open %d file", "Failed to open %d files", n), n); } /* display an error dialog to the user */ thunar_dialogs_show_error (action_mgr->widget, error, "%s", message); g_error_free (error); g_free (message); } else { /* add opened file(s) to `recent:///` */ for (lp = path_list; lp != NULL; lp = lp->next) { ThunarFile *file = thunar_file_get (G_FILE (lp->data), NULL); if (file != NULL) { thunar_file_add_to_recent (file); g_object_unref (file); } } } /* destroy the launch context */ g_object_unref (context); } static void thunar_action_manager_open_windows (ThunarActionManager *action_mgr, GList *directories) { ThunarApplication *application; GtkWidget *dialog; GtkWidget *window; GdkScreen *screen; gchar *label; GList *lp; gint response = GTK_RESPONSE_YES; gint n; /* ask the user if we would open more than one new window */ n = g_list_length (directories); if (G_UNLIKELY (n > 1)) { /* open a message dialog */ window = gtk_widget_get_toplevel (action_mgr->widget); dialog = gtk_message_dialog_new ((GtkWindow *) window, GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, _("Are you sure you want to open all folders?")); gtk_window_set_title (GTK_WINDOW (dialog), _("Open folders")); gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), ngettext ("This will open %d separate file manager window.", "This will open %d separate file manager windows.", n), n); label = g_strdup_printf (ngettext ("Open %d New Window", "Open %d New Windows", n), n); gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Cancel"), GTK_RESPONSE_CANCEL); gtk_dialog_add_button (GTK_DIALOG (dialog), label, GTK_RESPONSE_YES); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_YES); response = gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); g_free (label); } /* open n new windows if the user approved it */ if (G_LIKELY (response == GTK_RESPONSE_YES)) { /* query the application object */ application = thunar_application_get (); /* determine the screen on which to open the new windows */ screen = gtk_widget_get_screen (action_mgr->widget); /* open all requested windows */ for (lp = directories; lp != NULL; lp = lp->next) thunar_application_open_window (application, lp->data, screen, NULL, TRUE); /* release the application object */ g_object_unref (G_OBJECT (application)); } } static void thunar_action_manager_poke (ThunarActionManager *action_mgr, GAppInfo *application_to_use, ThunarActionManagerFolderOpenAction folder_open_action) { ThunarActionManagerPokeData *poke_data; _thunar_return_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr)); if (action_mgr->files_to_process == NULL) { g_warning ("No files to process. thunar_action_manager_poke aborted."); return; } poke_data = thunar_action_manager_poke_data_new (action_mgr->files_to_process, application_to_use, folder_open_action, action_mgr->location_to_process, action_mgr->device_to_process); if (action_mgr->device_to_process != NULL) { g_signal_emit (action_mgr, action_manager_signals[DEVICE_OPERATION_STARTED], 0, action_mgr->device_to_process); thunar_browser_poke_device (THUNAR_BROWSER (action_mgr), action_mgr->device_to_process, action_mgr->widget, thunar_action_manager_poke_device_finish, poke_data); } else if (action_mgr->location_to_process != NULL) { thunar_browser_poke_location (THUNAR_BROWSER (action_mgr), poke_data->location_to_poke, action_mgr->widget, thunar_action_manager_poke_location_finish, poke_data); } else { // We will only poke one file at a time, in order to dont use all available CPU's // TODO: Check if that could cause slowness thunar_browser_poke_file (THUNAR_BROWSER (action_mgr), poke_data->files_to_poke->data, action_mgr->widget, thunar_action_manager_poke_files_finish, poke_data); } } static void thunar_action_manager_poke_device_finish (ThunarBrowser *browser, ThunarDevice *volume, ThunarFile *mount_point, GError *error, gpointer user_data, gboolean cancelled) { ThunarActionManagerPokeData *poke_data = user_data; gchar *device_name; if (error != NULL) { device_name = thunar_device_get_name (volume); thunar_dialogs_show_error (GTK_WIDGET (THUNAR_ACTION_MANAGER (browser)->widget), error, _("Failed to mount \"%s\""), device_name); g_free (device_name); } if (cancelled == TRUE || error != NULL || mount_point == NULL) { g_signal_emit (browser, action_manager_signals[DEVICE_OPERATION_FINISHED], 0, volume); thunar_action_manager_poke_data_free (poke_data); return; } if (poke_data->folder_open_action == THUNAR_ACTION_MANAGER_OPEN_AS_NEW_TAB) { thunar_navigator_open_new_tab (THUNAR_NAVIGATOR (browser), mount_point); } else if (poke_data->folder_open_action == THUNAR_ACTION_MANAGER_OPEN_AS_NEW_WINDOW) { GList *directories = NULL; directories = g_list_append (directories, mount_point); thunar_action_manager_open_windows (THUNAR_ACTION_MANAGER (browser), directories); g_list_free (directories); } else if (poke_data->folder_open_action == THUNAR_ACTION_MANAGER_CHANGE_DIRECTORY) { thunar_navigator_change_directory (THUNAR_NAVIGATOR (browser), mount_point); } /* add device to `recent:///` */ thunar_file_add_to_recent (mount_point); g_signal_emit (browser, action_manager_signals[DEVICE_OPERATION_FINISHED], 0, volume); thunar_action_manager_poke_data_free (poke_data); } static void thunar_action_manager_poke_location_finish (ThunarBrowser *browser, GFile *location, ThunarFile *file, ThunarFile *target_file, GError *error, gpointer user_data) { ThunarActionManagerPokeData *poke_data = user_data; _thunar_return_if_fail (THUNAR_IS_BROWSER (browser)); if (error != NULL) { gchar *path = g_file_get_uri (location); thunar_dialogs_show_error (GTK_WIDGET (THUNAR_ACTION_MANAGER (browser)->widget), error, _("Failed to open \"%s\""), path); g_free (path); thunar_action_manager_poke_data_free (poke_data); return; } thunar_action_manager_poke_files_finish (browser, file, target_file, error, user_data); } static void thunar_action_manager_poke_files_finish (ThunarBrowser *browser, ThunarFile *file, ThunarFile *target_file, GError *error, gpointer user_data) { ThunarActionManagerPokeData *poke_data = user_data; gboolean executable = TRUE; gboolean open_new_window_as_tab = TRUE; GList *directories = NULL; GList *files = NULL; GList *lp; gboolean ask_for_exec = FALSE; _thunar_return_if_fail (THUNAR_IS_BROWSER (browser)); _thunar_return_if_fail (THUNAR_IS_FILE (file)); _thunar_return_if_fail (poke_data != NULL); _thunar_return_if_fail (poke_data->files_to_poke != NULL); /* check if poking succeeded */ if (error == NULL) { /* add the resolved file to the list of file to be opened/executed later */ poke_data->files_poked = g_list_prepend (poke_data->files_poked, g_object_ref (target_file)); } /* release and remove the just poked file from the list */ g_object_unref (poke_data->files_to_poke->data); poke_data->files_to_poke = g_list_delete_link (poke_data->files_to_poke, poke_data->files_to_poke); if (poke_data->files_to_poke == NULL) { /* separate files and directories in the selected files list */ for (lp = poke_data->files_poked; lp != NULL; lp = lp->next) { if (thunar_file_is_directory (lp->data)) { /* add to our directory list */ directories = g_list_prepend (directories, lp->data); /* add directory to `recent:///` */ thunar_file_add_to_recent (lp->data); } else { /* add to our file list */ files = g_list_prepend (files, lp->data); /* check if we should try to execute the file */ executable = (executable && (thunar_file_can_execute (lp->data, &ask_for_exec) || thunar_file_is_desktop_file (lp->data))); } } /* check if we have any directories to process */ if (G_LIKELY (directories != NULL)) { if (poke_data->application_to_use != NULL) { thunar_action_manager_open_files (THUNAR_ACTION_MANAGER (browser), directories, poke_data->application_to_use); } else if (poke_data->folder_open_action == THUNAR_ACTION_MANAGER_OPEN_AS_NEW_TAB) { for (lp = directories; lp != NULL; lp = lp->next) thunar_navigator_open_new_tab (THUNAR_NAVIGATOR (browser), lp->data); } else if (poke_data->folder_open_action == THUNAR_ACTION_MANAGER_OPEN_AS_NEW_WINDOW) { thunar_action_manager_open_windows (THUNAR_ACTION_MANAGER (browser), directories); } else if (poke_data->folder_open_action == THUNAR_ACTION_MANAGER_CHANGE_DIRECTORY) { /* If multiple directories are passed, we assume that we should open them all */ if (directories->next == NULL) thunar_navigator_change_directory (THUNAR_NAVIGATOR (browser), directories->data); else { g_object_get (G_OBJECT (THUNAR_ACTION_MANAGER (browser)->preferences), "misc-open-new-window-as-tab", &open_new_window_as_tab, NULL); if (open_new_window_as_tab) { for (lp = directories; lp != NULL; lp = lp->next) thunar_navigator_open_new_tab (THUNAR_NAVIGATOR (browser), lp->data); } else thunar_action_manager_open_windows (THUNAR_ACTION_MANAGER (browser), directories); } } else if (poke_data->folder_open_action == THUNAR_ACTION_MANAGER_NO_ACTION) { // nothing to do } else g_warning ("'folder_open_action' was not defined"); g_list_free (directories); } /* check if we have any files to process */ if (G_LIKELY (files != NULL)) { gboolean in_terminal = FALSE; gboolean can_open = TRUE; if (poke_data->application_to_use != NULL) { executable = FALSE; } else if (executable && ask_for_exec) { gint ask_execute_response = thunar_dialog_ask_execute (file, THUNAR_ACTION_MANAGER (browser)->widget, TRUE, g_list_length (files) == 1); if (ask_execute_response == THUNAR_FILE_ASK_EXECUTE_RESPONSE_OPEN) executable = FALSE; else if (ask_execute_response == THUNAR_FILE_ASK_EXECUTE_RESPONSE_RUN_IN_TERMINAL) in_terminal = TRUE; else if (ask_execute_response != THUNAR_FILE_ASK_EXECUTE_RESPONSE_RUN) executable = can_open = FALSE; } /* if all files are executable, we just run them here */ if (executable) { /* try to execute all given files */ thunar_action_manager_execute_files (THUNAR_ACTION_MANAGER (browser), files, in_terminal); } else if (can_open) { /* try to open all files */ thunar_action_manager_open_files (THUNAR_ACTION_MANAGER (browser), files, poke_data->application_to_use); } /* cleanup */ g_list_free (files); } /* free the poke data */ thunar_action_manager_poke_data_free (poke_data); } else { /* we need to continue this until all files have been resolved */ // We will only poke one file at a time, in order to dont use all available CPU's // TODO: Check if that could cause slowness thunar_browser_poke_file (browser, poke_data->files_to_poke->data, (THUNAR_ACTION_MANAGER (browser))->widget, thunar_action_manager_poke_files_finish, poke_data); } } static ThunarActionManagerPokeData * thunar_action_manager_poke_data_new (GList *files_to_poke, GAppInfo *application_to_use, ThunarActionManagerFolderOpenAction folder_open_action, GFile *location_to_poke, ThunarDevice *device_to_poke) { ThunarActionManagerPokeData *data; data = g_slice_new0 (ThunarActionManagerPokeData); data->files_to_poke = thunar_g_list_copy_deep (files_to_poke); data->files_poked = NULL; data->application_to_use = application_to_use; if (location_to_poke != NULL) data->location_to_poke = g_object_ref (location_to_poke); if (device_to_poke != NULL) data->device_to_poke = g_object_ref (device_to_poke); /* keep a reference on the appdata */ if (application_to_use != NULL) g_object_ref (application_to_use); data->folder_open_action = folder_open_action; return data; } static void thunar_action_manager_poke_data_free (ThunarActionManagerPokeData *data) { _thunar_return_if_fail (data != NULL); thunar_g_list_free_full (data->files_to_poke); thunar_g_list_free_full (data->files_poked); if (data->location_to_poke != NULL) g_object_unref (data->location_to_poke); if (data->device_to_poke != NULL) g_object_unref (data->device_to_poke); if (data->application_to_use != NULL) g_object_unref (data->application_to_use); g_slice_free (ThunarActionManagerPokeData, data); } static void thunar_action_manager_widget_destroyed (ThunarActionManager *action_mgr, GtkWidget *widget) { _thunar_return_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr)); _thunar_return_if_fail (action_mgr->widget == widget); _thunar_return_if_fail (GTK_IS_WIDGET (widget)); /* just reset the widget property for the action_mgr */ thunar_action_manager_set_widget (action_mgr, NULL); } /** * thunar_action_manager_open_selected_folders: * @action_mgr : a #ThunarActionManager instance * @open_in_tabs : TRUE to open each folder in a new tab, FALSE to open each folder in a new window * * Will open each selected folder in a new tab/window **/ void thunar_action_manager_open_selected_folders (ThunarActionManager *action_mgr, gboolean open_in_tabs) { GList *lp; _thunar_return_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr)); for (lp = action_mgr->files_to_process; lp != NULL; lp = lp->next) _thunar_return_if_fail (thunar_file_is_directory (THUNAR_FILE (lp->data))); if (open_in_tabs) thunar_action_manager_poke (action_mgr, NULL, THUNAR_ACTION_MANAGER_OPEN_AS_NEW_TAB); else thunar_action_manager_poke (action_mgr, NULL, THUNAR_ACTION_MANAGER_OPEN_AS_NEW_WINDOW); } static gboolean thunar_action_manager_action_open (ThunarActionManager *action_mgr) { _thunar_return_val_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr), FALSE); if (G_UNLIKELY (action_mgr->files_to_process == NULL)) return TRUE; thunar_action_manager_activate_selected_files (action_mgr, THUNAR_ACTION_MANAGER_CHANGE_DIRECTORY, NULL); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } /** * thunar_action_manager_action_open_in_new_tabs: * @action_mgr : a #ThunarActionManager instance * * Will open each selected folder in a new tab **/ static gboolean thunar_action_manager_action_open_in_new_tabs (ThunarActionManager *action_mgr) { _thunar_return_val_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr), FALSE); if (G_UNLIKELY (action_mgr->files_to_process == NULL)) return TRUE; thunar_action_manager_open_selected_folders (action_mgr, TRUE); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_action_manager_action_open_in_new_windows (ThunarActionManager *action_mgr) { _thunar_return_val_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr), FALSE); if (G_UNLIKELY (action_mgr->files_to_process == NULL)) return TRUE; thunar_action_manager_open_selected_folders (action_mgr, FALSE); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } void thunar_action_manager_set_searching (ThunarActionManager *action_mgr, gboolean b) { action_mgr->is_searching = b; } static gboolean thunar_action_manager_action_open_location (ThunarActionManager *action_mgr) { GList *lp; GList *gfiles = NULL; _thunar_return_val_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr), FALSE); if (G_UNLIKELY (action_mgr->files_to_process == NULL)) return TRUE; for (lp = action_mgr->files_to_process; lp != NULL; lp = lp->next) gfiles = g_list_prepend (gfiles, thunar_file_get_file (THUNAR_FILE (lp->data))); thunar_window_open_files_in_location (THUNAR_WINDOW (action_mgr->widget), gfiles); g_list_free (gfiles); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_action_manager_action_open_with_other (ThunarActionManager *action_mgr) { _thunar_return_val_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr), FALSE); if (action_mgr->n_files_to_process == 1) thunar_show_chooser_dialog (action_mgr->widget, action_mgr->files_to_process->data, TRUE, FALSE); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } /** * thunar_action_manager_action_set_default_app: * @action_mgr : a #ThunarActionManager instance * * Choose an application which should be used by default to open the selected file **/ static gboolean thunar_action_manager_action_set_default_app (ThunarActionManager *action_mgr) { _thunar_return_val_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr), FALSE); if (action_mgr->n_files_to_process == 1) thunar_show_chooser_dialog (action_mgr->widget, action_mgr->files_to_process->data, TRUE, TRUE); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } /** * thunar_action_manager_append_accelerators: * @action_mgr : a #ThunarActionManager. * @accel_group: a #GtkAccelGroup to be used used for new menu items * * Connects all accelerators and corresponding default keys of this widget to the global accelerator list **/ void thunar_action_manager_append_accelerators (ThunarActionManager *action_mgr, GtkAccelGroup *accel_group) { _thunar_return_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr)); xfce_gtk_accel_map_add_entries (thunar_action_manager_action_entries, G_N_ELEMENTS (thunar_action_manager_action_entries)); xfce_gtk_accel_group_connect_action_entries (accel_group, thunar_action_manager_action_entries, G_N_ELEMENTS (thunar_action_manager_action_entries), action_mgr); } static gboolean thunar_action_manager_show_trash (ThunarActionManager *action_mgr) { if (action_mgr->parent_folder == NULL) return FALSE; /* If the folder is read only, always show trash insensitive */ /* If we are outside waste basket, the selection is trashable and we support trash, show trash */ return !thunar_file_is_writable (action_mgr->parent_folder) || (!thunar_file_is_trashed (action_mgr->parent_folder) && action_mgr->files_to_process_trashable && thunar_g_vfs_is_uri_scheme_supported ("trash")); } /** * thunar_action_manager_append_menu_item: * @action_mgr: Instance of a #ThunarActionManager * @menu : #GtkMenuShell to which the item should be added * @action : #ThunarActionManagerAction to select which item should be added * @force : force to generate the item. If it cannot be used, it will be shown as insensitive * * Adds the selected, widget specific #GtkMenuItem to the passed #GtkMenuShell * * Return value: (transfer none): The added #GtkMenuItem **/ GtkWidget * thunar_action_manager_append_menu_item (ThunarActionManager *action_mgr, GtkMenuShell *menu, ThunarActionManagerAction action, gboolean force) { GtkWidget *item = NULL; GtkWidget *submenu; GtkWidget *focused_widget; gchar *label_text; gchar *tooltip_text; const XfceGtkActionEntry *action_entry = get_action_entry (action); gboolean show_delete_item; gboolean show_item; ThunarClipboardManager *clipboard; ThunarFile *parent; gint n; const gchar *eject_label; _thunar_return_val_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr), NULL); _thunar_return_val_if_fail (action_entry != NULL, NULL); /* This may occur when the thunar-window is build */ if (G_UNLIKELY (action_mgr->files_to_process == NULL) && action_mgr->device_to_process == NULL) return NULL; switch (action) { case THUNAR_ACTION_MANAGER_ACTION_OPEN: /* aka "activate" */ return xfce_gtk_image_menu_item_new_from_icon_name (action_entry->menu_item_label_text, ngettext ("Open the selected file", "Open the selected files", action_mgr->n_files_to_process), action_entry->accel_path, action_entry->callback, G_OBJECT (action_mgr), action_entry->menu_item_icon_name, menu); case THUNAR_ACTION_MANAGER_ACTION_EXECUTE: return xfce_gtk_image_menu_item_new_from_icon_name (action_entry->menu_item_label_text, ngettext ("Execute the selected file", "Execute the selected files", action_mgr->n_files_to_process), action_entry->accel_path, action_entry->callback, G_OBJECT (action_mgr), action_entry->menu_item_icon_name, menu); case THUNAR_ACTION_MANAGER_ACTION_EDIT_LAUNCHER: return xfce_gtk_menu_item_new_from_action_entry (action_entry, G_OBJECT (action_mgr), GTK_MENU_SHELL (menu)); case THUNAR_ACTION_MANAGER_ACTION_OPEN_IN_TAB: n = action_mgr->n_files_to_process > 0 ? action_mgr->n_files_to_process : 1; label_text = g_strdup_printf (ngettext (action_entry->menu_item_label_text, "Open in %d New _Tabs", n), n); tooltip_text = g_strdup_printf (ngettext ("Open the selected directory in new tab", "Open the selected directories in %d new tabs", n), n); item = xfce_gtk_menu_item_new (label_text, tooltip_text, action_entry->accel_path, action_entry->callback, G_OBJECT (action_mgr), menu); g_free (tooltip_text); g_free (label_text); return item; case THUNAR_ACTION_MANAGER_ACTION_OPEN_IN_WINDOW: n = action_mgr->n_files_to_process > 0 ? action_mgr->n_files_to_process : 1; label_text = g_strdup_printf (ngettext (action_entry->menu_item_label_text, "Open in %d New _Windows", n), n); tooltip_text = g_strdup_printf (ngettext ("Open the selected directory in new window", "Open the selected directories in %d new windows", n), n); item = xfce_gtk_menu_item_new (label_text, tooltip_text, action_entry->accel_path, action_entry->callback, G_OBJECT (action_mgr), menu); g_free (tooltip_text); g_free (label_text); return item; case THUNAR_ACTION_MANAGER_ACTION_OPEN_WITH_OTHER: return xfce_gtk_menu_item_new (action_entry->menu_item_label_text, action_entry->menu_item_tooltip_text, action_entry->accel_path, action_entry->callback, G_OBJECT (action_mgr), menu); case THUNAR_ACTION_MANAGER_ACTION_SET_DEFAULT_APP: if (action_mgr->n_files_to_process != 1) return NULL; return xfce_gtk_menu_item_new_from_action_entry (action_entry, G_OBJECT (action_mgr), GTK_MENU_SHELL (menu)); case THUNAR_ACTION_MANAGER_ACTION_SENDTO_MENU: if (action_mgr->files_are_selected == FALSE) return NULL; item = xfce_gtk_menu_item_new_from_action_entry (action_entry, G_OBJECT (action_mgr), GTK_MENU_SHELL (menu)); submenu = thunar_action_manager_build_sendto_submenu (action_mgr); gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu); return item; case THUNAR_ACTION_MANAGER_ACTION_SENDTO_SHORTCUTS: { if (action_mgr->n_directories_to_process > 0) return xfce_gtk_menu_item_new_from_action_entry (action_entry, G_OBJECT (action_mgr), GTK_MENU_SHELL (menu)); return NULL; } case THUNAR_ACTION_MANAGER_ACTION_MAKE_LINK: show_item = thunar_file_is_writable (action_mgr->current_directory) && action_mgr->files_are_selected && thunar_file_is_trash (action_mgr->current_directory) == FALSE; if (!show_item && !force) return NULL; label_text = ngettext (action_entry->menu_item_label_text, "Ma_ke Links", action_mgr->n_files_to_process); tooltip_text = ngettext ("Create a symbolic link for the selected file", "Create a symbolic link for each selected file", action_mgr->n_files_to_process); item = xfce_gtk_menu_item_new (label_text, tooltip_text, action_entry->accel_path, action_entry->callback, G_OBJECT (action_mgr), menu); gtk_widget_set_sensitive (item, show_item && action_mgr->parent_folder != NULL && thunar_file_is_writable (action_mgr->parent_folder) && !action_mgr->is_searching); return item; case THUNAR_ACTION_MANAGER_ACTION_DUPLICATE: show_item = thunar_file_is_writable (action_mgr->current_directory) && action_mgr->files_are_selected && thunar_file_is_trash (action_mgr->current_directory) == FALSE; if (!show_item && !force) return NULL; item = xfce_gtk_menu_item_new (action_entry->menu_item_label_text, action_entry->menu_item_tooltip_text, action_entry->accel_path, action_entry->callback, G_OBJECT (action_mgr), menu); gtk_widget_set_sensitive (item, show_item && action_mgr->parent_folder != NULL && thunar_file_is_writable (action_mgr->parent_folder) && !action_mgr->is_searching); return item; case THUNAR_ACTION_MANAGER_ACTION_RENAME: show_item = thunar_file_is_writable (action_mgr->current_directory) && action_mgr->files_are_selected && thunar_file_is_trash (action_mgr->current_directory) == FALSE; if (!show_item && !force) return NULL; tooltip_text = ngettext ("Rename the selected file", "Rename the selected files", action_mgr->n_files_to_process); if (action_mgr->n_files_to_process == 1) label_text = g_strdup (action_entry->menu_item_label_text); else label_text = g_strdup (_("Bulk _Rename...")); item = xfce_gtk_menu_item_new (label_text, tooltip_text, action_entry->accel_path, action_entry->callback, G_OBJECT (action_mgr), menu); g_free (label_text); gtk_widget_set_sensitive (item, show_item && action_mgr->parent_folder != NULL && thunar_file_is_writable (action_mgr->parent_folder)); return item; case THUNAR_ACTION_MANAGER_ACTION_RESTORE: if (action_mgr->files_are_selected && thunar_file_is_trash (action_mgr->current_directory)) { tooltip_text = ngettext ("Restore the selected file to its original location", "Restore the selected files to its original location", action_mgr->n_files_to_process); item = xfce_gtk_menu_item_new (action_entry->menu_item_label_text, tooltip_text, action_entry->accel_path, action_entry->callback, G_OBJECT (action_mgr), menu); gtk_widget_set_sensitive (item, thunar_file_is_writable (action_mgr->current_directory)); return item; } return NULL; case THUNAR_ACTION_MANAGER_ACTION_RESTORE_SHOW: if (action_mgr->files_are_selected && thunar_file_is_trash (action_mgr->current_directory)) { tooltip_text = ngettext ("Restore the selected file to its original location and open the location in a new window/tab", "Restore the selected files to their original locations and open the locations in a new window/tab", action_mgr->n_files_to_process); item = xfce_gtk_menu_item_new (action_entry->menu_item_label_text, tooltip_text, action_entry->accel_path, action_entry->callback, G_OBJECT (action_mgr), menu); gtk_widget_set_sensitive (item, thunar_file_is_writable (action_mgr->current_directory)); return item; } return NULL; case THUNAR_ACTION_MANAGER_ACTION_MOVE_TO_TRASH: if (!thunar_action_manager_show_trash (action_mgr)) return NULL; show_item = action_mgr->files_are_selected; if (!show_item && !force) return NULL; tooltip_text = ngettext ("Move the selected file to the Trash", "Move the selected files to the Trash", action_mgr->n_files_to_process); item = xfce_gtk_image_menu_item_new_from_icon_name (action_entry->menu_item_label_text, tooltip_text, action_entry->accel_path, action_entry->callback, G_OBJECT (action_mgr), action_entry->menu_item_icon_name, menu); gtk_widget_set_sensitive (item, show_item && action_mgr->parent_folder != NULL && thunar_file_is_writable (action_mgr->parent_folder)); return item; case THUNAR_ACTION_MANAGER_ACTION_DELETE: g_object_get (G_OBJECT (action_mgr->preferences), "misc-show-delete-action", &show_delete_item, NULL); if (thunar_action_manager_show_trash (action_mgr) && !show_delete_item) return NULL; show_item = action_mgr->files_are_selected; if (!show_item && !force) return NULL; tooltip_text = ngettext ("Permanently delete the selected file", "Permanently delete the selected files", action_mgr->n_files_to_process); item = xfce_gtk_image_menu_item_new_from_icon_name (action_entry->menu_item_label_text, tooltip_text, action_entry->accel_path, action_entry->callback, G_OBJECT (action_mgr), action_entry->menu_item_icon_name, menu); gtk_widget_set_sensitive (item, show_item && action_mgr->parent_folder != NULL && thunar_file_is_writable (action_mgr->parent_folder)); return item; case THUNAR_ACTION_MANAGER_ACTION_EMPTY_TRASH: if (action_mgr->single_directory_to_process == TRUE) { if (thunar_file_is_trash (action_mgr->single_folder)) { item = 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 (action_mgr), action_entry->menu_item_icon_name, menu); gtk_widget_set_sensitive (item, thunar_file_get_item_count (action_mgr->single_folder) > 0); return item; } } return NULL; case THUNAR_ACTION_MANAGER_ACTION_REMOVE_FROM_RECENT: if (action_mgr->files_are_selected && thunar_file_is_recent (action_mgr->current_directory)) { item = 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 (action_mgr), action_entry->menu_item_icon_name, menu); return item; } return NULL; case THUNAR_ACTION_MANAGER_ACTION_CREATE_FOLDER: if (THUNAR_IS_TREE_VIEW (action_mgr->widget) && action_mgr->files_are_selected && action_mgr->single_directory_to_process) parent = action_mgr->single_folder; else parent = action_mgr->current_directory; if (thunar_file_is_trash (parent)) return NULL; item = xfce_gtk_menu_item_new_from_action_entry (action_entry, G_OBJECT (action_mgr), GTK_MENU_SHELL (menu)); gtk_widget_set_sensitive (item, thunar_file_is_writable (parent) && !action_mgr->is_searching); return item; case THUNAR_ACTION_MANAGER_ACTION_CREATE_DOCUMENT: if (THUNAR_IS_TREE_VIEW (action_mgr->widget) && action_mgr->files_are_selected && action_mgr->single_directory_to_process) parent = action_mgr->single_folder; else parent = action_mgr->current_directory; if (thunar_file_is_trash (parent)) return NULL; item = xfce_gtk_menu_item_new_from_action_entry (action_entry, G_OBJECT (action_mgr), GTK_MENU_SHELL (menu)); submenu = thunar_action_manager_create_document_submenu_new (action_mgr); gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu); gtk_widget_set_sensitive (item, thunar_file_is_writable (parent) && !action_mgr->is_searching); return item; case THUNAR_ACTION_MANAGER_ACTION_CUT: focused_widget = thunar_gtk_get_focused_widget (); if (focused_widget && GTK_IS_EDITABLE (focused_widget)) { item = xfce_gtk_image_menu_item_new_from_icon_name ( action_entry->menu_item_label_text, N_ ("Cut the selection"), action_entry->accel_path, G_CALLBACK (gtk_editable_cut_clipboard), G_OBJECT (focused_widget), action_entry->menu_item_icon_name, menu); gtk_widget_set_sensitive (item, thunar_gtk_editable_can_cut (GTK_EDITABLE (focused_widget))); } else { show_item = action_mgr->files_are_selected; if (!show_item && !force) return NULL; tooltip_text = ngettext ("Prepare the selected file to be moved with a Paste command", "Prepare the selected files to be moved with a Paste command", action_mgr->n_files_to_process); item = xfce_gtk_image_menu_item_new_from_icon_name (action_entry->menu_item_label_text, tooltip_text, action_entry->accel_path, action_entry->callback, G_OBJECT (action_mgr), action_entry->menu_item_icon_name, menu); gtk_widget_set_sensitive (item, show_item && action_mgr->parent_folder != NULL && thunar_file_is_writable (action_mgr->parent_folder)); } return item; case THUNAR_ACTION_MANAGER_ACTION_COPY: focused_widget = thunar_gtk_get_focused_widget (); if (focused_widget && GTK_IS_EDITABLE (focused_widget)) { item = xfce_gtk_image_menu_item_new_from_icon_name ( action_entry->menu_item_label_text, N_ ("Copy the selection"), action_entry->accel_path, G_CALLBACK (gtk_editable_copy_clipboard), G_OBJECT (focused_widget), action_entry->menu_item_icon_name, menu); gtk_widget_set_sensitive (item, thunar_gtk_editable_can_copy (GTK_EDITABLE (focused_widget))); } else { show_item = action_mgr->files_are_selected; if (!show_item && !force) return NULL; tooltip_text = ngettext ("Prepare the selected file to be copied with a Paste command", "Prepare the selected files to be copied with a Paste command", action_mgr->n_files_to_process); item = xfce_gtk_image_menu_item_new_from_icon_name (action_entry->menu_item_label_text, tooltip_text, action_entry->accel_path, action_entry->callback, G_OBJECT (action_mgr), action_entry->menu_item_icon_name, menu); gtk_widget_set_sensitive (item, show_item); } return item; case THUNAR_ACTION_MANAGER_ACTION_PASTE_INTO_FOLDER: if (!(action_mgr->single_directory_to_process && action_mgr->files_are_selected)) return NULL; clipboard = thunar_clipboard_manager_get_for_display (gtk_widget_get_display (action_mgr->widget)); item = xfce_gtk_menu_item_new_from_action_entry (action_entry, G_OBJECT (action_mgr), GTK_MENU_SHELL (menu)); gtk_widget_set_sensitive (item, thunar_clipboard_manager_get_can_paste (clipboard) && thunar_file_is_writable (action_mgr->single_folder)); g_object_unref (clipboard); return item; case THUNAR_ACTION_MANAGER_ACTION_PASTE: focused_widget = thunar_gtk_get_focused_widget (); if (focused_widget && GTK_IS_EDITABLE (focused_widget)) { item = xfce_gtk_image_menu_item_new_from_icon_name ( action_entry->menu_item_label_text, N_ ("Paste the clipboard"), action_entry->accel_path, G_CALLBACK (gtk_editable_paste_clipboard), G_OBJECT (focused_widget), action_entry->menu_item_icon_name, menu); gtk_widget_set_sensitive (item, thunar_gtk_editable_can_paste (GTK_EDITABLE (focused_widget)) && !action_mgr->is_searching); } else { clipboard = thunar_clipboard_manager_get_for_display (gtk_widget_get_display (action_mgr->widget)); item = xfce_gtk_menu_item_new_from_action_entry (action_entry, G_OBJECT (action_mgr), GTK_MENU_SHELL (menu)); gtk_widget_set_sensitive (item, thunar_clipboard_manager_get_can_paste (clipboard) && thunar_file_is_writable (action_mgr->current_directory) && !action_mgr->is_searching); g_object_unref (clipboard); } return item; case THUNAR_ACTION_MANAGER_ACTION_MOUNT: if (action_mgr->device_to_process == NULL || thunar_device_is_mounted (action_mgr->device_to_process) == TRUE) return NULL; return xfce_gtk_menu_item_new_from_action_entry (action_entry, G_OBJECT (action_mgr), GTK_MENU_SHELL (menu)); case THUNAR_ACTION_MANAGER_ACTION_UNMOUNT: if (action_mgr->device_to_process == NULL || thunar_device_is_mounted (action_mgr->device_to_process) == FALSE) return NULL; return xfce_gtk_menu_item_new_from_action_entry (action_entry, G_OBJECT (action_mgr), GTK_MENU_SHELL (menu)); case THUNAR_ACTION_MANAGER_ACTION_EJECT: if (action_mgr->device_to_process == NULL || thunar_device_get_kind (action_mgr->device_to_process) != THUNAR_DEVICE_KIND_VOLUME) return NULL; item = xfce_gtk_menu_item_new_from_action_entry (action_entry, G_OBJECT (action_mgr), GTK_MENU_SHELL (menu)); gtk_widget_set_sensitive (item, thunar_device_can_eject (action_mgr->device_to_process)); eject_label = thunar_device_get_eject_label (action_mgr->device_to_process); gtk_menu_item_set_label (GTK_MENU_ITEM (item), eject_label); return item; case THUNAR_ACTION_MANAGER_ACTION_PROPERTIES: item = xfce_gtk_menu_item_new_from_action_entry (action_entry, G_OBJECT (action_mgr), GTK_MENU_SHELL (menu)); if (action_mgr->device_to_process != NULL) gtk_widget_set_sensitive (item, thunar_device_is_mounted (action_mgr->device_to_process)); return item; default: return xfce_gtk_menu_item_new_from_action_entry (action_entry, G_OBJECT (action_mgr), GTK_MENU_SHELL (menu)); } return NULL; } static gboolean thunar_action_manager_action_sendto_desktop (ThunarActionManager *action_mgr) { ThunarApplication *application; GFile *desktop_file; GList *files; _thunar_return_val_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr), FALSE); /* determine the source paths */ files = thunar_file_list_to_thunar_g_file_list (action_mgr->files_to_process); if (G_UNLIKELY (files == NULL)) return TRUE; /* determine the file to the ~/Desktop folder */ desktop_file = thunar_g_file_new_for_desktop (); /* launch the link job */ application = thunar_application_get (); thunar_application_link_into (application, action_mgr->widget, files, desktop_file, THUNAR_OPERATION_LOG_OPERATIONS, NULL); g_object_unref (G_OBJECT (application)); /* cleanup */ g_object_unref (desktop_file); thunar_g_list_free_full (files); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static void thunar_action_manager_sendto_device (ThunarActionManager *action_mgr, ThunarDevice *device) { ThunarApplication *application; GFile *mount_point; GList *files; _thunar_return_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr)); _thunar_return_if_fail (THUNAR_IS_DEVICE (device)); if (!thunar_device_is_mounted (device)) return; /* determine the source paths */ files = thunar_file_list_to_thunar_g_file_list (action_mgr->files_to_process); if (G_UNLIKELY (files == NULL)) return; mount_point = thunar_device_get_root (device); if (mount_point != NULL) { /* copy the files onto the specified device */ application = thunar_application_get (); thunar_application_copy_into (application, action_mgr->widget, files, mount_point, THUNAR_OPERATION_LOG_OPERATIONS, NULL); g_object_unref (application); g_object_unref (mount_point); } /* cleanup */ thunar_g_list_free_full (files); } static void thunar_action_manager_sendto_mount_finish (ThunarDevice *device, const GError *error, gpointer user_data) { ThunarActionManager *action_mgr = user_data; gchar *device_name; _thunar_return_if_fail (THUNAR_IS_DEVICE (device)); _thunar_return_if_fail (user_data != NULL); _thunar_return_if_fail (THUNAR_IS_ACTION_MANAGER (user_data)); if (error != NULL) { /* tell the user that we were unable to mount the device, which is * required to send files to it */ device_name = thunar_device_get_name (device); thunar_dialogs_show_error (action_mgr->widget, error, _("Failed to mount \"%s\""), device_name); g_free (device_name); } else { thunar_action_manager_sendto_device (action_mgr, device); } } static gboolean thunar_action_manager_action_sendto_device (ThunarActionManager *action_mgr, GObject *object) { GMountOperation *mount_operation; ThunarDevice *device; _thunar_return_val_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr), FALSE); /* determine the device to which to send */ device = g_object_get_qdata (G_OBJECT (object), thunar_action_manager_device_quark); if (G_UNLIKELY (device == NULL)) return TRUE; /* make sure to mount the device first, if it's not already mounted */ if (!thunar_device_is_mounted (device)) { /* allocate a GTK+ mount operation */ mount_operation = thunar_gtk_mount_operation_new (action_mgr->widget); /* try to mount the device and later start sending the files */ thunar_device_mount (device, mount_operation, NULL, thunar_action_manager_sendto_mount_finish, action_mgr); g_object_unref (mount_operation); } else { thunar_action_manager_sendto_device (action_mgr, device); } /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_action_manager_action_add_shortcuts (ThunarActionManager *action_mgr) { GList *lp; GtkWidget *window; const GtkWidget *sidepane; _thunar_return_val_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr), FALSE); /* determine the toplevel window we belong to */ window = gtk_widget_get_toplevel (action_mgr->widget); if (THUNAR_IS_WINDOW (window) == FALSE) return FALSE; if (thunar_window_has_shortcut_sidepane (THUNAR_WINDOW (window)) == FALSE) return TRUE; sidepane = thunar_window_get_sidepane (THUNAR_WINDOW (window)); if (sidepane != NULL && THUNAR_IS_SHORTCUTS_PANE (sidepane)) { for (lp = action_mgr->files_to_process; lp != NULL; lp = lp->next) thunar_shortcuts_pane_add_shortcut (THUNAR_SHORTCUTS_PANE (sidepane), lp->data); } /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static GtkWidget * thunar_action_manager_build_sendto_submenu (ThunarActionManager *action_mgr) { GList *lp; gboolean linkable = TRUE; gchar *label_text; gchar *tooltip_text; GtkWidget *image; GtkWidget *item; GtkWidget *submenu; GtkWidget *window; GList *devices; GList *appinfo_list; GIcon *icon; ThunarDeviceMonitor *device_monitor; ThunarSendtoModel *sendto_model; const XfceGtkActionEntry *action_entry; _thunar_return_val_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr), NULL); submenu = gtk_menu_new (); /* show "sent to shortcut" if only directories are selected */ if (action_mgr->n_directories_to_process > 0 && action_mgr->n_directories_to_process == action_mgr->n_files_to_process) { /* determine the toplevel window we belong to */ window = gtk_widget_get_toplevel (action_mgr->widget); if (THUNAR_IS_WINDOW (window) && thunar_window_has_shortcut_sidepane (THUNAR_WINDOW (window))) { action_entry = get_action_entry (THUNAR_ACTION_MANAGER_ACTION_SENDTO_SHORTCUTS); if (action_entry != NULL) { label_text = ngettext ("Side Pane (Add Bookmark)", "Side Pane (Add Bookmarks)", action_mgr->n_files_to_process); tooltip_text = ngettext ("Add the selected folder to the shortcuts side pane", "Add the selected folders to the shortcuts side pane", action_mgr->n_files_to_process); item = xfce_gtk_image_menu_item_new_from_icon_name (label_text, tooltip_text, action_entry->accel_path, action_entry->callback, G_OBJECT (action_mgr), action_entry->menu_item_icon_name, GTK_MENU_SHELL (submenu)); } } } /* Check whether at least one files is located in the trash (to en-/disable the "sendto-desktop" action). */ for (lp = action_mgr->files_to_process; lp != NULL; lp = lp->next) { if (G_UNLIKELY (thunar_file_is_trashed (lp->data))) linkable = FALSE; } if (linkable) { action_entry = get_action_entry (THUNAR_ACTION_MANAGER_ACTION_SENDTO_DESKTOP); if (action_entry != NULL) { label_text = ngettext ("Desktop (Create Link)", "Desktop (Create Links)", action_mgr->n_files_to_process); tooltip_text = ngettext ("Create a link to the selected file on the desktop", "Create links to the selected files on the desktop", action_mgr->n_files_to_process); item = xfce_gtk_image_menu_item_new_from_icon_name (label_text, tooltip_text, action_entry->accel_path, action_entry->callback, G_OBJECT (action_mgr), action_entry->menu_item_icon_name, GTK_MENU_SHELL (submenu)); } } item = gtk_separator_menu_item_new (); gtk_menu_shell_append (GTK_MENU_SHELL (submenu), item); gtk_widget_show (item); /* determine the currently active devices */ device_monitor = thunar_device_monitor_get (); devices = thunar_device_monitor_get_devices (device_monitor); g_object_unref (device_monitor); /* add removable (and writable) drives and media */ for (lp = devices; lp != NULL; lp = lp->next) { /* generate a unique name and tooltip for the device */ label_text = thunar_device_get_name (lp->data); tooltip_text = g_strdup_printf (ngettext ("Send the selected file to \"%s\"", "Send the selected files to \"%s\"", action_mgr->n_files_to_process), label_text); icon = thunar_device_get_icon (lp->data, FALSE); image = NULL; if (G_LIKELY (icon != NULL)) { image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_MENU); g_object_unref (icon); } item = xfce_gtk_image_menu_item_new (label_text, tooltip_text, NULL, G_CALLBACK (thunar_action_manager_action_sendto_device), G_OBJECT (action_mgr), image, GTK_MENU_SHELL (submenu)); g_object_set_qdata_full (G_OBJECT (item), thunar_action_manager_device_quark, lp->data, g_object_unref); g_object_set_data (G_OBJECT (lp->data), "skip-app-info-update", GUINT_TO_POINTER (1)); /* cleanup */ g_free (tooltip_text); g_free (label_text); } /* free the devices list */ g_list_free (devices); item = gtk_separator_menu_item_new (); gtk_menu_shell_append (GTK_MENU_SHELL (submenu), item); gtk_widget_show (item); /* determine the sendto appInfos for the selected files */ sendto_model = thunar_sendto_model_get_default (); appinfo_list = thunar_sendto_model_get_matching (sendto_model, action_mgr->files_to_process); g_object_unref (sendto_model); if (G_LIKELY (appinfo_list != NULL)) { /* add all handlers to the user interface */ for (lp = appinfo_list; lp != NULL; lp = lp->next) { /* generate a unique name and tooltip for the handler */ label_text = g_strdup (g_app_info_get_name (lp->data)); tooltip_text = g_strdup_printf (ngettext ("Send the selected file to \"%s\"", "Send the selected files to \"%s\"", action_mgr->n_files_to_process), label_text); icon = g_app_info_get_icon (lp->data); image = NULL; if (G_LIKELY (icon != NULL)) image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_MENU); item = xfce_gtk_image_menu_item_new (label_text, tooltip_text, NULL, G_CALLBACK (thunar_action_manager_menu_item_activated), G_OBJECT (action_mgr), image, GTK_MENU_SHELL (submenu)); g_object_set_qdata_full (G_OBJECT (item), thunar_action_manager_appinfo_quark, g_object_ref (lp->data), g_object_unref); g_object_set_data (G_OBJECT (lp->data), "skip-app-info-update", GUINT_TO_POINTER (1)); /* cleanup */ g_free (label_text); g_free (tooltip_text); } /* release the appinfo list */ g_list_free_full (appinfo_list, g_object_unref); } return submenu; } static gboolean thunar_action_manager_action_properties (ThunarActionManager *action_mgr) { GtkWidget *toplevel; GtkWidget *dialog; _thunar_return_val_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr), FALSE); /* popup the files dialog */ toplevel = gtk_widget_get_toplevel (action_mgr->widget); if (G_LIKELY (toplevel != NULL)) { dialog = thunar_properties_dialog_new (GTK_WINDOW (toplevel), THUNAR_PROPERTIES_DIALOG_SHOW_HIGHLIGHT); /* check if no files are currently selected */ if (action_mgr->files_to_process == NULL) { /* if we don't have any files selected, we just popup the properties dialog for the current folder. */ thunar_properties_dialog_set_file (THUNAR_PROPERTIES_DIALOG (dialog), action_mgr->current_directory); } else { /* popup the properties dialog for all file(s) */ thunar_properties_dialog_set_files (THUNAR_PROPERTIES_DIALOG (dialog), action_mgr->files_to_process); } gtk_widget_show (dialog); } /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_action_manager_action_make_link (ThunarActionManager *action_mgr) { ThunarApplication *application; GList *g_files = NULL; GList *lp; _thunar_return_val_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr), FALSE); if (G_UNLIKELY (action_mgr->current_directory == NULL) || G_UNLIKELY (action_mgr->is_searching)) return TRUE; if (action_mgr->files_are_selected == FALSE || thunar_file_is_trash (action_mgr->current_directory)) return TRUE; for (lp = action_mgr->files_to_process; lp != NULL; lp = lp->next) { g_files = g_list_append (g_files, thunar_file_get_file (lp->data)); } /* link the selected files into the current directory, which effectively * creates new unique links for the files. */ application = thunar_application_get (); thunar_application_link_into (application, action_mgr->widget, g_files, thunar_file_get_file (action_mgr->current_directory), THUNAR_OPERATION_LOG_OPERATIONS, action_mgr->new_files_created_closure); g_object_unref (G_OBJECT (application)); g_list_free (g_files); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_action_manager_action_duplicate (ThunarActionManager *action_mgr) { ThunarApplication *application; GList *files_to_process; _thunar_return_val_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr), FALSE); if (G_UNLIKELY (action_mgr->current_directory == NULL) || G_UNLIKELY (action_mgr->is_searching)) return TRUE; if (action_mgr->files_are_selected == FALSE || thunar_file_is_trash (action_mgr->current_directory)) return TRUE; /* determine the selected files for the view */ files_to_process = thunar_file_list_to_thunar_g_file_list (action_mgr->files_to_process); if (G_LIKELY (files_to_process != NULL)) { /* copy the selected files into the current directory, which effectively * creates duplicates of the files. */ application = thunar_application_get (); thunar_application_copy_into (application, action_mgr->widget, files_to_process, thunar_file_get_file (action_mgr->current_directory), THUNAR_OPERATION_LOG_OPERATIONS, action_mgr->new_files_created_closure); g_object_unref (G_OBJECT (application)); /* clean up */ thunar_g_list_free_full (files_to_process); } /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } /** * thunar_action_manager_append_custom_actions: * @action_mgr: a #ThunarActionManager instance * @menu : #GtkMenuShell on which the custom actions should be appended * * Will append all custom actions which match the file-type to the provided #GtkMenuShell * * Return value: TRUE if any custom action was added **/ gboolean thunar_action_manager_append_custom_actions (ThunarActionManager *action_mgr, GtkMenuShell *menu) { gboolean uca_added = FALSE; GtkWidget *window; GtkWidget *gtk_menu_item; ThunarxProviderFactory *provider_factory; GList *providers; GList *thunarx_menu_items = NULL; GList *lp_provider; GList *lp_item; _thunar_return_val_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr), FALSE); _thunar_return_val_if_fail (GTK_IS_MENU (menu), FALSE); /* determine the toplevel window we belong to */ window = gtk_widget_get_toplevel (action_mgr->widget); /* 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 FALSE; /* This may occur when the thunar-window is build */ if (G_UNLIKELY (action_mgr->files_to_process == NULL)) return FALSE; /* load the menu items offered by the menu providers */ for (lp_provider = providers; lp_provider != NULL; lp_provider = lp_provider->next) { if (action_mgr->files_are_selected == FALSE) thunarx_menu_items = thunarx_menu_provider_get_folder_menu_items (lp_provider->data, window, THUNARX_FILE_INFO (action_mgr->current_directory)); else thunarx_menu_items = thunarx_menu_provider_get_file_menu_items (lp_provider->data, window, action_mgr->files_to_process); for (lp_item = thunarx_menu_items; lp_item != NULL; lp_item = lp_item->next) { gtk_menu_item = thunar_gtk_menu_thunarx_menu_item_new (lp_item->data, 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_item->data); uca_added = TRUE; } g_list_free (thunarx_menu_items); } g_list_free_full (providers, g_object_unref); return uca_added; } static gboolean _thunar_action_manager_check_uca_key_activation_for_menu_items (GList *thunarx_menu_items, GdkEventKey *key_event, gboolean do_activate) { GList *lp_item; GtkAccelKey uca_key; gchar *name, *accel_path; ThunarxMenu *submenu; gboolean matching_uca_shortcut_found = FALSE; 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) { matching_uca_shortcut_found |= _thunar_action_manager_check_uca_key_activation_for_menu_items (thunarx_submenu_items, key_event, do_activate); thunarx_menu_item_list_free (thunarx_submenu_items); } g_object_unref (submenu); } else { /* a simple menu-item, check if the key-combo matches */ accel_path = g_strconcat ("/ThunarActions/", name, NULL); if (gtk_accel_map_lookup_entry (accel_path, &uca_key) == TRUE) { /* The passed key_event can have modifier AND upper-case keyval. So for comparison we need to lower the keyval */ if (g_unichar_tolower (key_event->keyval) == g_unichar_tolower (uca_key.accel_key)) { if ((key_event->state & gtk_accelerator_get_default_mod_mask ()) == uca_key.accel_mods) { if (do_activate) thunarx_menu_item_activate (lp_item->data); matching_uca_shortcut_found = TRUE; } } } g_free (accel_path); } g_free (name); } return matching_uca_shortcut_found; } gboolean thunar_action_manager_check_uca_key_activation (ThunarActionManager *action_mgr, GdkEventKey *key_event) { GtkWidget *window; ThunarxProviderFactory *provider_factory; GList *providers; GList *thunarx_file_menu_items = NULL; GList *thunarx_folder_menu_items = NULL; GList *lp_provider; gboolean matching_uca_shortcut_found = FALSE; /* determine the toplevel window we belong to */ window = gtk_widget_get_toplevel (action_mgr->widget); /* 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 matching_uca_shortcut_found; /* load the menu items offered by the menu providers */ for (lp_provider = providers; lp_provider != NULL; lp_provider = lp_provider->next) { thunarx_file_menu_items = thunarx_menu_provider_get_folder_menu_items (lp_provider->data, window, THUNARX_FILE_INFO (action_mgr->current_directory)); thunarx_folder_menu_items = thunarx_menu_provider_get_file_menu_items (lp_provider->data, window, action_mgr->files_to_process); /* Check if we processed the shortcut sucesfully */ matching_uca_shortcut_found |= _thunar_action_manager_check_uca_key_activation_for_menu_items (thunarx_file_menu_items, key_event, FALSE); matching_uca_shortcut_found |= _thunar_action_manager_check_uca_key_activation_for_menu_items (thunarx_folder_menu_items, key_event, FALSE); if (action_mgr->files_are_selected == FALSE) _thunar_action_manager_check_uca_key_activation_for_menu_items (thunarx_file_menu_items, key_event, TRUE); else _thunar_action_manager_check_uca_key_activation_for_menu_items (thunarx_folder_menu_items, key_event, TRUE); if (thunarx_file_menu_items != NULL) thunarx_menu_item_list_free (thunarx_file_menu_items); if (thunarx_folder_menu_items != NULL) thunarx_menu_item_list_free (thunarx_folder_menu_items); } g_list_free_full (providers, g_object_unref); return matching_uca_shortcut_found; } static gboolean thunar_action_manager_action_rename (ThunarActionManager *action_mgr) { GtkWidget *window; GdkScreen *screen; ThunarApplication *application; _thunar_return_val_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr), FALSE); if (action_mgr->files_to_process == NULL || g_list_length (action_mgr->files_to_process) == 0) return TRUE; if (action_mgr->files_are_selected == FALSE || thunar_file_is_trash (action_mgr->current_directory)) return TRUE; /* get the window and the screen */ window = gtk_widget_get_toplevel (action_mgr->widget); screen = thunar_util_parse_parent (window, NULL); /* start renaming if we have exactly one selected file */ if (g_list_length (action_mgr->files_to_process) == 1) { application = thunar_application_get (); thunar_application_rename_file (application, action_mgr->files_to_process->data, screen, NULL, THUNAR_OPERATION_LOG_OPERATIONS); g_object_unref (G_OBJECT (application)); } else { /* display the bulk rename dialog */ thunar_show_renamer_dialog (GTK_WIDGET (window), action_mgr->current_directory, action_mgr->files_to_process, FALSE, NULL); } /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } gboolean thunar_action_manager_action_restore (ThunarActionManager *action_mgr) { ThunarApplication *application; _thunar_return_val_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr), FALSE); if (action_mgr->files_are_selected == FALSE || !thunar_file_is_trash (action_mgr->current_directory)) return TRUE; /* restore the selected files */ application = thunar_application_get (); thunar_application_restore_files (application, action_mgr->widget, action_mgr->files_to_process, NULL); g_object_unref (G_OBJECT (application)); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } gboolean thunar_action_manager_action_restore_and_show (ThunarActionManager *action_mgr) { ThunarApplication *application; _thunar_return_val_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr), FALSE); if (action_mgr->files_are_selected == FALSE || !thunar_file_is_trash (action_mgr->current_directory)) return TRUE; /* restore the selected files */ application = thunar_application_get (); thunar_application_restore_files (application, action_mgr->widget, action_mgr->files_to_process, action_mgr->new_files_created_closure); 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 void thunar_action_manager_action_move_to_trash (ThunarActionManager *action_mgr) { ThunarApplication *application; gboolean warn; _thunar_return_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr)); if (action_mgr->parent_folder == NULL || action_mgr->files_are_selected == FALSE) return; /* check if the user wants a confirmation before moving to trash */ g_object_get (G_OBJECT (action_mgr->preferences), "misc-confirm-move-to-trash", &warn, NULL); application = thunar_application_get (); thunar_application_unlink_files (application, action_mgr->widget, action_mgr->files_to_process, FALSE, warn, THUNAR_OPERATION_LOG_OPERATIONS); g_object_unref (G_OBJECT (application)); } static gboolean thunar_action_manager_action_delete (ThunarActionManager *action_mgr) { ThunarApplication *application; _thunar_return_val_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr), FALSE); if (action_mgr->parent_folder == NULL || action_mgr->files_are_selected == FALSE) return TRUE; application = thunar_application_get (); thunar_application_unlink_files (application, action_mgr->widget, action_mgr->files_to_process, TRUE, TRUE, THUNAR_OPERATION_LOG_OPERATIONS); 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_action_manager_action_trash_delete (ThunarActionManager *action_mgr) { GdkModifierType event_state; _thunar_return_val_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr), FALSE); /* when shift modifier is pressed, we delete (as well via context menu) */ if (gtk_get_current_event_state (&event_state) && (event_state & GDK_SHIFT_MASK) != 0) thunar_action_manager_action_delete (action_mgr); else if (thunar_g_vfs_is_uri_scheme_supported ("trash") && !thunar_file_is_trashed (action_mgr->current_directory)) thunar_action_manager_action_move_to_trash (action_mgr); else thunar_action_manager_action_delete (action_mgr); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_action_manager_action_remove_from_recent (ThunarActionManager *action_mgr) { GtkRecentManager *recent_manager = gtk_recent_manager_get_default (); GList *lp; _thunar_return_val_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr), FALSE); if (action_mgr->parent_folder == NULL || action_mgr->files_are_selected == FALSE) return TRUE; for (lp = action_mgr->files_to_process; lp != NULL; lp = lp->next) { ThunarFile *file = lp->data; GFile *gfile = thunar_file_get_file (file); gchar *uri = g_file_get_uri (gfile); gtk_recent_manager_remove_item (recent_manager, uri, NULL); g_free (uri); } /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } gboolean thunar_action_manager_action_empty_trash (ThunarActionManager *action_mgr) { ThunarApplication *application; _thunar_return_val_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr), FALSE); application = thunar_application_get (); thunar_application_empty_trash (application, action_mgr->widget, NULL); 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_action_manager_action_create_folder (ThunarActionManager *action_mgr) { ThunarApplication *application; GList path_list; gchar *name; gchar *generated_name; _thunar_return_val_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr), FALSE); if (thunar_file_is_trash (action_mgr->current_directory) || action_mgr->is_searching) return TRUE; /* ask the user to enter a name for the new folder */ generated_name = thunar_util_next_new_file_name (action_mgr->current_directory, _("New Folder"), THUNAR_NEXT_FILE_NAME_MODE_NEW, TRUE); name = thunar_dialogs_show_create (action_mgr->widget, "inode/directory", generated_name, _("Create New Folder")); g_free (generated_name); if (G_LIKELY (name != NULL)) { /* fake the path list */ if (THUNAR_IS_TREE_VIEW (action_mgr->widget) && action_mgr->files_are_selected && action_mgr->single_directory_to_process) path_list.data = g_file_resolve_relative_path (thunar_file_get_file (action_mgr->single_folder), name); else path_list.data = g_file_resolve_relative_path (thunar_file_get_file (action_mgr->current_directory), name); path_list.next = path_list.prev = NULL; /* launch the operation */ application = thunar_application_get (); thunar_application_mkdir (application, action_mgr->widget, &path_list, action_mgr->new_files_created_closure, THUNAR_OPERATION_LOG_OPERATIONS); g_object_unref (G_OBJECT (application)); /* release the path */ g_object_unref (path_list.data); /* release the file name */ g_free (name); } /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_action_manager_action_create_document (ThunarActionManager *action_mgr, GtkWidget *menu_item) { ThunarApplication *application; GList target_path_list; gchar *name; gchar *generated_name; gchar *title; ThunarFile *template_file; _thunar_return_val_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr), FALSE); if (thunar_file_is_trash (action_mgr->current_directory) || action_mgr->is_searching) return TRUE; template_file = g_object_get_qdata (G_OBJECT (menu_item), thunar_action_manager_file_quark); if (template_file != NULL) { gchar *basename = g_file_get_basename (thunar_file_get_file (template_file)); /* generate a title for the create dialog */ title = g_strdup_printf (_("Create Document from template \"%s\""), thunar_file_get_display_name (template_file)); /* ask the user to enter a name for the new document */ generated_name = thunar_util_next_new_file_name (action_mgr->current_directory, basename, THUNAR_NEXT_FILE_NAME_MODE_NEW, FALSE); g_free (basename); name = thunar_dialogs_show_create (action_mgr->widget, thunar_file_get_content_type (THUNAR_FILE (template_file)), generated_name, title); /* cleanup */ g_free (title); } else { /* ask the user to enter a name for the new empty file */ generated_name = thunar_util_next_new_file_name (action_mgr->current_directory, _("New Empty File"), THUNAR_NEXT_FILE_NAME_MODE_NEW, FALSE); name = thunar_dialogs_show_create (action_mgr->widget, "text/plain", generated_name, _("New Empty File...")); } g_free (generated_name); if (G_LIKELY (name != NULL)) { if (G_LIKELY (action_mgr->parent_folder != NULL)) { /* fake the target path list */ if (THUNAR_IS_TREE_VIEW (action_mgr->widget) && action_mgr->files_are_selected && action_mgr->single_directory_to_process) target_path_list.data = g_file_get_child (thunar_file_get_file (action_mgr->single_folder), name); else target_path_list.data = g_file_get_child (thunar_file_get_file (action_mgr->current_directory), name); target_path_list.next = NULL; target_path_list.prev = NULL; /* launch the operation */ application = thunar_application_get (); thunar_application_creat (application, action_mgr->widget, &target_path_list, template_file != NULL ? thunar_file_get_file (template_file) : NULL, action_mgr->new_files_created_closure, THUNAR_OPERATION_LOG_OPERATIONS); g_object_unref (G_OBJECT (application)); /* release the target path */ g_object_unref (target_path_list.data); } /* release the file name */ g_free (name); } /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } /* helper method in order to find the parent menu for a menu item */ static GtkWidget * thunar_action_manager_create_document_submenu_templates_find_parent_menu (ThunarFile *file, GList *dirs, GList *items) { GtkWidget *parent_menu = NULL; GFile *parent; GList *lp; GList *ip; /* determine the parent of the file */ parent = g_file_get_parent (thunar_file_get_file (file)); /* check if the file has a parent at all */ if (parent == NULL) return NULL; /* iterate over all dirs and menu items */ for (lp = g_list_first (dirs), ip = g_list_first (items); parent_menu == NULL && lp != NULL && ip != NULL; lp = lp->next, ip = ip->next) { /* check if the current dir/item is the parent of our file */ if (g_file_equal (parent, thunar_file_get_file (lp->data))) { /* we want to insert an item for the file in this menu */ parent_menu = gtk_menu_item_get_submenu (ip->data); } } /* destroy the parent GFile */ g_object_unref (parent); return parent_menu; } /* recursive helper method in order to create menu items for all available templates */ static gboolean thunar_action_manager_create_document_submenu_templates (ThunarActionManager *action_mgr, GtkWidget *create_file_submenu, GList *files) { ThunarIconFactory *icon_factory; ThunarFile *file; GdkPixbuf *icon; cairo_surface_t *surface; GtkWidget *parent_menu; GtkWidget *submenu; GtkWidget *image; GtkWidget *item; GList *files_sorted; GList *lp; GList *dirs = NULL; GList *items = NULL; gint scale_factor; _thunar_return_val_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr), FALSE); /* do nothing if there is no menu */ if (create_file_submenu == NULL) return FALSE; /* get the icon factory */ icon_factory = thunar_icon_factory_get_default (); scale_factor = gtk_widget_get_scale_factor (create_file_submenu); /* sort items so that directories come before files and ancestors come * before descendants */ files_sorted = g_list_sort (thunar_g_list_copy_deep (files), (GCompareFunc) (void (*) (void)) thunar_file_compare_by_type); for (lp = g_list_first (files_sorted); lp != NULL; lp = lp->next) { file = lp->data; /* determine the parent menu for this file/directory */ parent_menu = thunar_action_manager_create_document_submenu_templates_find_parent_menu (file, dirs, items); if (parent_menu == NULL) parent_menu = create_file_submenu; /* determine the icon for this file/directory */ icon = thunar_icon_factory_load_file_icon (icon_factory, file, THUNAR_FILE_ICON_STATE_DEFAULT, 16, scale_factor, FALSE, NULL); surface = gdk_cairo_surface_create_from_pixbuf (icon, scale_factor, NULL); /* allocate an image based on the icon */ image = gtk_image_new_from_surface (surface); item = xfce_gtk_image_menu_item_new (thunar_file_get_display_name (file), NULL, NULL, NULL, NULL, image, GTK_MENU_SHELL (parent_menu)); if (thunar_file_is_directory (file)) { /* allocate a new submenu for the directory */ submenu = gtk_menu_new (); /* allocate a new menu item for the directory */ gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu); /* prepend the directory, its item and the parent menu it should * later be added to to the respective lists */ dirs = g_list_prepend (dirs, file); items = g_list_prepend (items, item); } else { g_signal_connect_swapped (G_OBJECT (item), "activate", G_CALLBACK (thunar_action_manager_action_create_document), action_mgr); g_object_set_qdata_full (G_OBJECT (item), thunar_action_manager_file_quark, g_object_ref (file), g_object_unref); } /* release the icon reference */ g_object_unref (icon); cairo_surface_destroy (surface); } g_list_free_full (files_sorted, g_object_unref); /* destroy lists */ g_list_free (dirs); g_list_free (items); /* release the icon factory */ g_object_unref (icon_factory); /* let the job destroy the file list */ return FALSE; } /** * thunar_action_manager_create_document_submenu_new: * @action_mgr : a #ThunarActionManager instance * * Will create a complete 'create_document* #GtkMenu and return it * * Return value: (transfer full): the created #GtkMenu **/ static GtkWidget * thunar_action_manager_create_document_submenu_new (ThunarActionManager *action_mgr) { GList *files = NULL; GFile *home_dir; GFile *templates_dir = NULL; const gchar *path; gchar *template_path; gchar *label_text; GtkWidget *submenu; GtkWidget *item; guint file_scan_limit; _thunar_return_val_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr), NULL); g_object_get (G_OBJECT (action_mgr->preferences), "misc-max-number-of-templates", &file_scan_limit, NULL); home_dir = thunar_g_file_new_for_home (); path = g_get_user_special_dir (G_USER_DIRECTORY_TEMPLATES); if (G_LIKELY (path != NULL)) templates_dir = g_file_new_for_path (path); /* If G_USER_DIRECTORY_TEMPLATES not found, set "~/Templates" directory as default */ if (G_UNLIKELY (path == NULL) || G_UNLIKELY (g_file_equal (templates_dir, home_dir))) { if (templates_dir != NULL) g_object_unref (templates_dir); templates_dir = g_file_resolve_relative_path (home_dir, "Templates"); } if (G_LIKELY (templates_dir != NULL)) { /* load the ThunarFiles */ files = thunar_io_scan_directory (NULL, templates_dir, G_FILE_QUERY_INFO_NONE, TRUE, FALSE, TRUE, &file_scan_limit, NULL); } submenu = gtk_menu_new (); if (files == NULL) { template_path = g_file_get_path (templates_dir); label_text = g_strdup_printf (_("No templates installed in\n\"%s\""), template_path); item = xfce_gtk_image_menu_item_new (label_text, NULL, NULL, NULL, NULL, NULL, GTK_MENU_SHELL (submenu)); gtk_widget_set_sensitive (item, FALSE); g_free (template_path); g_free (label_text); } else { thunar_action_manager_create_document_submenu_templates (action_mgr, submenu, files); thunar_g_list_free_full (files); } xfce_gtk_menu_append_separator (GTK_MENU_SHELL (submenu)); xfce_gtk_image_menu_item_new_from_icon_name (_("_Empty File"), NULL, NULL, G_CALLBACK (thunar_action_manager_action_create_document), G_OBJECT (action_mgr), "text-x-generic", GTK_MENU_SHELL (submenu)); if (file_scan_limit == 0) { xfce_gtk_menu_append_separator (GTK_MENU_SHELL (submenu)); xfce_gtk_image_menu_item_new_from_icon_name (("The maximum number of templates was exceeded.\n" "Adjust 'misc-max-number-of-templates' if required."), NULL, NULL, NULL, G_OBJECT (action_mgr), "dialog-warning", GTK_MENU_SHELL (submenu)); } g_object_unref (templates_dir); g_object_unref (home_dir); return submenu; } static gboolean thunar_action_manager_action_cut (ThunarActionManager *action_mgr) { ThunarClipboardManager *clipboard; _thunar_return_val_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr), FALSE); if (action_mgr->files_are_selected == FALSE || action_mgr->parent_folder == NULL) return TRUE; clipboard = thunar_clipboard_manager_get_for_display (gtk_widget_get_display (action_mgr->widget)); thunar_clipboard_manager_cut_files (clipboard, action_mgr->files_to_process); g_object_unref (G_OBJECT (clipboard)); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_action_manager_action_copy (ThunarActionManager *action_mgr) { ThunarClipboardManager *clipboard; _thunar_return_val_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr), FALSE); if (action_mgr->files_are_selected == FALSE) return TRUE; clipboard = thunar_clipboard_manager_get_for_display (gtk_widget_get_display (action_mgr->widget)); thunar_clipboard_manager_copy_files (clipboard, action_mgr->files_to_process); g_object_unref (G_OBJECT (clipboard)); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_action_manager_action_paste (ThunarActionManager *action_mgr) { ThunarClipboardManager *clipboard; _thunar_return_val_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr), FALSE); if (action_mgr->is_searching) return TRUE; clipboard = thunar_clipboard_manager_get_for_display (gtk_widget_get_display (action_mgr->widget)); thunar_clipboard_manager_paste_files (clipboard, thunar_file_get_file (action_mgr->current_directory), action_mgr->widget, action_mgr->new_files_created_closure); g_object_unref (G_OBJECT (clipboard)); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static gboolean thunar_action_manager_action_paste_into_folder (ThunarActionManager *action_mgr) { ThunarClipboardManager *clipboard; _thunar_return_val_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr), FALSE); if (!action_mgr->single_directory_to_process) return TRUE; clipboard = thunar_clipboard_manager_get_for_display (gtk_widget_get_display (action_mgr->widget)); thunar_clipboard_manager_paste_files (clipboard, thunar_file_get_file (action_mgr->single_folder), action_mgr->widget, action_mgr->new_files_created_closure); g_object_unref (G_OBJECT (clipboard)); /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static void thunar_action_manager_action_edit_launcher (ThunarActionManager *action_mgr) { _thunar_return_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr)); thunar_dialog_show_launcher_props (action_mgr->files_to_process->data, action_mgr->widget); } /** * thunar_action_manager_action_mount: * @action_mgr : a #ThunarActionManager instance * * Will mount the selected device, if any. The related folder will not be opened. **/ void thunar_action_manager_action_mount (ThunarActionManager *action_mgr) { thunar_action_manager_poke (action_mgr, NULL, THUNAR_ACTION_MANAGER_NO_ACTION); } static void thunar_action_manager_action_eject_finish (ThunarDevice *device, const GError *error, gpointer user_data) { ThunarActionManager *action_mgr = THUNAR_ACTION_MANAGER (user_data); gchar *device_name; _thunar_return_if_fail (THUNAR_IS_DEVICE (device)); _thunar_return_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr)); /* check if there was an error */ if (error != NULL) { /* display an error dialog to inform the user */ device_name = thunar_device_get_name (device); thunar_dialogs_show_error (GTK_WIDGET (action_mgr->widget), error, _("Failed to eject \"%s\""), device_name); g_free (device_name); } g_object_unref (action_mgr); g_signal_emit (action_mgr, action_manager_signals[DEVICE_OPERATION_FINISHED], 0, device); } /** * thunar_action_manager_action_eject: * @action_mgr : a #ThunarActionManager instance * * Will eject the selected device, if any **/ gboolean thunar_action_manager_action_eject (ThunarActionManager *action_mgr) { GMountOperation *mount_operation; _thunar_return_val_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr), FALSE); if (G_LIKELY (action_mgr->device_to_process != NULL)) { /* prepare a mount operation */ mount_operation = thunar_gtk_mount_operation_new (GTK_WIDGET (action_mgr->widget)); g_signal_emit (action_mgr, action_manager_signals[DEVICE_OPERATION_STARTED], 0, action_mgr->device_to_process); /* eject */ thunar_device_eject (action_mgr->device_to_process, mount_operation, NULL, thunar_action_manager_action_eject_finish, g_object_ref (action_mgr)); g_object_unref (mount_operation); } /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static void thunar_action_manager_action_unmount_finish (ThunarDevice *device, const GError *error, gpointer user_data) { ThunarActionManager *action_mgr = THUNAR_ACTION_MANAGER (user_data); gchar *device_name; _thunar_return_if_fail (THUNAR_IS_DEVICE (device)); _thunar_return_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr)); /* check if there was an error */ if (error != NULL) { /* display an error dialog to inform the user */ device_name = thunar_device_get_name (device); thunar_dialogs_show_error (GTK_WIDGET (action_mgr->widget), error, _("Failed to unmount \"%s\""), device_name); g_free (device_name); } g_object_unref (action_mgr); g_signal_emit (action_mgr, action_manager_signals[DEVICE_OPERATION_FINISHED], 0, device); } /** * thunar_action_manager_action_eject: * @action_mgr : a #ThunarActionManager instance * * Will unmount the selected device, if any **/ gboolean thunar_action_manager_action_unmount (ThunarActionManager *action_mgr) { GMountOperation *mount_operation; _thunar_return_val_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr), FALSE); if (G_LIKELY (action_mgr->device_to_process != NULL)) { /* prepare a mount operation */ mount_operation = thunar_gtk_mount_operation_new (GTK_WIDGET (action_mgr->widget)); g_signal_emit (action_mgr, action_manager_signals[DEVICE_OPERATION_STARTED], 0, action_mgr->device_to_process); /* eject */ thunar_device_unmount (action_mgr->device_to_process, mount_operation, NULL, thunar_action_manager_action_unmount_finish, g_object_ref (action_mgr)); /* release the device */ g_object_unref (mount_operation); } /* required in case of shortcut activation, in order to signal that the accel key got handled */ return TRUE; } static GtkWidget * thunar_action_manager_build_application_submenu (ThunarActionManager *action_mgr, GList *applications) { GList *lp; GtkWidget *submenu; GtkWidget *image; GtkWidget *item; gchar *tooltip_text; _thunar_return_val_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr), NULL); submenu = gtk_menu_new (); /* add open with subitem per application */ for (lp = applications; lp != NULL; lp = lp->next) { tooltip_text = g_strdup_printf (ngettext ("Use \"%s\" to open the selected file", "Use \"%s\" to open the selected files", action_mgr->n_files_to_process), g_app_info_get_name (lp->data)); image = gtk_image_new_from_gicon (g_app_info_get_icon (lp->data), GTK_ICON_SIZE_MENU); item = xfce_gtk_image_menu_item_new (g_app_info_get_name (lp->data), tooltip_text, NULL, G_CALLBACK (thunar_action_manager_menu_item_activated), G_OBJECT (action_mgr), image, GTK_MENU_SHELL (submenu)); g_object_set_qdata_full (G_OBJECT (item), thunar_action_manager_appinfo_quark, g_object_ref (lp->data), g_object_unref); g_free (tooltip_text); } if (action_mgr->n_files_to_process == 1) { xfce_gtk_menu_append_separator (GTK_MENU_SHELL (submenu)); thunar_action_manager_append_menu_item (action_mgr, GTK_MENU_SHELL (submenu), THUNAR_ACTION_MANAGER_ACTION_OPEN_WITH_OTHER, FALSE); xfce_gtk_menu_append_separator (GTK_MENU_SHELL (submenu)); thunar_action_manager_append_menu_item (action_mgr, GTK_MENU_SHELL (submenu), THUNAR_ACTION_MANAGER_ACTION_SET_DEFAULT_APP, FALSE); } return submenu; } /** * thunar_action_manager_append_open_section: * @action_mgr : a #ThunarActionManager instance * @menu : #GtkMenuShell on which the open section should be appended * @support_tabs : Set to TRUE if 'open in new tab' should be shown * @support_change_directory : Set to TRUE if 'open' should be shown * @force : Append the open section, even if the selected folder is the current folder * * Will append the section "open/open in new window/open in new tab/open with" to the provided #GtkMenuShell * * Return value: TRUE if the section was added **/ gboolean thunar_action_manager_append_open_section (ThunarActionManager *action_mgr, GtkMenuShell *menu, gboolean support_tabs, gboolean support_change_directory, gboolean force) { GList *applications; gchar *label_text; gchar *tooltip_text; GtkWidget *image; GtkWidget *menu_item; GtkWidget *submenu; const XfceGtkActionEntry *action_entry; _thunar_return_val_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr), FALSE); /* Usually it is not required to open the current directory */ if (action_mgr->files_are_selected == FALSE && !force) return FALSE; /* determine the set of applications that work for all selected files */ applications = thunar_file_list_get_applications (action_mgr->files_to_process); /* Execute (and EditLauncher) OR Open OR OpenWith */ if (G_UNLIKELY (action_mgr->files_are_all_executable)) { thunar_action_manager_append_menu_item (action_mgr, GTK_MENU_SHELL (menu), THUNAR_ACTION_MANAGER_ACTION_EXECUTE, FALSE); if (action_mgr->n_files_to_process == 1 && thunar_file_is_desktop_file (action_mgr->files_to_process->data)) { xfce_gtk_menu_append_separator (GTK_MENU_SHELL (menu)); thunar_action_manager_append_menu_item (action_mgr, GTK_MENU_SHELL (menu), THUNAR_ACTION_MANAGER_ACTION_EDIT_LAUNCHER, FALSE); } } else if (G_LIKELY (action_mgr->n_directories_to_process >= 1)) { if (support_change_directory) thunar_action_manager_append_menu_item (action_mgr, GTK_MENU_SHELL (menu), THUNAR_ACTION_MANAGER_ACTION_OPEN, FALSE); } else if (G_LIKELY (applications != NULL)) { action_entry = get_action_entry (THUNAR_ACTION_MANAGER_ACTION_OPEN); label_text = g_strdup_printf (_("_Open With \"%s\""), g_app_info_get_name (applications->data)); tooltip_text = g_strdup_printf (ngettext ("Use \"%s\" to open the selected file", "Use \"%s\" to open the selected files", action_mgr->n_files_to_process), g_app_info_get_name (applications->data)); image = gtk_image_new_from_gicon (g_app_info_get_icon (applications->data), GTK_ICON_SIZE_MENU); menu_item = xfce_gtk_image_menu_item_new (label_text, tooltip_text, action_entry->accel_path, G_CALLBACK (thunar_action_manager_menu_item_activated), G_OBJECT (action_mgr), image, menu); /* remember the default application for the "Open" action as quark */ g_object_set_qdata_full (G_OBJECT (menu_item), thunar_action_manager_appinfo_quark, applications->data, g_object_unref); g_free (tooltip_text); g_free (label_text); /* drop the default application from the list */ applications = g_list_delete_link (applications, applications); } else if (action_mgr->n_files_to_process > 1) { /* we can only show a generic "Open" action */ label_text = g_strdup (_("_Open With Default Applications")); tooltip_text = g_strdup (_("Open the selected files with the default applications")); xfce_gtk_menu_item_new (label_text, tooltip_text, NULL, G_CALLBACK (thunar_action_manager_menu_item_activated), G_OBJECT (action_mgr), menu); g_free (tooltip_text); g_free (label_text); } if (action_mgr->n_files_to_process == action_mgr->n_directories_to_process && action_mgr->n_directories_to_process >= 1) { if (support_tabs) thunar_action_manager_append_menu_item (action_mgr, GTK_MENU_SHELL (menu), THUNAR_ACTION_MANAGER_ACTION_OPEN_IN_TAB, FALSE); thunar_action_manager_append_menu_item (action_mgr, GTK_MENU_SHELL (menu), THUNAR_ACTION_MANAGER_ACTION_OPEN_IN_WINDOW, FALSE); } if (G_LIKELY (applications != NULL)) { xfce_gtk_menu_append_separator (GTK_MENU_SHELL (menu)); menu_item = xfce_gtk_menu_item_new (_("Ope_n With"), _("Choose another application with which to open the selected file"), NULL, NULL, NULL, menu); submenu = thunar_action_manager_build_application_submenu (action_mgr, applications); gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), submenu); } else { if (action_mgr->n_files_to_process == 1) { thunar_action_manager_append_menu_item (action_mgr, GTK_MENU_SHELL (menu), THUNAR_ACTION_MANAGER_ACTION_OPEN_WITH_OTHER, FALSE); xfce_gtk_menu_append_separator (GTK_MENU_SHELL (menu)); thunar_action_manager_append_menu_item (action_mgr, GTK_MENU_SHELL (menu), THUNAR_ACTION_MANAGER_ACTION_SET_DEFAULT_APP, FALSE); } } /* active while searching and while inside the 'recent:///' folder */ if (action_mgr->n_files_to_process > 0 && (action_mgr->is_searching || thunar_file_is_recent (action_mgr->current_directory))) { /* Dont show 'open location' on the recent folder shortcut itself */ if (!thunar_file_is_recent (action_mgr->files_to_process->data) && !THUNAR_IS_TREE_VIEW (action_mgr->widget)) { xfce_gtk_menu_append_separator (GTK_MENU_SHELL (menu)); thunar_action_manager_append_menu_item (action_mgr, GTK_MENU_SHELL (menu), THUNAR_ACTION_MANAGER_ACTION_OPEN_LOCATION, FALSE); } } g_list_free_full (applications, g_object_unref); return TRUE; } /** * thunar_action_manager_get_widget: * @action_mgr : a #ThunarActionManager instance * * Will return the parent widget of this #ThunarActionManager * * Return value: (transfer none): the parent widget of this #ThunarActionManager **/ GtkWidget * thunar_action_manager_get_widget (ThunarActionManager *action_mgr) { _thunar_return_val_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr), NULL); return action_mgr->widget; } /** * thunar_action_manager_set_selection: * @action_mgr: a #ThunarActionManager instance * @selected_thunar_files: #GList of selected #ThunarFile instances, or NULL * @selected_device: selected #ThunarDevice or NULL * @selected_location: selected #GFile (possibly only holds an URI), or NULL * * Will set the related items as "selection" and clear any previous selection. * Note that always only one of the 3 "selected" arguments should be set. **/ void thunar_action_manager_set_selection (ThunarActionManager *action_mgr, GList *selected_thunar_files, ThunarDevice *selected_device, GFile *selected_location) { _thunar_return_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr)); /* unref the current device/location */ if (action_mgr->device_to_process != NULL) { g_object_unref (action_mgr->device_to_process); action_mgr->device_to_process = NULL; } if (action_mgr->location_to_process != NULL) { g_object_unref (action_mgr->location_to_process); action_mgr->location_to_process = NULL; } /* ref the new device/location */ if (selected_device != NULL) action_mgr->device_to_process = g_object_ref (selected_device); if (selected_location != NULL) action_mgr->location_to_process = g_object_ref (selected_location); /* for selected files things are a bit more conmplicated */ thunar_action_manager_set_selected_files (THUNAR_COMPONENT (action_mgr), selected_thunar_files); } static void thunar_action_manager_new_files_created (ThunarActionManager *action_mgr, GList *new_thunar_files) { _thunar_return_if_fail (THUNAR_IS_ACTION_MANAGER (action_mgr)); g_signal_emit (action_mgr, action_manager_signals[NEW_FILES_CREATED], 0, new_thunar_files); } XfceGtkActionEntry * thunar_action_manager_get_action_entries (void) { return thunar_action_manager_action_entries; }