diff options
Diffstat (limited to 'src/nautilus-window-slot-dnd.c')
-rw-r--r-- | src/nautilus-window-slot-dnd.c | 568 |
1 files changed, 568 insertions, 0 deletions
diff --git a/src/nautilus-window-slot-dnd.c b/src/nautilus-window-slot-dnd.c new file mode 100644 index 0000000..96c5d9c --- /dev/null +++ b/src/nautilus-window-slot-dnd.c @@ -0,0 +1,568 @@ +/* + * nautilus-window-slot-dnd.c - Handle DnD for widgets acting as + * NautilusWindowSlot proxies + * + * Copyright (C) 2000, 2001 Eazel, Inc. + * Copyright (C) 2010, Red Hat, Inc. + * + * The Gnome Library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * The Gnome Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with the Gnome Library; see the file COPYING.LIB. If not, + * see <http://www.gnu.org/licenses/>. + * + * Authors: Pavel Cisler <pavel@eazel.com>, + * Ettore Perazzoli <ettore@gnu.org> + */ + +#include <config.h> + +#include "nautilus-notebook.h" +#include "nautilus-application.h" +#include "nautilus-files-view-dnd.h" +#include "nautilus-window-slot-dnd.h" + +typedef struct +{ + gboolean have_data; + gboolean have_valid_data; + + gboolean drop_occurred; + + unsigned int info; + union + { + GList *selection_list; + GList *uri_list; + GtkSelectionData *selection_data; + } data; + + NautilusFile *target_file; + NautilusWindowSlot *target_slot; + GtkWidget *widget; + + gboolean is_notebook; + guint switch_location_timer; +} NautilusDragSlotProxyInfo; + +static void +switch_tab (NautilusDragSlotProxyInfo *drag_info) +{ + GtkWidget *notebook, *slot; + gint idx, n_pages; + + if (drag_info->target_slot == NULL) + { + return; + } + + notebook = gtk_widget_get_ancestor (GTK_WIDGET (drag_info->target_slot), NAUTILUS_TYPE_NOTEBOOK); + n_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook)); + + for (idx = 0; idx < n_pages; idx++) + { + slot = gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), idx); + if (NAUTILUS_WINDOW_SLOT (slot) == drag_info->target_slot) + { + gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), idx); + break; + } + } +} + +static void +switch_location (NautilusDragSlotProxyInfo *drag_info) +{ + GFile *location; + GtkWidget *window; + + if (drag_info->target_file == NULL) + { + return; + } + + window = gtk_widget_get_toplevel (drag_info->widget); + g_assert (NAUTILUS_IS_WINDOW (window)); + + location = nautilus_file_get_location (drag_info->target_file); + nautilus_application_open_location_full (NAUTILUS_APPLICATION (g_application_get_default ()), + location, NAUTILUS_WINDOW_OPEN_FLAG_DONT_MAKE_ACTIVE, + NULL, NAUTILUS_WINDOW (window), NULL); + g_object_unref (location); +} + +static gboolean +slot_proxy_switch_location_timer (gpointer user_data) +{ + NautilusDragSlotProxyInfo *drag_info = user_data; + + drag_info->switch_location_timer = 0; + + if (drag_info->is_notebook) + { + switch_tab (drag_info); + } + else + { + switch_location (drag_info); + } + + return FALSE; +} + +static void +slot_proxy_check_switch_location_timer (NautilusDragSlotProxyInfo *drag_info, + GtkWidget *widget) +{ + GtkSettings *settings; + guint timeout; + + if (drag_info->switch_location_timer) + { + return; + } + + settings = gtk_widget_get_settings (widget); + g_object_get (settings, "gtk-timeout-expand", &timeout, NULL); + + drag_info->switch_location_timer = + gdk_threads_add_timeout (timeout, + slot_proxy_switch_location_timer, + drag_info); +} + +static void +slot_proxy_remove_switch_location_timer (NautilusDragSlotProxyInfo *drag_info) +{ + if (drag_info->switch_location_timer != 0) + { + g_source_remove (drag_info->switch_location_timer); + drag_info->switch_location_timer = 0; + } +} + +static gboolean +slot_proxy_drag_motion (GtkWidget *widget, + GdkDragContext *context, + int x, + int y, + unsigned int time, + gpointer user_data) +{ + NautilusDragSlotProxyInfo *drag_info; + NautilusWindowSlot *target_slot; + GtkWidget *window; + GdkAtom target; + int action; + char *target_uri; + GFile *location; + gboolean valid_text_drag; + gboolean valid_xds_drag; + + drag_info = user_data; + + action = 0; + valid_text_drag = FALSE; + valid_xds_drag = FALSE; + + if (gtk_drag_get_source_widget (context) == widget) + { + goto out; + } + + window = gtk_widget_get_toplevel (widget); + g_assert (NAUTILUS_IS_WINDOW (window)); + + if (!drag_info->have_data) + { + target = gtk_drag_dest_find_target (widget, context, NULL); + + if (target == GDK_NONE) + { + goto out; + } + + gtk_drag_get_data (widget, context, target, time); + } + + target_uri = NULL; + if (drag_info->target_file != NULL) + { + target_uri = nautilus_file_get_uri (drag_info->target_file); + } + else + { + if (drag_info->target_slot != NULL) + { + target_slot = drag_info->target_slot; + } + else + { + target_slot = nautilus_window_get_active_slot (NAUTILUS_WINDOW (window)); + } + + if (target_slot != NULL) + { + location = nautilus_window_slot_get_location (target_slot); + target_uri = g_file_get_uri (location); + } + } + + if (target_uri != NULL) + { + NautilusFile *file; + NautilusDirectory *directory; + gboolean can; + file = nautilus_file_get_existing_by_uri (target_uri); + directory = nautilus_directory_get_for_file (file); + can = nautilus_file_can_write (file) && nautilus_directory_is_editable (directory); + nautilus_directory_unref (directory); + g_object_unref (file); + if (!can) + { + action = 0; + goto out; + } + } + + if (drag_info->have_data && + drag_info->have_valid_data) + { + if (drag_info->info == NAUTILUS_ICON_DND_GNOME_ICON_LIST) + { + nautilus_drag_default_drop_action_for_icons (context, target_uri, + drag_info->data.selection_list, + 0, + &action); + } + else if (drag_info->info == NAUTILUS_ICON_DND_URI_LIST) + { + action = nautilus_drag_default_drop_action_for_uri_list (context, target_uri); + } + else if (drag_info->info == NAUTILUS_ICON_DND_TEXT) + { + valid_text_drag = TRUE; + } + else if (drag_info->info == NAUTILUS_ICON_DND_XDNDDIRECTSAVE || + drag_info->info == NAUTILUS_ICON_DND_RAW) + { + valid_xds_drag = TRUE; + } + } + + g_free (target_uri); + +out: + if (action != 0 || valid_text_drag || valid_xds_drag) + { + gtk_drag_highlight (widget); + slot_proxy_check_switch_location_timer (drag_info, widget); + } + else + { + gtk_drag_unhighlight (widget); + slot_proxy_remove_switch_location_timer (drag_info); + } + + gdk_drag_status (context, action, time); + + return TRUE; +} + +static void +drag_info_free (gpointer user_data) +{ + NautilusDragSlotProxyInfo *drag_info = user_data; + + g_clear_object (&drag_info->target_file); + g_clear_object (&drag_info->target_slot); + + g_slice_free (NautilusDragSlotProxyInfo, drag_info); +} + +static void +drag_info_clear (NautilusDragSlotProxyInfo *drag_info) +{ + slot_proxy_remove_switch_location_timer (drag_info); + + if (!drag_info->have_data) + { + goto out; + } + + if (drag_info->info == NAUTILUS_ICON_DND_GNOME_ICON_LIST) + { + nautilus_drag_destroy_selection_list (drag_info->data.selection_list); + } + else if (drag_info->info == NAUTILUS_ICON_DND_URI_LIST) + { + g_list_free (drag_info->data.uri_list); + } + else if (drag_info->info == NAUTILUS_ICON_DND_TEXT || + drag_info->info == NAUTILUS_ICON_DND_XDNDDIRECTSAVE || + drag_info->info == NAUTILUS_ICON_DND_RAW) + { + if (drag_info->data.selection_data != NULL) + { + gtk_selection_data_free (drag_info->data.selection_data); + } + } + +out: + drag_info->have_data = FALSE; + drag_info->have_valid_data = FALSE; + + drag_info->drop_occurred = FALSE; +} + +static void +slot_proxy_drag_leave (GtkWidget *widget, + GdkDragContext *context, + unsigned int time, + gpointer user_data) +{ + NautilusDragSlotProxyInfo *drag_info; + + drag_info = user_data; + + gtk_drag_unhighlight (widget); + drag_info_clear (drag_info); +} + +static gboolean +slot_proxy_drag_drop (GtkWidget *widget, + GdkDragContext *context, + int x, + int y, + unsigned int time, + gpointer user_data) +{ + GdkAtom target; + NautilusDragSlotProxyInfo *drag_info; + + drag_info = user_data; + g_assert (!drag_info->have_data); + + drag_info->drop_occurred = TRUE; + + target = gtk_drag_dest_find_target (widget, context, NULL); + gtk_drag_get_data (widget, context, target, time); + + return TRUE; +} + + +static void +slot_proxy_handle_drop (GtkWidget *widget, + GdkDragContext *context, + unsigned int time, + NautilusDragSlotProxyInfo *drag_info) +{ + GtkWidget *window; + NautilusWindowSlot *target_slot; + NautilusFilesView *target_view; + char *target_uri; + GList *uri_list; + GFile *location; + + if (!drag_info->have_data || + !drag_info->have_valid_data) + { + gtk_drag_finish (context, FALSE, FALSE, time); + drag_info_clear (drag_info); + return; + } + + window = gtk_widget_get_toplevel (widget); + g_assert (NAUTILUS_IS_WINDOW (window)); + + if (drag_info->target_slot != NULL) + { + target_slot = drag_info->target_slot; + } + else + { + target_slot = nautilus_window_get_active_slot (NAUTILUS_WINDOW (window)); + } + + target_uri = NULL; + if (drag_info->target_file != NULL) + { + target_uri = nautilus_file_get_uri (drag_info->target_file); + } + else if (target_slot != NULL) + { + location = nautilus_window_slot_get_location (target_slot); + target_uri = g_file_get_uri (location); + } + + target_view = NULL; + if (target_slot != NULL) + { + NautilusView *view; + + view = nautilus_window_slot_get_current_view (target_slot); + + if (view && NAUTILUS_IS_FILES_VIEW (view)) + { + target_view = NAUTILUS_FILES_VIEW (view); + } + } + + if (target_slot != NULL && target_view != NULL) + { + if (drag_info->info == NAUTILUS_ICON_DND_GNOME_ICON_LIST) + { + uri_list = nautilus_drag_uri_list_from_selection_list (drag_info->data.selection_list); + g_assert (uri_list != NULL); + + nautilus_files_view_drop_proxy_received_uris (target_view, + uri_list, + target_uri, + gdk_drag_context_get_selected_action (context)); + g_list_free_full (uri_list, g_free); + } + else if (drag_info->info == NAUTILUS_ICON_DND_URI_LIST) + { + nautilus_files_view_drop_proxy_received_uris (target_view, + drag_info->data.uri_list, + target_uri, + gdk_drag_context_get_selected_action (context)); + } + + gtk_drag_finish (context, TRUE, FALSE, time); + } + else + { + gtk_drag_finish (context, FALSE, FALSE, time); + } + + g_free (target_uri); + + drag_info_clear (drag_info); +} + +static void +slot_proxy_drag_data_received (GtkWidget *widget, + GdkDragContext *context, + int x, + int y, + GtkSelectionData *data, + unsigned int info, + unsigned int time, + gpointer user_data) +{ + NautilusDragSlotProxyInfo *drag_info; + char **uris; + + drag_info = user_data; + + g_assert (!drag_info->have_data); + + drag_info->have_data = TRUE; + drag_info->info = info; + + if (gtk_selection_data_get_length (data) < 0) + { + drag_info->have_valid_data = FALSE; + return; + } + + if (info == NAUTILUS_ICON_DND_GNOME_ICON_LIST) + { + drag_info->data.selection_list = nautilus_drag_build_selection_list (data); + + drag_info->have_valid_data = drag_info->data.selection_list != NULL; + } + else if (info == NAUTILUS_ICON_DND_URI_LIST) + { + uris = gtk_selection_data_get_uris (data); + drag_info->data.uri_list = nautilus_drag_uri_list_from_array ((const char **) uris); + g_strfreev (uris); + + drag_info->have_valid_data = drag_info->data.uri_list != NULL; + } + else if (info == NAUTILUS_ICON_DND_TEXT || + info == NAUTILUS_ICON_DND_XDNDDIRECTSAVE || + info == NAUTILUS_ICON_DND_RAW) + { + drag_info->data.selection_data = gtk_selection_data_copy (data); + drag_info->have_valid_data = drag_info->data.selection_data != NULL; + } + + if (drag_info->drop_occurred) + { + slot_proxy_handle_drop (widget, context, time, drag_info); + } +} + +void +nautilus_drag_slot_proxy_init (GtkWidget *widget, + NautilusFile *target_file, + NautilusWindowSlot *target_slot) +{ + NautilusDragSlotProxyInfo *drag_info; + + const GtkTargetEntry targets[] = + { + { NAUTILUS_ICON_DND_GNOME_ICON_LIST_TYPE, 0, NAUTILUS_ICON_DND_GNOME_ICON_LIST }, + { NAUTILUS_ICON_DND_XDNDDIRECTSAVE_TYPE, 0, NAUTILUS_ICON_DND_XDNDDIRECTSAVE }, /* XDS Protocol Type */ + { NAUTILUS_ICON_DND_RAW_TYPE, 0, NAUTILUS_ICON_DND_RAW } + }; + GtkTargetList *target_list; + + g_assert (GTK_IS_WIDGET (widget)); + + drag_info = g_slice_new0 (NautilusDragSlotProxyInfo); + + g_object_set_data_full (G_OBJECT (widget), "drag-slot-proxy-data", drag_info, + drag_info_free); + + drag_info->is_notebook = (g_object_get_data (G_OBJECT (widget), "nautilus-notebook-tab") != NULL); + + if (target_file != NULL) + { + drag_info->target_file = nautilus_file_ref (target_file); + } + + if (target_slot != NULL) + { + drag_info->target_slot = g_object_ref (target_slot); + } + + drag_info->widget = widget; + + gtk_drag_dest_set (widget, 0, + NULL, 0, + GDK_ACTION_MOVE | + GDK_ACTION_COPY | + GDK_ACTION_LINK | + GDK_ACTION_ASK); + + target_list = gtk_target_list_new (targets, G_N_ELEMENTS (targets)); + gtk_target_list_add_uri_targets (target_list, NAUTILUS_ICON_DND_URI_LIST); + gtk_target_list_add_text_targets (target_list, NAUTILUS_ICON_DND_TEXT); + gtk_drag_dest_set_target_list (widget, target_list); + gtk_target_list_unref (target_list); + + g_signal_connect (widget, "drag-motion", + G_CALLBACK (slot_proxy_drag_motion), + drag_info); + g_signal_connect (widget, "drag-drop", + G_CALLBACK (slot_proxy_drag_drop), + drag_info); + g_signal_connect (widget, "drag-data-received", + G_CALLBACK (slot_proxy_drag_data_received), + drag_info); + g_signal_connect (widget, "drag-leave", + G_CALLBACK (slot_proxy_drag_leave), + drag_info); +} |