* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
+#include <config.h>
#include "gdkconfig.h"
#include "gdk/gdkkeysyms.h"
#include "gtkdnd.h"
+#include "gtkiconfactory.h"
+#include "gtkicontheme.h"
#include "gtkimage.h"
#include "gtkinvisible.h"
#include "gtkmain.h"
+#include "gtkplug.h"
#include "gtkstock.h"
#include "gtkwindow.h"
+#include "gtkalias.h"
static GSList *source_widgets = NULL;
GtkImagePixmapData pixmap;
GtkImagePixbufData pixbuf;
GtkImageStockData stock;
+ GtkImageIconNameData name;
} icon_data;
GdkBitmap *icon_mask;
gint button; /* mouse button starting drag */
GtkDragStatus status; /* drag status */
- GdkEvent *last_event; /* motion event waiting for response */
+ GdkEvent *last_event; /* pending event */
gint start_x, start_y; /* Initial position */
gint cur_x, cur_y; /* Current Position */
GtkDragDestInfo *proxy_dest; /* Set if this is a proxy drag */
+ guint update_idle; /* Idle function to update the drag */
guint drop_timeout; /* Timeout for aborting drop */
guint destroy_icon : 1; /* If true, destroy icon_window
*/
GdkDragAction actions;
GdkWindow *proxy_window;
GdkDragProtocol proxy_protocol;
- gboolean do_proxy : 1;
- gboolean proxy_coords : 1;
- gboolean have_drag : 1;
+ guint do_proxy : 1;
+ guint proxy_coords : 1;
+ guint have_drag : 1;
};
struct _GtkDragDestInfo
GdkDragContext *context; /* Drag context */
GtkDragSourceInfo *proxy_source; /* Set if this is a proxy drag */
GtkSelectionData *proxy_data; /* Set while retrieving proxied data */
- gboolean dropped : 1; /* Set after we receive a drop */
+ guint dropped : 1; /* Set after we receive a drop */
guint32 proxy_drop_time; /* Timestamp for proxied drop */
- gboolean proxy_drop_wait : 1; /* Set if we are waiting for a
+ guint proxy_drop_wait : 1; /* Set if we are waiting for a
* status reply before sending
* a proxied drop on.
*/
static gint gtk_drag_anim_timeout (gpointer data);
static void gtk_drag_remove_icon (GtkDragSourceInfo *info);
static void gtk_drag_source_info_destroy (GtkDragSourceInfo *info);
+static void gtk_drag_add_update_idle (GtkDragSourceInfo *info);
+
static void gtk_drag_update (GtkDragSourceInfo *info,
GdkScreen *screen,
gint x_root,
const guchar *mask;
GdkCursor *cursor;
} drag_cursors[] = {
- { GDK_ACTION_DEFAULT, 0 },
+ { GDK_ACTION_DEFAULT, NULL },
{ GDK_ACTION_ASK, action_ask_bits, action_ask_mask_bits, NULL },
{ GDK_ACTION_COPY, action_copy_bits, action_copy_mask_bits, NULL },
{ GDK_ACTION_MOVE, action_move_bits, action_move_mask_bits, NULL },
if (GTK_WIDGET_DRAWABLE (widget))
{
+ cairo_t *cr;
+
if (GTK_WIDGET_NO_WINDOW (widget))
{
x = widget->allocation.x;
GTK_STATE_NORMAL, GTK_SHADOW_OUT,
NULL, widget, "dnd",
x, y, width, height);
-
- gdk_draw_rectangle (widget->window,
- widget->style->black_gc,
- FALSE,
- x, y, width - 1, height - 1);
+
+ cr = gdk_cairo_create (widget->window);
+ cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */
+ cairo_set_line_width (cr, 1.0);
+ cairo_rectangle (cr,
+ x + 0.5, y + 0.5,
+ width - 1, height - 1);
+ cairo_stroke (cr);
+ cairo_destroy (cr);
}
return FALSE;
site = g_object_get_data (G_OBJECT (widget), "gtk-drag-dest");
- if (site == NULL)
+ if (!site)
{
- g_warning ("can't set a target list on a widget until you've called gtk_drag_dest_set() to make the widget into a drag destination");
+ g_warning ("Can't set a target list on a widget until you've called gtk_drag_dest_set() "
+ "to make the widget into a drag destination");
return;
}
site->target_list = target_list;
}
+/**
+ * gtk_drag_dest_add_text_targets:
+ * @widget: a #GtkWidget that's a drag destination
+ *
+ * Add the text targets supported by #GtkSelection to
+ * the target list of the drag destination. The targets
+ * are added with @info = 0. If you need another value,
+ * use gtk_target_list_add_text_targets() and
+ * gtk_drag_dest_set_target_list().
+ *
+ * Since: 2.6
+ **/
+void
+gtk_drag_dest_add_text_targets (GtkWidget *widget)
+{
+ GtkTargetList *target_list;
+
+ target_list = gtk_drag_dest_get_target_list (widget);
+ if (target_list)
+ gtk_target_list_ref (target_list);
+ else
+ target_list = gtk_target_list_new (NULL, 0);
+ gtk_target_list_add_text_targets (target_list, 0);
+ gtk_drag_dest_set_target_list (widget, target_list);
+ gtk_target_list_unref (target_list);
+}
+
+/**
+ * gtk_drag_dest_add_image_targets:
+ * @widget: a #GtkWidget that's a drag destination
+ *
+ * Add the image targets supported by #GtkSelection to
+ * the target list of the drag destination. The targets
+ * are added with @info = 0. If you need another value,
+ * use gtk_target_list_add_image_targets() and
+ * gtk_drag_dest_set_target_list().
+ *
+ * Since: 2.6
+ **/
+void
+gtk_drag_dest_add_image_targets (GtkWidget *widget)
+{
+ GtkTargetList *target_list;
+
+ target_list = gtk_drag_dest_get_target_list (widget);
+ if (target_list)
+ gtk_target_list_ref (target_list);
+ else
+ target_list = gtk_target_list_new (NULL, 0);
+ gtk_target_list_add_image_targets (target_list, 0, FALSE);
+ gtk_drag_dest_set_target_list (widget, target_list);
+ gtk_target_list_unref (target_list);
+}
+
+/**
+ * gtk_drag_dest_add_uri_targets:
+ * @widget: a #GtkWidget that's a drag destination
+ *
+ * Add the URI targets supported by #GtkSelection to
+ * the target list of the drag destination. The targets
+ * are added with @info = 0. If you need another value,
+ * use gtk_target_list_add_uri_targets() and
+ * gtk_drag_dest_set_target_list().
+ *
+ * Since: 2.6
+ **/
+void
+gtk_drag_dest_add_uri_targets (GtkWidget *widget)
+{
+ GtkTargetList *target_list;
+
+ target_list = gtk_drag_dest_get_target_list (widget);
+ if (target_list)
+ gtk_target_list_ref (target_list);
+ else
+ target_list = gtk_target_list_new (NULL, 0);
+ gtk_target_list_add_uri_targets (target_list, 0);
+ gtk_drag_dest_set_target_list (widget, target_list);
+ gtk_target_list_unref (target_list);
+}
/*************************************************************
* _gtk_drag_dest_handle_event:
}
}
- gdk_window_get_origin (toplevel->window, &tx, &ty);
+#ifdef GDK_WINDOWING_X11
+ /* Hackaround for: http://bugzilla.gnome.org/show_bug.cgi?id=136112
+ *
+ * Currently gdk_window_get_position doesn't provide reliable
+ * information for embedded windows, so we call the much more
+ * expensive gdk_window_get_origin().
+ */
+ if (GTK_IS_PLUG (toplevel))
+ gdk_window_get_origin (toplevel->window, &tx, &ty);
+ else
+#endif /* GDK_WINDOWING_X11 */
+ gdk_window_get_position (toplevel->window, &tx, &ty);
data.x = event->dnd.x_root - tx;
data.y = event->dnd.y_root - ty;
* Source side *
***************/
-/*************************************************************
- * gtk_drag_begin: Start a drag operation
- *
- * arguments:
- * widget: Widget from which drag starts
- * handlers: List of handlers to supply the data for the drag
- * button: Button user used to start drag
- * time: Time of event starting drag
- *
- * results:
- *************************************************************/
-
-GdkDragContext *
-gtk_drag_begin (GtkWidget *widget,
- GtkTargetList *target_list,
- GdkDragAction actions,
- gint button,
- GdkEvent *event)
+/* Like GtkDragBegin, but also takes a GtkDragSourceSite,
+ * so that we can set the icon from the source site information
+ */
+static GdkDragContext *
+gtk_drag_begin_internal (GtkWidget *widget,
+ GtkDragSourceSite *site,
+ GtkTargetList *target_list,
+ GdkDragAction actions,
+ gint button,
+ GdkEvent *event)
{
GtkDragSourceInfo *info;
GList *targets = NULL;
GdkDragAction possible_actions, suggested_action;
GdkDragContext *context;
GtkWidget *ipc_widget;
-
- g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
- g_return_val_if_fail (GTK_WIDGET_REALIZED (widget), NULL);
- g_return_val_if_fail (target_list != NULL, NULL);
-
+ GdkCursor *cursor;
+
+ ipc_widget = gtk_drag_get_ipc_widget (gtk_widget_get_screen (widget));
+
+ gtk_drag_get_event_actions (event, button, actions,
+ &suggested_action, &possible_actions);
+
+ cursor = gtk_drag_get_cursor (gtk_widget_get_display (widget), suggested_action);
+
if (event)
time = gdk_event_get_time (event);
+ if (gdk_pointer_grab (ipc_widget->window, FALSE,
+ GDK_POINTER_MOTION_MASK |
+ GDK_BUTTON_RELEASE_MASK, NULL,
+ cursor, time) != 0)
+ {
+ gtk_drag_release_ipc_widget (ipc_widget);
+ return NULL;
+ }
+
+ if (gdk_keyboard_grab (ipc_widget->window, FALSE, time) != 0)
+ {
+ gtk_drag_release_ipc_widget (ipc_widget);
+ return NULL;
+ }
+
+ /* We use a GTK grab here to override any grabs that the widget
+ * we are dragging from might have held
+ */
+ gtk_grab_add (ipc_widget);
+
tmp_list = g_list_last (target_list->list);
while (tmp_list)
{
tmp_list = tmp_list->prev;
}
- ipc_widget = gtk_drag_get_ipc_widget (gtk_widget_get_screen (widget));
source_widgets = g_slist_prepend (source_widgets, ipc_widget);
context = gdk_drag_begin (ipc_widget->window, targets);
info->widget = gtk_widget_ref (widget);
info->button = button;
+ info->cursor = cursor;
info->target_list = target_list;
gtk_target_list_ref (target_list);
info->possible_actions = actions;
- info->cursor = NULL;
info->status = GTK_DRAG_STATUS_DRAG;
info->last_event = NULL;
info->selections = NULL;
info->icon_window = NULL;
info->destroy_icon = FALSE;
- gtk_drag_get_event_actions (event, info->button, actions,
- &suggested_action, &possible_actions);
-
- info->cursor = gtk_drag_get_cursor (gtk_widget_get_display (widget), suggested_action);
-
/* Set cur_x, cur_y here so if the "drag_begin" signal shows
* the drag icon, it will be in the right place
*/
g_signal_emit_by_name (widget, "drag_begin",
info->context);
-
+
+ /* Ensure that we have an icon before we start the drag; the
+ * application may have set one in ::drag_begin, or it may
+ * not have set one.
+ */
+ if (!info->icon_window)
+ {
+ if (!site || site->icon_type == GTK_IMAGE_EMPTY)
+ gtk_drag_set_icon_default (context);
+ else
+ switch (site->icon_type)
+ {
+ case GTK_IMAGE_PIXMAP:
+ gtk_drag_set_icon_pixmap (context,
+ site->colormap,
+ site->icon_data.pixmap.pixmap,
+ site->icon_mask,
+ -2, -2);
+ break;
+ case GTK_IMAGE_PIXBUF:
+ gtk_drag_set_icon_pixbuf (context,
+ site->icon_data.pixbuf.pixbuf,
+ -2, -2);
+ break;
+ case GTK_IMAGE_STOCK:
+ gtk_drag_set_icon_stock (context,
+ site->icon_data.stock.stock_id,
+ -2, -2);
+ break;
+ case GTK_IMAGE_ICON_NAME:
+ gtk_drag_set_icon_name (context,
+ site->icon_data.name.icon_name,
+ -2, -2);
+ break;
+ case GTK_IMAGE_EMPTY:
+ default:
+ g_assert_not_reached();
+ break;
+ }
+ }
+
if (event && event->type == GDK_MOTION_NOTIFY)
gtk_drag_motion_cb (info->ipc_widget, (GdkEventMotion *)event, info);
g_signal_connect (info->ipc_widget, "selection_get",
G_CALLBACK (gtk_drag_selection_get), info);
- /* We use a GTK grab here to override any grabs that the widget
- * we are dragging from might have held
- */
- gtk_grab_add (info->ipc_widget);
- if (gdk_pointer_grab (info->ipc_widget->window, FALSE,
- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
- GDK_BUTTON_RELEASE_MASK, NULL,
- info->cursor, time) == 0)
- {
- if (gdk_keyboard_grab (info->ipc_widget->window, FALSE, time) != 0)
- {
- gtk_drag_cancel (info, time);
- return NULL;
- }
- }
-
info->have_grab = TRUE;
info->grab_time = time;
return info->context;
}
+/**
+ * gtk_drag_begin:
+ * @widget: the source widget.
+ * @targets: The targets (data formats) in which the
+ * source can provide the data.
+ * @actions: A bitmask of the allowed drag actions for this drag.
+ * @button: The button the user clicked to start the drag.
+ * @event: The event that triggered the start of the drag.
+ *
+ * Initiates a drag on the source side. The function
+ * only needs to be used when the application is
+ * starting drags itself, and is not needed when
+ * gtk_drag_source_set() is used.
+ *
+ * Return value: the context for this drag.
+ **/
+GdkDragContext *
+gtk_drag_begin (GtkWidget *widget,
+ GtkTargetList *targets,
+ GdkDragAction actions,
+ gint button,
+ GdkEvent *event)
+{
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
+ g_return_val_if_fail (GTK_WIDGET_REALIZED (widget), NULL);
+ g_return_val_if_fail (targets != NULL, NULL);
+
+ return gtk_drag_begin_internal (widget, NULL, targets,
+ actions, button, event);
+}
+
/*************************************************************
* gtk_drag_source_set:
* Register a drop site, and possibly add default behaviors.
site->start_button_mask = start_button_mask;
- if (targets)
- site->target_list = gtk_target_list_new (targets, n_targets);
- else
- site->target_list = NULL;
+ site->target_list = gtk_target_list_new (targets, n_targets);
site->actions = actions;
-
}
/*************************************************************
}
}
+/**
+ * gtk_drag_source_get_target_list:
+ * @widget: a #GtkWidget
+ *
+ * Gets the list of targets this widget can provide for
+ * drag-and-drop.
+ *
+ * Return value: the #GtkTargetList, or %NULL if none
+ *
+ * Since: 2.4
+ **/
+GtkTargetList *
+gtk_drag_source_get_target_list (GtkWidget *widget)
+{
+ GtkDragSourceSite *site;
+
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
+
+ site = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
+
+ return site ? site->target_list : NULL;
+}
+
+/**
+ * gtk_drag_source_set_target_list:
+ * @widget: a #GtkWidget that's a drag source
+ * @target_list: list of draggable targets, or %NULL for none
+ *
+ * Changes the target types that this widget offers for drag-and-drop.
+ * The widget must first be made into a drag source with
+ * gtk_drag_source_set().
+ *
+ * Since: 2.4
+ **/
+void
+gtk_drag_source_set_target_list (GtkWidget *widget,
+ GtkTargetList *target_list)
+{
+ GtkDragSourceSite *site;
+
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+ site = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
+ if (site == NULL)
+ {
+ g_warning ("gtk_drag_source_set_target_list() requires the widget "
+ "to already be a drag source.");
+ return;
+ }
+
+ if (target_list)
+ gtk_target_list_ref (target_list);
+
+ if (site->target_list)
+ gtk_target_list_unref (site->target_list);
+
+ site->target_list = target_list;
+}
+
+/**
+ * gtk_drag_source_add_text_targets:
+ * @widget: a #GtkWidget that's is a drag source
+ *
+ * Add the text targets supported by #GtkSelection to
+ * the target list of the drag source. The targets
+ * are added with @info = 0. If you need another value,
+ * use gtk_target_list_add_text_targets() and
+ * gtk_drag_source_set_target_list().
+ *
+ * Since: 2.6
+ **/
+void
+gtk_drag_source_add_text_targets (GtkWidget *widget)
+{
+ GtkTargetList *target_list;
+
+ target_list = gtk_drag_source_get_target_list (widget);
+ if (target_list)
+ gtk_target_list_ref (target_list);
+ else
+ target_list = gtk_target_list_new (NULL, 0);
+ gtk_target_list_add_text_targets (target_list, 0);
+ gtk_drag_source_set_target_list (widget, target_list);
+ gtk_target_list_unref (target_list);
+}
+
+/**
+ * gtk_drag_source_add_image_targets:
+ * @widget: a #GtkWidget that's is a drag source
+ *
+ * Add the writable image targets supported by #GtkSelection to
+ * the target list of the drag source. The targets
+ * are added with @info = 0. If you need another value,
+ * use gtk_target_list_add_image_targets() and
+ * gtk_drag_source_set_target_list().
+ *
+ * Since: 2.6
+ **/
+void
+gtk_drag_source_add_image_targets (GtkWidget *widget)
+{
+ GtkTargetList *target_list;
+
+ target_list = gtk_drag_source_get_target_list (widget);
+ if (target_list)
+ gtk_target_list_ref (target_list);
+ else
+ target_list = gtk_target_list_new (NULL, 0);
+ gtk_target_list_add_image_targets (target_list, 0, TRUE);
+ gtk_drag_source_set_target_list (widget, target_list);
+ gtk_target_list_unref (target_list);
+}
+
+/**
+ * gtk_drag_source_add_uri_targets:
+ * @widget: a #GtkWidget that's is a drag source
+ *
+ * Add the URI targets supported by #GtkSelection to
+ * the target list of the drag source. The targets
+ * are added with @info = 0. If you need another value,
+ * use gtk_target_list_add_uri_targets() and
+ * gtk_drag_source_set_target_list().
+ *
+ * Since: 2.6
+ **/
+void
+gtk_drag_source_add_uri_targets (GtkWidget *widget)
+{
+ GtkTargetList *target_list;
+
+ target_list = gtk_drag_source_get_target_list (widget);
+ if (target_list)
+ gtk_target_list_ref (target_list);
+ else
+ target_list = gtk_target_list_new (NULL, 0);
+ gtk_target_list_add_uri_targets (target_list, 0);
+ gtk_drag_source_set_target_list (widget, target_list);
+ gtk_target_list_unref (target_list);
+}
+
static void
gtk_drag_source_unset_icon (GtkDragSourceSite *site)
{
g_object_unref (site->icon_data.pixbuf.pixbuf);
break;
case GTK_IMAGE_STOCK:
- g_free (G_OBJECT (site->icon_data.stock.stock_id));
+ g_free (site->icon_data.stock.stock_id);
+ break;
+ case GTK_IMAGE_ICON_NAME:
+ g_free (site->icon_data.name.icon_name);
break;
default:
g_assert_not_reached();
site->icon_data.stock.stock_id = g_strdup (stock_id);
}
+/**
+ * gtk_drag_source_set_icon_name:
+ * @widget: a #GtkWidget
+ * @icon_name: name of icon to use
+ *
+ * Sets the icon that will be used for drags from a particular source
+ * to a themed icon. See the docs for #GtkIconTheme for more details.
+ *
+ * Since: 2.8
+ **/
+void
+gtk_drag_source_set_icon_name (GtkWidget *widget,
+ const gchar *icon_name)
+{
+ GtkDragSourceSite *site;
+
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+ g_return_if_fail (icon_name != NULL);
+
+ site = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
+ g_return_if_fail (site != NULL);
+
+ gtk_drag_source_unset_icon (site);
+
+ site->icon_type = GTK_IMAGE_ICON_NAME;
+ site->icon_data.name.icon_name = g_strdup (icon_name);
+}
+
static void
gtk_drag_get_icon (GtkDragSourceInfo *info,
GtkWidget **icon_window,
* @hot_x: the X offset within the icon of the hotspot.
* @hot_y: the Y offset within the icon of the hotspot.
*
- * Sets the the icon for a given drag from a stock ID.
+ * Sets the icon for a given drag from a stock ID.
**/
void
gtk_drag_set_icon_stock (GdkDragContext *context,
gtk_drag_set_icon_window (context, window, hot_x, hot_y, TRUE);
}
+/**
+ * gtk_drag_set_icon_name:
+ * @context: the context for a drag. (This must be called
+ * with a context for the source side of a drag)
+ * @icon_name: name of icon to use
+ * @hot_x: the X offset of the hotspot within the icon
+ * @hot_y: the Y offset of the hotspot within the icon
+ *
+ * Sets the icon for the window from a named themed icon. See
+ * the docs for #GtkIconTheme for more details. Note that the
+ * size of the icon depends on the icon theme (the icon is
+ * loaded at the symbolic size #GTK_ICON_SIZE_DND), thus
+ * @hot_x and @hot_y have to be used with care.
+ *
+ * Since: 2.8
+ **/
+void
+gtk_drag_set_icon_name (GdkDragContext *context,
+ const gchar *icon_name,
+ gint hot_x,
+ gint hot_y)
+{
+ GdkScreen *screen;
+ GtkSettings *settings;
+ GtkIconTheme *icon_theme;
+ GdkPixbuf *pixbuf;
+ gint width, height, icon_size;
+
+ g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
+ g_return_if_fail (context->is_source);
+ g_return_if_fail (icon_name != NULL);
+
+ screen = gdk_drawable_get_screen (context->source_window);
+ g_return_if_fail (screen != NULL);
+
+ settings = gtk_settings_get_for_screen (screen);
+ if (gtk_icon_size_lookup_for_settings (settings,
+ GTK_ICON_SIZE_DND,
+ &width, &height))
+ icon_size = MAX (width, height);
+ else
+ icon_size = 32; /* default value for GTK_ICON_SIZE_DND */
+
+ icon_theme = gtk_icon_theme_get_for_screen (screen);
+
+ pixbuf = gtk_icon_theme_load_icon (icon_theme, icon_name,
+ icon_size, 0, NULL);
+ set_icon_stock_pixbuf (context, NULL, pixbuf, hot_x, hot_y);
+}
+
/**
* gtk_drag_set_icon_default:
* @context: the context for a drag. (This must be called
{
gdk_pointer_grab (widget->window, FALSE,
GDK_POINTER_MOTION_MASK |
- GDK_POINTER_MOTION_HINT_MASK |
GDK_BUTTON_RELEASE_MASK,
NULL,
cursor, info->grab_time);
}
if (info->last_event)
- {
- gtk_drag_update (info,
- info->cur_screen, info->cur_x, info->cur_y,
- info->last_event);
- info->last_event = NULL;
- }
+ gtk_drag_add_update_idle (info);
}
}
break;
{
GtkSelectionData selection_data;
GList *tmp_list;
- GdkAtom target = gdk_atom_intern ("application/x-rootwin-drop", FALSE);
+ /* GTK+ traditionally has used application/x-rootwin-drop, but the
+ * XDND spec specifies x-rootwindow-drop.
+ */
+ GdkAtom target1 = gdk_atom_intern ("application/x-rootwindow-drop", FALSE);
+ GdkAtom target2 = gdk_atom_intern ("application/x-rootwin-drop", FALSE);
tmp_list = info->target_list->list;
while (tmp_list)
{
GtkTargetPair *pair = tmp_list->data;
- if (pair->target == target)
+ if (pair->target == target1 || pair->target == target2)
{
selection_data.selection = GDK_NONE;
- selection_data.target = target;
+ selection_data.target = pair->target;
selection_data.data = NULL;
selection_data.length = -1;
if (gtk_drag_check_threshold (widget, site->x, site->y,
event->motion.x, event->motion.y))
{
- GtkDragSourceInfo *info;
GdkDragContext *context;
site->state = 0;
- context = gtk_drag_begin (widget, site->target_list,
- site->actions,
- i, event);
-
- info = gtk_drag_get_source_info (context, FALSE);
-
- if (!info->icon_window)
- {
- switch (site->icon_type)
- {
- case GTK_IMAGE_EMPTY:
- gtk_drag_set_icon_default (context);
- break;
- case GTK_IMAGE_PIXMAP:
- gtk_drag_set_icon_pixmap (context,
- site->colormap,
- site->icon_data.pixmap.pixmap,
- site->icon_mask,
- -2, -2);
- break;
- case GTK_IMAGE_PIXBUF:
- gtk_drag_set_icon_pixbuf (context,
- site->icon_data.pixbuf.pixbuf,
- -2, -2);
- break;
- case GTK_IMAGE_STOCK:
- gtk_drag_set_icon_stock (context,
- site->icon_data.stock.stock_id,
- -2, -2);
- break;
- default:
- g_assert_not_reached();
- break;
- }
- }
+ context = gtk_drag_begin_internal (widget, site, site->target_list,
+ site->actions,
+ i, event);
retval = TRUE;
}
g_free (info);
}
-/*************************************************************
- * gtk_drag_update:
- * Function to update the status of the drag when the
- * cursor moves or the modifier changes
- * arguments:
- * info: DragSourceInfo for the drag
- * x_root, y_root: position of darg
- * event: The event that triggered this call
- * results:
- *************************************************************/
-
-static void
-gtk_drag_update (GtkDragSourceInfo *info,
- GdkScreen *screen,
- gint x_root,
- gint y_root,
- GdkEvent *event)
+static gboolean
+gtk_drag_update_idle (gpointer data)
{
- GdkDragAction action;
- GdkDragAction possible_actions;
+ GtkDragSourceInfo *info = data;
GdkWindow *dest_window;
GdkDragProtocol protocol;
GdkAtom selection;
- guint32 time = gtk_drag_get_event_time (event);
- gtk_drag_get_event_actions (event,
+ GdkDragAction action;
+ GdkDragAction possible_actions;
+ guint32 time;
+
+ GDK_THREADS_ENTER ();
+
+ info->update_idle = 0;
+
+ time = gtk_drag_get_event_time (info->last_event);
+ gtk_drag_get_event_actions (info->last_event,
info->button,
info->possible_actions,
&action, &possible_actions);
- info->cur_screen = screen;
- info->cur_x = x_root;
- info->cur_y = y_root;
-
gtk_drag_update_icon (info);
gdk_drag_find_window_for_screen (info->context,
info->icon_window ? info->icon_window->window : NULL,
- screen, x_root, y_root,
+ info->cur_screen, info->cur_x, info->cur_y,
&dest_window, &protocol);
- if (gdk_drag_motion (info->context, dest_window, protocol,
- x_root, y_root, action,
- possible_actions,
- time))
- {
- if (info->last_event != event) /* Paranoia, should not happen */
- {
- if (info->last_event)
- gdk_event_free ((GdkEvent *)info->last_event);
- info->last_event = gdk_event_copy ((GdkEvent *)event);
- }
- }
- else
+ if (!gdk_drag_motion (info->context, dest_window, protocol,
+ info->cur_x, info->cur_y, action,
+ possible_actions,
+ time))
{
- if (info->last_event)
- {
- gdk_event_free ((GdkEvent *)info->last_event);
- info->last_event = NULL;
- }
+ gdk_event_free ((GdkEvent *)info->last_event);
+ info->last_event = NULL;
}
if (dest_window)
selection = gdk_drag_get_selection (info->context);
if (selection)
gtk_drag_source_check_selection (info, selection, time);
+
+ GDK_THREADS_LEAVE ();
+
+ return FALSE;
+}
+
+static void
+gtk_drag_add_update_idle (GtkDragSourceInfo *info)
+{
+ /* We use an idle lowerthan GDK_PRIORITY_REDRAW so that exposes
+ * from the last move can catch up before we move again.
+ */
+ if (!info->update_idle)
+ info->update_idle = g_idle_add_full (GDK_PRIORITY_REDRAW + 5,
+ gtk_drag_update_idle,
+ info,
+ NULL);
+}
+
+/**
+ * gtk_drag_update:
+ * @info: DragSourceInfo for the drag
+ * @screen: new screen
+ * @x_root: new X position
+ * @y_root: new y position
+ * @event: event received requiring update
+ *
+ * Updates the status of the drag; called when the
+ * cursor moves or the modifier changes
+ **/
+static void
+gtk_drag_update (GtkDragSourceInfo *info,
+ GdkScreen *screen,
+ gint x_root,
+ gint y_root,
+ GdkEvent *event)
+{
+ info->cur_screen = screen;
+ info->cur_x = x_root;
+ info->cur_y = y_root;
+ if (info->last_event)
+ gdk_event_free ((GdkEvent *)info->last_event);
+ info->last_event = gdk_event_copy ((GdkEvent *)event);
+
+ gtk_drag_add_update_idle (info);
}
/*************************************************************
GtkWidget *source_widget = info->widget;
GdkDisplay *display = gtk_widget_get_display (source_widget);
+ if (info->update_idle)
+ {
+ g_source_remove (info->update_idle);
+ info->update_idle = 0;
+ }
+
+ if (info->last_event)
+ {
+ gdk_event_free (info->last_event);
+ info->last_event = NULL;
+ }
+
info->have_grab = FALSE;
gdk_display_pointer_ungrab (display, time);
gtk_drag_key_cb,
info);
- /* Send on a release pair to the the original
+ /* Send on a release pair to the original
* widget to convince it to release its grab. We need to
* call gtk_propagate_event() here, instead of
* gtk_widget_event() because widget like GtkList may
* @current_y: current Y coordinate
*
* Checks to see if a mouse drag starting at (@start_x, @start_y) and ending
- * at (@current_x, @current_y) has passed the GTK+ drag threshhold, and thus
+ * at (@current_x, @current_y) has passed the GTK+ drag threshold, and thus
* should trigger the beginning of a drag-and-drop operation.
*
* Return Value: %TRUE if the drag threshold has been passed.
return (ABS (current_x - start_x) > drag_threshold ||
ABS (current_y - start_y) > drag_threshold);
}
+
+#define __GTK_DND_C__
+#include "gtkaliasdef.c"