Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/gtk+/ChangeLog,v
retrieving revision 1.1707
diff -u -r1.1707 ChangeLog
--- ChangeLog	2001/02/06 03:08:31	1.1707
+++ ChangeLog	2001/02/06 19:27:19
@@ -1,3 +1,25 @@
+2001-02-06  Jon K Hellan  <hellan@acm.org>
+
+	Implement fast browsing of tooltips:
+	
+	* gtk/gtktooltips.h (struct _GtkTooltips): Add sticky_delay,
+	use_sticky_delay and last_popdown
+	(gtk_tooltips_set_sticky_delay): Declare it.
+	
+	* gtk/gtktooltips.c (gtk_tooltips_init): Initialize sticky_delay,
+	use_sticky_delay and last_popdown.
+	(gtk_tooltips_set_sticky_delay): New public function. Set sticky
+	delay.
+	(gtk_tooltips_draw_tips, gtk_tooltips_set_active_widget): Record
+	time of popdown.
+	(gtk_tooltips_set_active_widget): Unset sticky behaviour if widget
+	is NULL.
+	(gtk_tooltips_recently_shown): New static function.  Return true
+	if < sticky_delay has elapsed since last popdown.
+	(gtk_tooltips_event_handler): Display window after sticky_delay
+	(presumably < normal delay) if < STICKY_REVERT_DELAY has elapsed
+	since last popdown.
+
 Mon Feb  5 22:05:57 2001  Owen Taylor  <otaylor@redhat.com>
 
 	* gdk/linux-fb/gdkimage-fb.c (_gdk_fb_get_image): Fix syntax
Index: gtk/gtktooltips.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtktooltips.h,v
retrieving revision 1.16
diff -u -r1.16 gtktooltips.h
--- gtk/gtktooltips.h	2000/08/30 00:33:38	1.16
+++ gtk/gtktooltips.h	2001/02/06 19:27:19
@@ -68,6 +68,9 @@
   guint   delay : 30;
   guint	  enabled : 1;
   gint	  timer_tag;
+  guint   sticky_delay;
+  gboolean use_sticky_delay;
+  GTimeVal last_popdown;
 };
 
 struct _GtkTooltipsClass
@@ -82,6 +85,8 @@
 void		 gtk_tooltips_disable	   (GtkTooltips   *tooltips);
 void		 gtk_tooltips_set_delay	   (GtkTooltips   *tooltips,
 					    guint	   delay);
+void		 gtk_tooltips_set_sticky_delay (GtkTooltips   *tooltips,
+					    guint	   sticky_delay);
 void		 gtk_tooltips_set_tip	   (GtkTooltips   *tooltips,
 					    GtkWidget	  *widget,
 					    const gchar   *tip_text,
Index: gtk/gtktooltips.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtktooltips.c,v
retrieving revision 1.30
diff -u -r1.30 gtktooltips.c
--- gtk/gtktooltips.c	2000/12/04 16:11:51	1.30
+++ gtk/gtktooltips.c	2001/02/06 19:27:20
@@ -38,6 +38,8 @@
 
 
 #define DEFAULT_DELAY 500           /* Default delay in ms */
+#define STICKY_REVERT_DELAY 1000    /* Delay before sticky tooltips revert
+				     * to normal */
 
 static void gtk_tooltips_class_init        (GtkTooltipsClass *klass);
 static void gtk_tooltips_init              (GtkTooltips      *tooltips);
@@ -103,8 +105,12 @@
   tooltips->tips_data_list = NULL;
   
   tooltips->delay = DEFAULT_DELAY;
+  tooltips->sticky_delay = 0;
   tooltips->enabled = TRUE;
   tooltips->timer_tag = 0;
+  tooltips->use_sticky_delay = FALSE;
+  tooltips->last_popdown.tv_sec = -1;
+  tooltips->last_popdown.tv_usec = -1;
 }
 
 GtkTooltips *
@@ -215,6 +221,16 @@
   tooltips->delay = delay;
 }
 
+void
+gtk_tooltips_set_sticky_delay (GtkTooltips *tooltips,
+			       guint        sticky_delay)
+{
+  g_return_if_fail (tooltips != NULL);
+  g_return_if_fail (GTK_IS_TOOLTIPS (tooltips));
+
+  tooltips->sticky_delay = sticky_delay;
+}
+
 GtkTooltipsData*
 gtk_tooltips_data_get (GtkWidget       *widget)
 {
@@ -310,7 +326,10 @@
   if (!tooltips->tip_window)
     gtk_tooltips_force_window (tooltips);
   else if (GTK_WIDGET_VISIBLE (tooltips->tip_window))
-    gtk_widget_hide (tooltips->tip_window);
+    {
+      gtk_widget_hide (tooltips->tip_window);
+      g_get_current_time (&tooltips->last_popdown);
+    }
 
   gtk_widget_ensure_style (tooltips->tip_window);
   style = tooltips->tip_window->style;
@@ -369,7 +388,11 @@
                                 GtkWidget   *widget)
 {
   if (tooltips->tip_window)
-    gtk_widget_hide (tooltips->tip_window);
+    {
+      if (GTK_WIDGET_VISIBLE (tooltips->tip_window))
+	g_get_current_time (&tooltips->last_popdown);
+      gtk_widget_hide (tooltips->tip_window);
+    }
   if (tooltips->timer_tag)
     {
       gtk_timeout_remove (tooltips->timer_tag);
@@ -396,8 +419,24 @@
 	    }
 	}
     }
+  else
+    {
+      tooltips->use_sticky_delay = FALSE;
+    }
 }
 
+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);
+}
+
 static gint
 gtk_tooltips_event_handler (GtkWidget *widget,
                             GdkEvent  *event)
@@ -429,14 +468,31 @@
       if (tooltips->enabled &&
 	  (!old_tips_data || old_tips_data->widget != widget))
 	{
+	  guint delay;
+	  
 	  gtk_tooltips_set_active_widget (tooltips, widget);
 	  
-	  tooltips->timer_tag = gtk_timeout_add (tooltips->delay,
+	  if (tooltips->use_sticky_delay  &&
+	      gtk_tooltips_recently_shown (tooltips))
+	    delay = tooltips->sticky_delay;
+	  else
+	    delay = tooltips->delay;
+	  tooltips->timer_tag = gtk_timeout_add (delay,
 						 gtk_tooltips_timeout,
 						 (gpointer) tooltips);
 	}
       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;
     default:
       gtk_tooltips_set_active_widget (tooltips, NULL);
       break;
