/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Pix * * Copyright (C) 2009 Free Software Foundation, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include "actions.h" #include "callbacks.h" #include "gth-copy-task.h" #include "gth-reorder-task.h" #define BROWSER_DATA_KEY "file-manager-browser-data" #define URI_LIST_ATOM (gdk_atom_intern_static_string ("text/uri-list")) #define XDND_ACTION_DIRECT_SAVE_ATOM (gdk_atom_intern_static_string ("XdndDirectSave0")) #define PIX_REORDERABLE_LIST_ATOM (gdk_atom_intern_static_string ("pix/reorderable-list")) #define TEXT_PLAIN_ATOM (gdk_atom_intern_static_string ("text/plain")) #define SCROLL_TIMEOUT 30 /* autoscroll timeout in milliseconds */ #define UPDATE_OPEN_MENU_DELAY 500 static const GActionEntry actions[] = { { "edit-cut", gth_browser_activate_edit_cut }, { "edit-copy", gth_browser_activate_edit_copy }, { "edit-paste", gth_browser_activate_edit_paste }, { "trash", gth_browser_activate_trash }, { "delete", gth_browser_activate_delete }, { "remove-from-source", gth_browser_activate_remove_from_source }, { "remove-from-source-permanently", gth_browser_activate_remove_from_source_permanently }, { "rename", gth_browser_activate_rename }, { "file-list-rename", gth_browser_activate_file_list_rename }, { "duplicate", gth_browser_activate_duplicate }, { "copy-to-folder", gth_browser_activate_copy_to_folder }, { "move-to-folder", gth_browser_activate_move_to_folder }, { "create-folder", gth_browser_activate_create_folder }, { "folder-context-open-with-fm", gth_browser_activate_folder_context_open_in_file_manager }, { "folder-context-create", gth_browser_activate_folder_context_create }, { "folder-context-rename", gth_browser_activate_folder_context_rename }, { "folder-context-cut", gth_browser_activate_folder_context_cut }, { "folder-context-copy", gth_browser_activate_folder_context_copy }, { "folder-context-paste-into-folder", gth_browser_activate_folder_context_paste_into_folder }, { "folder-context-copy-to", gth_browser_activate_folder_context_copy_to }, { "folder-context-move-to", gth_browser_activate_folder_context_move_to }, { "folder-context-trash", gth_browser_activate_folder_context_trash }, { "folder-context-delete", gth_browser_activate_folder_context_delete }, { "open-with-gimp", gth_browser_activate_open_with_gimp }, { "open-with-application", gth_browser_activate_open_with_application, "i" } }; static const GthMenuEntry fixed_menu_entries_edit[] = { { N_("Cut"), "win.edit-cut" }, { N_("Copy"), "win.edit-copy" }, { N_("Paste"), "win.edit-paste" }, }; static const GthMenuEntry fixed_menu_entries_file[] = { { N_("Copy to…"), "win.copy-to-folder" }, { N_("Move to…"), "win.move-to-folder" }, { N_("Rename"), "win.file-list-rename" }, }; static const GthMenuEntry fixed_menu_entries_delete[] = { { N_("Move to Trash"), "win.trash" }, { N_("Delete"), "win.delete" }, }; static const GthMenuEntry folder_context_open_entries[] = { { N_("Open with the File Manager"), "win.folder-context-open-with-fm" } }; static const GthMenuEntry folder_context_create_entries[] = { { N_("Create Folder"), "win.folder-context-create" } }; static const GthMenuEntry folder_context_edit_entries[] = { { N_("Cut"), "win.folder-context-cut" }, { N_("Copy"), "win.folder-context-copy" }, { N_("Paste Into Folder"), "win.folder-context-paste-into-folder" } }; static const GthMenuEntry folder_context_folder_entries[] = { { N_("Rename"), "win.folder-context-rename" }, { N_("Copy to…"), "win.folder-context-copy-to" }, { N_("Move to…"), "win.folder-context-move-to" }, { N_("Move to Trash"), "win.folder-context-trash" }, { N_("Delete"), "win.folder-context-delete" } }; static const GthMenuEntry vfs_entries[] = { { N_("Duplicate"), "win.duplicate" } }; static const GthShortcut shortcuts[] = { { "edit-cut", N_("Cut"), GTH_SHORTCUT_CONTEXT_BROWSER | GTH_SHORTCUT_CONTEXT_FIXED, GTH_SHORTCUT_CATEGORY_FILE_MANAGER, "x" }, { "edit-copy", N_("Copy"), GTH_SHORTCUT_CONTEXT_BROWSER | GTH_SHORTCUT_CONTEXT_FIXED, GTH_SHORTCUT_CATEGORY_FILE_MANAGER, "c" }, { "edit-paste", N_("Paste"), GTH_SHORTCUT_CONTEXT_BROWSER | GTH_SHORTCUT_CONTEXT_FIXED, GTH_SHORTCUT_CATEGORY_FILE_MANAGER, "v" }, { "rename", N_("Rename"), GTH_SHORTCUT_CONTEXT_BROWSER_VIEWER, GTH_SHORTCUT_CATEGORY_FILE_MANAGER, "F2" }, { "duplicate", N_("Duplicate"), GTH_SHORTCUT_CONTEXT_BROWSER_VIEWER, GTH_SHORTCUT_CATEGORY_FILE_MANAGER, "d" }, { "remove-from-source", N_("Delete"), GTH_SHORTCUT_CONTEXT_BROWSER_VIEWER, GTH_SHORTCUT_CATEGORY_FILE_MANAGER, "Delete" }, { "remove-from-source-permanently", N_("Delete permanently"), GTH_SHORTCUT_CONTEXT_BROWSER_VIEWER, GTH_SHORTCUT_CATEGORY_FILE_MANAGER, "Delete" }, { "open-with-gimp", N_("Open with Gimp"), GTH_SHORTCUT_CONTEXT_BROWSER_VIEWER, GTH_SHORTCUT_CATEGORY_FILE_MANAGER, "g" }, }; static GtkTargetEntry reorderable_drag_dest_targets[] = { { "text/uri-list", 0, 0 }, { "text/uri-list", GTK_TARGET_SAME_WIDGET, 0 }, { "pix/reorderable-list", 0, 0 } }; static GtkTargetEntry reorderable_drag_source_targets[] = { { "pix/reorderable-list", 0, 0 } }; static GtkTargetEntry non_reorderable_drag_dest_targets[] = { { "text/uri-list", GTK_TARGET_OTHER_WIDGET, 0 }, { "XdndDirectSave0", GTK_TARGET_SAME_WIDGET, 1 } }; typedef struct { guint vfs_merge_id; guint folder_context_open_id; guint folder_context_create_id; guint folder_context_edit_id; guint folder_context_folder_id; guint update_open_menu_id; GMenu *open_with_menu; GList *applications; gboolean can_paste; int drop_pos; int scroll_diff; guint scroll_event; } BrowserData; static void browser_data_free (BrowserData *data) { if (data->update_open_menu_id > 0) { g_source_remove (data->update_open_menu_id); data->update_open_menu_id = 0; } _g_object_unref (data->open_with_menu); _g_object_list_unref (data->applications); g_free (data); } static void gth_file_list_drag_data_received (GtkWidget *widget, GdkDragContext *context, int x, int y, GtkSelectionData *selection_data, guint info, guint time, gpointer user_data) { GthBrowser *browser = user_data; GtkWidget *file_view; gboolean success = FALSE; char **uris; GList *selected_files; GdkDragAction action; file_view = gth_browser_get_file_list_view (browser); action = gdk_drag_context_get_suggested_action (context); if (action == GDK_ACTION_COPY || action == GDK_ACTION_MOVE) { success = TRUE; } if (action == GDK_ACTION_ASK) { GdkDragAction actions = _gtk_menu_ask_drag_drop_action (file_view, gdk_drag_context_get_actions (context)); gdk_drag_status (context, actions, time); success = gdk_drag_context_get_selected_action (context) != 0; } if (gtk_selection_data_get_data_type (selection_data) == XDND_ACTION_DIRECT_SAVE_ATOM) { const guchar *data; int format; int length; data = gtk_selection_data_get_data (selection_data); format = gtk_selection_data_get_format (selection_data); length = gtk_selection_data_get_length (selection_data); if ((format == 8) && (length == 1) && (data[0] == 'S')) { success = TRUE; } else { gdk_property_change (gdk_drag_context_get_dest_window (context), XDND_ACTION_DIRECT_SAVE_ATOM, TEXT_PLAIN_ATOM, 8, GDK_PROP_MODE_REPLACE, (const guchar *) "", 0); success = FALSE; } gtk_drag_finish (context, success, FALSE, time); return; } gtk_drag_finish (context, success, FALSE, time); if (! success) return; uris = gtk_selection_data_get_uris (selection_data); selected_files = _g_file_list_new_from_uriv (uris); if (selected_files != NULL) { if (gtk_drag_get_source_widget (context) == file_view) { GList *file_data_list; GList *visible_files; BrowserData *data; GthTask *task; file_data_list = gth_file_store_get_visibles (gth_browser_get_file_store (browser)); visible_files = gth_file_data_list_to_file_list (file_data_list); data = g_object_get_data (G_OBJECT (browser), BROWSER_DATA_KEY); task = gth_reorder_task_new (gth_browser_get_location_source (browser), gth_browser_get_location_data (browser), visible_files, selected_files, data->drop_pos); gth_browser_exec_task (browser, task, GTH_TASK_FLAGS_DEFAULT); g_object_unref (task); _g_object_list_unref (visible_files); _g_object_list_unref (file_data_list); } else { GthFileSource *file_source; gboolean cancel = FALSE; gboolean move; file_source = gth_browser_get_location_source (browser); move = gdk_drag_context_get_selected_action (context) == GDK_ACTION_MOVE; if (move && ! gth_file_source_can_cut (file_source)) { GtkWidget *dialog; int response; dialog = _gtk_message_dialog_new (GTK_WINDOW (browser), GTK_DIALOG_MODAL, _GTK_ICON_NAME_DIALOG_QUESTION, _("Could not move the files"), _("Files cannot be moved to the current location, as alternative you can choose to copy them."), _GTK_LABEL_CANCEL, GTK_RESPONSE_CANCEL, _GTK_LABEL_COPY, GTK_RESPONSE_OK, NULL); response = gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); if (response == GTK_RESPONSE_CANCEL) cancel = TRUE; move = FALSE; } if (! cancel) { GthFileSource *location_source; BrowserData *data; GthTask *task; location_source = gth_main_get_file_source (gth_browser_get_location (browser)); data = g_object_get_data (G_OBJECT (browser), BROWSER_DATA_KEY); task = gth_copy_task_new (location_source, gth_browser_get_location_data (browser), move, selected_files, data->drop_pos); gth_browser_exec_task (browser, task, GTH_TASK_FLAGS_DEFAULT); g_object_unref (task); g_object_unref (location_source); } } } _g_object_list_unref (selected_files); g_strfreev (uris); } static gboolean gth_file_list_drag_drop (GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, gpointer user_data) { GthBrowser *browser = user_data; int filename_len; char *filename; g_signal_stop_emission_by_name (widget, "drag-drop"); if (gdk_property_get (gdk_drag_context_get_source_window (context), XDND_ACTION_DIRECT_SAVE_ATOM, TEXT_PLAIN_ATOM, 0, 1024, FALSE, NULL, NULL, &filename_len, (guchar **) &filename) && GTH_IS_FILE_SOURCE_VFS (gth_browser_get_location_source (browser))) { GFile *file; char *uri; filename = g_realloc (filename, filename_len + 1); filename[filename_len] = '\0'; file = _g_file_append_path (gth_browser_get_location (browser), filename); uri = g_file_get_uri (file); gdk_property_change (gdk_drag_context_get_source_window (context), XDND_ACTION_DIRECT_SAVE_ATOM, TEXT_PLAIN_ATOM, 8, GDK_PROP_MODE_REPLACE, (const guchar *) uri, strlen (uri)); g_free (uri); g_object_unref (file); g_free (filename); gtk_drag_get_data (widget, context, XDND_ACTION_DIRECT_SAVE_ATOM, time); } else gtk_drag_get_data (widget, context, URI_LIST_ATOM, time); return TRUE; } static gboolean drag_motion_autoscroll_cb (gpointer user_data) { GthBrowser *browser = user_data; BrowserData *data; GtkAdjustment *adj; double max_value; double value; data = g_object_get_data (G_OBJECT (browser), BROWSER_DATA_KEY); adj = gth_file_list_get_vadjustment (GTH_FILE_LIST (gth_browser_get_file_list (browser))); max_value = gtk_adjustment_get_upper (adj) - gtk_adjustment_get_page_size (adj); value = gtk_adjustment_get_value (adj) + data->scroll_diff; if (value > max_value) value = max_value; gtk_adjustment_set_value (adj, value); return TRUE; } static gboolean gth_file_list_drag_motion (GtkWidget *file_view, GdkDragContext *context, gint x, gint y, guint time, gpointer extra_data) { GthBrowser *browser = extra_data; BrowserData *data; GthFileData *location_data; data = g_object_get_data (G_OBJECT (browser), BROWSER_DATA_KEY); data->drop_pos = -1; if (GTH_IS_EMPTY_LIST (file_view)) { gth_file_list_enable_empty_view (GTH_FILE_LIST (gth_browser_get_file_list (browser)), FALSE); gdk_drag_status (context, 0, time); return FALSE; } if ((gtk_drag_get_source_widget (context) == file_view) && ! gth_file_source_is_reorderable (gth_browser_get_location_source (browser))) { gdk_drag_status (context, 0, time); return FALSE; } location_data = gth_browser_get_location_data (browser); if (! g_file_info_get_attribute_boolean (location_data->info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE)) { gdk_drag_status (context, 0, time); return FALSE; } if (gth_file_source_is_reorderable (gth_browser_get_location_source (browser))) { GtkAllocation allocation; if (gtk_drag_get_source_widget (context) == file_view) gdk_drag_status (context, GDK_ACTION_MOVE, time); else gdk_drag_status (context, GDK_ACTION_COPY, time); gth_file_view_set_drag_dest_pos (GTH_FILE_VIEW (file_view), context, x, y, time, &data->drop_pos); gtk_widget_get_allocation (file_view, &allocation); if (y < 10) data->scroll_diff = - (10 - y); else if (y > allocation.height - 10) data->scroll_diff = (10 - (allocation.height - y)); else data->scroll_diff = 0; if (data->scroll_diff != 0) { if (data->scroll_event == 0) data->scroll_event = gdk_threads_add_timeout (SCROLL_TIMEOUT, drag_motion_autoscroll_cb, browser); } else if (data->scroll_event != 0) { g_source_remove (data->scroll_event); data->scroll_event = 0; } } else if (gdk_drag_context_get_suggested_action (context) == GDK_ACTION_ASK) { gdk_drag_status (context, GDK_ACTION_ASK, time); } else { gboolean source_is_reorderable = FALSE; GList *targets = gdk_drag_context_list_targets (context); GList *scan; /* use COPY when dragging a file from a catalog to a directory */ for (scan = targets; scan; scan = scan->next) { GdkAtom target = scan->data; if (target == PIX_REORDERABLE_LIST_ATOM) { source_is_reorderable = TRUE; break; } } gdk_drag_status (context, source_is_reorderable ? GDK_ACTION_COPY : GDK_ACTION_MOVE, time); } return TRUE; } static gboolean gth_file_list_drag_leave (GtkWidget *file_view, GdkDragContext *context, guint time, gpointer extra_data) { GthBrowser *browser = extra_data; if (gtk_drag_get_source_widget (context) == file_view) gth_file_view_set_drag_dest_pos (GTH_FILE_VIEW (file_view), context, -1, -1, time, NULL); gth_file_list_enable_empty_view (GTH_FILE_LIST (gth_browser_get_file_list (browser)), TRUE); return TRUE; } static void gth_file_list_drag_end (GtkWidget *widget, GdkDragContext *drag_context, gpointer user_data) { GthBrowser *browser = user_data; BrowserData *data; data = g_object_get_data (G_OBJECT (browser), BROWSER_DATA_KEY); if (data->scroll_event != 0) { g_source_remove (data->scroll_event); data->scroll_event = 0; } } /* -- selection_changed -- */ void gth_browser_activate_open_with_application (GSimpleAction *action, GVariant *parameter, gpointer user_data) { GthBrowser *browser = user_data; BrowserData *data; GList *appinfo_link; GAppInfo *appinfo; GList *items; GList *file_list; GList *uris; GList *scan; GdkAppLaunchContext *context; GError *error = NULL; data = g_object_get_data (G_OBJECT (browser), BROWSER_DATA_KEY); g_return_if_fail (data != NULL); appinfo_link = g_list_nth (data->applications, g_variant_get_int32 (parameter)); g_return_if_fail (appinfo_link != NULL); appinfo = appinfo_link->data; g_return_if_fail (G_IS_APP_INFO (appinfo)); items = gth_file_selection_get_selected (GTH_FILE_SELECTION (gth_browser_get_file_list_view (browser))); file_list = gth_file_list_get_files (GTH_FILE_LIST (gth_browser_get_file_list (browser)), items); uris = NULL; for (scan = file_list; scan; scan = scan->next) { GthFileData *file_data = scan->data; uris = g_list_prepend (uris, g_file_get_uri (file_data->file)); } uris = g_list_reverse (uris); context = gdk_display_get_app_launch_context (gtk_widget_get_display (GTK_WIDGET (browser))); gdk_app_launch_context_set_timestamp (context, 0); gdk_app_launch_context_set_icon (context, g_app_info_get_icon (appinfo)); if (! g_app_info_launch_uris (appinfo, uris, G_APP_LAUNCH_CONTEXT (context), &error)) { _gtk_error_dialog_from_gerror_show (GTK_WINDOW (browser), _("Could not perform the operation"), error); g_clear_error (&error); } g_object_unref (context); g_list_free (uris); _g_object_list_unref (file_list); _gtk_tree_path_list_free (items); } static int sort_app_info_by_display_name (gconstpointer a, gconstpointer b) { GAppInfo *app_info_a = G_APP_INFO (a); GAppInfo *app_info_b = G_APP_INFO (b); return g_utf8_collate (g_app_info_get_display_name (app_info_a), g_app_info_get_display_name (app_info_b)); } static void _gth_browser_update_open_menu (GthBrowser *browser) { BrowserData *data; GList *items; GList *file_list; GList *scan; int n; GHashTable *used_mime_types; GHashTable *used_apps; data = g_object_get_data (G_OBJECT (browser), BROWSER_DATA_KEY); g_return_if_fail (data != NULL); g_menu_remove_all (data->open_with_menu); _g_object_list_unref (data->applications); data->applications = NULL; items = gth_file_selection_get_selected (GTH_FILE_SELECTION (gth_browser_get_file_list_view (browser))); file_list = gth_file_list_get_files (GTH_FILE_LIST (gth_browser_get_file_list (browser)), items); data->applications = NULL; used_mime_types = g_hash_table_new (g_str_hash, g_str_equal); for (scan = file_list; scan; scan = scan->next) { GthFileData *file_data = scan->data; const char *mime_type; mime_type = gth_file_data_get_mime_type (file_data); if ((mime_type == NULL) || g_content_type_is_unknown (mime_type)) continue; if (g_hash_table_lookup (used_mime_types, mime_type) != NULL) continue; data->applications = g_list_concat (data->applications, g_app_info_get_all_for_type (mime_type)); g_hash_table_insert (used_mime_types, (gpointer) mime_type, GINT_TO_POINTER (1)); } g_hash_table_destroy (used_mime_types); data->applications = g_list_sort (data->applications, sort_app_info_by_display_name); used_apps = g_hash_table_new (g_str_hash, g_str_equal); for (scan = data->applications, n = 0; scan; scan = scan->next, n++) { GAppInfo *appinfo = scan->data; GIcon *icon; GMenuItem *item; if (strstr (g_app_info_get_executable (appinfo), "pix") != NULL) continue; if (g_hash_table_lookup (used_apps, g_app_info_get_id (appinfo)) != NULL) continue; g_hash_table_insert (used_apps, (gpointer) g_app_info_get_id (appinfo), GINT_TO_POINTER (1)); item = g_menu_item_new (g_app_info_get_display_name (appinfo), NULL); g_menu_item_set_action_and_target (item, "win.open-with-application", "i", n); icon = g_app_info_get_icon (appinfo); if (icon == NULL) { icon = g_themed_icon_new ("application-x-executable"); if (icon != NULL) { g_menu_item_set_icon (item, icon); g_object_unref (icon); } } else g_menu_item_set_icon (item, icon); g_menu_append_item (data->open_with_menu, item); g_object_unref (item); } gth_window_enable_action (GTH_WINDOW (browser), "open-with-application", data->applications != NULL); g_hash_table_destroy (used_apps); _g_object_list_unref (file_list); _gtk_tree_path_list_free (items); } static gboolean update_open_menu_cb (gpointer user_data) { GthBrowser *browser = user_data; BrowserData *data; data = g_object_get_data (G_OBJECT (browser), BROWSER_DATA_KEY); g_return_val_if_fail (data != NULL, FALSE); if (data->update_open_menu_id > 0) { g_source_remove (data->update_open_menu_id); data->update_open_menu_id = 0; } _gth_browser_update_open_menu (GTH_BROWSER (user_data)); return FALSE; } static void file_selection_changed_cb (GthFileSelection *self, GthBrowser *browser) { BrowserData *data; data = g_object_get_data (G_OBJECT (browser), BROWSER_DATA_KEY); g_return_if_fail (data != NULL); if (data->update_open_menu_id > 0) g_source_remove (data->update_open_menu_id); data->update_open_menu_id = g_timeout_add (UPDATE_OPEN_MENU_DELAY, update_open_menu_cb, browser); } void fm__gth_browser_construct_cb (GthBrowser *browser) { BrowserData *data; GtkWidget *file_view; GMenu *open_actions; g_return_if_fail (GTH_IS_BROWSER (browser)); data = g_new0 (BrowserData, 1); data->update_open_menu_id = 0; g_action_map_add_action_entries (G_ACTION_MAP (browser), actions, G_N_ELEMENTS (actions), browser); gth_menu_manager_append_entries (gth_browser_get_menu_manager (browser, GTH_BROWSER_MENU_MANAGER_FILE_LIST_EDIT_ACTIONS), fixed_menu_entries_edit, G_N_ELEMENTS (fixed_menu_entries_edit)); gth_menu_manager_append_entries (gth_browser_get_menu_manager (browser, GTH_BROWSER_MENU_MANAGER_FILE_LIST_FILE_ACTIONS), fixed_menu_entries_file, G_N_ELEMENTS (fixed_menu_entries_file)); gth_menu_manager_append_entries (gth_browser_get_menu_manager (browser, GTH_BROWSER_MENU_MANAGER_FILE_LIST_DELETE_ACTIONS), fixed_menu_entries_delete, G_N_ELEMENTS (fixed_menu_entries_delete)); gth_menu_manager_append_entries (gth_browser_get_menu_manager (browser, GTH_BROWSER_MENU_MANAGER_FILE_FILE_ACTIONS), fixed_menu_entries_file, G_N_ELEMENTS (fixed_menu_entries_file)); gth_menu_manager_append_entries (gth_browser_get_menu_manager (browser, GTH_BROWSER_MENU_MANAGER_FILE_DELETE_ACTIONS), fixed_menu_entries_delete, G_N_ELEMENTS (fixed_menu_entries_delete)); gth_window_add_shortcuts (GTH_WINDOW (browser), shortcuts, G_N_ELEMENTS (shortcuts)); gth_browser_add_header_bar_button (browser, GTH_BROWSER_HEADER_SECTION_BROWSER_LOCATIONS, "user-home-symbolic", _("Home Folder"), "win.go-home", NULL); data->open_with_menu = g_menu_new (); open_actions = gth_menu_manager_get_menu (gth_browser_get_menu_manager (browser, GTH_BROWSER_MENU_MANAGER_FILE_LIST_OPEN_ACTIONS)); g_menu_append_submenu (open_actions, _("Open _With"), G_MENU_MODEL (data->open_with_menu)); open_actions = gth_menu_manager_get_menu (gth_browser_get_menu_manager (browser, GTH_BROWSER_MENU_MANAGER_FILE_OPEN_ACTIONS)); g_menu_append_submenu (open_actions, _("Open _With"), G_MENU_MODEL (data->open_with_menu)); gth_window_enable_action (GTH_WINDOW (browser), "edit-paste", FALSE); file_view = gth_file_list_get_view (GTH_FILE_LIST (gth_browser_get_file_list (browser))); g_signal_connect (file_view, "drag_data_received", G_CALLBACK (gth_file_list_drag_data_received), browser); g_signal_connect (file_view, "drag_drop", G_CALLBACK (gth_file_list_drag_drop), browser); g_signal_connect (file_view, "drag_motion", G_CALLBACK (gth_file_list_drag_motion), browser); g_signal_connect (file_view, "drag_leave", G_CALLBACK (gth_file_list_drag_leave), browser); g_signal_connect (file_view, "drag_end", G_CALLBACK (gth_file_list_drag_end), browser); g_signal_connect (file_view, "file-selection-changed", G_CALLBACK (file_selection_changed_cb), browser); file_view = gth_file_list_get_empty_view (GTH_FILE_LIST (gth_browser_get_file_list (browser))); g_signal_connect (file_view, "drag-motion", G_CALLBACK (gth_file_list_drag_motion), browser); g_signal_connect (file_view, "drag_data_received", G_CALLBACK (gth_file_list_drag_data_received), browser); g_signal_connect (file_view, "drag_drop", G_CALLBACK (gth_file_list_drag_drop), browser); g_object_set_data_full (G_OBJECT (browser), BROWSER_DATA_KEY, data, (GDestroyNotify) browser_data_free); } static void file_manager_update_ui (BrowserData *data, GthBrowser *browser) { if (GTH_IS_FILE_SOURCE_VFS (gth_browser_get_location_source (browser))) { if (data->vfs_merge_id == 0) data->vfs_merge_id = gth_menu_manager_append_entries (gth_browser_get_menu_manager (browser, GTH_BROWSER_MENU_MANAGER_FILE_LIST_FILE_ACTIONS), vfs_entries, G_N_ELEMENTS (vfs_entries)); } else { gth_menu_manager_remove_entries (gth_browser_get_menu_manager (browser, GTH_BROWSER_MENU_MANAGER_FILE_LIST_FILE_ACTIONS), data->vfs_merge_id); data->vfs_merge_id = 0; } } void fm__gth_browser_set_current_page_cb (GthBrowser *browser) { BrowserData *data; data = g_object_get_data (G_OBJECT (browser), BROWSER_DATA_KEY); file_manager_update_ui (data, browser); } void fm__gth_browser_load_location_after_cb (GthBrowser *browser, GthFileData *location_data) { BrowserData *data; GtkWidget *file_list; GtkWidget *file_view; GtkTargetList *source_target_list; GtkTargetEntry *source_targets; int n_source_targets; GdkDragAction source_actions; data = g_object_get_data (G_OBJECT (browser), BROWSER_DATA_KEY); file_manager_update_ui (data, browser); source_target_list = gtk_target_list_new (NULL, 0); gtk_target_list_add_uri_targets (source_target_list, 0); gtk_target_list_add_text_targets (source_target_list, 0); source_actions = GDK_ACTION_PRIVATE; file_list = gth_browser_get_file_list (browser); if (! g_file_info_get_attribute_boolean (location_data->info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE)) { file_view = gth_file_list_get_view (GTH_FILE_LIST (file_list)); gth_file_view_unset_drag_dest (GTH_FILE_VIEW (file_view)); file_view = gth_file_list_get_empty_view (GTH_FILE_LIST (file_list)); gtk_drag_dest_unset (file_view); source_actions = GDK_ACTION_COPY; } else if (gth_file_source_is_reorderable (gth_browser_get_location_source (browser))) { file_view = gth_file_list_get_view (GTH_FILE_LIST (file_list)); gth_file_view_enable_drag_dest (GTH_FILE_VIEW (file_view), reorderable_drag_dest_targets, G_N_ELEMENTS (reorderable_drag_dest_targets), GDK_ACTION_COPY | GDK_ACTION_MOVE); file_view = gth_file_list_get_empty_view (GTH_FILE_LIST (file_list)); gtk_drag_dest_set (file_view, 0, reorderable_drag_dest_targets, G_N_ELEMENTS (reorderable_drag_dest_targets), GDK_ACTION_COPY | GDK_ACTION_MOVE); gtk_target_list_add_table (source_target_list, reorderable_drag_source_targets, G_N_ELEMENTS (reorderable_drag_source_targets)); source_actions = GDK_ACTION_COPY | GDK_ACTION_MOVE; } else { file_view = gth_file_list_get_view (GTH_FILE_LIST (file_list)); gth_file_view_enable_drag_dest (GTH_FILE_VIEW (file_view), non_reorderable_drag_dest_targets, G_N_ELEMENTS (non_reorderable_drag_dest_targets), GDK_ACTION_COPY | GDK_ACTION_MOVE); file_view = gth_file_list_get_empty_view (GTH_FILE_LIST (file_list)); gtk_drag_dest_set (file_view, 0, non_reorderable_drag_dest_targets, G_N_ELEMENTS (non_reorderable_drag_dest_targets), GDK_ACTION_COPY | GDK_ACTION_MOVE); source_actions = GDK_ACTION_MOVE | GDK_ACTION_ASK; } /* set the drag source targets */ source_targets = gtk_target_table_new_from_list (source_target_list, &n_source_targets); gth_file_view_enable_drag_source (GTH_FILE_VIEW (gth_file_list_get_view (GTH_FILE_LIST (file_list))), GDK_BUTTON1_MASK | GDK_BUTTON2_MASK, source_targets, n_source_targets, source_actions); gtk_target_list_unref (source_target_list); gtk_target_table_free (source_targets, n_source_targets); } void fm__gth_browser_folder_tree_popup_before_cb (GthBrowser *browser, GthFileSource *file_source, GthFileData *folder) { BrowserData *data; data = g_object_get_data (G_OBJECT (browser), BROWSER_DATA_KEY); g_return_if_fail (data != NULL); if (GTH_IS_FILE_SOURCE_VFS (file_source)) { if (data->folder_context_open_id == 0) data->folder_context_open_id = gth_menu_manager_append_entries (gth_browser_get_menu_manager (browser, GTH_BROWSER_MENU_MANAGER_FOLDER_OPEN_ACTIONS), folder_context_open_entries, G_N_ELEMENTS (folder_context_open_entries)); if (data->folder_context_create_id == 0) data->folder_context_create_id = gth_menu_manager_append_entries (gth_browser_get_menu_manager (browser, GTH_BROWSER_MENU_MANAGER_FOLDER_CREATE_ACTIONS), folder_context_create_entries, G_N_ELEMENTS (folder_context_create_entries)); if (data->folder_context_edit_id == 0) data->folder_context_edit_id = gth_menu_manager_append_entries (gth_browser_get_menu_manager (browser, GTH_BROWSER_MENU_MANAGER_FOLDER_EDIT_ACTIONS), folder_context_edit_entries, G_N_ELEMENTS (folder_context_edit_entries)); if (data->folder_context_folder_id == 0) data->folder_context_folder_id = gth_menu_manager_append_entries (gth_browser_get_menu_manager (browser, GTH_BROWSER_MENU_MANAGER_FOLDER_FOLDER_ACTIONS), folder_context_folder_entries, G_N_ELEMENTS (folder_context_folder_entries)); fm__gth_browser_update_sensitivity_cb (browser); } else { if (data->folder_context_open_id != 0) gth_menu_manager_remove_entries (gth_browser_get_menu_manager (browser, GTH_BROWSER_MENU_MANAGER_FOLDER_OPEN_ACTIONS), data->folder_context_open_id); if (data->folder_context_create_id != 0) gth_menu_manager_remove_entries (gth_browser_get_menu_manager (browser, GTH_BROWSER_MENU_MANAGER_FOLDER_CREATE_ACTIONS), data->folder_context_create_id); if (data->folder_context_edit_id != 0) gth_menu_manager_remove_entries (gth_browser_get_menu_manager (browser, GTH_BROWSER_MENU_MANAGER_FOLDER_EDIT_ACTIONS), data->folder_context_edit_id); if (data->folder_context_folder_id != 0) gth_menu_manager_remove_entries (gth_browser_get_menu_manager (browser, GTH_BROWSER_MENU_MANAGER_FOLDER_FOLDER_ACTIONS), data->folder_context_folder_id); data->folder_context_open_id = 0; data->folder_context_create_id = 0; data->folder_context_edit_id = 0; data->folder_context_folder_id = 0; } } void fm__gth_browser_folder_tree_drag_data_received_cb (GthBrowser *browser, GthFileData *destination, GList *file_list, GdkDragAction action) { int n_files; GthFileSource *destination_source; GFile *first_file; GthFileSource *file_list_source; gboolean move_files; GtkWidget *dialog; GthTask *task; char *message; int response; if (destination == NULL) return; n_files = g_list_length (file_list); if (n_files == 0) return; if ((action != GDK_ACTION_MOVE) && (action != GDK_ACTION_COPY)) return; destination_source = gth_main_get_file_source (destination->file); if (destination_source == NULL) return; first_file = G_FILE (file_list->data); file_list_source = gth_main_get_file_source (first_file); if (file_list_source == NULL) return; if (action == GDK_ACTION_MOVE) action |= GDK_ACTION_COPY; action = action & gth_file_source_get_drop_actions (destination_source, destination->file, first_file); if (action == 0) { _gtk_error_dialog_run (GTK_WINDOW (browser), "%s", _("Could not perform the operation")); return; } move_files = (action & GDK_ACTION_MOVE) != 0; /* ask confirmation */ response = GTK_RESPONSE_OK; if (n_files == 1) { GFileInfo *info; char *filename; info = gth_file_source_get_file_info (file_list_source, first_file, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME); if (info != NULL) filename = g_strdup (g_file_info_get_display_name (info)); else filename = _g_file_get_display_name (first_file); if (move_files) message = g_strdup_printf (_("Do you want to move “%s” to “%s”?"), filename, g_file_info_get_display_name (destination->info)); else message = g_strdup_printf (_("Do you want to copy “%s” to “%s”?"), filename, g_file_info_get_display_name (destination->info)); g_free (filename); _g_object_unref (info); } else { if (move_files) message = g_strdup_printf (_("Do you want to move the dragged files to “%s”?"), g_file_info_get_display_name (destination->info)); else message = g_strdup_printf (_("Do you want to copy the dragged files to “%s”?"), g_file_info_get_display_name (destination->info)); } dialog = _gtk_message_dialog_new (GTK_WINDOW (browser), GTK_DIALOG_MODAL, _GTK_ICON_NAME_DIALOG_QUESTION, message, NULL, _GTK_LABEL_CANCEL, GTK_RESPONSE_CANCEL, (move_files ? _("Move") : _("_Copy")), GTK_RESPONSE_OK, NULL); response = gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); g_free (message); if (response != GTK_RESPONSE_OK) return; /* exec task */ task = gth_copy_task_new (destination_source, destination, move_files, file_list, -1); gth_browser_exec_task (browser, task, GTH_TASK_FLAGS_DEFAULT); g_object_unref (task); g_object_unref (destination_source); } void fm__gth_browser_folder_tree_selection_changed_cb (GthBrowser *browser) { fm__gth_browser_update_sensitivity_cb (browser); } static void clipboard_targets_received_cb (GtkClipboard *clipboard, GdkAtom *atoms, int n_atoms, gpointer user_data) { GthBrowser *browser = user_data; BrowserData *data; int i; GthFileData *folder; data = g_object_get_data (G_OBJECT (browser), BROWSER_DATA_KEY); data->can_paste = FALSE; for (i = 0; ! data->can_paste && (i < n_atoms); i++) if (atoms[i] == GNOME_COPIED_FILES) data->can_paste = TRUE; gth_window_enable_action (GTH_WINDOW (browser), "edit-paste", data->can_paste); folder = gth_browser_get_folder_popup_file_data (browser); gth_window_enable_action (GTH_WINDOW (browser), "folder-context-paste-into-folder", (folder != NULL) && data->can_paste && g_file_info_get_attribute_boolean (folder->info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE)); _g_object_unref (folder); g_object_unref (browser); } static void _gth_browser_update_paste_command_sensitivity (GthBrowser *browser, GtkClipboard *clipboard) { BrowserData *data; data = g_object_get_data (G_OBJECT (browser), BROWSER_DATA_KEY); g_return_if_fail (data != NULL); data->can_paste = FALSE; gth_window_enable_action (GTH_WINDOW (browser), "edit-paste", data->can_paste); if (clipboard == NULL) clipboard = gtk_widget_get_clipboard (GTK_WIDGET (browser), GDK_SELECTION_CLIPBOARD); gtk_clipboard_request_targets (clipboard, clipboard_targets_received_cb, g_object_ref (browser)); } void fm__gth_browser_update_sensitivity_cb (GthBrowser *browser) { BrowserData *data; GthFileSource *file_source; int n_selected; gboolean sensitive; GthFileData *folder; data = g_object_get_data (G_OBJECT (browser), BROWSER_DATA_KEY); g_return_if_fail (data != NULL); file_source = gth_browser_get_location_source (browser); n_selected = gth_file_selection_get_n_selected (GTH_FILE_SELECTION (gth_browser_get_file_list_view (browser))); sensitive = (n_selected > 0) && (file_source != NULL) && gth_file_source_can_cut (file_source); gth_window_enable_action (GTH_WINDOW (browser), "edit-cut", sensitive); sensitive = (n_selected > 0) && (file_source != NULL); gth_window_enable_action (GTH_WINDOW (browser), "edit-copy", sensitive); gth_window_enable_action (GTH_WINDOW (browser), "trash", sensitive); gth_window_enable_action (GTH_WINDOW (browser), "delete", sensitive); gth_window_enable_action (GTH_WINDOW (browser), "duplicate", sensitive); gth_window_enable_action (GTH_WINDOW (browser), "move-to-folder", sensitive); gth_window_enable_action (GTH_WINDOW (browser), "copy-to-folder", sensitive); gth_window_enable_action (GTH_WINDOW (browser), "file-list-rename", n_selected > 0); folder = gth_browser_get_folder_popup_file_data (browser); gth_window_enable_action (GTH_WINDOW (browser), "folder-context-create", (folder != NULL) && g_file_info_get_attribute_boolean (folder->info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE)); gth_window_enable_action (GTH_WINDOW (browser), "folder-context-rename", (folder != NULL) && g_file_info_get_attribute_boolean (folder->info, G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME)); gth_window_enable_action (GTH_WINDOW (browser), "folder-context-delete", (folder != NULL) && g_file_info_get_attribute_boolean (folder->info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE)); gth_window_enable_action (GTH_WINDOW (browser), "folder-context-trash", (folder != NULL) && g_file_info_get_attribute_boolean (folder->info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH)); gth_window_enable_action (GTH_WINDOW (browser), "folder-context-cut", (folder != NULL) && g_file_info_get_attribute_boolean (folder->info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE)); gth_window_enable_action (GTH_WINDOW (browser), "folder-context-move-to", (folder != NULL) && g_file_info_get_attribute_boolean (folder->info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE)); gth_window_enable_action (GTH_WINDOW (browser), "rename", ((folder != NULL) && g_file_info_get_attribute_boolean (folder->info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE)) || (n_selected > 0)); gth_window_enable_action (GTH_WINDOW (browser), "folder-context-copy", (folder != NULL) && (g_file_info_get_file_type (folder->info) != G_FILE_TYPE_MOUNTABLE)); gth_window_enable_action (GTH_WINDOW (browser), "folder-context-copy-to", (folder != NULL) && (g_file_info_get_file_type (folder->info) != G_FILE_TYPE_MOUNTABLE)); _g_object_unref (folder); _gth_browser_update_paste_command_sensitivity (browser, NULL); } static void clipboard_owner_change_cb (GtkClipboard *clipboard, GdkEvent *event, gpointer user_data) { _gth_browser_update_paste_command_sensitivity ((GthBrowser *) user_data, clipboard); } void fm__gth_browser_realize_cb (GthBrowser *browser) { GtkClipboard *clipboard; clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); g_signal_connect (clipboard, "owner_change", G_CALLBACK (clipboard_owner_change_cb), browser); } void fm__gth_browser_unrealize_cb (GthBrowser *browser) { GtkClipboard *clipboard; clipboard = gtk_widget_get_clipboard (GTK_WIDGET (browser), GDK_SELECTION_CLIPBOARD); g_signal_handlers_disconnect_by_func (clipboard, G_CALLBACK (clipboard_owner_change_cb), browser); }