]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtktooltip.c
Deprecate widget flag: GTK_WIDGET_VISIBLE
[~andy/gtk] / gtk / gtktooltip.c
index c6062053ae23f9d55fd27a1f29c06f52addda2a1..87871e885cdf2f014c91ad80ca11ba892577fcc4 100644 (file)
@@ -19,7 +19,7 @@
  * Boston, MA 02111-1307, USA.
  */
 
-#include <config.h>
+#include "config.h"
 #include "gtktooltip.h"
 #include "gtkintl.h"
 #include "gtkwindow.h"
@@ -33,6 +33,8 @@
 
 #include <string.h>
 
+#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))
@@ -69,6 +71,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
@@ -76,19 +79,22 @@ 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_dispose              (GObject         *object);
 
+static void       gtk_tooltip_window_style_set     (GtkTooltip      *tooltip);
 static gboolean   gtk_tooltip_paint_window         (GtkTooltip      *tooltip);
 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);
@@ -100,7 +106,7 @@ 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
@@ -138,7 +144,9 @@ gtk_tooltip_init (GtkTooltip *tooltip)
   gtk_container_add (GTK_CONTAINER (tooltip->window), tooltip->alignment);
   gtk_widget_show (tooltip->alignment);
 
-  g_signal_connect_swapped (tooltip->window, "expose_event",
+  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);
@@ -150,6 +158,7 @@ gtk_tooltip_init (GtkTooltip *tooltip)
                      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);
 
@@ -157,7 +166,7 @@ gtk_tooltip_init (GtkTooltip *tooltip)
 }
 
 static void
-gtk_tooltip_finalize (GObject *object)
+gtk_tooltip_dispose (GObject *object)
 {
   GtkTooltip *tooltip = GTK_TOOLTIP (object);
 
@@ -173,6 +182,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;
@@ -182,9 +194,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 */
@@ -192,7 +205,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
@@ -218,7 +231,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().
@@ -242,7 +255,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.
@@ -268,8 +281,8 @@ gtk_tooltip_set_icon (GtkTooltip *tooltip,
 /**
  * gtk_tooltip_set_icon_from_stock:
  * @tooltip: a #GtkTooltip
- * @stock_id: a stock icon name, 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
@@ -292,15 +305,72 @@ gtk_tooltip_set_icon_from_stock (GtkTooltip  *tooltip,
     gtk_widget_hide (tooltip->image);
 }
 
+/**
+ * gtk_tooltip_set_icon_from_icon_name:
+ * @tooltip: a #GtkTooltip
+ * @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.14
+ */
+void
+gtk_tooltip_set_icon_from_icon_name (GtkTooltip  *tooltip,
+                                    const gchar *icon_name,
+                                    GtkIconSize  size)
+{
+  g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
+
+  gtk_image_set_from_icon_name (GTK_IMAGE (tooltip->image), icon_name, size);
+
+  if (icon_name)
+    gtk_widget_show (tooltip->image);
+  else
+    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
  */
@@ -312,11 +382,25 @@ 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)
     {
-      gtk_container_remove (GTK_CONTAINER (tooltip->box),
-                           tooltip->custom_widget);
-      g_object_unref (tooltip->custom_widget);
+      GtkWidget *custom = tooltip->custom_widget;
+      /* Note: We must reset tooltip->custom_widget first, 
+       * since gtk_container_remove() will recurse into 
+       * gtk_tooltip_set_custom()
+       */
+      tooltip->custom_widget = NULL;
+      gtk_container_remove (GTK_CONTAINER (tooltip->box), custom);
+      g_object_unref (custom);
     }
 
   if (custom_widget)
@@ -326,8 +410,6 @@ gtk_tooltip_set_custom (GtkTooltip *tooltip,
       gtk_container_add (GTK_CONTAINER (tooltip->box), custom_widget);
       gtk_widget_show (custom_widget);
     }
-  else
-    tooltip->custom_widget = NULL;
 }
 
 /**
@@ -347,8 +429,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));
 
@@ -390,6 +472,10 @@ 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;
+
   _gtk_tooltip_handle_event (&event);
 }
 
@@ -400,8 +486,26 @@ 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)
+{
+  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_box_set_spacing (GTK_BOX (tooltip->box),
+                      tooltip->window->style->xthickness);
+
+  gtk_widget_queue_draw (tooltip->window);
 }
 
 static gboolean
@@ -427,8 +531,7 @@ gtk_tooltip_window_hide (GtkWidget *widget,
 {
   GtkTooltip *tooltip = GTK_TOOLTIP (user_data);
 
-  if (tooltip->custom_widget)
-    gtk_tooltip_set_custom (tooltip, NULL);
+  gtk_tooltip_set_custom (tooltip, NULL);
 }
 
 /* event handling, etc */
@@ -450,14 +553,33 @@ child_location_foreach (GtkWidget *child,
   struct ChildLocation *child_loc = data;
 
   /* Ignore invisible widgets */
-  if (!GTK_WIDGET_DRAWABLE (child))
+  if (!gtk_widget_is_drawable (child))
     return;
 
+  x = 0;
+  y = 0;
+
+  /* (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)
         {
@@ -465,6 +587,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;
@@ -483,6 +608,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,
@@ -491,11 +619,14 @@ window_to_alloc (GtkWidget *dest_widget,
                 gint      *dest_y)
 {
   /* 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) && dest_widget->parent)
     {
       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;
     }
@@ -511,6 +642,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,
@@ -524,9 +658,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;
@@ -538,12 +683,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.
@@ -552,11 +691,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;
@@ -564,12 +708,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)
@@ -578,6 +733,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,
@@ -591,11 +749,14 @@ 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);
 
-  /* Make sure the pointer can actually be on the widget returned */
-  if (!tmp ||
-      tx < 0 || tx >= tmp->allocation.width ||
+  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)
     return NULL;
 
@@ -629,7 +790,25 @@ gtk_tooltip_display_closed (GdkDisplay *display,
                            gboolean    was_error,
                            GtkTooltip *tooltip)
 {
-  g_object_set (display, "gdk-display-current-tooltip", NULL);
+  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
@@ -671,6 +850,12 @@ 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;
 }
 
@@ -689,7 +874,7 @@ gtk_tooltip_position (GtkTooltip *tooltip,
   if (tooltip->keyboard_mode_enabled)
     {
       gdk_window_get_origin (new_tooltip_widget->window, &x, &y);
-      if (GTK_WIDGET_NO_WINDOW (new_tooltip_widget))
+      if (!gtk_widget_get_has_window (new_tooltip_widget))
         {
          x += new_tooltip_widget->allocation.x;
          y += new_tooltip_widget->allocation.y;
@@ -738,7 +923,15 @@ gtk_tooltip_position (GtkTooltip *tooltip,
 
       if (y + requisition.height > monitor.y + monitor.height)
         y -= y - (monitor.y + monitor.height) + requisition.height;
-
+  
+      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;
+        }
+  
       gtk_window_move (GTK_WINDOW (tooltip->current_window), x, y);
       gtk_widget_show (GTK_WIDGET (tooltip->current_window));
     }
@@ -762,6 +955,7 @@ gtk_tooltip_show_tooltip (GdkDisplay *display)
 
   if (tooltip->keyboard_mode_enabled)
     {
+      x = y = -1;
       pointer_widget = tooltip_widget = tooltip->keyboard_widget;
     }
   else
@@ -784,8 +978,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;
@@ -887,11 +1079,17 @@ tooltip_popup_timeout (gpointer data)
   GtkTooltip *tooltip;
 
   display = GDK_DISPLAY_OBJECT (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;
@@ -907,7 +1105,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)
@@ -1007,6 +1205,9 @@ _gtk_tooltip_toggle_keyboard_mode (GtkWidget *widget)
       g_object_set_data_full (G_OBJECT (display),
                              "gdk-display-current-tooltip",
                              tooltip, g_object_unref);
+      g_signal_connect (display, "closed",
+                       G_CALLBACK (gtk_tooltip_display_closed),
+                       tooltip);
     }
 
   tooltip->keyboard_mode_enabled ^= 1;
@@ -1049,6 +1250,25 @@ _gtk_tooltip_hide (GtkWidget *widget)
     gtk_tooltip_hide_tooltip (tooltip);
 }
 
+static gboolean
+tooltips_enabled (GdkWindow *window)
+{
+  gboolean enabled;
+  gboolean touchscreen;
+  GdkScreen *screen;
+  GtkSettings *settings;
+
+  screen = gdk_drawable_get_screen (window);
+  settings = gtk_settings_get_for_screen (screen);
+
+  g_object_get (settings,
+               "gtk-touchscreen-mode", &touchscreen,
+               "gtk-enable-tooltips", &enabled,
+               NULL);
+
+  return (!touchscreen && enabled);
+}
+
 void
 _gtk_tooltip_handle_event (GdkEvent *event)
 {
@@ -1058,6 +1278,10 @@ _gtk_tooltip_handle_event (GdkEvent *event)
   GdkDisplay *display;
   GtkTooltip *current_tooltip;
 
+  if (!tooltips_enabled (event->any.window))
+    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),
@@ -1065,7 +1289,7 @@ _gtk_tooltip_handle_event (GdkEvent *event)
 
   if (current_tooltip)
     {
-      current_tooltip->last_window = event->any.window;
+      gtk_tooltip_set_last_window (current_tooltip, event->any.window);
       gdk_event_get_root_coords (event,
                                &current_tooltip->last_x,
                                &current_tooltip->last_y);
@@ -1089,13 +1313,24 @@ _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);
 
   /* Hide the tooltip when there's no new tooltip widget */
   if (!has_tooltip_widget)
     {
-      if (current_tooltip && GTK_TOOLTIP_VISIBLE (current_tooltip))
+      if (current_tooltip)
        gtk_tooltip_hide_tooltip (current_tooltip);
 
       return;
@@ -1132,6 +1367,9 @@ _gtk_tooltip_handle_event (GdkEvent *event)
            /* Requested to be hidden? */
            hide_tooltip = !return_value;
 
+           /* Leave notify should override the query function */
+           hide_tooltip = (event->type == GDK_LEAVE_NOTIFY);
+
            /* Is the pointer above another widget now? */
            if (GTK_TOOLTIP_VISIBLE (current_tooltip))
              hide_tooltip |= has_tooltip_widget != current_tooltip->tooltip_widget;
@@ -1155,8 +1393,11 @@ _gtk_tooltip_handle_event (GdkEvent *event)
            g_object_set_data_full (G_OBJECT (display),
                                    "gdk-display-current-tooltip",
                                    current_tooltip, g_object_unref);
+           g_signal_connect (display, "closed",
+                             G_CALLBACK (gtk_tooltip_display_closed),
+                             current_tooltip);
 
-           current_tooltip->last_window = event->any.window;
+           gtk_tooltip_set_last_window (current_tooltip, event->any.window);
            gdk_event_get_root_coords (event,
                                       &current_tooltip->last_x,
                                       &current_tooltip->last_y);