Bug 615162 - Fix tooltips on offscreen widgets

Fix the "widget under pointer" logic and keyboard tooltip positioning
to do the right thing on offscreen widgets.
This commit is contained in:
Michael Natterer 2010-04-15 13:03:43 +02:00
parent fdf936b5ad
commit ece97b2359

View File

@ -20,6 +20,10 @@
*/
#include "config.h"
#include <math.h>
#include <string.h>
#include "gtktooltip.h"
#include "gtkintl.h"
#include "gtkwindow.h"
@ -31,8 +35,6 @@
#include "gtkalias.h"
#include <string.h>
#undef DEBUG_TOOLTIP
@ -472,9 +474,9 @@ gtk_tooltip_trigger_tooltip_query (GdkDisplay *display)
event.motion.y = y;
event.motion.is_hint = FALSE;
gdk_window_get_origin (window, &x, &y);
event.motion.x_root = event.motion.x + x;
event.motion.y_root = event.motion.y + y;
gdk_window_get_root_coords (window, x, y, &x, &y);
event.motion.x_root = x;
event.motion.y_root = y;
_gtk_tooltip_handle_event (&event);
}
@ -674,13 +676,15 @@ find_widget_under_pointer (GdkWindow *window,
*/
while (window && window != event_widget->window)
{
gint px, py;
gdouble px, py;
gdk_window_get_position (window, &px, &py);
child_loc.x += px;
child_loc.y += py;
gdk_window_coords_to_parent (window,
child_loc.x, child_loc.y,
&px, &py);
child_loc.x = px;
child_loc.y = py;
window = gdk_window_get_parent (window);
window = gdk_window_get_effective_parent (window);
}
/* Failing to find widget->window can happen for e.g. a detached handle box;
@ -859,6 +863,39 @@ gtk_tooltip_run_requery (GtkWidget **widget,
return return_value;
}
static void
get_bounding_box (GtkWidget *widget,
GdkRectangle *bounds)
{
GdkWindow *window;
gint x, y;
gint w, h;
gint x1, y1;
gint x2, y2;
gint x3, y3;
gint x4, y4;
window = gtk_widget_get_parent_window (widget);
x = widget->allocation.x;
y = widget->allocation.y;
w = widget->allocation.width;
h = widget->allocation.height;
gdk_window_get_root_coords (window, x, y, &x1, &y1);
gdk_window_get_root_coords (window, x + w, y, &x2, &y2);
gdk_window_get_root_coords (window, x, y + h, &x3, &y3);
gdk_window_get_root_coords (window, x + w, y + h, &x4, &y4);
#define MIN4(a,b,c,d) MIN(MIN(a,b),MIN(c,d))
#define MAX4(a,b,c,d) MAX(MAX(a,b),MAX(c,d))
bounds->x = floor (MIN4 (x1, x2, x3, x4));
bounds->y = floor (MIN4 (y1, y2, y3, y4));
bounds->width = ceil (MAX4 (x1, x2, x3, x4)) - bounds->x;
bounds->height = ceil (MAX4 (y1, y2, y3, y4)) - bounds->y;
}
static void
gtk_tooltip_position (GtkTooltip *tooltip,
GdkDisplay *display,
@ -873,18 +910,15 @@ gtk_tooltip_position (GtkTooltip *tooltip,
/* FIXME: should we swap this when RTL is enabled? */
if (tooltip->keyboard_mode_enabled)
{
gdk_window_get_origin (new_tooltip_widget->window, &x, &y);
if (!gtk_widget_get_has_window (new_tooltip_widget))
{
x += new_tooltip_widget->allocation.x;
y += new_tooltip_widget->allocation.y;
}
GdkRectangle bounds;
get_bounding_box (new_tooltip_widget, &bounds);
/* For keyboard mode we position the tooltip below the widget,
* right of the center of the widget.
*/
x += new_tooltip_widget->allocation.width / 2;
y += new_tooltip_widget->allocation.height + 4;
x = bounds.x + bounds.width / 2;
y = bounds.y + bounds.height + 4;
}
else
{
@ -960,14 +994,18 @@ gtk_tooltip_show_tooltip (GdkDisplay *display)
}
else
{
gint tx, ty;
window = tooltip->last_window;
if (!GDK_IS_WINDOW (window))
return;
gdk_window_get_origin (window, &x, &y);
x = tooltip->last_x - x;
y = tooltip->last_y - y;
gdk_window_get_pointer (window, &x, &y, NULL);
gdk_window_get_root_coords (window, x, y, &tx, &ty);
tooltip->last_x = tx;
tooltip->last_y = ty;
pointer_widget = tooltip_widget = find_widget_under_pointer (window,
&x, &y);
@ -1290,9 +1328,6 @@ _gtk_tooltip_handle_event (GdkEvent *event)
if (current_tooltip)
{
gtk_tooltip_set_last_window (current_tooltip, event->any.window);
gdk_event_get_root_coords (event,
&current_tooltip->last_x,
&current_tooltip->last_y);
}
if (current_tooltip && current_tooltip->keyboard_mode_enabled)
@ -1398,9 +1433,6 @@ _gtk_tooltip_handle_event (GdkEvent *event)
current_tooltip);
gtk_tooltip_set_last_window (current_tooltip, event->any.window);
gdk_event_get_root_coords (event,
&current_tooltip->last_x,
&current_tooltip->last_y);
gtk_tooltip_start_delay (display);
}