diff --git a/ChangeLog b/ChangeLog index dc5f7024eb..31951ed6f2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2007-08-21 Kristian Rietveld + + Fix #457642, reported by Christian Persch. + + * gtk/gtktooltip.c: added debugging output which can be compiled + in with a #define, annotated all coordinate translations in the + source code, + (find_widget_under_pointer): remove the "no-window correction"; + always convert the coordinates from window relative to allocation + relative; after recursing through a container, translate the + coordinates from container allocation relative to child widget + allocation relative; + (find_topmost_widget_from_event): now we get allocation relative + coordinates here we do not have to distinguish no-window and window + widgets. + 2007-08-18 Cody Russell * gtk/gtkimcontextsimple.c: Fixed incorrect compose mapping diff --git a/gtk/gtktooltip.c b/gtk/gtktooltip.c index cc44d5d50a..46ca8179ab 100644 --- a/gtk/gtktooltip.c +++ b/gtk/gtktooltip.c @@ -33,6 +33,8 @@ #include +#undef DEBUG_TOOLTIP + #define GTK_TOOLTIP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_TOOLTIP, GtkTooltipClass)) #define GTK_IS_TOOLTIP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_TOOLTIP)) @@ -456,11 +458,27 @@ child_location_foreach (GtkWidget *child, if (!GTK_WIDGET_DRAWABLE (child)) return; + /* (child_loc->x, child_loc->y) are relative to + * child_loc->container's allocation. + */ + if (!child_loc->child && gtk_widget_translate_coordinates (child_loc->container, child, child_loc->x, child_loc->y, &x, &y)) { +#ifdef DEBUG_TOOLTIP + g_print ("candidate: %s alloc=[(%d,%d) %dx%d] (%d, %d)->(%d, %d)\n", + gtk_widget_get_name (child), + child->allocation.x, + child->allocation.y, + child->allocation.width, + child->allocation.height, + child_loc->x, child_loc->y, + x, y); +#endif /* DEBUG_TOOLTIP */ + + /* (x, y) relative to child's allocation. */ if (x >= 0 && x < child->allocation.width && y >= 0 && y < child->allocation.height) { @@ -468,6 +486,9 @@ child_location_foreach (GtkWidget *child, { struct ChildLocation tmp = { NULL, NULL, 0, 0 }; + /* Take (x, y) relative the child's allocation and + * recurse. + */ tmp.x = x; tmp.y = y; tmp.container = child; @@ -486,6 +507,9 @@ child_location_foreach (GtkWidget *child, } } +/* Translates coordinates from dest_widget->window relative (src_x, src_y), + * to allocation relative (dest_x, dest_y) of dest_widget. + */ static void window_to_alloc (GtkWidget *dest_widget, gint src_x, @@ -499,6 +523,9 @@ window_to_alloc (GtkWidget *dest_widget, gint wx, wy; gdk_window_get_position (dest_widget->window, &wx, &wy); + /* Offset coordinates if widget->window is smaller than + * widget->allocation. + */ src_x += wx - dest_widget->allocation.x; src_y += wy - dest_widget->allocation.y; } @@ -514,6 +541,9 @@ window_to_alloc (GtkWidget *dest_widget, *dest_y = src_y; } +/* Translates coordinates from window relative (x, y) to + * allocation relative (x, y) of the returned widget. + */ static GtkWidget * find_widget_under_pointer (GdkWindow *window, gint *x, @@ -527,9 +557,20 @@ find_widget_under_pointer (GdkWindow *window, if (!event_widget) return NULL; +#ifdef DEBUG_TOOLTIP + g_print ("event window %p (belonging to %p (%s)) (%d, %d)\n", + window, event_widget, gtk_widget_get_name (event_widget), + *x, *y); +#endif + + /* Coordinates are relative to event window */ child_loc.x = *x; child_loc.y = *y; + /* We go down the window hierarchy to the widget->window, + * coordinates stay relative to the current window. + * We end up with window == widget->window, coordinates relative to that. + */ while (window && window != event_widget->window) { gint px, py; @@ -541,12 +582,6 @@ find_widget_under_pointer (GdkWindow *window, window = gdk_window_get_parent (window); } - if (GTK_WIDGET_NO_WINDOW (event_widget)) - { - child_loc.x += event_widget->allocation.x; - child_loc.y += event_widget->allocation.y; - } - /* Failing to find widget->window can happen for e.g. a detached handle box; * chaining ::query-tooltip up to its parent probably makes little sense, * and users better implement tooltips on handle_box->child. @@ -555,11 +590,16 @@ find_widget_under_pointer (GdkWindow *window, if (!window) return NULL; + /* Convert the window relative coordinates to allocation + * relative coordinates. + */ + window_to_alloc (event_widget, + child_loc.x, child_loc.y, + &child_loc.x, &child_loc.y); + if (GTK_IS_CONTAINER (event_widget)) { - window_to_alloc (event_widget, - child_loc.x, child_loc.y, - &child_loc.x, &child_loc.y); + GtkWidget *container = event_widget; child_loc.container = event_widget; child_loc.child = NULL; @@ -567,12 +607,23 @@ find_widget_under_pointer (GdkWindow *window, gtk_container_forall (GTK_CONTAINER (event_widget), child_location_foreach, &child_loc); + /* Here we have a widget, with coordinates relative to + * child_loc.container's allocation. + */ + if (child_loc.child) event_widget = child_loc.child; else if (child_loc.container) event_widget = child_loc.container; + + /* Translate to event_widget's allocation */ + gtk_widget_translate_coordinates (container, event_widget, + child_loc.x, child_loc.y, + &child_loc.x, &child_loc.y); + } + /* We return (x, y) relative to the allocation of event_widget. */ if (x) *x = child_loc.x; if (y) @@ -581,6 +632,9 @@ find_widget_under_pointer (GdkWindow *window, return event_widget; } +/* Ignores (x, y) on input, translates event coordinates to + * allocation relative (x, y) of the returned widget. + */ static GtkWidget * find_topmost_widget_coords_from_event (GdkEvent *event, gint *x, @@ -594,26 +648,16 @@ find_topmost_widget_coords_from_event (GdkEvent *event, tx = dx; ty = dy; + /* Returns coordinates relative to tmp's allocation. */ tmp = find_widget_under_pointer (event->any.window, &tx, &ty); if (!tmp) return NULL; - /* Make sure the pointer can actually be on the widget returned */ - if (GTK_WIDGET_NO_WINDOW (tmp)) - { - if (tx < tmp->allocation.x || - tx >= tmp->allocation.x + tmp->allocation.width || - ty < tmp->allocation.y || - ty >= tmp->allocation.y + tmp->allocation.height) - return NULL; - } - else - { - if (tx < 0 || tx >= tmp->allocation.width || - ty < 0 || ty >= tmp->allocation.height) - return NULL; - } + /* Make sure the pointer can actually be on the widget returned. */ + if (tx < 0 || tx >= tmp->allocation.width || + ty < 0 || ty >= tmp->allocation.height) + return NULL; if (x) *x = tx; @@ -1093,6 +1137,7 @@ _gtk_tooltip_handle_event (GdkEvent *event) if (touchscreen) return; + /* Returns coordinates relative to has_tooltip_widget's allocation. */ has_tooltip_widget = find_topmost_widget_coords_from_event (event, &x, &y); display = gdk_drawable_get_display (event->any.window); current_tooltip = g_object_get_data (G_OBJECT (display), @@ -1124,6 +1169,17 @@ _gtk_tooltip_handle_event (GdkEvent *event) return; } +#ifdef DEBUG_TOOLTIP + if (has_tooltip_widget) + g_print ("%p (%s) at (%d, %d) %dx%d pointer: (%d, %d)\n", + has_tooltip_widget, gtk_widget_get_name (has_tooltip_widget), + has_tooltip_widget->allocation.x, + has_tooltip_widget->allocation.y, + has_tooltip_widget->allocation.width, + has_tooltip_widget->allocation.height, + x, y); +#endif /* DEBUG_TOOLTIP */ + /* Always poll for a next motion event */ gdk_event_request_motions (&event->motion);