]> Pileus Git - ~andy/gtk/commitdiff
Bug 615162 - Fix tooltips on offscreen widgets
authorMichael Natterer <mitch@gimp.org>
Thu, 15 Apr 2010 11:03:43 +0000 (13:03 +0200)
committerMichael Natterer <mitch@gimp.org>
Thu, 15 Apr 2010 11:03:43 +0000 (13:03 +0200)
Fix the "widget under pointer" logic and keyboard tooltip positioning
to do the right thing on offscreen widgets.

gtk/gtktooltip.c

index 87871e885cdf2f014c91ad80ca11ba892577fcc4..5cc2334c3126a734b968f0b85fb09cd4b0d033da 100644 (file)
  */
 
 #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);
          }