long standing dnd bug fixes
- From: Tim Janik <timj gtk org>
- To: Owen Taylor <otaylor gtk org>
- Cc: Gtk+ Developers <gtk-devel-list gnome org>
- Subject: long standing dnd bug fixes
- Date: Wed, 2 Jan 2002 15:29:07 +0100 (CET)
hi owen,
i got annoyed enough by my dnd-bug workaround code in beast to actually
sat down and fix the mroe serious bugs in gtkdnd.c.
the patch to gtk_drag_find_widget() is appended, it adresses:
1) dnd code messing up if the widget tree changes during motion (happens
if a target-indicator widget is added/removed under the drag icon)
2) wrong drop position calculations within scrolled windows that have
non-0 scroll offsets (and probably other cases where parent->window !=
gtk_widget_get_parent_window (child)).
btw, i suspect my new (like your old) code to still be broken for
handleboxes, since the position calculation relies on parent->window
and widget->window to form a chain via gdk_window_get_parent().
---
ciaoTJ
Index: gtkdnd.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkdnd.c,v
retrieving revision 1.74
diff -u -p -u -r1.74 gtkdnd.c
--- gtkdnd.c 2001/12/09 22:08:26 1.74
+++ gtkdnd.c 2002/01/02 14:06:05
@@ -1206,6 +1206,16 @@ gtk_drag_selection_received (GtkWidget
gtk_drag_release_ipc_widget (widget);
}
+static void
+prepend_and_ref_drawable (GtkWidget *widget,
+ gpointer data)
+{
+ GSList **slist_p = data;
+
+ if (GTK_WIDGET_DRAWABLE (widget))
+ *slist_p = g_slist_prepend (*slist_p, gtk_widget_ref (widget));
+}
+
/*************************************************************
* gtk_drag_find_widget:
* Recursive callback used to locate widgets for
@@ -1220,6 +1230,7 @@ gtk_drag_find_widget (GtkWidget *w
GtkDragFindData *data)
{
GtkAllocation new_allocation;
+ GtkDragFindData new_data;
gint x_offset = 0;
gint y_offset = 0;
@@ -1234,66 +1245,102 @@ gtk_drag_find_widget (GtkWidget *w
* but within the allocation are not counted. This is consistent
* with the way we highlight drag targets.
*/
- if (!GTK_WIDGET_NO_WINDOW (widget))
- {
- new_allocation.x = 0;
- new_allocation.y = 0;
- }
-
+
+ /* data.x/y are relative to widget->parent->window,
+ * translate and constrain to widget->window
+ */
if (widget->parent)
{
- GdkWindow *window = widget->window;
+ GSList *slist, *wlist = NULL;
+ GdkWindow *pwindow = gtk_widget_get_parent_window (widget);
+ GdkWindow *window = pwindow;
+ gint tx, ty, twidth, theight;
+
+ /* translate offset relative to widget's parent window */
while (window != widget->parent->window)
{
- gint tx, ty, twidth, theight;
- gdk_window_get_size (window, &twidth, &theight);
+ wlist = g_slist_prepend (wlist, window);
+ window = gdk_window_get_parent (window);
+ }
+ for (slist = wlist; slist; slist = slist->next)
+ {
+ window = slist->data;
+ gdk_window_get_position (window, &tx, &ty);
+ x_offset += tx;
+ y_offset += ty;
+ }
+ g_slist_free (wlist);
+ wlist = NULL;
- if (new_allocation.x < 0)
+ /* translate and constrain offset and allocation relative to widget->window */
+ window = widget->window;
+ while (window != pwindow)
+ {
+ wlist = g_slist_prepend (wlist, window);
+ window = gdk_window_get_parent (window);
+ }
+ for (slist = wlist; slist; slist = slist->next)
+ {
+ window = slist->data;
+ gdk_window_get_position (window, &tx, &ty);
+ gdk_window_get_size (window, &twidth, &theight);
+ x_offset += tx;
+ y_offset += ty;
+ if (tx > new_allocation.x)
{
- new_allocation.width += new_allocation.x;
+ new_allocation.width -= tx - new_allocation.x;
new_allocation.x = 0;
+ new_allocation.width = MIN (new_allocation.width, twidth);
+ }
+ else
+ {
+ new_allocation.x -= tx;
+ new_allocation.width = MIN (new_allocation.width, twidth - new_allocation.x);
}
- if (new_allocation.y < 0)
+ if (ty > new_allocation.y)
{
- new_allocation.height += new_allocation.y;
+ new_allocation.height -= ty - new_allocation.y;
new_allocation.y = 0;
+ new_allocation.height = MIN (new_allocation.height, theight);
}
- if (new_allocation.x + new_allocation.width > twidth)
- new_allocation.width = twidth - new_allocation.x;
- if (new_allocation.y + new_allocation.height > theight)
- new_allocation.height = theight - new_allocation.y;
-
- gdk_window_get_position (window, &tx, &ty);
- new_allocation.x += tx;
- x_offset += tx;
- new_allocation.y += ty;
- y_offset += ty;
-
- window = gdk_window_get_parent (window);
+ else
+ {
+ new_allocation.y -= ty;
+ new_allocation.height = MIN (new_allocation.height, theight - new_allocation.y);
+ }
}
+ g_slist_free (wlist);
}
+ new_data = *data;
+ new_data.x -= x_offset;
+ new_data.y -= y_offset;
+ new_data.found = FALSE;
+ new_data.toplevel = FALSE;
+
if (data->toplevel ||
- ((data->x >= new_allocation.x) && (data->y >= new_allocation.y) &&
- (data->x < new_allocation.x + new_allocation.width) &&
- (data->y < new_allocation.y + new_allocation.height)))
+ ((new_data.x >= new_allocation.x) && (new_data.y >= new_allocation.y) &&
+ (new_data.x < new_allocation.x + new_allocation.width) &&
+ (new_data.y < new_allocation.y + new_allocation.height)))
{
/* First, check if the drag is in a valid drop site in
* one of our children
*/
if (GTK_IS_CONTAINER (widget))
{
- GtkDragFindData new_data = *data;
-
- new_data.x -= x_offset;
- new_data.y -= y_offset;
- new_data.found = FALSE;
- new_data.toplevel = FALSE;
-
- gtk_container_forall (GTK_CONTAINER (widget),
- (GtkCallback)gtk_drag_find_widget,
- &new_data);
-
+ GSList *slist, *children = NULL;
+
+ /* need to reference children temoprarily to cope with
+ * widget tree changes during motion
+ */
+ gtk_container_forall (GTK_CONTAINER (widget), prepend_and_ref_drawable, &children);
+ for (slist = children; slist; slist = slist->next)
+ {
+ if (!new_data.found && GTK_WIDGET_DRAWABLE (slist->data))
+ gtk_drag_find_widget (slist->data, &new_data);
+ gtk_widget_unref (slist->data);
+ }
+ g_slist_free (children);
data->found = new_data.found;
}
@@ -1306,16 +1353,14 @@ gtk_drag_find_widget (GtkWidget *w
{
data->found = data->callback (widget,
data->context,
- data->x - new_allocation.x,
- data->y - new_allocation.y,
+ new_data.x - new_allocation.x,
+ new_data.y - new_allocation.y,
data->time);
/* If so, send a "drag_leave" to the last widget */
if (data->found)
{
if (data->info->widget && data->info->widget != widget)
- {
- gtk_drag_dest_leave (data->info->widget, data->context, data->time);
- }
+ gtk_drag_dest_leave (data->info->widget, data->context, data->time);
data->info->widget = widget;
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]