]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtktooltip.c
stylecontext: Do invalidation on first resize container
[~andy/gtk] / gtk / gtktooltip.c
index 762840374b26d873ec47052e232d428e6d215819..aba9ffb38a173b8be9a9a377bc19c76c4c9f05d2 100644 (file)
  * Library General Public License for more details.
  *
  * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <config.h>
+#include "config.h"
+
 #include "gtktooltip.h"
+
+#include <math.h>
+#include <string.h>
+
 #include "gtkintl.h"
 #include "gtkwindow.h"
 #include "gtkmain.h"
 #include "gtklabel.h"
 #include "gtkimage.h"
-#include "gtkhbox.h"
-#include "gtkalignment.h"
+#include "gtkbox.h"
+#include "gtksettings.h"
+#include "gtksizerequest.h"
+#include "gtkstylecontext.h"
+#include "gtkwindowprivate.h"
 
-#include "gtkalias.h"
 
-#include <string.h>
+#ifdef GDK_WINDOWING_WAYLAND
+#include "wayland/gdkwayland.h"
+#endif
+
+
+/**
+ * SECTION:gtktooltip
+ * @Short_description: Add tips to your widgets
+ * @Title: GtkTooltip
+ *
+ * Basic tooltips can be realized simply by using gtk_widget_set_tooltip_text()
+ * or gtk_widget_set_tooltip_markup() without any explicit tooltip object.
+ *
+ * When you need a tooltip with a little more fancy contents, like adding an
+ * image, or you want the tooltip to have different contents per #GtkTreeView
+ * row or cell, you will have to do a little more work:
+ * <itemizedlist>
+ * <listitem>
+ * <para>
+ * Set the #GtkWidget:has-tooltip property to %TRUE, this will make GTK+
+ * monitor the widget for motion and related events which are needed to
+ * determine when and where to show a tooltip.
+ * </para>
+ * </listitem>
+ * <listitem>
+ * <para>
+ * Connect to the #GtkWidget::query-tooltip signal.  This signal will be
+ * emitted when a tooltip is supposed to be shown. One of the arguments passed
+ * to the signal handler is a GtkTooltip object. This is the object that we
+ * are about to display as a tooltip, and can be manipulated in your callback
+ * using functions like gtk_tooltip_set_icon(). There are functions for setting
+ * the tooltip's markup, setting an image from a stock icon, or even putting in
+ * a custom widget.
+ * </para>
+ * </listitem>
+ * <listitem>
+ * <para>
+ * Return %TRUE from your query-tooltip handler. This causes the tooltip to be
+ * show. If you return %FALSE, it will not be shown.
+ * </para>
+ * </listitem>
+ * </itemizedlist>
+ *
+ * In the probably rare case where you want to have even more control over the
+ * tooltip that is about to be shown, you can set your own #GtkWindow which
+ * will be used as tooltip window.  This works as follows:
+ * <itemizedlist>
+ * <listitem>
+ * <para>
+ * Set #GtkWidget:has-tooltip and connect to #GtkWidget::query-tooltip as
+ * before.
+ * </para>
+ * </listitem>
+ * <listitem>
+ * <para>
+ * Use gtk_widget_set_tooltip_window() to set a #GtkWindow created by you as
+ * tooltip window.
+ * </para>
+ * </listitem>
+ * <listitem>
+ * <para>
+ * In the #GtkWidget::query-tooltip callback you can access your window using
+ * gtk_widget_get_tooltip_window() and manipulate as you wish. The semantics of
+ * the return value are exactly as before, return %TRUE to show the window,
+ * %FALSE to not show it.
+ * </para>
+ * </listitem>
+ * </itemizedlist>
+ */
+
 
 #undef DEBUG_TOOLTIP
 
@@ -47,7 +121,6 @@ struct _GtkTooltip
   GObject parent_instance;
 
   GtkWidget *window;
-  GtkWidget *alignment;
   GtkWidget *box;
   GtkWidget *image;
   GtkWidget *label;
@@ -71,6 +144,7 @@ struct _GtkTooltip
   guint browse_mode_enabled : 1;
   guint keyboard_mode_enabled : 1;
   guint tip_area_set : 1;
+  guint custom_was_reset : 1;
 };
 
 struct _GtkTooltipClass
@@ -78,20 +152,26 @@ struct _GtkTooltipClass
   GObjectClass parent_class;
 };
 
-#define GTK_TOOLTIP_VISIBLE(tooltip) ((tooltip)->current_window && GTK_WIDGET_VISIBLE ((tooltip)->current_window))
+#define GTK_TOOLTIP_VISIBLE(tooltip) ((tooltip)->current_window && gtk_widget_get_visible (GTK_WIDGET((tooltip)->current_window)))
 
 
 static void       gtk_tooltip_class_init           (GtkTooltipClass *klass);
 static void       gtk_tooltip_init                 (GtkTooltip      *tooltip);
-static void       gtk_tooltip_finalize             (GObject         *object);
-
-static void       gtk_tooltip_window_style_set     (GtkTooltip      *tooltip);
-static gboolean   gtk_tooltip_paint_window         (GtkTooltip      *tooltip);
+static void       gtk_tooltip_dispose              (GObject         *object);
+
+static gboolean   gtk_tooltip_paint_window         (GtkTooltip      *tooltip,
+                                                    cairo_t         *cr);
+static void       gtk_tooltip_realize_window       (GtkTooltip      *tooltip,
+                                                    GtkWidget       *widget);
+static void       gtk_tooltip_composited_changed   (GtkTooltip      *tooltip,
+                                                    GtkWidget       *widget);
 static void       gtk_tooltip_window_hide          (GtkWidget       *widget,
                                                    gpointer         user_data);
 static void       gtk_tooltip_display_closed       (GdkDisplay      *display,
                                                    gboolean         was_error,
                                                    GtkTooltip      *tooltip);
+static void       gtk_tooltip_set_last_window      (GtkTooltip      *tooltip,
+                                                   GdkWindow       *window);
 
 
 G_DEFINE_TYPE (GtkTooltip, gtk_tooltip, G_TYPE_OBJECT);
@@ -103,12 +183,20 @@ gtk_tooltip_class_init (GtkTooltipClass *klass)
 
   object_class = G_OBJECT_CLASS (klass);
 
-  object_class->finalize = gtk_tooltip_finalize;
+  object_class->dispose = gtk_tooltip_dispose;
 }
 
 static void
 gtk_tooltip_init (GtkTooltip *tooltip)
 {
+  GtkStyleContext *context;
+  GtkWidget *window;
+  GtkWidget *box;
+  GtkWidget *image;
+  GtkWidget *label;
+  GdkScreen *screen;
+  GdkVisual *visual;
+
   tooltip->timeout_id = 0;
   tooltip->browse_mode_timeout_id = 0;
 
@@ -123,47 +211,55 @@ gtk_tooltip_init (GtkTooltip *tooltip)
 
   tooltip->last_window = NULL;
 
-  tooltip->window = g_object_ref (gtk_window_new (GTK_WINDOW_POPUP));
-  gtk_window_set_type_hint (GTK_WINDOW (tooltip->window),
-                           GDK_WINDOW_TYPE_HINT_TOOLTIP);
-  gtk_widget_set_app_paintable (tooltip->window, TRUE);
-  gtk_window_set_resizable (GTK_WINDOW (tooltip->window), FALSE);
-  gtk_widget_set_name (tooltip->window, "gtk-tooltip");
-  g_signal_connect (tooltip->window, "hide",
-                   G_CALLBACK (gtk_tooltip_window_hide), tooltip);
-
-  tooltip->alignment = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
-  gtk_alignment_set_padding (GTK_ALIGNMENT (tooltip->alignment),
-                            tooltip->window->style->ythickness,
-                            tooltip->window->style->ythickness,
-                            tooltip->window->style->xthickness,
-                            tooltip->window->style->xthickness);
-  gtk_container_add (GTK_CONTAINER (tooltip->window), tooltip->alignment);
-  gtk_widget_show (tooltip->alignment);
-
-  g_signal_connect_swapped (tooltip->window, "style_set",
-                           G_CALLBACK (gtk_tooltip_window_style_set), tooltip);
-  g_signal_connect_swapped (tooltip->window, "expose_event",
-                           G_CALLBACK (gtk_tooltip_paint_window), tooltip);
-
-  tooltip->box = gtk_hbox_new (FALSE, tooltip->window->style->xthickness);
-  gtk_container_add (GTK_CONTAINER (tooltip->alignment), tooltip->box);
-  gtk_widget_show (tooltip->box);
-
-  tooltip->image = gtk_image_new ();
-  gtk_box_pack_start (GTK_BOX (tooltip->box), tooltip->image,
-                     FALSE, FALSE, 0);
-
-  tooltip->label = gtk_label_new ("");
-  gtk_label_set_line_wrap (GTK_LABEL (tooltip->label), TRUE);
-  gtk_box_pack_start (GTK_BOX (tooltip->box), tooltip->label,
-                     FALSE, FALSE, 0);
-
+  window = gtk_window_new (GTK_WINDOW_POPUP);
+  screen = gtk_widget_get_screen (window);
+  visual = gdk_screen_get_rgba_visual (screen);
+
+  if (visual != NULL)
+    gtk_widget_set_visual (window, visual);
+
+  gtk_window_set_type_hint (GTK_WINDOW (window), GDK_WINDOW_TYPE_HINT_TOOLTIP);
+  gtk_widget_set_app_paintable (window, TRUE);
+  gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
+  gtk_widget_set_name (window, "gtk-tooltip");
+  g_signal_connect (window, "hide",
+                    G_CALLBACK (gtk_tooltip_window_hide), tooltip);
+
+  context = gtk_widget_get_style_context (window);
+  gtk_style_context_add_class (context, GTK_STYLE_CLASS_TOOLTIP);
+
+  g_signal_connect_swapped (window, "draw",
+                            G_CALLBACK (gtk_tooltip_paint_window), tooltip);
+  g_signal_connect_swapped (window, "realize",
+                            G_CALLBACK (gtk_tooltip_realize_window), tooltip);
+  g_signal_connect_swapped (window, "composited-changed",
+                            G_CALLBACK (gtk_tooltip_composited_changed), tooltip);
+
+  /* FIXME: don't hardcode the padding */
+  box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+  gtk_widget_set_margin_left (box, 6);
+  gtk_widget_set_margin_right (box, 6);
+  gtk_widget_set_margin_top (box, 6);
+  gtk_widget_set_margin_bottom (box, 6);
+  gtk_container_add (GTK_CONTAINER (window), box);
+  gtk_widget_show (box);
+
+  image = gtk_image_new ();
+  gtk_box_pack_start (GTK_BOX (box), image, FALSE, FALSE, 0);
+
+  label = gtk_label_new ("");
+  gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+  gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
+
+  tooltip->window = window;
+  tooltip->box = box;
+  tooltip->image = image;
+  tooltip->label = label;
   tooltip->custom_widget = NULL;
 }
 
 static void
-gtk_tooltip_finalize (GObject *object)
+gtk_tooltip_dispose (GObject *object)
 {
   GtkTooltip *tooltip = GTK_TOOLTIP (object);
 
@@ -179,6 +275,9 @@ gtk_tooltip_finalize (GObject *object)
       tooltip->browse_mode_timeout_id = 0;
     }
 
+  gtk_tooltip_set_custom (tooltip, NULL);
+  gtk_tooltip_set_last_window (tooltip, NULL);
+
   if (tooltip->window)
     {
       GdkDisplay *display;
@@ -188,9 +287,10 @@ gtk_tooltip_finalize (GObject *object)
                                            gtk_tooltip_display_closed,
                                            tooltip);
       gtk_widget_destroy (tooltip->window);
+      tooltip->window = NULL;
     }
 
-  G_OBJECT_CLASS (gtk_tooltip_parent_class)->finalize (object);
+  G_OBJECT_CLASS (gtk_tooltip_parent_class)->dispose (object);
 }
 
 /* public API */
@@ -198,7 +298,7 @@ gtk_tooltip_finalize (GObject *object)
 /**
  * gtk_tooltip_set_markup:
  * @tooltip: a #GtkTooltip
- * @markup: a markup string (see <link linkend="PangoMarkupFormat">Pango markup format</link>) or %NULL
+ * @markup: (allow-none): a markup string (see <link linkend="PangoMarkupFormat">Pango markup format</link>) or %NULL
  *
  * Sets the text of the tooltip to be @markup, which is marked up
  * with the <link
@@ -224,7 +324,7 @@ gtk_tooltip_set_markup (GtkTooltip  *tooltip,
 /**
  * gtk_tooltip_set_text:
  * @tooltip: a #GtkTooltip
- * @text: a text string or %NULL
+ * @text: (allow-none): a text string or %NULL
  *
  * Sets the text of the tooltip to be @text. If @text is %NULL, the label
  * will be hidden. See also gtk_tooltip_set_markup().
@@ -248,7 +348,7 @@ gtk_tooltip_set_text (GtkTooltip  *tooltip,
 /**
  * gtk_tooltip_set_icon:
  * @tooltip: a #GtkTooltip
- * @pixbuf: a #GdkPixbuf, or %NULL
+ * @pixbuf: (allow-none): a #GdkPixbuf, or %NULL
  *
  * Sets the icon of the tooltip (which is in front of the text) to be
  * @pixbuf.  If @pixbuf is %NULL, the image will be hidden.
@@ -274,8 +374,8 @@ gtk_tooltip_set_icon (GtkTooltip *tooltip,
 /**
  * gtk_tooltip_set_icon_from_stock:
  * @tooltip: a #GtkTooltip
- * @stock_id: a stock id, or %NULL
- * @size: a stock icon size
+ * @stock_id: (allow-none): a stock id, or %NULL
+ * @size: (type int): a stock icon size
  *
  * Sets the icon of the tooltip (which is in front of the text) to be
  * the stock item indicated by @stock_id with the size indicated
@@ -301,19 +401,19 @@ gtk_tooltip_set_icon_from_stock (GtkTooltip  *tooltip,
 /**
  * gtk_tooltip_set_icon_from_icon_name:
  * @tooltip: a #GtkTooltip
- * @icon_name: an icon name, or %NULL
- * @size: a stock icon size
+ * @icon_name: (allow-none): an icon name, or %NULL
+ * @size: (type int): a stock icon size
  *
  * Sets the icon of the tooltip (which is in front of the text) to be
  * the icon indicated by @icon_name with the size indicated
  * by @size.  If @icon_name is %NULL, the image will be hidden.
  *
- * Since: 2.16
+ * Since: 2.14
  */
 void
-gtk_tooltip_set_icon_from_icon_name(GtkTooltip  *tooltip,
-                                   const gchar *icon_name,
-                                   GtkIconSize  size)
+gtk_tooltip_set_icon_from_icon_name (GtkTooltip  *tooltip,
+                                    const gchar *icon_name,
+                                    GtkIconSize  size)
 {
   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
 
@@ -325,15 +425,45 @@ gtk_tooltip_set_icon_from_icon_name(GtkTooltip  *tooltip,
     gtk_widget_hide (tooltip->image);
 }
 
+/**
+ * gtk_tooltip_set_icon_from_gicon:
+ * @tooltip: a #GtkTooltip
+ * @gicon: (allow-none): a #GIcon representing the icon, or %NULL
+ * @size: (type int): a stock icon size
+ *
+ * Sets the icon of the tooltip (which is in front of the text)
+ * to be the icon indicated by @gicon with the size indicated
+ * by @size. If @gicon is %NULL, the image will be hidden.
+ *
+ * Since: 2.20
+ */
+void
+gtk_tooltip_set_icon_from_gicon (GtkTooltip  *tooltip,
+                                GIcon       *gicon,
+                                GtkIconSize  size)
+{
+  g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
+
+  gtk_image_set_from_gicon (GTK_IMAGE (tooltip->image), gicon, size);
+
+  if (gicon)
+    gtk_widget_show (tooltip->image);
+  else
+    gtk_widget_hide (tooltip->image);
+}
+
 /**
  * gtk_tooltip_set_custom:
  * @tooltip: a #GtkTooltip
- * @custom_widget: a #GtkWidget
+ * @custom_widget: (allow-none): a #GtkWidget, or %NULL to unset the old custom widget.
  *
- * Replaces the widget packed into the tooltip with @custom_widget.  
+ * Replaces the widget packed into the tooltip with
+ * @custom_widget. @custom_widget does not get destroyed when the tooltip goes
+ * away.
  * By default a box with a #GtkImage and #GtkLabel is embedded in 
  * the tooltip, which can be configured using gtk_tooltip_set_markup() 
  * and gtk_tooltip_set_icon().
+
  *
  * Since: 2.12
  */
@@ -345,6 +475,15 @@ gtk_tooltip_set_custom (GtkTooltip *tooltip,
   if (custom_widget)
     g_return_if_fail (GTK_IS_WIDGET (custom_widget));
 
+  /* The custom widget has been updated from the query-tooltip
+   * callback, so we do not want to reset the custom widget later on.
+   */
+  tooltip->custom_was_reset = TRUE;
+
+  /* No need to do anything if the custom widget stays the same */
+  if (tooltip->custom_widget == custom_widget)
+    return;
+
   if (tooltip->custom_widget)
     {
       GtkWidget *custom = tooltip->custom_widget;
@@ -383,8 +522,8 @@ gtk_tooltip_set_custom (GtkTooltip *tooltip,
  * Since: 2.12
  */
 void
-gtk_tooltip_set_tip_area (GtkTooltip   *tooltip,
-                         GdkRectangle *rect)
+gtk_tooltip_set_tip_area (GtkTooltip         *tooltip,
+                         const GdkRectangle *rect)
 {
   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
 
@@ -414,9 +553,11 @@ gtk_tooltip_trigger_tooltip_query (GdkDisplay *display)
   gint x, y;
   GdkWindow *window;
   GdkEvent event;
+  GdkDevice *device;
 
   /* Trigger logic as if the mouse moved */
-  window = gdk_display_get_window_at_pointer (display, &x, &y);
+  device = gdk_device_manager_get_client_pointer (gdk_display_get_device_manager (display));
+  window = gdk_device_get_window_at_position (device, &x, &y);
   if (!window)
     return;
 
@@ -426,6 +567,10 @@ gtk_tooltip_trigger_tooltip_query (GdkDisplay *display)
   event.motion.y = y;
   event.motion.is_hint = FALSE;
 
+  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);
 }
 
@@ -436,35 +581,92 @@ gtk_tooltip_reset (GtkTooltip *tooltip)
 {
   gtk_tooltip_set_markup (tooltip, NULL);
   gtk_tooltip_set_icon (tooltip, NULL);
-  gtk_tooltip_set_custom (tooltip, NULL);
   gtk_tooltip_set_tip_area (tooltip, NULL);
+
+  /* See if the custom widget is again set from the query-tooltip
+   * callback.
+   */
+  tooltip->custom_was_reset = FALSE;
 }
 
 static void
-gtk_tooltip_window_style_set (GtkTooltip *tooltip)
+paint_background_and_frame (GtkTooltip *tooltip,
+                            cairo_t *cr)
 {
-  gtk_alignment_set_padding (GTK_ALIGNMENT (tooltip->alignment),
-                            tooltip->window->style->ythickness,
-                            tooltip->window->style->ythickness,
-                            tooltip->window->style->xthickness,
-                            tooltip->window->style->xthickness);
+  GtkStyleContext *context;
+  gint width, height;
 
-  gtk_widget_queue_draw (tooltip->window);
+  width = gtk_widget_get_allocated_width (tooltip->window);
+  height = gtk_widget_get_allocated_height (tooltip->window);
+  context = gtk_widget_get_style_context (tooltip->window);
+
+  gtk_render_background (context, cr,
+                         0, 0, width, height);
+  gtk_render_frame (context, cr,
+                    0, 0, width, height);  
+}
+
+static void
+maybe_update_shape (GtkTooltip *tooltip)
+{
+  cairo_t *cr;
+  cairo_surface_t *surface;
+  cairo_region_t *region;
+
+  /* fallback to XShape only for non-composited clients */
+  if (gtk_widget_is_composited (tooltip->window))
+    {
+      gtk_widget_shape_combine_region (tooltip->window, NULL);
+      return;
+    }
+
+  surface = gdk_window_create_similar_surface (gtk_widget_get_window (tooltip->window),
+                                               CAIRO_CONTENT_COLOR_ALPHA,
+                                               gtk_widget_get_allocated_width (tooltip->window),
+                                               gtk_widget_get_allocated_height (tooltip->window));
+
+  cr = cairo_create (surface);
+  paint_background_and_frame (tooltip, cr);
+  cairo_destroy (cr);
+
+  region = gdk_cairo_region_create_from_surface (surface);
+  gtk_widget_shape_combine_region (tooltip->window, region);
+
+  cairo_surface_destroy (surface);
+  cairo_region_destroy (region);
+}
+
+static void
+gtk_tooltip_composited_changed (GtkTooltip *tooltip,
+                                GtkWidget  *widget)
+{
+  if (gtk_widget_get_realized (tooltip->window))
+    maybe_update_shape (tooltip);
+}
+
+static void
+gtk_tooltip_realize_window (GtkTooltip *tooltip,
+                            GtkWidget *widget)
+{
+  maybe_update_shape (tooltip);
 }
 
 static gboolean
-gtk_tooltip_paint_window (GtkTooltip *tooltip)
+gtk_tooltip_paint_window (GtkTooltip *tooltip,
+                          cairo_t    *cr)
 {
-  gtk_paint_flat_box (tooltip->window->style,
-                     tooltip->window->window,
-                     GTK_STATE_NORMAL,
-                     GTK_SHADOW_OUT,
-                     NULL,
-                     tooltip->window,
-                     "tooltip",
-                     0, 0,
-                     tooltip->window->allocation.width,
-                     tooltip->window->allocation.height);
+  if (gtk_widget_is_composited (tooltip->window))
+    {
+      /* clear any background */
+      cairo_save (cr);
+      cairo_set_source_rgba (cr, 0, 0, 0, 0);
+      cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+      cairo_paint (cr);
+      cairo_restore (cr);
+    }
+
+  maybe_update_shape (tooltip);
+  paint_background_and_frame (tooltip, cr);
 
   return FALSE;
 }
@@ -493,13 +695,19 @@ static void
 child_location_foreach (GtkWidget *child,
                        gpointer   data)
 {
+  GtkAllocation child_allocation;
   gint x, y;
   struct ChildLocation *child_loc = data;
 
   /* Ignore invisible widgets */
-  if (!GTK_WIDGET_DRAWABLE (child))
+  if (!gtk_widget_is_drawable (child))
     return;
 
+  gtk_widget_get_allocation (child, &child_allocation);
+
+  x = 0;
+  y = 0;
+
   /* (child_loc->x, child_loc->y) are relative to
    * child_loc->container's allocation.
    */
@@ -512,17 +720,17 @@ child_location_foreach (GtkWidget *child,
 #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_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)
+      if (x >= 0 && x < child_allocation.width
+         && y >= 0 && y < child_allocation.height)
         {
          if (GTK_IS_CONTAINER (child))
            {
@@ -559,22 +767,28 @@ window_to_alloc (GtkWidget *dest_widget,
                 gint      *dest_x,
                 gint      *dest_y)
 {
+  GtkAllocation allocation;
+
+  gtk_widget_get_allocation (dest_widget, &allocation);
+
   /* Translate from window relative to allocation relative */
-  if (!GTK_WIDGET_NO_WINDOW (dest_widget) && dest_widget->parent)
+  if (gtk_widget_get_has_window (dest_widget) &&
+      gtk_widget_get_parent (dest_widget))
     {
       gint wx, wy;
-      gdk_window_get_position (dest_widget->window, &wx, &wy);
+      gdk_window_get_position (gtk_widget_get_window (dest_widget),
+                               &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;
+      src_x += wx - allocation.x;
+      src_y += wy - allocation.y;
     }
   else
     {
-      src_x -= dest_widget->allocation.x;
-      src_y -= dest_widget->allocation.y;
+      src_x -= allocation.x;
+      src_y -= allocation.y;
     }
 
   if (dest_x)
@@ -586,14 +800,18 @@ window_to_alloc (GtkWidget *dest_widget,
 /* 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,
-                          gint      *y)
+GtkWidget *
+_gtk_widget_find_at_coords (GdkWindow *window,
+                            gint       window_x,
+                            gint       window_y,
+                            gint      *widget_x,
+                            gint      *widget_y)
 {
   GtkWidget *event_widget;
   struct ChildLocation child_loc = { NULL, NULL, 0, 0 };
 
+  g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
+
   gdk_window_get_user_data (window, (void **)&event_widget);
 
   if (!event_widget)
@@ -602,26 +820,28 @@ find_widget_under_pointer (GdkWindow *window,
 #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);
+          window_x, window_y);
 #endif
 
   /* Coordinates are relative to event window */
-  child_loc.x = *x;
-  child_loc.y = *y;
+  child_loc.x = window_x;
+  child_loc.y = window_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)
+  while (window && window != gtk_widget_get_window (event_widget))
     {
-      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;
@@ -662,14 +882,13 @@ find_widget_under_pointer (GdkWindow *window,
       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)
-    *y = child_loc.y;
+  if (widget_x)
+    *widget_x = child_loc.x;
+  if (widget_y)
+    *widget_y = child_loc.y;
 
   return event_widget;
 }
@@ -682,23 +901,23 @@ find_topmost_widget_coords_from_event (GdkEvent *event,
                                       gint     *x,
                                       gint     *y)
 {
+  GtkAllocation allocation;
   gint tx, ty;
   gdouble dx, dy;
   GtkWidget *tmp;
 
   gdk_event_get_coords (event, &dx, &dy);
-  tx = dx;
-  ty = dy;
 
   /* Returns coordinates relative to tmp's allocation. */
-  tmp = find_widget_under_pointer (event->any.window, &tx, &ty);
+  tmp = _gtk_widget_find_at_coords (event->any.window, dx, dy, &tx, &ty);
 
   if (!tmp)
     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)
+  gtk_widget_get_allocation (tmp, &allocation);
+  if (tx < 0 || tx >= allocation.width ||
+      ty < 0 || ty >= allocation.height)
     return NULL;
 
   if (x)
@@ -734,6 +953,24 @@ gtk_tooltip_display_closed (GdkDisplay *display,
   g_object_set_data (G_OBJECT (display), "gdk-display-current-tooltip", NULL);
 }
 
+static void
+gtk_tooltip_set_last_window (GtkTooltip *tooltip,
+                            GdkWindow  *window)
+{
+  if (tooltip->last_window == window)
+    return;
+
+  if (tooltip->last_window)
+    g_object_remove_weak_pointer (G_OBJECT (tooltip->last_window),
+                                 (gpointer *) &tooltip->last_window);
+
+  tooltip->last_window = window;
+
+  if (window)
+    g_object_add_weak_pointer (G_OBJECT (tooltip->last_window),
+                              (gpointer *) &tooltip->last_window);
+}
+
 static gboolean
 gtk_tooltip_run_requery (GtkWidget  **widget,
                         GtkTooltip  *tooltip,
@@ -761,7 +998,7 @@ gtk_tooltip_run_requery (GtkWidget  **widget,
 
       if (!return_value)
         {
-         GtkWidget *parent = (*widget)->parent;
+         GtkWidget *parent = gtk_widget_get_parent (*widget);
 
          if (parent)
            gtk_widget_translate_coordinates (*widget, parent, *x, *y, x, y);
@@ -773,82 +1010,215 @@ gtk_tooltip_run_requery (GtkWidget  **widget,
     }
   while (*widget);
 
+  /* If the custom widget was not reset in the query-tooltip
+   * callback, we clear it here.
+   */
+  if (!tooltip->custom_was_reset)
+    gtk_tooltip_set_custom (tooltip, NULL);
+
   return return_value;
 }
 
+static void
+get_bounding_box (GtkWidget    *widget,
+                  GdkRectangle *bounds)
+{
+  GtkAllocation allocation;
+  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);
+  if (window == NULL)
+    window = gtk_widget_get_window (widget);
+
+  gtk_widget_get_allocation (widget, &allocation);
+  x = allocation.x;
+  y = allocation.y;
+  w = allocation.width;
+  h = 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,
                      GtkWidget  *new_tooltip_widget)
 {
-  gint x, y;
+  gint x, y, width, height;
   GdkScreen *screen;
+  gint monitor_num;
+  GdkRectangle monitor;
+  guint cursor_size;
+  GdkRectangle bounds;
+
+#define MAX_DISTANCE 32
+
+  gtk_widget_realize (GTK_WIDGET (tooltip->current_window));
 
   tooltip->tooltip_widget = new_tooltip_widget;
 
+  screen = gtk_widget_get_screen (new_tooltip_widget);
+
+  width = gtk_widget_get_allocated_width (GTK_WIDGET (tooltip->current_window));
+  height = gtk_widget_get_allocated_height (GTK_WIDGET (tooltip->current_window));
+
+  monitor_num = gdk_screen_get_monitor_at_point (screen,
+                                                 tooltip->last_x,
+                                                 tooltip->last_y);
+  gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
+
+  get_bounding_box (new_tooltip_widget, &bounds);
+
   /* Position the tooltip */
-  /* FIXME: should we swap this when RTL is enabled? */
-  if (tooltip->keyboard_mode_enabled)
+
+  cursor_size = gdk_display_get_default_cursor_size (display);
+
+  /* Try below */
+  x = bounds.x + bounds.width / 2 - width / 2;
+  y = bounds.y + bounds.height + 4;
+
+  if (y + height <= monitor.y + monitor.height)
     {
-      gdk_window_get_origin (new_tooltip_widget->window, &x, &y);
-      if (GTK_WIDGET_NO_WINDOW (new_tooltip_widget))
+      if (tooltip->keyboard_mode_enabled)
+        goto found;
+
+      if (y <= tooltip->last_y + cursor_size + MAX_DISTANCE)
         {
-         x += new_tooltip_widget->allocation.x;
-         y += new_tooltip_widget->allocation.y;
-       }
+          if (tooltip->last_x + cursor_size + MAX_DISTANCE < x)
+            x = tooltip->last_x + cursor_size + MAX_DISTANCE;
+          else if (x + width < tooltip->last_x - MAX_DISTANCE)
+            x = tooltip->last_x - MAX_DISTANCE - width;
 
-      /* 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;
+          goto found;
+        }
+   }
+
+  /* Try above */
+  x = bounds.x + bounds.width / 2 - width / 2;
+  y = bounds.y - height - 4;
+
+  if (y >= monitor.y)
+    {
+      if (tooltip->keyboard_mode_enabled)
+        goto found;
+
+      if (y + height >= tooltip->last_y - MAX_DISTANCE)
+        {
+          if (tooltip->last_x + cursor_size + MAX_DISTANCE < x)
+            x = tooltip->last_x + cursor_size + MAX_DISTANCE;
+          else if (x + width < tooltip->last_x - MAX_DISTANCE)
+            x = tooltip->last_x - MAX_DISTANCE - width;
+
+          goto found;
+        }
     }
-  else
+
+  /* Try right FIXME: flip on rtl ? */
+  x = bounds.x + bounds.width + 4;
+  y = bounds.y + bounds.height / 2 - height / 2;
+
+  if (x + width <= monitor.x + monitor.width)
     {
-      guint cursor_size;
+      if (tooltip->keyboard_mode_enabled)
+        goto found;
 
-      x = tooltip->last_x;
-      y = tooltip->last_y;
+      if (x <= tooltip->last_x + cursor_size + MAX_DISTANCE)
+        {
+          if (tooltip->last_y + cursor_size + MAX_DISTANCE < y)
+            y = tooltip->last_y + cursor_size + MAX_DISTANCE;
+          else if (y + height < tooltip->last_y - MAX_DISTANCE)
+            y = tooltip->last_y - MAX_DISTANCE - height;
 
-      /* For mouse mode, we position the tooltip right of the cursor,
-       * a little below the cursor's center.
-       */
-      cursor_size = gdk_display_get_default_cursor_size (display);
-      x += cursor_size / 2;
-      y += cursor_size / 2;
+          goto found;
+        }
     }
 
-  screen = gtk_widget_get_screen (new_tooltip_widget);
+  /* Try left FIXME: flip on rtl ? */
+  x = bounds.x - width - 4;
+  y = bounds.y + bounds.height / 2 - height / 2;
 
-  /* Show it */
-  if (tooltip->current_window)
+  if (x >= monitor.x)
     {
-      gint monitor_num;
-      GdkRectangle monitor;
-      GtkRequisition requisition;
+      if (tooltip->keyboard_mode_enabled)
+        goto found;
+
+      if (x + width >= tooltip->last_x - MAX_DISTANCE)
+        {
+          if (tooltip->last_y + cursor_size + MAX_DISTANCE < y)
+            y = tooltip->last_y + cursor_size + MAX_DISTANCE;
+          else if (y + height < tooltip->last_y - MAX_DISTANCE)
+            y = tooltip->last_y - MAX_DISTANCE - height;
 
-      gtk_widget_size_request (GTK_WIDGET (tooltip->current_window),
-                               &requisition);
+          goto found;
+        }
+    }
 
-      monitor_num = gdk_screen_get_monitor_at_point (screen, x, y);
-      gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
+   /* Fallback */
+  if (tooltip->keyboard_mode_enabled)
+    {
+      x = bounds.x + bounds.width / 2 - width / 2;
+      y = bounds.y + bounds.height + 4;
+    }
+  else
+    {
+      /* At cursor */
+      x = tooltip->last_x + cursor_size * 3 / 4;
+      y = tooltip->last_y + cursor_size * 3 / 4;
+    }
 
-      if (x + requisition.width > monitor.x + monitor.width)
-        x -= x - (monitor.x + monitor.width) + requisition.width;
+found:
+  /* Show it */
+  if (tooltip->current_window)
+    {
+      if (x + width > monitor.x + monitor.width)
+        x -= x - (monitor.x + monitor.width) + width;
       else if (x < monitor.x)
         x = monitor.x;
 
-      if (y + requisition.height > monitor.y + monitor.height)
-        y -= y - (monitor.y + monitor.height) + requisition.height;
-  
+      if (y + height > monitor.y + monitor.height)
+        y -= y - (monitor.y + monitor.height) + height;
+      else if (y < monitor.y)
+        y = monitor.y;
+
       if (!tooltip->keyboard_mode_enabled)
         {
           /* don't pop up under the pointer */
-          if (x <= tooltip->last_x && tooltip->last_x < x + requisition.width &&
-              y <= tooltip->last_y && tooltip->last_y < y + requisition.height)
-            y = tooltip->last_y - requisition.height - 2;
+          if (x <= tooltip->last_x && tooltip->last_x < x + width &&
+              y <= tooltip->last_y && tooltip->last_y < y + height)
+            y = tooltip->last_y - height - 2;
         }
-  
+
+#ifdef GDK_WINDOWING_WAYLAND
+      /* set the transient parent on the tooltip when running with the Wayland
+       * backend to allow correct positioning of the tooltip windows */
+      if (GDK_IS_WAYLAND_DISPLAY (display))
+        {
+          GtkWidget *toplevel;
+
+          toplevel = gtk_widget_get_toplevel (tooltip->tooltip_widget);
+          if (GTK_IS_WINDOW (toplevel))
+            gtk_window_set_transient_for (GTK_WINDOW (tooltip->current_window),
+                                          GTK_WINDOW (toplevel));
+        }
+#endif
+
       gtk_window_move (GTK_WINDOW (tooltip->current_window), x, y);
       gtk_widget_show (GTK_WIDGET (tooltip->current_window));
     }
@@ -862,31 +1232,37 @@ gtk_tooltip_show_tooltip (GdkDisplay *display)
 
   GdkWindow *window;
   GtkWidget *tooltip_widget;
-  GtkWidget *pointer_widget;
   GtkTooltip *tooltip;
   gboolean has_tooltip;
   gboolean return_value = FALSE;
 
   tooltip = g_object_get_data (G_OBJECT (display),
-                              "gdk-display-current-tooltip");
+                               "gdk-display-current-tooltip");
 
   if (tooltip->keyboard_mode_enabled)
     {
-      pointer_widget = tooltip_widget = tooltip->keyboard_widget;
+      x = y = -1;
+      tooltip_widget = tooltip->keyboard_widget;
     }
   else
     {
+      GdkDevice *device;
+      gint tx, ty;
+
       window = tooltip->last_window;
 
       if (!GDK_IS_WINDOW (window))
-       return;
+        return;
+
+      device = gdk_device_manager_get_client_pointer (gdk_display_get_device_manager (display));
+
+      gdk_window_get_device_position (window, device, &x, &y, NULL);
 
-      gdk_window_get_origin (window, &x, &y);
-      x = tooltip->last_x - x;
-      y = tooltip->last_y - y;
+      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);
+      tooltip_widget = _gtk_widget_find_at_coords (window, x, y, &x, &y);
     }
 
   if (!tooltip_widget)
@@ -894,8 +1270,6 @@ gtk_tooltip_show_tooltip (GdkDisplay *display)
 
   g_object_get (tooltip_widget, "has-tooltip", &has_tooltip, NULL);
 
-  g_assert (tooltip != NULL);
-
   return_value = gtk_tooltip_run_requery (&tooltip_widget, tooltip, &x, &y);
   if (!return_value)
     return;
@@ -903,9 +1277,9 @@ gtk_tooltip_show_tooltip (GdkDisplay *display)
   if (!tooltip->current_window)
     {
       if (gtk_widget_get_tooltip_window (tooltip_widget))
-       tooltip->current_window = gtk_widget_get_tooltip_window (tooltip_widget);
+        tooltip->current_window = gtk_widget_get_tooltip_window (tooltip_widget);
       else
-       tooltip->current_window = GTK_WINDOW (GTK_TOOLTIP (tooltip)->window);
+        tooltip->current_window = GTK_WINDOW (GTK_TOOLTIP (tooltip)->window);
     }
 
   screen = gtk_widget_get_screen (tooltip_widget);
@@ -914,13 +1288,13 @@ gtk_tooltip_show_tooltip (GdkDisplay *display)
   if (screen != gtk_widget_get_screen (tooltip->window))
     {
       g_signal_handlers_disconnect_by_func (display,
-                                           gtk_tooltip_display_closed,
-                                           tooltip);
+                                            gtk_tooltip_display_closed,
+                                            tooltip);
 
       gtk_window_set_screen (GTK_WINDOW (tooltip->window), screen);
 
       g_signal_connect (display, "closed",
-                       G_CALLBACK (gtk_tooltip_display_closed), tooltip);
+                        G_CALLBACK (gtk_tooltip_display_closed), tooltip);
     }
 
   gtk_tooltip_position (tooltip, display, tooltip_widget);
@@ -996,12 +1370,18 @@ tooltip_popup_timeout (gpointer data)
   GdkDisplay *display;
   GtkTooltip *tooltip;
 
-  display = GDK_DISPLAY_OBJECT (data);
+  display = GDK_DISPLAY (data);
+  tooltip = g_object_get_data (G_OBJECT (display),
+                              "gdk-display-current-tooltip");
+
+  /* This usually does not happen.  However, it does occur in language
+   * bindings were reference counting of objects behaves differently.
+   */
+  if (!tooltip)
+    return FALSE;
 
   gtk_tooltip_show_tooltip (display);
 
-  tooltip = g_object_get_data (G_OBJECT (display),
-                              "gdk-display-current-tooltip");
   tooltip->timeout_id = 0;
 
   return FALSE;
@@ -1017,7 +1397,7 @@ gtk_tooltip_start_delay (GdkDisplay *display)
   tooltip = g_object_get_data (G_OBJECT (display),
                               "gdk-display-current-tooltip");
 
-  if (tooltip && GTK_TOOLTIP_VISIBLE (tooltip))
+  if (!tooltip || GTK_TOOLTIP_VISIBLE (tooltip))
     return;
 
   if (tooltip->timeout_id)
@@ -1043,6 +1423,7 @@ _gtk_tooltip_focus_in (GtkWidget *widget)
   gboolean return_value = FALSE;
   GdkDisplay *display;
   GtkTooltip *tooltip;
+  GdkDevice *device;
 
   /* Get current tooltip for this display */
   display = gtk_widget_get_display (widget);
@@ -1053,12 +1434,24 @@ _gtk_tooltip_focus_in (GtkWidget *widget)
   if (!tooltip || !tooltip->keyboard_mode_enabled)
     return;
 
+  device = gtk_get_current_event_device ();
+
+  if (device && gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
+    device = gdk_device_get_associated_device (device);
+
+  /* This function should be called by either a focus in event,
+   * or a key binding. In either case there should be a device.
+   */
+  if (!device)
+    return;
+
   if (tooltip->keyboard_widget)
     g_object_unref (tooltip->keyboard_widget);
 
   tooltip->keyboard_widget = g_object_ref (widget);
 
-  gdk_window_get_pointer (widget->window, &x, &y, NULL);
+  gdk_window_get_device_position (gtk_widget_get_window (widget),
+                                  device, &x, &y, NULL);
 
   return_value = gtk_tooltip_run_requery (&widget, tooltip, &x, &y);
   if (!return_value)
@@ -1158,42 +1551,61 @@ _gtk_tooltip_hide (GtkWidget *widget)
   toplevel = gtk_widget_get_toplevel (widget);
 
   if (widget == tooltip->tooltip_widget
-      || toplevel->window == tooltip->toplevel_window)
+      || gtk_widget_get_window (toplevel) == tooltip->toplevel_window)
     gtk_tooltip_hide_tooltip (tooltip);
 }
 
+static gboolean
+tooltips_enabled (GdkEvent *event)
+{
+  GdkDevice *source_device;
+  GdkInputSource source;
+  GdkWindow *window;
+  gboolean enabled;
+  GdkScreen *screen;
+  GtkSettings *settings;
+
+  window = event->any.window;
+  source_device = gdk_event_get_source_device (event);
+
+  if (!source_device)
+    return FALSE;
+
+  source = gdk_device_get_source (source_device);
+  screen = gdk_window_get_screen (window);
+  settings = gtk_settings_get_for_screen (screen);
+
+  g_object_get (settings,
+               "gtk-enable-tooltips", &enabled,
+               NULL);
+
+  if (enabled && source != GDK_SOURCE_TOUCHSCREEN)
+    return TRUE;
+
+  return FALSE;
+}
+
 void
 _gtk_tooltip_handle_event (GdkEvent *event)
 {
   gint x, y;
   gboolean return_value = FALSE;
-  gboolean touchscreen;
   GtkWidget *has_tooltip_widget = NULL;
-  GdkScreen *screen;
   GdkDisplay *display;
   GtkTooltip *current_tooltip;
-  GtkSettings *settings;
 
-  /* Disable tooltips in touchscreen mode */
-  screen = gdk_drawable_get_screen (event->any.window);
-  settings = gtk_settings_get_for_screen (screen);
-  g_object_get (settings, "gtk-touchscreen-mode", &touchscreen, NULL);
-
-  if (touchscreen)
+  if (!tooltips_enabled (event))
     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);
+  display = gdk_window_get_display (event->any.window);
   current_tooltip = g_object_get_data (G_OBJECT (display),
                                       "gdk-display-current-tooltip");
 
   if (current_tooltip)
     {
-      current_tooltip->last_window = event->any.window;
-      gdk_event_get_root_coords (event,
-                               &current_tooltip->last_x,
-                               &current_tooltip->last_y);
+      gtk_tooltip_set_last_window (current_tooltip, event->any.window);
     }
 
   if (current_tooltip && current_tooltip->keyboard_mode_enabled)
@@ -1245,13 +1657,13 @@ _gtk_tooltip_handle_event (GdkEvent *event)
       case GDK_KEY_PRESS:
       case GDK_DRAG_ENTER:
       case GDK_GRAB_BROKEN:
+      case GDK_SCROLL:
        gtk_tooltip_hide_tooltip (current_tooltip);
        break;
 
       case GDK_MOTION_NOTIFY:
       case GDK_ENTER_NOTIFY:
       case GDK_LEAVE_NOTIFY:
-      case GDK_SCROLL:
        if (current_tooltip)
          {
            gboolean tip_area_set;
@@ -1298,10 +1710,7 @@ _gtk_tooltip_handle_event (GdkEvent *event)
                              G_CALLBACK (gtk_tooltip_display_closed),
                              current_tooltip);
 
-           current_tooltip->last_window = event->any.window;
-           gdk_event_get_root_coords (event,
-                                      &current_tooltip->last_x,
-                                      &current_tooltip->last_y);
+           gtk_tooltip_set_last_window (current_tooltip, event->any.window);
 
            gtk_tooltip_start_delay (display);
          }
@@ -1311,7 +1720,3 @@ _gtk_tooltip_handle_event (GdkEvent *event)
        break;
     }
 }
-
-
-#define __GTK_TOOLTIP_C__
-#include "gtkaliasdef.c"