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