gtktooltips.c 17.7 KB
Newer Older
Elliot Lee's avatar
Elliot Lee committed
1
2
3
4
/* GTK - The GIMP Toolkit
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * This library is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Lesser General Public
Elliot Lee's avatar
Elliot Lee committed
6
7
8
9
10
11
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
 * Lesser General Public License for more details.
Elliot Lee's avatar
Elliot Lee committed
13
 *
14
 * You should have received a copy of the GNU Lesser General Public
15
16
17
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
Elliot Lee's avatar
Elliot Lee committed
18
 */
19
20

/*
21
 * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22
23
24
25
26
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
 */

Elliot Lee's avatar
Elliot Lee committed
27
28
#include <stdlib.h>
#include <string.h>
29
#include <stdio.h>
Elliot Lee's avatar
Elliot Lee committed
30

31
#include "gtklabel.h"
Elliot Lee's avatar
Elliot Lee committed
32
#include "gtkmain.h"
33
#include "gtkmenuitem.h"
34
#include "gtkprivate.h"
Elliot Lee's avatar
Elliot Lee committed
35
#include "gtkwidget.h"
Owen Taylor's avatar
Owen Taylor committed
36
#include "gtkwindow.h"
Elliot Lee's avatar
Elliot Lee committed
37
38
39
40
41
#include "gtkstyle.h"
#include "gtktooltips.h"


#define DEFAULT_DELAY 500           /* Default delay in ms */
42
43
44
45
46
47
#define STICKY_DELAY 0              /* Delay before popping up next tip
                                     * if we're sticky
                                     */
#define STICKY_REVERT_DELAY 1000    /* Delay before sticky tooltips revert
				     * to normal
                                     */
Elliot Lee's avatar
Elliot Lee committed
48

49
50
51
static void gtk_tooltips_class_init        (GtkTooltipsClass *klass);
static void gtk_tooltips_init              (GtkTooltips      *tooltips);
static void gtk_tooltips_destroy           (GtkObject        *object);
Elliot Lee's avatar
Elliot Lee committed
52

53
static void gtk_tooltips_event_handler     (GtkWidget   *widget,
Elliot Lee's avatar
Elliot Lee committed
54
55
56
57
58
59
60
61
                                            GdkEvent    *event);
static void gtk_tooltips_widget_unmap      (GtkWidget   *widget,
                                            gpointer     data);
static void gtk_tooltips_widget_remove     (GtkWidget   *widget,
                                            gpointer     data);
static void gtk_tooltips_set_active_widget (GtkTooltips *tooltips,
                                            GtkWidget   *widget);
static gint gtk_tooltips_timeout           (gpointer     data);
62

63
static gint gtk_tooltips_paint_window      (GtkTooltips *tooltips);
Elliot Lee's avatar
Elliot Lee committed
64
65
static void gtk_tooltips_draw_tips         (GtkTooltips *tooltips);

66
67
static gboolean get_keyboard_mode          (GtkWidget   *widget);

Havoc Pennington's avatar
Delete.    
Havoc Pennington committed
68
static GtkObjectClass *parent_class;
69
static const gchar  *tooltips_data_key = "_GtkTooltipsData";
Elliot Lee's avatar
Elliot Lee committed
70

Manish Singh's avatar
Manish Singh committed
71
GType
72
gtk_tooltips_get_type (void)
73
{
Manish Singh's avatar
Manish Singh committed
74
  static GType tooltips_type = 0;
Elliot Lee's avatar
Elliot Lee committed
75

76
  if (!tooltips_type)
Elliot Lee's avatar
Elliot Lee committed
77
    {
Manish Singh's avatar
Manish Singh committed
78
      static const GTypeInfo tooltips_info =
79
80
      {
	sizeof (GtkTooltipsClass),
Manish Singh's avatar
Manish Singh committed
81
82
83
84
85
86
87
88
	NULL,		/* base_init */
	NULL,		/* base_finalize */
	(GClassInitFunc) gtk_tooltips_class_init,
	NULL,		/* class_finalize */
	NULL,		/* class_data */
	sizeof (GtkTooltips),
	0,		/* n_preallocs */
	(GInstanceInitFunc) gtk_tooltips_init,
89
90
      };

Manish Singh's avatar
Manish Singh committed
91
92
      tooltips_type = g_type_register_static (GTK_TYPE_OBJECT, "GtkTooltips",
					      &tooltips_info, 0);
Elliot Lee's avatar
Elliot Lee committed
93
94
    }

95
  return tooltips_type;
Elliot Lee's avatar
Elliot Lee committed
96
97
}

98
99
static void
gtk_tooltips_class_init (GtkTooltipsClass *class)
Elliot Lee's avatar
Elliot Lee committed
100
{
101
102
103
  GtkObjectClass *object_class;

  object_class = (GtkObjectClass*) class;
Manish Singh's avatar
Manish Singh committed
104
105

  parent_class = g_type_class_peek_parent (class);
106
107

  object_class->destroy = gtk_tooltips_destroy;
Elliot Lee's avatar
Elliot Lee committed
108
109
}

110
111
static void
gtk_tooltips_init (GtkTooltips *tooltips)
Elliot Lee's avatar
Elliot Lee committed
112
{
113
114
115
116
117
118
119
  tooltips->tip_window = NULL;
  tooltips->active_tips_data = NULL;
  tooltips->tips_data_list = NULL;
  
  tooltips->delay = DEFAULT_DELAY;
  tooltips->enabled = TRUE;
  tooltips->timer_tag = 0;
120
121
122
  tooltips->use_sticky_delay = FALSE;
  tooltips->last_popdown.tv_sec = -1;
  tooltips->last_popdown.tv_usec = -1;
123
124
125
}

GtkTooltips *
126
gtk_tooltips_new (void)
127
{
Manish Singh's avatar
Manish Singh committed
128
  return g_object_new (GTK_TYPE_TOOLTIPS, NULL);
Elliot Lee's avatar
Elliot Lee committed
129
130
131
}

static void
132
gtk_tooltips_destroy_data (GtkTooltipsData *tooltipsdata)
Elliot Lee's avatar
Elliot Lee committed
133
{
134
135
  g_free (tooltipsdata->tip_text);
  g_free (tooltipsdata->tip_private);
Manish Singh's avatar
Manish Singh committed
136
137
138
139
140
141
142
143
144
145
146
147
148

  g_signal_handlers_disconnect_by_func (tooltipsdata->widget,
					gtk_tooltips_event_handler,
					tooltipsdata);
  g_signal_handlers_disconnect_by_func (tooltipsdata->widget,
					gtk_tooltips_widget_unmap,
					tooltipsdata);
  g_signal_handlers_disconnect_by_func (tooltipsdata->widget,
					gtk_tooltips_widget_remove,
					tooltipsdata);

  g_object_set_data (G_OBJECT (tooltipsdata->widget), tooltips_data_key, NULL);
  g_object_unref (tooltipsdata->widget);
Elliot Lee's avatar
Elliot Lee committed
149
150
151
  g_free (tooltipsdata);
}

152
static void
153
gtk_tooltips_destroy (GtkObject *object)
Elliot Lee's avatar
Elliot Lee committed
154
{
155
  GtkTooltips *tooltips = GTK_TOOLTIPS (object);
Elliot Lee's avatar
Elliot Lee committed
156
157
158
159
160
  GList *current;
  GtkTooltipsData *tooltipsdata;

  g_return_if_fail (tooltips != NULL);

161
  if (tooltips->timer_tag)
Elliot Lee's avatar
Elliot Lee committed
162
163
    {
      gtk_timeout_remove (tooltips->timer_tag);
164
      tooltips->timer_tag = 0;
Elliot Lee's avatar
Elliot Lee committed
165
166
    }

167
  if (tooltips->tips_data_list != NULL)
Elliot Lee's avatar
Elliot Lee committed
168
    {
169
      current = g_list_first (tooltips->tips_data_list);
Elliot Lee's avatar
Elliot Lee committed
170
171
172
173
      while (current != NULL)
	{
	  tooltipsdata = (GtkTooltipsData*) current->data;
	  current = current->next;
174
	  gtk_tooltips_widget_remove (tooltipsdata->widget, tooltipsdata);
Elliot Lee's avatar
Elliot Lee committed
175
176
177
	}
    }

178
179
  if (tooltips->tip_window)
    gtk_widget_destroy (tooltips->tip_window);
Elliot Lee's avatar
Elliot Lee committed
180
181
}

182
183
void
gtk_tooltips_force_window (GtkTooltips *tooltips)
184
{
185
186
187
188
  g_return_if_fail (GTK_IS_TOOLTIPS (tooltips));

  if (!tooltips->tip_window)
    {
Owen Taylor's avatar
Owen Taylor committed
189
      tooltips->tip_window = gtk_window_new (GTK_WINDOW_POPUP);
190
191
      gtk_window_set_screen (GTK_WINDOW (tooltips->tip_window),
			     gtk_widget_get_screen (tooltips->active_tips_data->widget));
192
      gtk_widget_set_app_paintable (tooltips->tip_window, TRUE);
193
      gtk_window_set_resizable (GTK_WINDOW (tooltips->tip_window), FALSE);
194
      gtk_widget_set_name (tooltips->tip_window, "gtk-tooltips");
195
196
      gtk_container_set_border_width (GTK_CONTAINER (tooltips->tip_window), 4);

Manish Singh's avatar
Manish Singh committed
197
198
199
200
      g_signal_connect_swapped (tooltips->tip_window,
				"expose_event",
				G_CALLBACK (gtk_tooltips_paint_window), 
				tooltips);
201

202
203
204
205
206
207
208
      tooltips->tip_label = gtk_label_new (NULL);
      gtk_label_set_line_wrap (GTK_LABEL (tooltips->tip_label), TRUE);
      gtk_misc_set_alignment (GTK_MISC (tooltips->tip_label), 0.5, 0.5);
      gtk_widget_show (tooltips->tip_label);
      
      gtk_container_add (GTK_CONTAINER (tooltips->tip_window), tooltips->tip_label);

Manish Singh's avatar
Manish Singh committed
209
210
211
212
      g_signal_connect (tooltips->tip_window,
			"destroy",
			G_CALLBACK (gtk_widget_destroyed),
			&tooltips->tip_window);
213
    }
214
215
}

Elliot Lee's avatar
Elliot Lee committed
216
217
218
219
220
221
222
223
224
225
226
227
228
void
gtk_tooltips_enable (GtkTooltips *tooltips)
{
  g_return_if_fail (tooltips != NULL);

  tooltips->enabled = TRUE;
}

void
gtk_tooltips_disable (GtkTooltips *tooltips)
{
  g_return_if_fail (tooltips != NULL);

229
  gtk_tooltips_set_active_widget (tooltips, NULL);
Elliot Lee's avatar
Elliot Lee committed
230

231
  tooltips->enabled = FALSE;
Elliot Lee's avatar
Elliot Lee committed
232
233
234
235
}

void
gtk_tooltips_set_delay (GtkTooltips *tooltips,
236
                        guint         delay)
Elliot Lee's avatar
Elliot Lee committed
237
238
239
240
241
242
{
  g_return_if_fail (tooltips != NULL);

  tooltips->delay = delay;
}

243
244
245
246
247
GtkTooltipsData*
gtk_tooltips_data_get (GtkWidget       *widget)
{
  g_return_val_if_fail (widget != NULL, NULL);

Manish Singh's avatar
Manish Singh committed
248
  return g_object_get_data (G_OBJECT (widget), tooltips_data_key);
249
250
}

Elliot Lee's avatar
Elliot Lee committed
251
void
252
253
254
255
gtk_tooltips_set_tip (GtkTooltips *tooltips,
		      GtkWidget   *widget,
		      const gchar *tip_text,
		      const gchar *tip_private)
Elliot Lee's avatar
Elliot Lee committed
256
257
258
{
  GtkTooltipsData *tooltipsdata;

259
  g_return_if_fail (GTK_IS_TOOLTIPS (tooltips));
Elliot Lee's avatar
Elliot Lee committed
260
261
  g_return_if_fail (widget != NULL);

262
  tooltipsdata = gtk_tooltips_data_get (widget);
Elliot Lee's avatar
Elliot Lee committed
263

264
  if (!tip_text)
265
266
267
268
269
270
271
272
273
274
275
276
    {
      if (tooltipsdata)
	gtk_tooltips_widget_remove (tooltipsdata->widget, tooltipsdata);
      return;
    }
  
  if (tooltips->active_tips_data 
      && tooltips->active_tips_data->widget == widget
      && GTK_WIDGET_DRAWABLE (tooltips->active_tips_data->widget))
    {
      g_free (tooltipsdata->tip_text);
      g_free (tooltipsdata->tip_private);
Elliot Lee's avatar
Elliot Lee committed
277

278
279
280
281
282
283
      tooltipsdata->tip_text = g_strdup (tip_text);
      tooltipsdata->tip_private = g_strdup (tip_private);
      
      gtk_tooltips_draw_tips (tooltips);
    }
  else 
Elliot Lee's avatar
Elliot Lee committed
284
    {
Manish Singh's avatar
Manish Singh committed
285
      g_object_ref (widget);
286
287
288
289
290
291
      
      if (tooltipsdata)
        gtk_tooltips_widget_remove (tooltipsdata->widget, tooltipsdata);
      
      tooltipsdata = g_new0 (GtkTooltipsData, 1);
      
292
      tooltipsdata->tooltips = tooltips;
Elliot Lee's avatar
Elliot Lee committed
293
294
      tooltipsdata->widget = widget;

295
296
      tooltipsdata->tip_text = g_strdup (tip_text);
      tooltipsdata->tip_private = g_strdup (tip_private);
Elliot Lee's avatar
Elliot Lee committed
297

298
      tooltips->tips_data_list = g_list_append (tooltips->tips_data_list,
299
                                                tooltipsdata);
Manish Singh's avatar
Manish Singh committed
300
301
302
      g_signal_connect_after (widget, "event-after",
                              G_CALLBACK (gtk_tooltips_event_handler),
			      tooltipsdata);
Elliot Lee's avatar
Elliot Lee committed
303

Manish Singh's avatar
Manish Singh committed
304
305
      g_object_set_data (G_OBJECT (widget), tooltips_data_key,
                         tooltipsdata);
Elliot Lee's avatar
Elliot Lee committed
306

Manish Singh's avatar
Manish Singh committed
307
308
309
      g_signal_connect (widget, "unmap",
			G_CALLBACK (gtk_tooltips_widget_unmap),
			tooltipsdata);
Elliot Lee's avatar
Elliot Lee committed
310

Manish Singh's avatar
Manish Singh committed
311
312
313
      g_signal_connect (widget, "unrealize",
			G_CALLBACK (gtk_tooltips_widget_unmap),
			tooltipsdata);
314

Manish Singh's avatar
Manish Singh committed
315
316
317
      g_signal_connect (widget, "destroy",
                        G_CALLBACK (gtk_tooltips_widget_remove),
			tooltipsdata);
Elliot Lee's avatar
Elliot Lee committed
318
319
320
    }
}

321
static gint
322
gtk_tooltips_paint_window (GtkTooltips *tooltips)
323
{
324
325
326
327
  gtk_paint_flat_box (tooltips->tip_window->style, tooltips->tip_window->window,
		      GTK_STATE_NORMAL, GTK_SHADOW_OUT, 
		      NULL, GTK_WIDGET(tooltips->tip_window), "tooltip",
		      0, 0, -1, -1);
328

329
  return FALSE;
330
331
}

Elliot Lee's avatar
Elliot Lee committed
332
static void
333
gtk_tooltips_draw_tips (GtkTooltips *tooltips)
Elliot Lee's avatar
Elliot Lee committed
334
{
335
  GtkRequisition requisition;
Elliot Lee's avatar
Elliot Lee committed
336
  GtkWidget *widget;
337
  GtkStyle *style;
338
  gint x, y, w, h, scr_w, scr_h;
Elliot Lee's avatar
Elliot Lee committed
339
  GtkTooltipsData *data;
340
  gboolean keyboard_mode;
341
  GdkScreen *screen;
Elliot Lee's avatar
Elliot Lee committed
342

343
  if (!tooltips->tip_window)
344
    gtk_tooltips_force_window (tooltips);
345
  else if (GTK_WIDGET_VISIBLE (tooltips->tip_window))
346
    g_get_current_time (&tooltips->last_popdown);
Elliot Lee's avatar
Elliot Lee committed
347

348
  gtk_widget_ensure_style (tooltips->tip_window);
349
350
  style = tooltips->tip_window->style;
  
351
  widget = tooltips->active_tips_data->widget;
Elliot Lee's avatar
Elliot Lee committed
352

353
  keyboard_mode = get_keyboard_mode (widget);
354
355
356
357
  
  screen = gtk_widget_get_screen (widget);
  scr_w = gdk_screen_get_width (screen);
  scr_h = gdk_screen_get_height (screen);
Elliot Lee's avatar
Elliot Lee committed
358

359
  data = tooltips->active_tips_data;
360

361
  gtk_label_set_text (GTK_LABEL (tooltips->tip_label), data->tip_text);
362

363
364
365
  gtk_widget_size_request (tooltips->tip_window, &requisition);
  w = requisition.width;
  h = requisition.height;
Elliot Lee's avatar
Elliot Lee committed
366

367
  gdk_window_get_origin (widget->window, &x, &y);
368
  if (GTK_WIDGET_NO_WINDOW (widget))
369
370
371
372
373
374
375
376
    {
      x += widget->allocation.x;
      y += widget->allocation.y;
    }

  x += widget->allocation.width / 2;
    
  if (!keyboard_mode)
377
378
    gdk_window_get_pointer (gdk_screen_get_root_window (screen),
			    &x, NULL, NULL);
Elliot Lee's avatar
Elliot Lee committed
379

380
  x -= (w / 2 + 4);
Elliot Lee's avatar
Elliot Lee committed
381
382
383
384
385
386
387
388
389
390
391

  if ((x + w) > scr_w)
    x -= (x + w) - scr_w;
  else if (x < 0)
    x = 0;

  if ((y + h + widget->allocation.height + 4) > scr_h)
    y = y - h - 4;
  else
    y = y + widget->allocation.height + 4;

392
  gtk_window_move (GTK_WINDOW (tooltips->tip_window), x, y);
393
  gtk_widget_show (tooltips->tip_window);
Elliot Lee's avatar
Elliot Lee committed
394
395
396
397
398
399
400
}

static gint
gtk_tooltips_timeout (gpointer data)
{
  GtkTooltips *tooltips = (GtkTooltips *) data;

401
  GDK_THREADS_ENTER ();
402
  
403
404
  if (tooltips->active_tips_data != NULL &&
      GTK_WIDGET_DRAWABLE (tooltips->active_tips_data->widget))
Elliot Lee's avatar
Elliot Lee committed
405
406
    gtk_tooltips_draw_tips (tooltips);

407
  GDK_THREADS_LEAVE ();
408

Elliot Lee's avatar
Elliot Lee committed
409
410
411
412
413
414
415
  return FALSE;
}

static void
gtk_tooltips_set_active_widget (GtkTooltips *tooltips,
                                GtkWidget   *widget)
{
416
  if (tooltips->tip_window)
417
418
419
420
421
    {
      if (GTK_WIDGET_VISIBLE (tooltips->tip_window))
	g_get_current_time (&tooltips->last_popdown);
      gtk_widget_hide (tooltips->tip_window);
    }
422
  if (tooltips->timer_tag)
Elliot Lee's avatar
Elliot Lee committed
423
    {
424
425
426
427
428
429
430
431
432
433
434
      gtk_timeout_remove (tooltips->timer_tag);
      tooltips->timer_tag = 0;
    }
  
  tooltips->active_tips_data = NULL;
  
  if (widget)
    {
      GList *list;
      
      for (list = tooltips->tips_data_list; list; list = list->next)
Elliot Lee's avatar
Elliot Lee committed
435
	{
436
437
438
439
440
441
442
443
444
445
	  GtkTooltipsData *tooltipsdata;
	  
	  tooltipsdata = list->data;
	  
	  if (tooltipsdata->widget == widget &&
	      GTK_WIDGET_DRAWABLE (widget))
	    {
	      tooltips->active_tips_data = tooltipsdata;
	      break;
	    }
Elliot Lee's avatar
Elliot Lee committed
446
447
	}
    }
448
449
450
451
452
453
  else
    {
      tooltips->use_sticky_delay = FALSE;
    }
}

454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
static void
gtk_tooltips_show_tip (GtkWidget *widget)
{
  GtkTooltipsData *tooltipsdata;

  tooltipsdata = gtk_tooltips_data_get (widget);

  if (tooltipsdata &&
      (!tooltipsdata->tooltips->active_tips_data ||
       tooltipsdata->tooltips->active_tips_data->widget != widget))
    {
      gtk_tooltips_set_active_widget (tooltipsdata->tooltips, widget);
      gtk_tooltips_draw_tips (tooltipsdata->tooltips);
    }
}

static void
gtk_tooltips_hide_tip (GtkWidget *widget)
{
  GtkTooltipsData *tooltipsdata;

  tooltipsdata = gtk_tooltips_data_get (widget);

  if (tooltipsdata &&
      (tooltipsdata->tooltips->active_tips_data &&
       tooltipsdata->tooltips->active_tips_data->widget == widget))
    gtk_tooltips_set_active_widget (tooltipsdata->tooltips, NULL);
}

483
484
485
486
487
488
489
490
491
492
static gboolean
gtk_tooltips_recently_shown (GtkTooltips *tooltips)
{
  GTimeVal now;
  glong msec;
  
  g_get_current_time (&now);
  msec = (now.tv_sec  - tooltips->last_popdown.tv_sec) * 1000 +
	  (now.tv_usec - tooltips->last_popdown.tv_usec) / 1000;
  return (msec < STICKY_REVERT_DELAY);
Elliot Lee's avatar
Elliot Lee committed
493
494
}

495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
static gboolean
get_keyboard_mode (GtkWidget *widget)
{
  GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
  if (GTK_IS_WINDOW (toplevel))
    return GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (toplevel), "gtk-tooltips-keyboard-mode"));
  else
    return FALSE;
}

static void
start_keyboard_mode (GtkWidget *widget)
{
  GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
  if (GTK_IS_WINDOW (toplevel))
    {
      GtkWidget *focus = GTK_WINDOW (toplevel)->focus_widget;
512
513
514

      g_object_set_data (G_OBJECT (toplevel), "gtk-tooltips-keyboard-mode", GUINT_TO_POINTER (TRUE));

515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
      if (focus)
	gtk_tooltips_show_tip (focus);
    }
}

static void
stop_keyboard_mode (GtkWidget *widget)
{
  GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
  if (GTK_IS_WINDOW (toplevel))
    {
      GtkWidget *focus = GTK_WINDOW (toplevel)->focus_widget;
      if (focus)
	gtk_tooltips_hide_tip (focus);
      
      g_object_set_data (G_OBJECT (toplevel), "gtk-tooltips-keyboard-mode", GUINT_TO_POINTER (FALSE));
    }
}

534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
static void
gtk_tooltips_start_delay (GtkTooltips *tooltips,
			  GtkWidget   *widget)
{
  GtkTooltipsData *old_tips_data;
  
  old_tips_data = tooltips->active_tips_data;
  if (tooltips->enabled &&
      (!old_tips_data || old_tips_data->widget != widget))
    {
      guint delay;
      
      gtk_tooltips_set_active_widget (tooltips, widget);
      
      if (tooltips->use_sticky_delay &&
	  gtk_tooltips_recently_shown (tooltips))
	delay = STICKY_DELAY;
      else
	delay = tooltips->delay;
      tooltips->timer_tag = gtk_timeout_add (delay,
					     gtk_tooltips_timeout,
					     (gpointer) tooltips);
    }
}

559
static void
Elliot Lee's avatar
Elliot Lee committed
560
561
562
563
gtk_tooltips_event_handler (GtkWidget *widget,
                            GdkEvent  *event)
{
  GtkTooltips *tooltips;
564
  GtkTooltipsData *old_tips_data;
565
  GtkWidget *event_widget;
566
  gboolean keyboard_mode = get_keyboard_mode (widget);
Elliot Lee's avatar
Elliot Lee committed
567
568
569

  if ((event->type == GDK_LEAVE_NOTIFY || event->type == GDK_ENTER_NOTIFY) &&
      event->crossing.detail == GDK_NOTIFY_INFERIOR)
570
    return;
571
572
573

  old_tips_data = gtk_tooltips_data_get (widget);
  tooltips = old_tips_data->tooltips;
Elliot Lee's avatar
Elliot Lee committed
574

575
  if (keyboard_mode)
Elliot Lee's avatar
Elliot Lee committed
576
    {
577
      switch (event->type)
Elliot Lee's avatar
Elliot Lee committed
578
	{
579
580
581
582
583
584
585
586
587
588
589
590
	case GDK_FOCUS_CHANGE:
	  if (event->focus_change.in)
	    gtk_tooltips_show_tip (widget);
	  else
	    gtk_tooltips_hide_tip (widget);
	  break;
	default:
	  break;
	}
    }
  else
    {
591
592
593
594
595
596
      if (event->type != GDK_KEY_PRESS && event->type != GDK_KEY_RELEASE)
	{
	  event_widget = gtk_get_event_widget (event);
	  if (event_widget != widget)
	    return;
	}
597
598
599
600
601
602
603
  
      switch (event->type)
	{
	case GDK_EXPOSE:
	  /* do nothing */
	  break;
	case GDK_ENTER_NOTIFY:
604
605
	  if (!(GTK_IS_MENU_ITEM (widget) && GTK_MENU_ITEM (widget)->submenu))
	    gtk_tooltips_start_delay (tooltips, widget);
606
607
608
609
610
611
612
613
614
615
616
617
	  break;
	  
	case GDK_LEAVE_NOTIFY:
	  {
	    gboolean use_sticky_delay;
	    
	    use_sticky_delay = tooltips->tip_window &&
	      GTK_WIDGET_VISIBLE (tooltips->tip_window);
	    gtk_tooltips_set_active_widget (tooltips, NULL);
	    tooltips->use_sticky_delay = use_sticky_delay;
	  }
	  break;
618

619
620
621
622
	case GDK_MOTION_NOTIFY:
	  /* Handle menu items specially ... pend popup for each motion
	   * on other widgets, we ignore motion.
	   */
623
	  if (GTK_IS_MENU_ITEM (widget) && !GTK_MENU_ITEM (widget)->submenu)
624
	    {
625
626
627
	      /* Completely evil hack to make sure we get the LEAVE_NOTIFY
	       */
	      GTK_PRIVATE_SET_FLAG (widget, GTK_LEAVE_PENDING);
628
629
630
631
632
	      gtk_tooltips_set_active_widget (tooltips, NULL);
	      gtk_tooltips_start_delay (tooltips, widget);
	      break;
	    }
	  break;		/* ignore */
633
634
635
636
637
638
	case GDK_BUTTON_PRESS:
	case GDK_BUTTON_RELEASE:
	case GDK_KEY_PRESS:
	case GDK_KEY_RELEASE:
	case GDK_PROXIMITY_IN:
	case GDK_SCROLL:
639
640
	  gtk_tooltips_set_active_widget (tooltips, NULL);
	  break;
641
642
	default:
	  break;
Elliot Lee's avatar
Elliot Lee committed
643
644
645
646
647
648
649
650
	}
    }
}

static void
gtk_tooltips_widget_unmap (GtkWidget *widget,
			   gpointer   data)
{
651
652
  GtkTooltipsData *tooltipsdata = (GtkTooltipsData *)data;
  GtkTooltips *tooltips = tooltipsdata->tooltips;
653
654
655
656
  
  if (tooltips->active_tips_data &&
      (tooltips->active_tips_data->widget == widget))
    gtk_tooltips_set_active_widget (tooltips, NULL);
Elliot Lee's avatar
Elliot Lee committed
657
658
659
660
661
662
}

static void
gtk_tooltips_widget_remove (GtkWidget *widget,
			    gpointer   data)
{
663
  GtkTooltipsData *tooltipsdata = (GtkTooltipsData*) data;
664
  GtkTooltips *tooltips = tooltipsdata->tooltips;
Elliot Lee's avatar
Elliot Lee committed
665
666

  gtk_tooltips_widget_unmap (widget, data);
667
668
  tooltips->tips_data_list = g_list_remove (tooltips->tips_data_list,
					    tooltipsdata);
669
  gtk_tooltips_destroy_data (tooltipsdata);
Elliot Lee's avatar
Elliot Lee committed
670
}
671

672
673
void
_gtk_tooltips_toggle_keyboard_mode (GtkWidget *widget)
674
{
675
676
677
678
  if (get_keyboard_mode (widget))
    stop_keyboard_mode (widget);
  else
    start_keyboard_mode (widget);
679
}
680