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