diff options
Diffstat (limited to 'src/nautilus-dnd.c')
-rw-r--r-- | src/nautilus-dnd.c | 978 |
1 files changed, 978 insertions, 0 deletions
diff --git a/src/nautilus-dnd.c b/src/nautilus-dnd.c new file mode 100644 index 0000000..8071d5b --- /dev/null +++ b/src/nautilus-dnd.c @@ -0,0 +1,978 @@ +/* nautilus-dnd.c - Common Drag & drop handling code shared by the icon container + * and the list view. + * + * Copyright (C) 2000, 2001 Eazel, 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-dnd.h" + +#include "nautilus-program-choosing.h" +#include <eel/eel-glib-extensions.h> +#include <eel/eel-gtk-extensions.h> +#include <eel/eel-string.h> +#include <eel/eel-vfs-extensions.h> +#include <gtk/gtk.h> +#include <glib/gi18n.h> +#include "nautilus-file-utilities.h" +#include "nautilus-canvas-dnd.h" +#include <src/nautilus-list-view-dnd.h> +#include <stdio.h> +#include <string.h> + +/* a set of defines stolen from the eel-icon-dnd.c file. + * These are in microseconds. + */ +#define AUTOSCROLL_TIMEOUT_INTERVAL 100 +#define AUTOSCROLL_INITIAL_DELAY 100000 + +/* drag this close to the view edge to start auto scroll*/ +#define AUTO_SCROLL_MARGIN 30 + +/* the smallest amount of auto scroll used when we just enter the autoscroll + * margin + */ +#define MIN_AUTOSCROLL_DELTA 5 + +/* the largest amount of auto scroll used when we are right over the view + * edge + */ +#define MAX_AUTOSCROLL_DELTA 50 + +void +nautilus_drag_init (NautilusDragInfo *drag_info, + const GtkTargetEntry *drag_types, + int drag_type_count, + gboolean add_text_targets) +{ + drag_info->target_list = gtk_target_list_new (drag_types, + drag_type_count); + + if (add_text_targets) + { + gtk_target_list_add_text_targets (drag_info->target_list, + NAUTILUS_ICON_DND_TEXT); + } + + drag_info->drop_occurred = FALSE; + drag_info->need_to_destroy = FALSE; +} + +void +nautilus_drag_finalize (NautilusDragInfo *drag_info) +{ + gtk_target_list_unref (drag_info->target_list); + nautilus_drag_destroy_selection_list (drag_info->selection_list); + nautilus_drag_destroy_selection_list (drag_info->selection_cache); + + g_free (drag_info); +} + + +/* Functions to deal with NautilusDragSelectionItems. */ + +NautilusDragSelectionItem * +nautilus_drag_selection_item_new (void) +{ + return g_new0 (NautilusDragSelectionItem, 1); +} + +static void +drag_selection_item_destroy (NautilusDragSelectionItem *item) +{ + g_clear_object (&item->file); + g_free (item->uri); + g_free (item); +} + +void +nautilus_drag_destroy_selection_list (GList *list) +{ + GList *p; + + if (list == NULL) + { + return; + } + + for (p = list; p != NULL; p = p->next) + { + drag_selection_item_destroy (p->data); + } + + g_list_free (list); +} + +GList * +nautilus_drag_uri_list_from_selection_list (const GList *selection_list) +{ + NautilusDragSelectionItem *selection_item; + GList *uri_list; + const GList *l; + + uri_list = NULL; + for (l = selection_list; l != NULL; l = l->next) + { + selection_item = (NautilusDragSelectionItem *) l->data; + if (selection_item->uri != NULL) + { + uri_list = g_list_prepend (uri_list, g_strdup (selection_item->uri)); + } + } + + return g_list_reverse (uri_list); +} + +/* + * Transfer: Full. Free with g_list_free_full (list, g_object_unref); + */ +GList * +nautilus_drag_file_list_from_selection_list (const GList *selection_list) +{ + NautilusDragSelectionItem *selection_item; + GList *file_list; + const GList *l; + + file_list = NULL; + for (l = selection_list; l != NULL; l = l->next) + { + selection_item = (NautilusDragSelectionItem *) l->data; + if (selection_item->file != NULL) + { + file_list = g_list_prepend (file_list, g_object_ref (selection_item->file)); + } + } + + return g_list_reverse (file_list); +} + +GList * +nautilus_drag_uri_list_from_array (const char **uris) +{ + GList *uri_list; + int i; + + if (uris == NULL) + { + return NULL; + } + + uri_list = NULL; + + for (i = 0; uris[i] != NULL; i++) + { + uri_list = g_list_prepend (uri_list, g_strdup (uris[i])); + } + + return g_list_reverse (uri_list); +} + +GList * +nautilus_drag_build_selection_list (GtkSelectionData *data) +{ + GList *result; + const guchar *p, *oldp; + int size; + + result = NULL; + oldp = gtk_selection_data_get_data (data); + size = gtk_selection_data_get_length (data); + + while (size > 0) + { + NautilusDragSelectionItem *item; + guint len; + + /* The list is in the form: + * + * name\rx:y:width:height\r\n + * + * The geometry information after the first \r is optional. */ + + /* 1: Decode name. */ + + p = memchr (oldp, '\r', size); + if (p == NULL) + { + break; + } + + item = nautilus_drag_selection_item_new (); + + len = p - oldp; + + item->uri = g_malloc (len + 1); + memcpy (item->uri, oldp, len); + item->uri[len] = 0; + item->file = nautilus_file_get_by_uri (item->uri); + + p++; + if (*p == '\n' || *p == '\0') + { + result = g_list_prepend (result, item); + if (p == 0) + { + g_warning ("Invalid x-special/gnome-icon-list data received: " + "missing newline character."); + break; + } + else + { + oldp = p + 1; + continue; + } + } + + size -= p - oldp; + oldp = p; + + /* 2: Decode geometry information. */ + + item->got_icon_position = sscanf ((const gchar *) p, "%d:%d:%d:%d%*s", + &item->icon_x, &item->icon_y, + &item->icon_width, &item->icon_height) == 4; + if (!item->got_icon_position) + { + g_warning ("Invalid x-special/gnome-icon-list data received: " + "invalid icon position specification."); + } + + result = g_list_prepend (result, item); + + p = memchr (p, '\r', size); + if (p == NULL || p[1] != '\n') + { + g_warning ("Invalid x-special/gnome-icon-list data received: " + "missing newline character."); + if (p == NULL) + { + break; + } + } + else + { + p += 2; + } + + size -= p - oldp; + oldp = p; + } + + return g_list_reverse (result); +} + +static gboolean +nautilus_drag_file_local_internal (const char *target_uri_string, + const char *first_source_uri) +{ + /* check if the first item on the list has target_uri_string as a parent + * FIXME: + * we should really test each item but that would be slow for large selections + * and currently dropped items can only be from the same container + */ + GFile *target, *item, *parent; + gboolean result; + + result = FALSE; + + target = g_file_new_for_uri (target_uri_string); + + /* get the parent URI of the first item in the selection */ + item = g_file_new_for_uri (first_source_uri); + parent = g_file_get_parent (item); + g_object_unref (item); + + if (parent != NULL) + { + result = g_file_equal (parent, target); + g_object_unref (parent); + } + + g_object_unref (target); + + return result; +} + +gboolean +nautilus_drag_uris_local (const char *target_uri, + const GList *source_uri_list) +{ + /* must have at least one item */ + g_assert (source_uri_list); + + return nautilus_drag_file_local_internal (target_uri, source_uri_list->data); +} + +gboolean +nautilus_drag_items_local (const char *target_uri_string, + const GList *selection_list) +{ + /* must have at least one item */ + g_assert (selection_list); + + return nautilus_drag_file_local_internal (target_uri_string, + ((NautilusDragSelectionItem *) selection_list->data)->uri); +} + +GdkDragAction +nautilus_drag_default_drop_action_for_netscape_url (GdkDragContext *context) +{ + /* Mozilla defaults to copy, but unless thats the + * only allowed thing (enforced by ctrl) we want to LINK */ + if (gdk_drag_context_get_suggested_action (context) == GDK_ACTION_COPY && + gdk_drag_context_get_actions (context) != GDK_ACTION_COPY) + { + return GDK_ACTION_LINK; + } + else if (gdk_drag_context_get_suggested_action (context) == GDK_ACTION_MOVE) + { + /* Don't support move */ + return GDK_ACTION_COPY; + } + + return gdk_drag_context_get_suggested_action (context); +} + +static gboolean +check_same_fs (NautilusFile *file1, + NautilusFile *file2) +{ + char *id1, *id2; + gboolean result; + + result = FALSE; + + if (file1 != NULL && file2 != NULL) + { + id1 = nautilus_file_get_filesystem_id (file1); + id2 = nautilus_file_get_filesystem_id (file2); + + if (id1 != NULL && id2 != NULL) + { + result = (strcmp (id1, id2) == 0); + } + + g_free (id1); + g_free (id2); + } + + return result; +} + +static gboolean +source_is_deletable (GFile *file) +{ + NautilusFile *naut_file; + gboolean ret; + + /* if there's no a cached NautilusFile, it returns NULL */ + naut_file = nautilus_file_get (file); + if (naut_file == NULL) + { + return FALSE; + } + + ret = nautilus_file_can_delete (naut_file); + nautilus_file_unref (naut_file); + + return ret; +} + +NautilusDragInfo * +nautilus_drag_get_source_data (GdkDragContext *context) +{ + GtkWidget *source_widget; + NautilusDragInfo *source_data; + + source_widget = gtk_drag_get_source_widget (context); + if (source_widget == NULL) + { + return NULL; + } + + if (NAUTILUS_IS_CANVAS_CONTAINER (source_widget)) + { + source_data = nautilus_canvas_dnd_get_drag_source_data (NAUTILUS_CANVAS_CONTAINER (source_widget), + context); + } + else if (GTK_IS_TREE_VIEW (source_widget)) + { + NautilusWindow *window; + NautilusWindowSlot *active_slot; + NautilusView *view; + + window = NAUTILUS_WINDOW (gtk_widget_get_toplevel (source_widget)); + active_slot = nautilus_window_get_active_slot (window); + view = nautilus_window_slot_get_current_view (active_slot); + if (NAUTILUS_IS_LIST_VIEW (view)) + { + source_data = nautilus_list_view_dnd_get_drag_source_data (NAUTILUS_LIST_VIEW (view), + context); + } + else + { + g_warning ("Got a drag context with a tree view source widget, but current view is not list view"); + source_data = NULL; + } + } + else + { + /* it's a slot or something else */ + g_warning ("Requested drag source data from a widget that doesn't support it"); + source_data = NULL; + } + + return source_data; +} + +void +nautilus_drag_default_drop_action_for_icons (GdkDragContext *context, + const char *target_uri_string, + const GList *items, + guint32 source_actions, + int *action) +{ + gboolean same_fs; + gboolean target_is_source_parent; + gboolean source_deletable; + const char *dropped_uri; + GFile *target, *dropped, *dropped_directory; + GdkDragAction actions; + NautilusFile *dropped_file, *target_file; + + if (target_uri_string == NULL) + { + *action = 0; + return; + } + + /* this is needed because of how dnd works. The actions at the time drag-begin + * is done are not set, because they are first set on drag-motion. However, + * for our use case, which is validation with the sidebar for dnd feedback + * when the dnd doesn't have as a destination the sidebar itself, we need + * a way to know the actions at drag-begin time. Either canvas view or + * list view know them when starting the drag, but asking for them here + * would be breaking the current model too much. So instead we rely on the + * caller, which will ask if appropiate to those objects about the actions + * available, instead of relying solely on the context here. */ + if (source_actions) + { + actions = source_actions & (GDK_ACTION_MOVE | GDK_ACTION_COPY); + } + else + { + actions = gdk_drag_context_get_actions (context) & (GDK_ACTION_MOVE | GDK_ACTION_COPY); + } + if (actions == 0) + { + /* We can't use copy or move, just go with the suggested action. */ + *action = gdk_drag_context_get_suggested_action (context); + return; + } + + if (gdk_drag_context_get_suggested_action (context) == GDK_ACTION_ASK) + { + /* Don't override ask */ + *action = gdk_drag_context_get_suggested_action (context); + return; + } + + dropped_uri = ((NautilusDragSelectionItem *) items->data)->uri; + dropped_file = ((NautilusDragSelectionItem *) items->data)->file; + target_file = nautilus_file_get_by_uri (target_uri_string); + + /* + * Check for trash URI. We do a find_directory for any Trash directory. + * Passing 0 permissions as gnome-vfs would override the permissions + * passed with 700 while creating .Trash directory + */ + if (eel_uri_is_trash (target_uri_string)) + { + /* Only move to Trash */ + if (actions & GDK_ACTION_MOVE) + { + *action = GDK_ACTION_MOVE; + } + nautilus_file_unref (target_file); + return; + } + else if (target_file != NULL && nautilus_file_is_archive (target_file)) + { + *action = GDK_ACTION_COPY; + + nautilus_file_unref (target_file); + return; + } + else + { + target = g_file_new_for_uri (target_uri_string); + } + + same_fs = check_same_fs (target_file, dropped_file); + + nautilus_file_unref (target_file); + + /* Compare the first dropped uri with the target uri for same fs match. */ + dropped = g_file_new_for_uri (dropped_uri); + dropped_directory = g_file_get_parent (dropped); + target_is_source_parent = FALSE; + if (dropped_directory != NULL) + { + /* If the dropped file is already in the same directory but + * is in another filesystem we still want to move, not copy + * as this is then just a move of a mountpoint to another + * position in the dir */ + target_is_source_parent = g_file_equal (dropped_directory, target); + g_object_unref (dropped_directory); + } + source_deletable = source_is_deletable (dropped); + + if ((same_fs && source_deletable) || target_is_source_parent || + g_file_has_uri_scheme (dropped, "trash")) + { + if (actions & GDK_ACTION_MOVE) + { + *action = GDK_ACTION_MOVE; + } + else + { + *action = gdk_drag_context_get_suggested_action (context); + } + } + else + { + if (actions & GDK_ACTION_COPY) + { + *action = GDK_ACTION_COPY; + } + else + { + *action = gdk_drag_context_get_suggested_action (context); + } + } + + g_object_unref (target); + g_object_unref (dropped); +} + +GdkDragAction +nautilus_drag_default_drop_action_for_uri_list (GdkDragContext *context, + const char *target_uri_string) +{ + if (eel_uri_is_trash (target_uri_string) && (gdk_drag_context_get_actions (context) & GDK_ACTION_MOVE)) + { + /* Only move to Trash */ + return GDK_ACTION_MOVE; + } + else + { + return gdk_drag_context_get_suggested_action (context); + } +} + +/* Encode a "x-special/gnome-icon-list" selection. + * Along with the URIs of the dragged files, this encodes + * the location and size of each icon relative to the cursor. + */ +static void +add_one_gnome_icon (const char *uri, + int x, + int y, + int w, + int h, + gpointer data) +{ + GString *result; + + result = (GString *) data; + + g_string_append_printf (result, "%s\r%d:%d:%hu:%hu\r\n", + uri, x, y, w, h); +} + +static void +add_one_uri (const char *uri, + int x, + int y, + int w, + int h, + gpointer data) +{ + GString *result; + + result = (GString *) data; + + g_string_append (result, uri); + g_string_append (result, "\r\n"); +} + +static void +cache_one_item (const char *uri, + int x, + int y, + int w, + int h, + gpointer data) +{ + GList **cache = data; + NautilusDragSelectionItem *item; + + item = nautilus_drag_selection_item_new (); + item->uri = nautilus_uri_to_native_uri (uri); + + if (item->uri == NULL) + { + item->uri = g_strdup (uri); + } + + item->file = nautilus_file_get_by_uri (uri); + item->icon_x = x; + item->icon_y = y; + item->icon_width = w; + item->icon_height = h; + *cache = g_list_prepend (*cache, item); +} + +GList * +nautilus_drag_create_selection_cache (gpointer container_context, + NautilusDragEachSelectedItemIterator each_selected_item_iterator) +{ + GList *cache = NULL; + + (*each_selected_item_iterator)(cache_one_item, container_context, &cache); + cache = g_list_reverse (cache); + + return cache; +} + +/* Common function for drag_data_get_callback calls. + * Returns FALSE if it doesn't handle drag data */ +gboolean +nautilus_drag_drag_data_get_from_cache (GList *cache, + GdkDragContext *context, + GtkSelectionData *selection_data, + guint info, + guint32 time) +{ + GList *l; + GString *result; + NautilusDragEachSelectedItemDataGet func; + + if (cache == NULL) + { + return FALSE; + } + + switch (info) + { + case NAUTILUS_ICON_DND_GNOME_ICON_LIST: + { + func = add_one_gnome_icon; + } + break; + + case NAUTILUS_ICON_DND_URI_LIST: + case NAUTILUS_ICON_DND_TEXT: + { + func = add_one_uri; + } + break; + + default: + return FALSE; + } + + result = g_string_new (NULL); + + for (l = cache; l != NULL; l = l->next) + { + NautilusDragSelectionItem *item = l->data; + (*func)(item->uri, item->icon_x, item->icon_y, item->icon_width, item->icon_height, result); + } + + gtk_selection_data_set (selection_data, + gtk_selection_data_get_target (selection_data), + 8, (guchar *) result->str, result->len); + g_string_free (result, TRUE); + + return TRUE; +} + +typedef struct +{ + GMainLoop *loop; + GdkDragAction chosen; +} DropActionMenuData; + +static void +menu_deactivate_callback (GtkWidget *menu, + gpointer data) +{ + DropActionMenuData *damd; + + damd = data; + + if (g_main_loop_is_running (damd->loop)) + { + g_main_loop_quit (damd->loop); + } +} + +static void +drop_action_activated_callback (GtkWidget *menu_item, + gpointer data) +{ + DropActionMenuData *damd; + + damd = data; + + damd->chosen = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menu_item), + "action")); + + if (g_main_loop_is_running (damd->loop)) + { + g_main_loop_quit (damd->loop); + } +} + +static void +append_drop_action_menu_item (GtkWidget *menu, + const char *text, + GdkDragAction action, + gboolean sensitive, + DropActionMenuData *damd) +{ + GtkWidget *menu_item; + + menu_item = gtk_menu_item_new_with_mnemonic (text); + gtk_widget_set_sensitive (menu_item, sensitive); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item); + + g_object_set_data (G_OBJECT (menu_item), + "action", + GINT_TO_POINTER (action)); + + g_signal_connect (menu_item, "activate", + G_CALLBACK (drop_action_activated_callback), + damd); + + gtk_widget_show (menu_item); +} + +/* Pops up a menu of actions to perform on dropped files */ +GdkDragAction +nautilus_drag_drop_action_ask (GtkWidget *widget, + GdkDragAction actions) +{ + GtkWidget *menu; + GtkWidget *menu_item; + DropActionMenuData damd; + + /* Create the menu and set the sensitivity of the items based on the + * allowed actions. + */ + menu = gtk_menu_new (); + gtk_menu_set_screen (GTK_MENU (menu), gtk_widget_get_screen (widget)); + + append_drop_action_menu_item (menu, _("_Move Here"), + GDK_ACTION_MOVE, + (actions & GDK_ACTION_MOVE) != 0, + &damd); + + append_drop_action_menu_item (menu, _("_Copy Here"), + GDK_ACTION_COPY, + (actions & GDK_ACTION_COPY) != 0, + &damd); + + append_drop_action_menu_item (menu, _("_Link Here"), + GDK_ACTION_LINK, + (actions & GDK_ACTION_LINK) != 0, + &damd); + + eel_gtk_menu_append_separator (GTK_MENU (menu)); + + menu_item = gtk_menu_item_new_with_mnemonic (_("Cancel")); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item); + gtk_widget_show (menu_item); + + damd.chosen = 0; + damd.loop = g_main_loop_new (NULL, FALSE); + + g_signal_connect (menu, "deactivate", + G_CALLBACK (menu_deactivate_callback), + &damd); + + gtk_grab_add (menu); + + gtk_menu_popup_at_pointer (GTK_MENU (menu), + NULL); + + g_main_loop_run (damd.loop); + + gtk_grab_remove (menu); + + g_main_loop_unref (damd.loop); + + g_object_ref_sink (menu); + g_object_unref (menu); + + return damd.chosen; +} + +gboolean +nautilus_drag_autoscroll_in_scroll_region (GtkWidget *widget) +{ + float x_scroll_delta, y_scroll_delta; + + nautilus_drag_autoscroll_calculate_delta (widget, &x_scroll_delta, &y_scroll_delta); + + return x_scroll_delta != 0 || y_scroll_delta != 0; +} + + +void +nautilus_drag_autoscroll_calculate_delta (GtkWidget *widget, + float *x_scroll_delta, + float *y_scroll_delta) +{ + GtkAllocation allocation; + GdkDisplay *display; + GdkSeat *seat; + GdkDevice *pointer; + int x, y; + + g_assert (GTK_IS_WIDGET (widget)); + + display = gtk_widget_get_display (widget); + seat = gdk_display_get_default_seat (display); + pointer = gdk_seat_get_pointer (seat); + gdk_window_get_device_position (gtk_widget_get_window (widget), pointer, + &x, &y, NULL); + + /* Find out if we are anywhere close to the tree view edges + * to see if we need to autoscroll. + */ + *x_scroll_delta = 0; + *y_scroll_delta = 0; + + if (x < AUTO_SCROLL_MARGIN) + { + *x_scroll_delta = (float) (x - AUTO_SCROLL_MARGIN); + } + + gtk_widget_get_allocation (widget, &allocation); + if (x > allocation.width - AUTO_SCROLL_MARGIN) + { + if (*x_scroll_delta != 0) + { + /* Already trying to scroll because of being too close to + * the top edge -- must be the window is really short, + * don't autoscroll. + */ + return; + } + *x_scroll_delta = (float) (x - (allocation.width - AUTO_SCROLL_MARGIN)); + } + + if (y < AUTO_SCROLL_MARGIN) + { + *y_scroll_delta = (float) (y - AUTO_SCROLL_MARGIN); + } + + if (y > allocation.height - AUTO_SCROLL_MARGIN) + { + if (*y_scroll_delta != 0) + { + /* Already trying to scroll because of being too close to + * the top edge -- must be the window is really narrow, + * don't autoscroll. + */ + return; + } + *y_scroll_delta = (float) (y - (allocation.height - AUTO_SCROLL_MARGIN)); + } + + if (*x_scroll_delta == 0 && *y_scroll_delta == 0) + { + /* no work */ + return; + } + + /* Adjust the scroll delta to the proper acceleration values depending on how far + * into the sroll margins we are. + * FIXME bugzilla.eazel.com 2486: + * we could use an exponential acceleration factor here for better feel + */ + if (*x_scroll_delta != 0) + { + *x_scroll_delta /= AUTO_SCROLL_MARGIN; + *x_scroll_delta *= (MAX_AUTOSCROLL_DELTA - MIN_AUTOSCROLL_DELTA); + *x_scroll_delta += MIN_AUTOSCROLL_DELTA; + } + + if (*y_scroll_delta != 0) + { + *y_scroll_delta /= AUTO_SCROLL_MARGIN; + *y_scroll_delta *= (MAX_AUTOSCROLL_DELTA - MIN_AUTOSCROLL_DELTA); + *y_scroll_delta += MIN_AUTOSCROLL_DELTA; + } +} + + + +void +nautilus_drag_autoscroll_start (NautilusDragInfo *drag_info, + GtkWidget *widget, + GSourceFunc callback, + gpointer user_data) +{ + if (nautilus_drag_autoscroll_in_scroll_region (widget)) + { + if (drag_info->auto_scroll_timeout_id == 0) + { + drag_info->waiting_to_autoscroll = TRUE; + drag_info->start_auto_scroll_in = g_get_monotonic_time () + + AUTOSCROLL_INITIAL_DELAY; + + drag_info->auto_scroll_timeout_id = g_timeout_add + (AUTOSCROLL_TIMEOUT_INTERVAL, + callback, + user_data); + } + } + else + { + if (drag_info->auto_scroll_timeout_id != 0) + { + g_source_remove (drag_info->auto_scroll_timeout_id); + drag_info->auto_scroll_timeout_id = 0; + } + } +} + +void +nautilus_drag_autoscroll_stop (NautilusDragInfo *drag_info) +{ + if (drag_info->auto_scroll_timeout_id != 0) + { + g_source_remove (drag_info->auto_scroll_timeout_id); + drag_info->auto_scroll_timeout_id = 0; + } +} |