]> Pileus Git - ~andy/gtk/blob - gtk/gtktooltips.c
Don't translate NULL messages. (#161789, Morten Welinder)
[~andy/gtk] / gtk / gtktooltips.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include <config.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <stdio.h>
31
32 #include "gtkalias.h"
33 #include "gtklabel.h"
34 #include "gtkmain.h"
35 #include "gtkmenuitem.h"
36 #include "gtkprivate.h"
37 #include "gtkwidget.h"
38 #include "gtkwindow.h"
39 #include "gtkstyle.h"
40 #include "gtktooltips.h"
41
42
43 #define DEFAULT_DELAY 500           /* Default delay in ms */
44 #define STICKY_DELAY 0              /* Delay before popping up next tip
45                                      * if we're sticky
46                                      */
47 #define STICKY_REVERT_DELAY 1000    /* Delay before sticky tooltips revert
48                                      * to normal
49                                      */
50
51 static void gtk_tooltips_class_init        (GtkTooltipsClass *klass);
52 static void gtk_tooltips_init              (GtkTooltips      *tooltips);
53 static void gtk_tooltips_destroy           (GtkObject        *object);
54
55 static void gtk_tooltips_event_handler     (GtkWidget   *widget,
56                                             GdkEvent    *event);
57 static void gtk_tooltips_widget_unmap      (GtkWidget   *widget,
58                                             gpointer     data);
59 static void gtk_tooltips_widget_remove     (GtkWidget   *widget,
60                                             gpointer     data);
61 static void gtk_tooltips_set_active_widget (GtkTooltips *tooltips,
62                                             GtkWidget   *widget);
63 static gint gtk_tooltips_timeout           (gpointer     data);
64
65 static gint gtk_tooltips_paint_window      (GtkTooltips *tooltips);
66 static void gtk_tooltips_draw_tips         (GtkTooltips *tooltips);
67 static void gtk_tooltips_unset_tip_window  (GtkTooltips *tooltips);
68
69 static gboolean get_keyboard_mode          (GtkWidget   *widget);
70
71 static GtkObjectClass *parent_class;
72 static const gchar  *tooltips_data_key = "_GtkTooltipsData";
73 static const gchar  *tooltips_info_key = "_GtkTooltipsInfo";
74
75 GType
76 gtk_tooltips_get_type (void)
77 {
78   static GType tooltips_type = 0;
79
80   if (!tooltips_type)
81     {
82       static const GTypeInfo tooltips_info =
83       {
84         sizeof (GtkTooltipsClass),
85         NULL,           /* base_init */
86         NULL,           /* base_finalize */
87         (GClassInitFunc) gtk_tooltips_class_init,
88         NULL,           /* class_finalize */
89         NULL,           /* class_data */
90         sizeof (GtkTooltips),
91         0,              /* n_preallocs */
92         (GInstanceInitFunc) gtk_tooltips_init,
93       };
94
95       tooltips_type = g_type_register_static (GTK_TYPE_OBJECT, "GtkTooltips",
96                                               &tooltips_info, 0);
97     }
98
99   return tooltips_type;
100 }
101
102 static void
103 gtk_tooltips_class_init (GtkTooltipsClass *class)
104 {
105   GtkObjectClass *object_class;
106
107   object_class = (GtkObjectClass*) class;
108
109   parent_class = g_type_class_peek_parent (class);
110
111   object_class->destroy = gtk_tooltips_destroy;
112 }
113
114 static void
115 gtk_tooltips_init (GtkTooltips *tooltips)
116 {
117   tooltips->tip_window = NULL;
118   tooltips->active_tips_data = NULL;
119   tooltips->tips_data_list = NULL;
120   
121   tooltips->delay = DEFAULT_DELAY;
122   tooltips->enabled = TRUE;
123   tooltips->timer_tag = 0;
124   tooltips->use_sticky_delay = FALSE;
125   tooltips->last_popdown.tv_sec = -1;
126   tooltips->last_popdown.tv_usec = -1;
127 }
128
129 GtkTooltips *
130 gtk_tooltips_new (void)
131 {
132   return g_object_new (GTK_TYPE_TOOLTIPS, NULL);
133 }
134
135 static void
136 gtk_tooltips_destroy_data (GtkTooltipsData *tooltipsdata)
137 {
138   g_free (tooltipsdata->tip_text);
139   g_free (tooltipsdata->tip_private);
140
141   g_signal_handlers_disconnect_by_func (tooltipsdata->widget,
142                                         gtk_tooltips_event_handler,
143                                         tooltipsdata);
144   g_signal_handlers_disconnect_by_func (tooltipsdata->widget,
145                                         gtk_tooltips_widget_unmap,
146                                         tooltipsdata);
147   g_signal_handlers_disconnect_by_func (tooltipsdata->widget,
148                                         gtk_tooltips_widget_remove,
149                                         tooltipsdata);
150
151   g_object_set_data (G_OBJECT (tooltipsdata->widget), tooltips_data_key, NULL);
152   g_object_unref (tooltipsdata->widget);
153   g_free (tooltipsdata);
154 }
155
156 static void
157 tip_window_display_closed (GdkDisplay  *display,
158                            gboolean     was_error,
159                            GtkTooltips *tooltips)
160 {
161   gtk_tooltips_unset_tip_window (tooltips);
162 }
163
164 static void
165 disconnect_tip_window_display_closed (GtkTooltips *tooltips)
166 {
167   g_signal_handlers_disconnect_by_func (gtk_widget_get_display (tooltips->tip_window),
168                                         (gpointer) tip_window_display_closed,
169                                         tooltips);
170 }
171
172 static void
173 gtk_tooltips_unset_tip_window (GtkTooltips *tooltips)
174 {
175   if (tooltips->tip_window)
176     {
177       disconnect_tip_window_display_closed (tooltips);
178       
179       gtk_widget_destroy (tooltips->tip_window);
180       tooltips->tip_window = NULL;
181     }
182 }
183
184 static void
185 gtk_tooltips_destroy (GtkObject *object)
186 {
187   GtkTooltips *tooltips = GTK_TOOLTIPS (object);
188   GList *current;
189   GtkTooltipsData *tooltipsdata;
190
191   g_return_if_fail (tooltips != NULL);
192
193   if (tooltips->timer_tag)
194     {
195       g_source_remove (tooltips->timer_tag);
196       tooltips->timer_tag = 0;
197     }
198
199   if (tooltips->tips_data_list != NULL)
200     {
201       current = g_list_first (tooltips->tips_data_list);
202       while (current != NULL)
203         {
204           tooltipsdata = (GtkTooltipsData*) current->data;
205           current = current->next;
206           gtk_tooltips_widget_remove (tooltipsdata->widget, tooltipsdata);
207         }
208     }
209
210   gtk_tooltips_unset_tip_window (tooltips);
211
212   GTK_OBJECT_CLASS (parent_class)->destroy (object);
213 }
214
215 static void
216 gtk_tooltips_update_screen (GtkTooltips *tooltips,
217                             gboolean     new_window)
218 {
219   gboolean screen_changed = FALSE;
220   
221   if (tooltips->active_tips_data &&
222       tooltips->active_tips_data->widget)
223     {
224       GdkScreen *screen = gtk_widget_get_screen (tooltips->active_tips_data->widget);
225
226       screen_changed = (screen != gtk_widget_get_screen (tooltips->tip_window));
227
228       if (screen_changed)
229         {
230           if (!new_window)
231             disconnect_tip_window_display_closed (tooltips);
232       
233           gtk_window_set_screen (GTK_WINDOW (tooltips->tip_window), screen);
234         }
235     }
236
237   if (screen_changed || new_window)
238     g_signal_connect (gtk_widget_get_display (tooltips->tip_window), "closed",
239                       G_CALLBACK (tip_window_display_closed), tooltips);
240
241 }
242
243 void
244 gtk_tooltips_force_window (GtkTooltips *tooltips)
245 {
246   g_return_if_fail (GTK_IS_TOOLTIPS (tooltips));
247
248   if (!tooltips->tip_window)
249     {
250       tooltips->tip_window = gtk_window_new (GTK_WINDOW_POPUP);
251       gtk_tooltips_update_screen (tooltips, TRUE);
252       gtk_widget_set_app_paintable (tooltips->tip_window, TRUE);
253       gtk_window_set_resizable (GTK_WINDOW (tooltips->tip_window), FALSE);
254       gtk_widget_set_name (tooltips->tip_window, "gtk-tooltips");
255       gtk_container_set_border_width (GTK_CONTAINER (tooltips->tip_window), 4);
256
257       g_signal_connect_swapped (tooltips->tip_window,
258                                 "expose_event",
259                                 G_CALLBACK (gtk_tooltips_paint_window), 
260                                 tooltips);
261
262       tooltips->tip_label = gtk_label_new (NULL);
263       gtk_label_set_line_wrap (GTK_LABEL (tooltips->tip_label), TRUE);
264       gtk_misc_set_alignment (GTK_MISC (tooltips->tip_label), 0.5, 0.5);
265       gtk_widget_show (tooltips->tip_label);
266       
267       gtk_container_add (GTK_CONTAINER (tooltips->tip_window), tooltips->tip_label);
268
269       g_signal_connect (tooltips->tip_window,
270                         "destroy",
271                         G_CALLBACK (gtk_widget_destroyed),
272                         &tooltips->tip_window);
273     }
274 }
275
276 void
277 gtk_tooltips_enable (GtkTooltips *tooltips)
278 {
279   g_return_if_fail (tooltips != NULL);
280
281   tooltips->enabled = TRUE;
282 }
283
284 void
285 gtk_tooltips_disable (GtkTooltips *tooltips)
286 {
287   g_return_if_fail (tooltips != NULL);
288
289   gtk_tooltips_set_active_widget (tooltips, NULL);
290
291   tooltips->enabled = FALSE;
292 }
293
294 void
295 gtk_tooltips_set_delay (GtkTooltips *tooltips,
296                         guint         delay)
297 {
298   g_return_if_fail (tooltips != NULL);
299
300   tooltips->delay = delay;
301 }
302
303 GtkTooltipsData*
304 gtk_tooltips_data_get (GtkWidget       *widget)
305 {
306   g_return_val_if_fail (widget != NULL, NULL);
307
308   return g_object_get_data (G_OBJECT (widget), tooltips_data_key);
309 }
310
311 void
312 gtk_tooltips_set_tip (GtkTooltips *tooltips,
313                       GtkWidget   *widget,
314                       const gchar *tip_text,
315                       const gchar *tip_private)
316 {
317   GtkTooltipsData *tooltipsdata;
318
319   g_return_if_fail (GTK_IS_TOOLTIPS (tooltips));
320   g_return_if_fail (widget != NULL);
321
322   tooltipsdata = gtk_tooltips_data_get (widget);
323
324   if (!tip_text)
325     {
326       if (tooltipsdata)
327         gtk_tooltips_widget_remove (tooltipsdata->widget, tooltipsdata);
328       return;
329     }
330   
331   if (tooltips->active_tips_data 
332       && tooltips->active_tips_data->widget == widget
333       && GTK_WIDGET_DRAWABLE (tooltips->active_tips_data->widget))
334     {
335       g_free (tooltipsdata->tip_text);
336       g_free (tooltipsdata->tip_private);
337
338       tooltipsdata->tip_text = g_strdup (tip_text);
339       tooltipsdata->tip_private = g_strdup (tip_private);
340       
341       gtk_tooltips_draw_tips (tooltips);
342     }
343   else 
344     {
345       g_object_ref (widget);
346       
347       if (tooltipsdata)
348         gtk_tooltips_widget_remove (tooltipsdata->widget, tooltipsdata);
349       
350       tooltipsdata = g_new0 (GtkTooltipsData, 1);
351       
352       tooltipsdata->tooltips = tooltips;
353       tooltipsdata->widget = widget;
354
355       tooltipsdata->tip_text = g_strdup (tip_text);
356       tooltipsdata->tip_private = g_strdup (tip_private);
357
358       tooltips->tips_data_list = g_list_append (tooltips->tips_data_list,
359                                                 tooltipsdata);
360       g_signal_connect_after (widget, "event-after",
361                               G_CALLBACK (gtk_tooltips_event_handler),
362                               tooltipsdata);
363
364       g_object_set_data (G_OBJECT (widget), tooltips_data_key,
365                          tooltipsdata);
366
367       g_signal_connect (widget, "unmap",
368                         G_CALLBACK (gtk_tooltips_widget_unmap),
369                         tooltipsdata);
370
371       g_signal_connect (widget, "unrealize",
372                         G_CALLBACK (gtk_tooltips_widget_unmap),
373                         tooltipsdata);
374
375       g_signal_connect (widget, "destroy",
376                         G_CALLBACK (gtk_tooltips_widget_remove),
377                         tooltipsdata);
378     }
379 }
380
381 static gint
382 gtk_tooltips_paint_window (GtkTooltips *tooltips)
383 {
384   GtkRequisition req;
385
386   gtk_widget_size_request (tooltips->tip_window, &req);
387   gtk_paint_flat_box (tooltips->tip_window->style, tooltips->tip_window->window,
388                       GTK_STATE_NORMAL, GTK_SHADOW_OUT, 
389                       NULL, GTK_WIDGET(tooltips->tip_window), "tooltip",
390                       0, 0, req.width, req.height);
391
392   return FALSE;
393 }
394
395 static void
396 gtk_tooltips_draw_tips (GtkTooltips *tooltips)
397 {
398   GtkRequisition requisition;
399   GtkWidget *widget;
400   GtkStyle *style;
401   gint x, y, w, h;
402   GtkTooltipsData *data;
403   gboolean keyboard_mode;
404   GdkScreen *screen;
405   GdkScreen *pointer_screen;
406   gint monitor_num, px, py;
407   GdkRectangle monitor;
408
409   if (!tooltips->tip_window)
410     gtk_tooltips_force_window (tooltips);
411   else if (GTK_WIDGET_VISIBLE (tooltips->tip_window))
412     g_get_current_time (&tooltips->last_popdown);
413
414   gtk_widget_ensure_style (tooltips->tip_window);
415   style = tooltips->tip_window->style;
416   
417   widget = tooltips->active_tips_data->widget;
418   g_object_set_data (G_OBJECT (tooltips->tip_window), tooltips_info_key,
419                      tooltips);
420
421   keyboard_mode = get_keyboard_mode (widget);
422
423   gtk_tooltips_update_screen (tooltips, FALSE);
424   
425   screen = gtk_widget_get_screen (widget);
426
427   data = tooltips->active_tips_data;
428
429   gtk_label_set_text (GTK_LABEL (tooltips->tip_label), data->tip_text);
430
431   gtk_widget_size_request (tooltips->tip_window, &requisition);
432   w = requisition.width;
433   h = requisition.height;
434
435   gdk_window_get_origin (widget->window, &x, &y);
436   if (GTK_WIDGET_NO_WINDOW (widget))
437     {
438       x += widget->allocation.x;
439       y += widget->allocation.y;
440     }
441
442   x += widget->allocation.width / 2;
443     
444   if (!keyboard_mode)
445     gdk_window_get_pointer (gdk_screen_get_root_window (screen),
446                             &x, NULL, NULL);
447
448   x -= (w / 2 + 4);
449
450   gdk_display_get_pointer (gdk_screen_get_display (screen),
451                            &pointer_screen, &px, &py, NULL);
452   if (pointer_screen != screen) 
453     {
454       px = x;
455       py = y;
456     }
457   monitor_num = gdk_screen_get_monitor_at_point (screen, px, py);
458   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
459
460   if ((x + w) > monitor.x + monitor.width)
461     x -= (x + w) - (monitor.x + monitor.width);
462   else if (x < monitor.x)
463     x = monitor.x;
464
465   if ((y + h + widget->allocation.height + 4) > monitor.y + monitor.height)
466     y = y - h - 4;
467   else
468     y = y + widget->allocation.height + 4;
469
470   gtk_window_move (GTK_WINDOW (tooltips->tip_window), x, y);
471   gtk_widget_show (tooltips->tip_window);
472 }
473
474 static gint
475 gtk_tooltips_timeout (gpointer data)
476 {
477   GtkTooltips *tooltips = (GtkTooltips *) data;
478
479   GDK_THREADS_ENTER ();
480   
481   if (tooltips->active_tips_data != NULL &&
482       GTK_WIDGET_DRAWABLE (tooltips->active_tips_data->widget))
483     gtk_tooltips_draw_tips (tooltips);
484
485   GDK_THREADS_LEAVE ();
486
487   return FALSE;
488 }
489
490 static void
491 gtk_tooltips_set_active_widget (GtkTooltips *tooltips,
492                                 GtkWidget   *widget)
493 {
494   if (tooltips->tip_window)
495     {
496       if (GTK_WIDGET_VISIBLE (tooltips->tip_window))
497         g_get_current_time (&tooltips->last_popdown);
498       gtk_widget_hide (tooltips->tip_window);
499     }
500   if (tooltips->timer_tag)
501     {
502       g_source_remove (tooltips->timer_tag);
503       tooltips->timer_tag = 0;
504     }
505   
506   tooltips->active_tips_data = NULL;
507   
508   if (widget)
509     {
510       GList *list;
511       
512       for (list = tooltips->tips_data_list; list; list = list->next)
513         {
514           GtkTooltipsData *tooltipsdata;
515           
516           tooltipsdata = list->data;
517           
518           if (tooltipsdata->widget == widget &&
519               GTK_WIDGET_DRAWABLE (widget))
520             {
521               tooltips->active_tips_data = tooltipsdata;
522               break;
523             }
524         }
525     }
526   else
527     {
528       tooltips->use_sticky_delay = FALSE;
529     }
530 }
531
532 static void
533 gtk_tooltips_show_tip (GtkWidget *widget)
534 {
535   GtkTooltipsData *tooltipsdata;
536
537   tooltipsdata = gtk_tooltips_data_get (widget);
538
539   if (tooltipsdata &&
540       (!tooltipsdata->tooltips->active_tips_data ||
541        tooltipsdata->tooltips->active_tips_data->widget != widget))
542     {
543       gtk_tooltips_set_active_widget (tooltipsdata->tooltips, widget);
544       gtk_tooltips_draw_tips (tooltipsdata->tooltips);
545     }
546 }
547
548 static void
549 gtk_tooltips_hide_tip (GtkWidget *widget)
550 {
551   GtkTooltipsData *tooltipsdata;
552
553   tooltipsdata = gtk_tooltips_data_get (widget);
554
555   if (tooltipsdata &&
556       (tooltipsdata->tooltips->active_tips_data &&
557        tooltipsdata->tooltips->active_tips_data->widget == widget))
558     gtk_tooltips_set_active_widget (tooltipsdata->tooltips, NULL);
559 }
560
561 static gboolean
562 gtk_tooltips_recently_shown (GtkTooltips *tooltips)
563 {
564   GTimeVal now;
565   glong msec;
566   
567   g_get_current_time (&now);
568   msec = (now.tv_sec  - tooltips->last_popdown.tv_sec) * 1000 +
569           (now.tv_usec - tooltips->last_popdown.tv_usec) / 1000;
570   return (msec < STICKY_REVERT_DELAY);
571 }
572
573 static gboolean
574 get_keyboard_mode (GtkWidget *widget)
575 {
576   GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
577   if (GTK_IS_WINDOW (toplevel))
578     return GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (toplevel), "gtk-tooltips-keyboard-mode"));
579   else
580     return FALSE;
581 }
582
583 static void
584 start_keyboard_mode (GtkWidget *widget)
585 {
586   GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
587   if (GTK_IS_WINDOW (toplevel))
588     {
589       GtkWidget *focus = GTK_WINDOW (toplevel)->focus_widget;
590
591       g_object_set_data (G_OBJECT (toplevel), "gtk-tooltips-keyboard-mode", GUINT_TO_POINTER (TRUE));
592
593       if (focus)
594         gtk_tooltips_show_tip (focus);
595     }
596 }
597
598 static void
599 stop_keyboard_mode (GtkWidget *widget)
600 {
601   GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
602   if (GTK_IS_WINDOW (toplevel))
603     {
604       GtkWidget *focus = GTK_WINDOW (toplevel)->focus_widget;
605       if (focus)
606         gtk_tooltips_hide_tip (focus);
607       
608       g_object_set_data (G_OBJECT (toplevel), "gtk-tooltips-keyboard-mode", GUINT_TO_POINTER (FALSE));
609     }
610 }
611
612 static void
613 gtk_tooltips_start_delay (GtkTooltips *tooltips,
614                           GtkWidget   *widget)
615 {
616   GtkTooltipsData *old_tips_data;
617   
618   old_tips_data = tooltips->active_tips_data;
619   if (tooltips->enabled &&
620       (!old_tips_data || old_tips_data->widget != widget))
621     {
622       guint delay;
623       
624       gtk_tooltips_set_active_widget (tooltips, widget);
625       
626       if (tooltips->use_sticky_delay &&
627           gtk_tooltips_recently_shown (tooltips))
628         delay = STICKY_DELAY;
629       else
630         delay = tooltips->delay;
631       tooltips->timer_tag = g_timeout_add (delay,
632                                            gtk_tooltips_timeout,
633                                            (gpointer) tooltips);
634     }
635 }
636
637 static void
638 gtk_tooltips_event_handler (GtkWidget *widget,
639                             GdkEvent  *event)
640 {
641   GtkTooltips *tooltips;
642   GtkTooltipsData *old_tips_data;
643   GtkWidget *event_widget;
644   gboolean keyboard_mode = get_keyboard_mode (widget);
645
646   if ((event->type == GDK_LEAVE_NOTIFY || event->type == GDK_ENTER_NOTIFY) &&
647       event->crossing.detail == GDK_NOTIFY_INFERIOR)
648     return;
649
650   old_tips_data = gtk_tooltips_data_get (widget);
651   tooltips = old_tips_data->tooltips;
652
653   if (keyboard_mode)
654     {
655       switch (event->type)
656         {
657         case GDK_FOCUS_CHANGE:
658           if (event->focus_change.in)
659             gtk_tooltips_show_tip (widget);
660           else
661             gtk_tooltips_hide_tip (widget);
662           break;
663         default:
664           break;
665         }
666     }
667   else
668     {
669       if (event->type != GDK_KEY_PRESS && event->type != GDK_KEY_RELEASE)
670         {
671           event_widget = gtk_get_event_widget (event);
672           if (event_widget != widget)
673             return;
674         }
675   
676       switch (event->type)
677         {
678         case GDK_EXPOSE:
679           /* do nothing */
680           break;
681         case GDK_ENTER_NOTIFY:
682           if (!(GTK_IS_MENU_ITEM (widget) && GTK_MENU_ITEM (widget)->submenu))
683             gtk_tooltips_start_delay (tooltips, widget);
684           break;
685           
686         case GDK_LEAVE_NOTIFY:
687           {
688             gboolean use_sticky_delay;
689             
690             use_sticky_delay = tooltips->tip_window &&
691               GTK_WIDGET_VISIBLE (tooltips->tip_window);
692             gtk_tooltips_set_active_widget (tooltips, NULL);
693             tooltips->use_sticky_delay = use_sticky_delay;
694           }
695           break;
696
697         case GDK_MOTION_NOTIFY:
698           /* Handle menu items specially ... pend popup for each motion
699            * on other widgets, we ignore motion.
700            */
701           if (GTK_IS_MENU_ITEM (widget) && !GTK_MENU_ITEM (widget)->submenu)
702             {
703               /* Completely evil hack to make sure we get the LEAVE_NOTIFY
704                */
705               GTK_PRIVATE_SET_FLAG (widget, GTK_LEAVE_PENDING);
706               gtk_tooltips_set_active_widget (tooltips, NULL);
707               gtk_tooltips_start_delay (tooltips, widget);
708               break;
709             }
710           break;                /* ignore */
711         case GDK_BUTTON_PRESS:
712         case GDK_BUTTON_RELEASE:
713         case GDK_KEY_PRESS:
714         case GDK_KEY_RELEASE:
715         case GDK_PROXIMITY_IN:
716         case GDK_SCROLL:
717           gtk_tooltips_set_active_widget (tooltips, NULL);
718           break;
719         default:
720           break;
721         }
722     }
723 }
724
725 static void
726 gtk_tooltips_widget_unmap (GtkWidget *widget,
727                            gpointer   data)
728 {
729   GtkTooltipsData *tooltipsdata = (GtkTooltipsData *)data;
730   GtkTooltips *tooltips = tooltipsdata->tooltips;
731   
732   if (tooltips->active_tips_data &&
733       (tooltips->active_tips_data->widget == widget))
734     gtk_tooltips_set_active_widget (tooltips, NULL);
735 }
736
737 static void
738 gtk_tooltips_widget_remove (GtkWidget *widget,
739                             gpointer   data)
740 {
741   GtkTooltipsData *tooltipsdata = (GtkTooltipsData*) data;
742   GtkTooltips *tooltips = tooltipsdata->tooltips;
743
744   gtk_tooltips_widget_unmap (widget, data);
745   tooltips->tips_data_list = g_list_remove (tooltips->tips_data_list,
746                                             tooltipsdata);
747   gtk_tooltips_destroy_data (tooltipsdata);
748 }
749
750 void
751 _gtk_tooltips_toggle_keyboard_mode (GtkWidget *widget)
752 {
753   if (get_keyboard_mode (widget))
754     stop_keyboard_mode (widget);
755   else
756     start_keyboard_mode (widget);
757 }
758
759 /**
760  * gtk_tooltips_get_info_from_tip_window:
761  * @tip_window: a #GtkWindow 
762  * @tooltips: the return location for the tooltips which are displayed 
763  *    in @tip_window, or %NULL
764  * @current_widget: the return location for the widget whose tooltips 
765  *    are displayed, or %NULL
766  * 
767  * Determines the tooltips and the widget they belong to from the window in 
768  * which they are displayed. 
769  *
770  * This function is mostly intended for use by accessibility technologies;
771  * applications should have little use for it.
772  * 
773  * Return value: %TRUE if @tip_window is displaying tooltips, otherwise %FALSE.
774  *
775  * Since: 2.4
776  **/
777 gboolean
778 gtk_tooltips_get_info_from_tip_window (GtkWindow    *tip_window,
779                                        GtkTooltips **tooltips,
780                                        GtkWidget   **current_widget)
781 {
782   GtkTooltips  *current_tooltips;  
783   gboolean has_tips;
784
785   g_return_val_if_fail (GTK_IS_WINDOW (tip_window), FALSE);
786
787   current_tooltips = g_object_get_data (G_OBJECT (tip_window), tooltips_info_key);
788
789   has_tips = current_tooltips != NULL;
790
791   if (tooltips)
792     *tooltips = current_tooltips;
793   if (current_widget)
794     *current_widget = has_tips ? current_tooltips->active_tips_data->widget : NULL;
795
796   return has_tips;
797 }