Patch: "sticky" tooltips



Hi,

Here's a patch to let the tooltip pop up immediately if a tooltip has
been shown within the last - say - 500 msec.

So if you want to find out what each widget does, e.g. in a toolbar,
you can browse the tooltips very quickly.

Immediate popup is turned off when "interesting" events, e.g. button
presses, occur. So most of the time, you would experience the normal
delay.

I've seen this behaviour on Windows, in Opera for Linux (standard in
Qt?), and in the WindowMaker configuration utility, and find it
convenient. In particular when you want to find out what each icon in
a toolbar or a tool palette does.

I posted the patch early this summer, and have tried to improve it as
suggested in the comments i received. But there were no reactions to
the revised proposal. I hope you have time to review this.

There is one new api function: gtk_tooltips_set_sticky_delay. This
sets the "sticky delay", the delay before the tooltip pops up in fast
browse mode. By default, this is 0, meaning immediate popup. By
setting it to the same value as the normal delay, we get traditional
behaviour. 

How it works:

Where the tooltip timer is set, the (private) use_sticky_delay
attribute is examined. If true, we check how long it's been since last
time a tooltip popped down. If it's below a certain limit, the tooltip
pops up after the sticky_delay, which is presumably smaller than the
regular delay.

use_sticky_delay is turned on when leaving a window when its tooltip
was visible, and turned off leaving a window when its tooltip was not
visible. It is also turned off when the active widget is set to NULL.

Regards

Jon Kåre

Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/gtk+/ChangeLog,v
retrieving revision 1.1434
diff -u -r1.1434 ChangeLog
--- ChangeLog	2000/10/18 18:42:45	1.1434
+++ ChangeLog	2000/10/18 19:01:55
@@ -1,3 +1,25 @@
+2000-10-18  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.
+
 2000-10-18  Havoc Pennington  <hp redhat com>
 
 	* gtk/gtktextiter.c (gtk_text_iter_forward_to_newline): Fix a bug 
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	2000/10/18 19:01:56
@@ -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.29
diff -u -r1.29 gtktooltips.c
--- gtk/gtktooltips.c	2000/07/26 11:32:55	1.29
+++ gtk/gtktooltips.c	2000/10/18 19:01:56
@@ -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 *
@@ -219,6 +225,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)
 {
@@ -314,7 +330,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;
@@ -373,7 +392,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);
@@ -400,8 +423,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)
@@ -433,14 +472,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;




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]