]> Pileus Git - ~andy/gtk/blob - gtk/gtktooltip.c
Merge the xi2-for-master branch
[~andy/gtk] / gtk / gtktooltip.c
1 /* gtktooltip.c
2  *
3  * Copyright (C) 2006-2007 Imendio AB
4  * Contact: Kristian Rietveld <kris@imendio.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #include "config.h"
23
24 #include <math.h>
25 #include <string.h>
26
27 #include "gtktooltip.h"
28 #include "gtkintl.h"
29 #include "gtkwindow.h"
30 #include "gtkmain.h"
31 #include "gtklabel.h"
32 #include "gtkimage.h"
33 #include "gtkhbox.h"
34 #include "gtkalignment.h"
35
36 #include "gtkalias.h"
37
38 #undef DEBUG_TOOLTIP
39
40
41 #define GTK_TOOLTIP_CLASS(klass)         (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_TOOLTIP, GtkTooltipClass))
42 #define GTK_IS_TOOLTIP_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_TOOLTIP))
43 #define GTK_TOOLTIP_GET_CLASS(obj)       (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_TOOLTIP, GtkTooltipClass))
44
45 typedef struct _GtkTooltipClass   GtkTooltipClass;
46
47 struct _GtkTooltip
48 {
49   GObject parent_instance;
50
51   GtkWidget *window;
52   GtkWidget *alignment;
53   GtkWidget *box;
54   GtkWidget *image;
55   GtkWidget *label;
56   GtkWidget *custom_widget;
57
58   GtkWindow *current_window;
59   GtkWidget *keyboard_widget;
60
61   GtkWidget *tooltip_widget;
62   GdkWindow *toplevel_window;
63
64   gdouble last_x;
65   gdouble last_y;
66   GdkWindow *last_window;
67
68   guint timeout_id;
69   guint browse_mode_timeout_id;
70
71   GdkRectangle tip_area;
72
73   guint browse_mode_enabled : 1;
74   guint keyboard_mode_enabled : 1;
75   guint tip_area_set : 1;
76   guint custom_was_reset : 1;
77 };
78
79 struct _GtkTooltipClass
80 {
81   GObjectClass parent_class;
82 };
83
84 #define GTK_TOOLTIP_VISIBLE(tooltip) ((tooltip)->current_window && gtk_widget_get_visible (GTK_WIDGET((tooltip)->current_window)))
85
86
87 static void       gtk_tooltip_class_init           (GtkTooltipClass *klass);
88 static void       gtk_tooltip_init                 (GtkTooltip      *tooltip);
89 static void       gtk_tooltip_dispose              (GObject         *object);
90
91 static void       gtk_tooltip_window_style_set     (GtkTooltip      *tooltip);
92 static gboolean   gtk_tooltip_paint_window         (GtkTooltip      *tooltip);
93 static void       gtk_tooltip_window_hide          (GtkWidget       *widget,
94                                                     gpointer         user_data);
95 static void       gtk_tooltip_display_closed       (GdkDisplay      *display,
96                                                     gboolean         was_error,
97                                                     GtkTooltip      *tooltip);
98 static void       gtk_tooltip_set_last_window      (GtkTooltip      *tooltip,
99                                                     GdkWindow       *window);
100
101
102 G_DEFINE_TYPE (GtkTooltip, gtk_tooltip, G_TYPE_OBJECT);
103
104 static void
105 gtk_tooltip_class_init (GtkTooltipClass *klass)
106 {
107   GObjectClass *object_class;
108
109   object_class = G_OBJECT_CLASS (klass);
110
111   object_class->dispose = gtk_tooltip_dispose;
112 }
113
114 static void
115 gtk_tooltip_init (GtkTooltip *tooltip)
116 {
117   tooltip->timeout_id = 0;
118   tooltip->browse_mode_timeout_id = 0;
119
120   tooltip->browse_mode_enabled = FALSE;
121   tooltip->keyboard_mode_enabled = FALSE;
122
123   tooltip->current_window = NULL;
124   tooltip->keyboard_widget = NULL;
125
126   tooltip->tooltip_widget = NULL;
127   tooltip->toplevel_window = NULL;
128
129   tooltip->last_window = NULL;
130
131   tooltip->window = g_object_ref (gtk_window_new (GTK_WINDOW_POPUP));
132   gtk_window_set_type_hint (GTK_WINDOW (tooltip->window),
133                             GDK_WINDOW_TYPE_HINT_TOOLTIP);
134   gtk_widget_set_app_paintable (tooltip->window, TRUE);
135   gtk_window_set_resizable (GTK_WINDOW (tooltip->window), FALSE);
136   gtk_widget_set_name (tooltip->window, "gtk-tooltip");
137   g_signal_connect (tooltip->window, "hide",
138                     G_CALLBACK (gtk_tooltip_window_hide), tooltip);
139
140   tooltip->alignment = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
141   gtk_alignment_set_padding (GTK_ALIGNMENT (tooltip->alignment),
142                              tooltip->window->style->ythickness,
143                              tooltip->window->style->ythickness,
144                              tooltip->window->style->xthickness,
145                              tooltip->window->style->xthickness);
146   gtk_container_add (GTK_CONTAINER (tooltip->window), tooltip->alignment);
147   gtk_widget_show (tooltip->alignment);
148
149   g_signal_connect_swapped (tooltip->window, "style-set",
150                             G_CALLBACK (gtk_tooltip_window_style_set), tooltip);
151   g_signal_connect_swapped (tooltip->window, "expose-event",
152                             G_CALLBACK (gtk_tooltip_paint_window), tooltip);
153
154   tooltip->box = gtk_hbox_new (FALSE, tooltip->window->style->xthickness);
155   gtk_container_add (GTK_CONTAINER (tooltip->alignment), tooltip->box);
156   gtk_widget_show (tooltip->box);
157
158   tooltip->image = gtk_image_new ();
159   gtk_box_pack_start (GTK_BOX (tooltip->box), tooltip->image,
160                       FALSE, FALSE, 0);
161
162   tooltip->label = gtk_label_new ("");
163   gtk_label_set_line_wrap (GTK_LABEL (tooltip->label), TRUE);
164   gtk_box_pack_start (GTK_BOX (tooltip->box), tooltip->label,
165                       FALSE, FALSE, 0);
166
167   tooltip->custom_widget = NULL;
168 }
169
170 static void
171 gtk_tooltip_dispose (GObject *object)
172 {
173   GtkTooltip *tooltip = GTK_TOOLTIP (object);
174
175   if (tooltip->timeout_id)
176     {
177       g_source_remove (tooltip->timeout_id);
178       tooltip->timeout_id = 0;
179     }
180
181   if (tooltip->browse_mode_timeout_id)
182     {
183       g_source_remove (tooltip->browse_mode_timeout_id);
184       tooltip->browse_mode_timeout_id = 0;
185     }
186
187   gtk_tooltip_set_custom (tooltip, NULL);
188   gtk_tooltip_set_last_window (tooltip, NULL);
189
190   if (tooltip->window)
191     {
192       GdkDisplay *display;
193
194       display = gtk_widget_get_display (tooltip->window);
195       g_signal_handlers_disconnect_by_func (display,
196                                             gtk_tooltip_display_closed,
197                                             tooltip);
198       gtk_widget_destroy (tooltip->window);
199       tooltip->window = NULL;
200     }
201
202   G_OBJECT_CLASS (gtk_tooltip_parent_class)->dispose (object);
203 }
204
205 /* public API */
206
207 /**
208  * gtk_tooltip_set_markup:
209  * @tooltip: a #GtkTooltip
210  * @markup: (allow-none): a markup string (see <link linkend="PangoMarkupFormat">Pango markup format</link>) or %NULL
211  *
212  * Sets the text of the tooltip to be @markup, which is marked up
213  * with the <link
214  * linkend="PangoMarkupFormat">Pango text markup language</link>.
215  * If @markup is %NULL, the label will be hidden.
216  *
217  * Since: 2.12
218  */
219 void
220 gtk_tooltip_set_markup (GtkTooltip  *tooltip,
221                         const gchar *markup)
222 {
223   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
224
225   gtk_label_set_markup (GTK_LABEL (tooltip->label), markup);
226
227   if (markup)
228     gtk_widget_show (tooltip->label);
229   else
230     gtk_widget_hide (tooltip->label);
231 }
232
233 /**
234  * gtk_tooltip_set_text:
235  * @tooltip: a #GtkTooltip
236  * @text: (allow-none): a text string or %NULL
237  *
238  * Sets the text of the tooltip to be @text. If @text is %NULL, the label
239  * will be hidden. See also gtk_tooltip_set_markup().
240  *
241  * Since: 2.12
242  */
243 void
244 gtk_tooltip_set_text (GtkTooltip  *tooltip,
245                       const gchar *text)
246 {
247   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
248
249   gtk_label_set_text (GTK_LABEL (tooltip->label), text);
250
251   if (text)
252     gtk_widget_show (tooltip->label);
253   else
254     gtk_widget_hide (tooltip->label);
255 }
256
257 /**
258  * gtk_tooltip_set_icon:
259  * @tooltip: a #GtkTooltip
260  * @pixbuf: (allow-none): a #GdkPixbuf, or %NULL
261  *
262  * Sets the icon of the tooltip (which is in front of the text) to be
263  * @pixbuf.  If @pixbuf is %NULL, the image will be hidden.
264  *
265  * Since: 2.12
266  */
267 void
268 gtk_tooltip_set_icon (GtkTooltip *tooltip,
269                       GdkPixbuf  *pixbuf)
270 {
271   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
272   if (pixbuf)
273     g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
274
275   gtk_image_set_from_pixbuf (GTK_IMAGE (tooltip->image), pixbuf);
276
277   if (pixbuf)
278     gtk_widget_show (tooltip->image);
279   else
280     gtk_widget_hide (tooltip->image);
281 }
282
283 /**
284  * gtk_tooltip_set_icon_from_stock:
285  * @tooltip: a #GtkTooltip
286  * @stock_id: (allow-none): a stock id, or %NULL
287  * @size: (type int): a stock icon size
288  *
289  * Sets the icon of the tooltip (which is in front of the text) to be
290  * the stock item indicated by @stock_id with the size indicated
291  * by @size.  If @stock_id is %NULL, the image will be hidden.
292  *
293  * Since: 2.12
294  */
295 void
296 gtk_tooltip_set_icon_from_stock (GtkTooltip  *tooltip,
297                                  const gchar *stock_id,
298                                  GtkIconSize  size)
299 {
300   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
301
302   gtk_image_set_from_stock (GTK_IMAGE (tooltip->image), stock_id, size);
303
304   if (stock_id)
305     gtk_widget_show (tooltip->image);
306   else
307     gtk_widget_hide (tooltip->image);
308 }
309
310 /**
311  * gtk_tooltip_set_icon_from_icon_name:
312  * @tooltip: a #GtkTooltip
313  * @icon_name: (allow-none): an icon name, or %NULL
314  * @size: (type int): a stock icon size
315  *
316  * Sets the icon of the tooltip (which is in front of the text) to be
317  * the icon indicated by @icon_name with the size indicated
318  * by @size.  If @icon_name is %NULL, the image will be hidden.
319  *
320  * Since: 2.14
321  */
322 void
323 gtk_tooltip_set_icon_from_icon_name (GtkTooltip  *tooltip,
324                                      const gchar *icon_name,
325                                      GtkIconSize  size)
326 {
327   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
328
329   gtk_image_set_from_icon_name (GTK_IMAGE (tooltip->image), icon_name, size);
330
331   if (icon_name)
332     gtk_widget_show (tooltip->image);
333   else
334     gtk_widget_hide (tooltip->image);
335 }
336
337 /**
338  * gtk_tooltip_set_icon_from_gicon:
339  * @tooltip: a #GtkTooltip
340  * @gicon: (allow-none): a #GIcon representing the icon, or %NULL
341  * @size: (type int): a stock icon size
342  *
343  * Sets the icon of the tooltip (which is in front of the text)
344  * to be the icon indicated by @gicon with the size indicated
345  * by @size. If @gicon is %NULL, the image will be hidden.
346  *
347  * Since: 2.20
348  */
349 void
350 gtk_tooltip_set_icon_from_gicon (GtkTooltip  *tooltip,
351                                  GIcon       *gicon,
352                                  GtkIconSize  size)
353 {
354   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
355
356   gtk_image_set_from_gicon (GTK_IMAGE (tooltip->image), gicon, size);
357
358   if (gicon)
359     gtk_widget_show (tooltip->image);
360   else
361     gtk_widget_hide (tooltip->image);
362 }
363
364 /**
365  * gtk_tooltip_set_custom:
366  * @tooltip: a #GtkTooltip
367  * @custom_widget: (allow-none): a #GtkWidget, or %NULL to unset the old custom widget.
368  *
369  * Replaces the widget packed into the tooltip with
370  * @custom_widget. @custom_widget does not get destroyed when the tooltip goes
371  * away.
372  * By default a box with a #GtkImage and #GtkLabel is embedded in 
373  * the tooltip, which can be configured using gtk_tooltip_set_markup() 
374  * and gtk_tooltip_set_icon().
375
376  *
377  * Since: 2.12
378  */
379 void
380 gtk_tooltip_set_custom (GtkTooltip *tooltip,
381                         GtkWidget  *custom_widget)
382 {
383   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
384   if (custom_widget)
385     g_return_if_fail (GTK_IS_WIDGET (custom_widget));
386
387   /* The custom widget has been updated from the query-tooltip
388    * callback, so we do not want to reset the custom widget later on.
389    */
390   tooltip->custom_was_reset = TRUE;
391
392   /* No need to do anything if the custom widget stays the same */
393   if (tooltip->custom_widget == custom_widget)
394     return;
395
396   if (tooltip->custom_widget)
397     {
398       GtkWidget *custom = tooltip->custom_widget;
399       /* Note: We must reset tooltip->custom_widget first, 
400        * since gtk_container_remove() will recurse into 
401        * gtk_tooltip_set_custom()
402        */
403       tooltip->custom_widget = NULL;
404       gtk_container_remove (GTK_CONTAINER (tooltip->box), custom);
405       g_object_unref (custom);
406     }
407
408   if (custom_widget)
409     {
410       tooltip->custom_widget = g_object_ref (custom_widget);
411
412       gtk_container_add (GTK_CONTAINER (tooltip->box), custom_widget);
413       gtk_widget_show (custom_widget);
414     }
415 }
416
417 /**
418  * gtk_tooltip_set_tip_area:
419  * @tooltip: a #GtkTooltip
420  * @rect: a #GdkRectangle
421  *
422  * Sets the area of the widget, where the contents of this tooltip apply,
423  * to be @rect (in widget coordinates).  This is especially useful for
424  * properly setting tooltips on #GtkTreeView rows and cells, #GtkIconViews,
425  * etc.
426  *
427  * For setting tooltips on #GtkTreeView, please refer to the convenience
428  * functions for this: gtk_tree_view_set_tooltip_row() and
429  * gtk_tree_view_set_tooltip_cell().
430  *
431  * Since: 2.12
432  */
433 void
434 gtk_tooltip_set_tip_area (GtkTooltip         *tooltip,
435                           const GdkRectangle *rect)
436 {
437   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
438
439   if (!rect)
440     tooltip->tip_area_set = FALSE;
441   else
442     {
443       tooltip->tip_area_set = TRUE;
444       tooltip->tip_area = *rect;
445     }
446 }
447
448 /**
449  * gtk_tooltip_trigger_tooltip_query:
450  * @display: a #GdkDisplay
451  *
452  * Triggers a new tooltip query on @display, in order to update the current
453  * visible tooltip, or to show/hide the current tooltip.  This function is
454  * useful to call when, for example, the state of the widget changed by a
455  * key press.
456  *
457  * Since: 2.12
458  */
459 void
460 gtk_tooltip_trigger_tooltip_query (GdkDisplay *display)
461 {
462   gint x, y;
463   GdkWindow *window;
464   GdkEvent event;
465
466   /* Trigger logic as if the mouse moved */
467   window = gdk_display_get_window_at_pointer (display, &x, &y);
468   if (!window)
469     return;
470
471   event.type = GDK_MOTION_NOTIFY;
472   event.motion.window = window;
473   event.motion.x = x;
474   event.motion.y = y;
475   event.motion.is_hint = FALSE;
476
477   gdk_window_get_root_coords (window, x, y, &x, &y);
478   event.motion.x_root = x;
479   event.motion.y_root = y;
480
481   _gtk_tooltip_handle_event (&event);
482 }
483
484 /* private functions */
485
486 static void
487 gtk_tooltip_reset (GtkTooltip *tooltip)
488 {
489   gtk_tooltip_set_markup (tooltip, NULL);
490   gtk_tooltip_set_icon (tooltip, NULL);
491   gtk_tooltip_set_tip_area (tooltip, NULL);
492
493   /* See if the custom widget is again set from the query-tooltip
494    * callback.
495    */
496   tooltip->custom_was_reset = FALSE;
497 }
498
499 static void
500 gtk_tooltip_window_style_set (GtkTooltip *tooltip)
501 {
502   gtk_alignment_set_padding (GTK_ALIGNMENT (tooltip->alignment),
503                              tooltip->window->style->ythickness,
504                              tooltip->window->style->ythickness,
505                              tooltip->window->style->xthickness,
506                              tooltip->window->style->xthickness);
507   gtk_box_set_spacing (GTK_BOX (tooltip->box),
508                        tooltip->window->style->xthickness);
509
510   gtk_widget_queue_draw (tooltip->window);
511 }
512
513 static gboolean
514 gtk_tooltip_paint_window (GtkTooltip *tooltip)
515 {
516   gtk_paint_flat_box (tooltip->window->style,
517                       tooltip->window->window,
518                       GTK_STATE_NORMAL,
519                       GTK_SHADOW_OUT,
520                       NULL,
521                       tooltip->window,
522                       "tooltip",
523                       0, 0,
524                       tooltip->window->allocation.width,
525                       tooltip->window->allocation.height);
526
527   return FALSE;
528 }
529
530 static void
531 gtk_tooltip_window_hide (GtkWidget *widget,
532                          gpointer   user_data)
533 {
534   GtkTooltip *tooltip = GTK_TOOLTIP (user_data);
535
536   gtk_tooltip_set_custom (tooltip, NULL);
537 }
538
539 /* event handling, etc */
540
541 struct ChildLocation
542 {
543   GtkWidget *child;
544   GtkWidget *container;
545
546   gint x;
547   gint y;
548 };
549
550 static void
551 child_location_foreach (GtkWidget *child,
552                         gpointer   data)
553 {
554   gint x, y;
555   struct ChildLocation *child_loc = data;
556
557   /* Ignore invisible widgets */
558   if (!gtk_widget_is_drawable (child))
559     return;
560
561   x = 0;
562   y = 0;
563
564   /* (child_loc->x, child_loc->y) are relative to
565    * child_loc->container's allocation.
566    */
567
568   if (!child_loc->child &&
569       gtk_widget_translate_coordinates (child_loc->container, child,
570                                         child_loc->x, child_loc->y,
571                                         &x, &y))
572     {
573 #ifdef DEBUG_TOOLTIP
574       g_print ("candidate: %s  alloc=[(%d,%d)  %dx%d]     (%d, %d)->(%d, %d)\n",
575                gtk_widget_get_name (child),
576                child->allocation.x,
577                child->allocation.y,
578                child->allocation.width,
579                child->allocation.height,
580                child_loc->x, child_loc->y,
581                x, y);
582 #endif /* DEBUG_TOOLTIP */
583
584       /* (x, y) relative to child's allocation. */
585       if (x >= 0 && x < child->allocation.width
586           && y >= 0 && y < child->allocation.height)
587         {
588           if (GTK_IS_CONTAINER (child))
589             {
590               struct ChildLocation tmp = { NULL, NULL, 0, 0 };
591
592               /* Take (x, y) relative the child's allocation and
593                * recurse.
594                */
595               tmp.x = x;
596               tmp.y = y;
597               tmp.container = child;
598
599               gtk_container_forall (GTK_CONTAINER (child),
600                                     child_location_foreach, &tmp);
601
602               if (tmp.child)
603                 child_loc->child = tmp.child;
604               else
605                 child_loc->child = child;
606             }
607           else
608             child_loc->child = child;
609         }
610     }
611 }
612
613 /* Translates coordinates from dest_widget->window relative (src_x, src_y),
614  * to allocation relative (dest_x, dest_y) of dest_widget.
615  */
616 static void
617 window_to_alloc (GtkWidget *dest_widget,
618                  gint       src_x,
619                  gint       src_y,
620                  gint      *dest_x,
621                  gint      *dest_y)
622 {
623   /* Translate from window relative to allocation relative */
624   if (gtk_widget_get_has_window (dest_widget) && dest_widget->parent)
625     {
626       gint wx, wy;
627       gdk_window_get_position (dest_widget->window, &wx, &wy);
628
629       /* Offset coordinates if widget->window is smaller than
630        * widget->allocation.
631        */
632       src_x += wx - dest_widget->allocation.x;
633       src_y += wy - dest_widget->allocation.y;
634     }
635   else
636     {
637       src_x -= dest_widget->allocation.x;
638       src_y -= dest_widget->allocation.y;
639     }
640
641   if (dest_x)
642     *dest_x = src_x;
643   if (dest_y)
644     *dest_y = src_y;
645 }
646
647 /* Translates coordinates from window relative (x, y) to
648  * allocation relative (x, y) of the returned widget.
649  */
650 static GtkWidget *
651 find_widget_under_pointer (GdkWindow *window,
652                            gint      *x,
653                            gint      *y)
654 {
655   GtkWidget *event_widget;
656   struct ChildLocation child_loc = { NULL, NULL, 0, 0 };
657
658   gdk_window_get_user_data (window, (void **)&event_widget);
659
660   if (!event_widget)
661     return NULL;
662
663 #ifdef DEBUG_TOOLTIP
664   g_print ("event window %p (belonging to %p (%s))  (%d, %d)\n",
665            window, event_widget, gtk_widget_get_name (event_widget),
666            *x, *y);
667 #endif
668
669   /* Coordinates are relative to event window */
670   child_loc.x = *x;
671   child_loc.y = *y;
672
673   /* We go down the window hierarchy to the widget->window,
674    * coordinates stay relative to the current window.
675    * We end up with window == widget->window, coordinates relative to that.
676    */
677   while (window && window != event_widget->window)
678     {
679       gdouble px, py;
680
681       gdk_window_coords_to_parent (window,
682                                    child_loc.x, child_loc.y,
683                                    &px, &py);
684       child_loc.x = px;
685       child_loc.y = py;
686
687       window = gdk_window_get_effective_parent (window);
688     }
689
690   /* Failing to find widget->window can happen for e.g. a detached handle box;
691    * chaining ::query-tooltip up to its parent probably makes little sense,
692    * and users better implement tooltips on handle_box->child.
693    * so we simply ignore the event for tooltips here.
694    */
695   if (!window)
696     return NULL;
697
698   /* Convert the window relative coordinates to allocation
699    * relative coordinates.
700    */
701   window_to_alloc (event_widget,
702                    child_loc.x, child_loc.y,
703                    &child_loc.x, &child_loc.y);
704
705   if (GTK_IS_CONTAINER (event_widget))
706     {
707       GtkWidget *container = event_widget;
708
709       child_loc.container = event_widget;
710       child_loc.child = NULL;
711
712       gtk_container_forall (GTK_CONTAINER (event_widget),
713                             child_location_foreach, &child_loc);
714
715       /* Here we have a widget, with coordinates relative to
716        * child_loc.container's allocation.
717        */
718
719       if (child_loc.child)
720         event_widget = child_loc.child;
721       else if (child_loc.container)
722         event_widget = child_loc.container;
723
724       /* Translate to event_widget's allocation */
725       gtk_widget_translate_coordinates (container, event_widget,
726                                         child_loc.x, child_loc.y,
727                                         &child_loc.x, &child_loc.y);
728
729     }
730
731   /* We return (x, y) relative to the allocation of event_widget. */
732   if (x)
733     *x = child_loc.x;
734   if (y)
735     *y = child_loc.y;
736
737   return event_widget;
738 }
739
740 /* Ignores (x, y) on input, translates event coordinates to
741  * allocation relative (x, y) of the returned widget.
742  */
743 static GtkWidget *
744 find_topmost_widget_coords_from_event (GdkEvent *event,
745                                        gint     *x,
746                                        gint     *y)
747 {
748   gint tx, ty;
749   gdouble dx, dy;
750   GtkWidget *tmp;
751
752   gdk_event_get_coords (event, &dx, &dy);
753   tx = dx;
754   ty = dy;
755
756   /* Returns coordinates relative to tmp's allocation. */
757   tmp = find_widget_under_pointer (event->any.window, &tx, &ty);
758
759   if (!tmp)
760     return NULL;
761
762   /* Make sure the pointer can actually be on the widget returned. */
763   if (tx < 0 || tx >= tmp->allocation.width ||
764       ty < 0 || ty >= tmp->allocation.height)
765     return NULL;
766
767   if (x)
768     *x = tx;
769   if (y)
770     *y = ty;
771
772   return tmp;
773 }
774
775 static gint
776 tooltip_browse_mode_expired (gpointer data)
777 {
778   GtkTooltip *tooltip;
779
780   tooltip = GTK_TOOLTIP (data);
781
782   tooltip->browse_mode_enabled = FALSE;
783   tooltip->browse_mode_timeout_id = 0;
784
785   /* destroy tooltip */
786   g_object_set_data (G_OBJECT (gtk_widget_get_display (tooltip->window)),
787                      "gdk-display-current-tooltip", NULL);
788
789   return FALSE;
790 }
791
792 static void
793 gtk_tooltip_display_closed (GdkDisplay *display,
794                             gboolean    was_error,
795                             GtkTooltip *tooltip)
796 {
797   g_object_set_data (G_OBJECT (display), "gdk-display-current-tooltip", NULL);
798 }
799
800 static void
801 gtk_tooltip_set_last_window (GtkTooltip *tooltip,
802                              GdkWindow  *window)
803 {
804   if (tooltip->last_window == window)
805     return;
806
807   if (tooltip->last_window)
808     g_object_remove_weak_pointer (G_OBJECT (tooltip->last_window),
809                                   (gpointer *) &tooltip->last_window);
810
811   tooltip->last_window = window;
812
813   if (window)
814     g_object_add_weak_pointer (G_OBJECT (tooltip->last_window),
815                                (gpointer *) &tooltip->last_window);
816 }
817
818 static gboolean
819 gtk_tooltip_run_requery (GtkWidget  **widget,
820                          GtkTooltip  *tooltip,
821                          gint        *x,
822                          gint        *y)
823 {
824   gboolean has_tooltip = FALSE;
825   gboolean return_value = FALSE;
826
827   gtk_tooltip_reset (tooltip);
828
829   do
830     {
831       g_object_get (*widget,
832                     "has-tooltip", &has_tooltip,
833                     NULL);
834
835       if (has_tooltip)
836         g_signal_emit_by_name (*widget,
837                                "query-tooltip",
838                                *x, *y,
839                                tooltip->keyboard_mode_enabled,
840                                tooltip,
841                                &return_value);
842
843       if (!return_value)
844         {
845           GtkWidget *parent = (*widget)->parent;
846
847           if (parent)
848             gtk_widget_translate_coordinates (*widget, parent, *x, *y, x, y);
849
850           *widget = parent;
851         }
852       else
853         break;
854     }
855   while (*widget);
856
857   /* If the custom widget was not reset in the query-tooltip
858    * callback, we clear it here.
859    */
860   if (!tooltip->custom_was_reset)
861     gtk_tooltip_set_custom (tooltip, NULL);
862
863   return return_value;
864 }
865
866 static void
867 get_bounding_box (GtkWidget    *widget,
868                   GdkRectangle *bounds)
869 {
870   GdkWindow *window;
871   gint x, y;
872   gint w, h;
873   gint x1, y1;
874   gint x2, y2;
875   gint x3, y3;
876   gint x4, y4;
877
878   window = gtk_widget_get_parent_window (widget);
879
880   x = widget->allocation.x;
881   y = widget->allocation.y;
882   w = widget->allocation.width;
883   h = widget->allocation.height;
884
885   gdk_window_get_root_coords (window, x, y, &x1, &y1);
886   gdk_window_get_root_coords (window, x + w, y, &x2, &y2);
887   gdk_window_get_root_coords (window, x, y + h, &x3, &y3);
888   gdk_window_get_root_coords (window, x + w, y + h, &x4, &y4);
889
890 #define MIN4(a,b,c,d) MIN(MIN(a,b),MIN(c,d))
891 #define MAX4(a,b,c,d) MAX(MAX(a,b),MAX(c,d))
892
893   bounds->x = floor (MIN4 (x1, x2, x3, x4));
894   bounds->y = floor (MIN4 (y1, y2, y3, y4));
895   bounds->width = ceil (MAX4 (x1, x2, x3, x4)) - bounds->x;
896   bounds->height = ceil (MAX4 (y1, y2, y3, y4)) - bounds->y;
897 }
898
899 static void
900 gtk_tooltip_position (GtkTooltip *tooltip,
901                       GdkDisplay *display,
902                       GtkWidget  *new_tooltip_widget)
903 {
904   gint x, y;
905   GdkScreen *screen;
906   gint monitor_num;
907   GdkRectangle monitor;
908   GtkRequisition requisition;
909   guint cursor_size;
910   GdkRectangle bounds;
911
912 #define MAX_DISTANCE 32
913
914   tooltip->tooltip_widget = new_tooltip_widget;
915
916   screen = gtk_widget_get_screen (new_tooltip_widget);
917
918   gtk_widget_size_request (GTK_WIDGET (tooltip->current_window), &requisition);
919
920   monitor_num = gdk_screen_get_monitor_at_point (screen,
921                                                  tooltip->last_x,
922                                                  tooltip->last_y);
923   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
924
925   get_bounding_box (new_tooltip_widget, &bounds);
926
927   /* Position the tooltip */
928
929   cursor_size = gdk_display_get_default_cursor_size (display);
930
931   /* Try below */
932   x = bounds.x + bounds.width / 2 - requisition.width / 2;
933   y = bounds.y + bounds.height + 4;
934
935   if (y + requisition.height <= monitor.y + monitor.height)
936     {
937       if (tooltip->keyboard_mode_enabled)
938         goto found;
939
940       if (y <= tooltip->last_y + cursor_size + MAX_DISTANCE)
941         {
942           if (tooltip->last_x + cursor_size + MAX_DISTANCE < x)
943             x = tooltip->last_x + cursor_size + MAX_DISTANCE;
944           else if (x + requisition.width < tooltip->last_x - MAX_DISTANCE)
945             x = tooltip->last_x - MAX_DISTANCE - requisition.width;
946
947           goto found;
948         }
949    }
950
951   /* Try above */
952   x = bounds.x + bounds.width / 2 - requisition.width / 2;
953   y = bounds.y - requisition.height - 4;
954
955   if (y >= monitor.y)
956     {
957       if (tooltip->keyboard_mode_enabled)
958         goto found;
959
960       if (y + requisition.height >= tooltip->last_y - MAX_DISTANCE)
961         {
962           if (tooltip->last_x + cursor_size + MAX_DISTANCE < x)
963             x = tooltip->last_x + cursor_size + MAX_DISTANCE;
964           else if (x + requisition.width < tooltip->last_x - MAX_DISTANCE)
965             x = tooltip->last_x - MAX_DISTANCE - requisition.width;
966
967           goto found;
968         }
969     }
970
971   /* Try right FIXME: flip on rtl ? */
972   x = bounds.x + bounds.width + 4;
973   y = bounds.y + bounds.height / 2 - requisition.height / 2;
974
975   if (x + requisition.width <= monitor.x + monitor.width)
976     {
977       if (tooltip->keyboard_mode_enabled)
978         goto found;
979
980       if (x <= tooltip->last_x + cursor_size + MAX_DISTANCE)
981         {
982           if (tooltip->last_y + cursor_size + MAX_DISTANCE < y)
983             y = tooltip->last_y + cursor_size + MAX_DISTANCE;
984           else if (y + requisition.height < tooltip->last_y - MAX_DISTANCE)
985             y = tooltip->last_y - MAX_DISTANCE - requisition.height;
986
987           goto found;
988         }
989     }
990
991   /* Try left FIXME: flip on rtl ? */
992   x = bounds.x - requisition.width - 4;
993   y = bounds.y + bounds.height / 2 - requisition.height / 2;
994
995   if (x >= monitor.x)
996     {
997       if (tooltip->keyboard_mode_enabled)
998         goto found;
999
1000       if (x + requisition.width >= tooltip->last_x - MAX_DISTANCE)
1001         {
1002           if (tooltip->last_y + cursor_size + MAX_DISTANCE < y)
1003             y = tooltip->last_y + cursor_size + MAX_DISTANCE;
1004           else if (y + requisition.height < tooltip->last_y - MAX_DISTANCE)
1005             y = tooltip->last_y - MAX_DISTANCE - requisition.height;
1006
1007           goto found;
1008         }
1009     }
1010
1011    /* Fallback */
1012   if (tooltip->keyboard_mode_enabled)
1013     {
1014       x = bounds.x + bounds.width / 2 - requisition.width / 2;
1015       y = bounds.y + bounds.height + 4;
1016     }
1017   else
1018     {
1019       /* At cursor */
1020       x = tooltip->last_x + cursor_size * 3 / 4;
1021       y = tooltip->last_y + cursor_size * 3 / 4;
1022     }
1023
1024 found:
1025   /* Show it */
1026   if (tooltip->current_window)
1027     {
1028       if (x + requisition.width > monitor.x + monitor.width)
1029         x -= x - (monitor.x + monitor.width) + requisition.width;
1030       else if (x < monitor.x)
1031         x = monitor.x;
1032
1033       if (y + requisition.height > monitor.y + monitor.height)
1034         y -= y - (monitor.y + monitor.height) + requisition.height;
1035       else if (y < monitor.y)
1036         y = monitor.y;
1037
1038       if (!tooltip->keyboard_mode_enabled)
1039         {
1040           /* don't pop up under the pointer */
1041           if (x <= tooltip->last_x && tooltip->last_x < x + requisition.width &&
1042               y <= tooltip->last_y && tooltip->last_y < y + requisition.height)
1043             y = tooltip->last_y - requisition.height - 2;
1044         }
1045
1046       gtk_window_move (GTK_WINDOW (tooltip->current_window), x, y);
1047       gtk_widget_show (GTK_WIDGET (tooltip->current_window));
1048     }
1049 }
1050
1051 static void
1052 gtk_tooltip_show_tooltip (GdkDisplay *display)
1053 {
1054   gint x, y;
1055   GdkScreen *screen;
1056
1057   GdkWindow *window;
1058   GtkWidget *tooltip_widget;
1059   GtkWidget *pointer_widget;
1060   GtkTooltip *tooltip;
1061   gboolean has_tooltip;
1062   gboolean return_value = FALSE;
1063
1064   tooltip = g_object_get_data (G_OBJECT (display),
1065                                "gdk-display-current-tooltip");
1066
1067   if (tooltip->keyboard_mode_enabled)
1068     {
1069       x = y = -1;
1070       pointer_widget = tooltip_widget = tooltip->keyboard_widget;
1071     }
1072   else
1073     {
1074       gint tx, ty;
1075
1076       window = tooltip->last_window;
1077
1078       if (!GDK_IS_WINDOW (window))
1079         return;
1080
1081       gdk_window_get_pointer (window, &x, &y, NULL);
1082
1083       gdk_window_get_root_coords (window, x, y, &tx, &ty);
1084       tooltip->last_x = tx;
1085       tooltip->last_y = ty;
1086
1087       pointer_widget = tooltip_widget = find_widget_under_pointer (window,
1088                                                                    &x, &y);
1089     }
1090
1091   if (!tooltip_widget)
1092     return;
1093
1094   g_object_get (tooltip_widget, "has-tooltip", &has_tooltip, NULL);
1095
1096   return_value = gtk_tooltip_run_requery (&tooltip_widget, tooltip, &x, &y);
1097   if (!return_value)
1098     return;
1099
1100   if (!tooltip->current_window)
1101     {
1102       if (gtk_widget_get_tooltip_window (tooltip_widget))
1103         tooltip->current_window = gtk_widget_get_tooltip_window (tooltip_widget);
1104       else
1105         tooltip->current_window = GTK_WINDOW (GTK_TOOLTIP (tooltip)->window);
1106     }
1107
1108   screen = gtk_widget_get_screen (tooltip_widget);
1109
1110   /* FIXME: should use tooltip->current_window iso tooltip->window */
1111   if (screen != gtk_widget_get_screen (tooltip->window))
1112     {
1113       g_signal_handlers_disconnect_by_func (display,
1114                                             gtk_tooltip_display_closed,
1115                                             tooltip);
1116
1117       gtk_window_set_screen (GTK_WINDOW (tooltip->window), screen);
1118
1119       g_signal_connect (display, "closed",
1120                         G_CALLBACK (gtk_tooltip_display_closed), tooltip);
1121     }
1122
1123   gtk_tooltip_position (tooltip, display, tooltip_widget);
1124
1125   /* Now a tooltip is visible again on the display, make sure browse
1126    * mode is enabled.
1127    */
1128   tooltip->browse_mode_enabled = TRUE;
1129   if (tooltip->browse_mode_timeout_id)
1130     {
1131       g_source_remove (tooltip->browse_mode_timeout_id);
1132       tooltip->browse_mode_timeout_id = 0;
1133     }
1134 }
1135
1136 static void
1137 gtk_tooltip_hide_tooltip (GtkTooltip *tooltip)
1138 {
1139   if (!tooltip)
1140     return;
1141
1142   if (tooltip->timeout_id)
1143     {
1144       g_source_remove (tooltip->timeout_id);
1145       tooltip->timeout_id = 0;
1146     }
1147
1148   if (!GTK_TOOLTIP_VISIBLE (tooltip))
1149     return;
1150
1151   tooltip->tooltip_widget = NULL;
1152
1153   if (!tooltip->keyboard_mode_enabled)
1154     {
1155       guint timeout;
1156       GtkSettings *settings;
1157
1158       settings = gtk_widget_get_settings (GTK_WIDGET (tooltip->window));
1159
1160       g_object_get (settings,
1161                     "gtk-tooltip-browse-mode-timeout", &timeout,
1162                     NULL);
1163
1164       /* The tooltip is gone, after (by default, should be configurable) 500ms
1165        * we want to turn off browse mode
1166        */
1167       if (!tooltip->browse_mode_timeout_id)
1168         tooltip->browse_mode_timeout_id =
1169           gdk_threads_add_timeout_full (0, timeout,
1170                                         tooltip_browse_mode_expired,
1171                                         g_object_ref (tooltip),
1172                                         g_object_unref);
1173     }
1174   else
1175     {
1176       if (tooltip->browse_mode_timeout_id)
1177         {
1178           g_source_remove (tooltip->browse_mode_timeout_id);
1179           tooltip->browse_mode_timeout_id = 0;
1180         }
1181     }
1182
1183   if (tooltip->current_window)
1184     {
1185       gtk_widget_hide (GTK_WIDGET (tooltip->current_window));
1186       tooltip->current_window = NULL;
1187     }
1188 }
1189
1190 static gint
1191 tooltip_popup_timeout (gpointer data)
1192 {
1193   GdkDisplay *display;
1194   GtkTooltip *tooltip;
1195
1196   display = GDK_DISPLAY_OBJECT (data);
1197   tooltip = g_object_get_data (G_OBJECT (display),
1198                                "gdk-display-current-tooltip");
1199
1200   /* This usually does not happen.  However, it does occur in language
1201    * bindings were reference counting of objects behaves differently.
1202    */
1203   if (!tooltip)
1204     return FALSE;
1205
1206   gtk_tooltip_show_tooltip (display);
1207
1208   tooltip->timeout_id = 0;
1209
1210   return FALSE;
1211 }
1212
1213 static void
1214 gtk_tooltip_start_delay (GdkDisplay *display)
1215 {
1216   guint timeout;
1217   GtkTooltip *tooltip;
1218   GtkSettings *settings;
1219
1220   tooltip = g_object_get_data (G_OBJECT (display),
1221                                "gdk-display-current-tooltip");
1222
1223   if (!tooltip || GTK_TOOLTIP_VISIBLE (tooltip))
1224     return;
1225
1226   if (tooltip->timeout_id)
1227     g_source_remove (tooltip->timeout_id);
1228
1229   settings = gtk_widget_get_settings (GTK_WIDGET (tooltip->window));
1230
1231   if (tooltip->browse_mode_enabled)
1232     g_object_get (settings, "gtk-tooltip-browse-timeout", &timeout, NULL);
1233   else
1234     g_object_get (settings, "gtk-tooltip-timeout", &timeout, NULL);
1235
1236   tooltip->timeout_id = gdk_threads_add_timeout_full (0, timeout,
1237                                                       tooltip_popup_timeout,
1238                                                       g_object_ref (display),
1239                                                       g_object_unref);
1240 }
1241
1242 void
1243 _gtk_tooltip_focus_in (GtkWidget *widget)
1244 {
1245   gint x, y;
1246   gboolean return_value = FALSE;
1247   GdkDisplay *display;
1248   GtkTooltip *tooltip;
1249   GdkDevice *device;
1250
1251   /* Get current tooltip for this display */
1252   display = gtk_widget_get_display (widget);
1253   tooltip = g_object_get_data (G_OBJECT (display),
1254                                "gdk-display-current-tooltip");
1255
1256   /* Check if keyboard mode is enabled at this moment */
1257   if (!tooltip || !tooltip->keyboard_mode_enabled)
1258     return;
1259
1260   device = gtk_get_current_event_device ();
1261
1262   if (device && device->source == GDK_SOURCE_KEYBOARD)
1263     device = gdk_device_get_associated_device (device);
1264
1265   /* This function should be called by either a focus in event,
1266    * or a key binding. In either case there should be a device.
1267    */
1268   if (!device)
1269     return;
1270
1271   if (tooltip->keyboard_widget)
1272     g_object_unref (tooltip->keyboard_widget);
1273
1274   tooltip->keyboard_widget = g_object_ref (widget);
1275
1276   gdk_window_get_device_position (widget->window, device, &x, &y, NULL);
1277
1278   return_value = gtk_tooltip_run_requery (&widget, tooltip, &x, &y);
1279   if (!return_value)
1280     {
1281       gtk_tooltip_hide_tooltip (tooltip);
1282       return;
1283     }
1284
1285   if (!tooltip->current_window)
1286     {
1287       if (gtk_widget_get_tooltip_window (widget))
1288         tooltip->current_window = gtk_widget_get_tooltip_window (widget);
1289       else
1290         tooltip->current_window = GTK_WINDOW (GTK_TOOLTIP (tooltip)->window);
1291     }
1292
1293   gtk_tooltip_show_tooltip (display);
1294 }
1295
1296 void
1297 _gtk_tooltip_focus_out (GtkWidget *widget)
1298 {
1299   GdkDisplay *display;
1300   GtkTooltip *tooltip;
1301
1302   /* Get current tooltip for this display */
1303   display = gtk_widget_get_display (widget);
1304   tooltip = g_object_get_data (G_OBJECT (display),
1305                                "gdk-display-current-tooltip");
1306
1307   if (!tooltip || !tooltip->keyboard_mode_enabled)
1308     return;
1309
1310   if (tooltip->keyboard_widget)
1311     {
1312       g_object_unref (tooltip->keyboard_widget);
1313       tooltip->keyboard_widget = NULL;
1314     }
1315
1316   gtk_tooltip_hide_tooltip (tooltip);
1317 }
1318
1319 void
1320 _gtk_tooltip_toggle_keyboard_mode (GtkWidget *widget)
1321 {
1322   GdkDisplay *display;
1323   GtkTooltip *tooltip;
1324
1325   display = gtk_widget_get_display (widget);
1326   tooltip = g_object_get_data (G_OBJECT (display),
1327                                "gdk-display-current-tooltip");
1328
1329   if (!tooltip)
1330     {
1331       tooltip = g_object_new (GTK_TYPE_TOOLTIP, NULL);
1332       g_object_set_data_full (G_OBJECT (display),
1333                               "gdk-display-current-tooltip",
1334                               tooltip, g_object_unref);
1335       g_signal_connect (display, "closed",
1336                         G_CALLBACK (gtk_tooltip_display_closed),
1337                         tooltip);
1338     }
1339
1340   tooltip->keyboard_mode_enabled ^= 1;
1341
1342   if (tooltip->keyboard_mode_enabled)
1343     {
1344       tooltip->keyboard_widget = g_object_ref (widget);
1345       _gtk_tooltip_focus_in (widget);
1346     }
1347   else
1348     {
1349       if (tooltip->keyboard_widget)
1350         {
1351           g_object_unref (tooltip->keyboard_widget);
1352           tooltip->keyboard_widget = NULL;
1353         }
1354
1355       gtk_tooltip_hide_tooltip (tooltip);
1356     }
1357 }
1358
1359 void
1360 _gtk_tooltip_hide (GtkWidget *widget)
1361 {
1362   GtkWidget *toplevel;
1363   GdkDisplay *display;
1364   GtkTooltip *tooltip;
1365
1366   display = gtk_widget_get_display (widget);
1367   tooltip = g_object_get_data (G_OBJECT (display),
1368                                "gdk-display-current-tooltip");
1369
1370   if (!tooltip || !GTK_TOOLTIP_VISIBLE (tooltip) || !tooltip->tooltip_widget)
1371     return;
1372
1373   toplevel = gtk_widget_get_toplevel (widget);
1374
1375   if (widget == tooltip->tooltip_widget
1376       || toplevel->window == tooltip->toplevel_window)
1377     gtk_tooltip_hide_tooltip (tooltip);
1378 }
1379
1380 static gboolean
1381 tooltips_enabled (GdkWindow *window)
1382 {
1383   gboolean enabled;
1384   gboolean touchscreen;
1385   GdkScreen *screen;
1386   GtkSettings *settings;
1387
1388   screen = gdk_drawable_get_screen (window);
1389   settings = gtk_settings_get_for_screen (screen);
1390
1391   g_object_get (settings,
1392                 "gtk-touchscreen-mode", &touchscreen,
1393                 "gtk-enable-tooltips", &enabled,
1394                 NULL);
1395
1396   return (!touchscreen && enabled);
1397 }
1398
1399 void
1400 _gtk_tooltip_handle_event (GdkEvent *event)
1401 {
1402   gint x, y;
1403   gboolean return_value = FALSE;
1404   GtkWidget *has_tooltip_widget = NULL;
1405   GdkDisplay *display;
1406   GtkTooltip *current_tooltip;
1407
1408   if (!tooltips_enabled (event->any.window))
1409     return;
1410
1411   /* Returns coordinates relative to has_tooltip_widget's allocation. */
1412   has_tooltip_widget = find_topmost_widget_coords_from_event (event, &x, &y);
1413   display = gdk_drawable_get_display (event->any.window);
1414   current_tooltip = g_object_get_data (G_OBJECT (display),
1415                                        "gdk-display-current-tooltip");
1416
1417   if (current_tooltip)
1418     {
1419       gtk_tooltip_set_last_window (current_tooltip, event->any.window);
1420     }
1421
1422   if (current_tooltip && current_tooltip->keyboard_mode_enabled)
1423     {
1424       has_tooltip_widget = current_tooltip->keyboard_widget;
1425       if (!has_tooltip_widget)
1426         return;
1427
1428       return_value = gtk_tooltip_run_requery (&has_tooltip_widget,
1429                                               current_tooltip,
1430                                               &x, &y);
1431
1432       if (!return_value)
1433         gtk_tooltip_hide_tooltip (current_tooltip);
1434       else
1435         gtk_tooltip_start_delay (display);
1436
1437       return;
1438     }
1439
1440 #ifdef DEBUG_TOOLTIP
1441   if (has_tooltip_widget)
1442     g_print ("%p (%s) at (%d, %d) %dx%d     pointer: (%d, %d)\n",
1443              has_tooltip_widget, gtk_widget_get_name (has_tooltip_widget),
1444              has_tooltip_widget->allocation.x,
1445              has_tooltip_widget->allocation.y,
1446              has_tooltip_widget->allocation.width,
1447              has_tooltip_widget->allocation.height,
1448              x, y);
1449 #endif /* DEBUG_TOOLTIP */
1450
1451   /* Always poll for a next motion event */
1452   gdk_event_request_motions (&event->motion);
1453
1454   /* Hide the tooltip when there's no new tooltip widget */
1455   if (!has_tooltip_widget)
1456     {
1457       if (current_tooltip)
1458         gtk_tooltip_hide_tooltip (current_tooltip);
1459
1460       return;
1461     }
1462
1463   switch (event->type)
1464     {
1465       case GDK_BUTTON_PRESS:
1466       case GDK_2BUTTON_PRESS:
1467       case GDK_3BUTTON_PRESS:
1468       case GDK_KEY_PRESS:
1469       case GDK_DRAG_ENTER:
1470       case GDK_GRAB_BROKEN:
1471         gtk_tooltip_hide_tooltip (current_tooltip);
1472         break;
1473
1474       case GDK_MOTION_NOTIFY:
1475       case GDK_ENTER_NOTIFY:
1476       case GDK_LEAVE_NOTIFY:
1477       case GDK_SCROLL:
1478         if (current_tooltip)
1479           {
1480             gboolean tip_area_set;
1481             GdkRectangle tip_area;
1482             gboolean hide_tooltip;
1483
1484             tip_area_set = current_tooltip->tip_area_set;
1485             tip_area = current_tooltip->tip_area;
1486
1487             return_value = gtk_tooltip_run_requery (&has_tooltip_widget,
1488                                                     current_tooltip,
1489                                                     &x, &y);
1490
1491             /* Requested to be hidden? */
1492             hide_tooltip = !return_value;
1493
1494             /* Leave notify should override the query function */
1495             hide_tooltip = (event->type == GDK_LEAVE_NOTIFY);
1496
1497             /* Is the pointer above another widget now? */
1498             if (GTK_TOOLTIP_VISIBLE (current_tooltip))
1499               hide_tooltip |= has_tooltip_widget != current_tooltip->tooltip_widget;
1500
1501             /* Did the pointer move out of the previous "context area"? */
1502             if (tip_area_set)
1503               hide_tooltip |= (x <= tip_area.x
1504                                || x >= tip_area.x + tip_area.width
1505                                || y <= tip_area.y
1506                                || y >= tip_area.y + tip_area.height);
1507
1508             if (hide_tooltip)
1509               gtk_tooltip_hide_tooltip (current_tooltip);
1510             else
1511               gtk_tooltip_start_delay (display);
1512           }
1513         else
1514           {
1515             /* Need a new tooltip for this display */
1516             current_tooltip = g_object_new (GTK_TYPE_TOOLTIP, NULL);
1517             g_object_set_data_full (G_OBJECT (display),
1518                                     "gdk-display-current-tooltip",
1519                                     current_tooltip, g_object_unref);
1520             g_signal_connect (display, "closed",
1521                               G_CALLBACK (gtk_tooltip_display_closed),
1522                               current_tooltip);
1523
1524             gtk_tooltip_set_last_window (current_tooltip, event->any.window);
1525
1526             gtk_tooltip_start_delay (display);
1527           }
1528         break;
1529
1530       default:
1531         break;
1532     }
1533 }
1534
1535
1536 #define __GTK_TOOLTIP_C__
1537 #include "gtkaliasdef.c"