Tooltips keynav patch



I was looking at the Bug 53614, "KEYNAV: GtkTooltip" and the patch
from Padraig on there. The patch seemed to implement the right
behavior, but I wasn't entirely comfortable with the way it did
things, in particular the changes to gtkwindow.c.

So, I took a stab at reimplementing it, attached below; this version
is mostly inside gtktooltips.c with a small change in gtkwidget.c

Limitations of this patch:

 1) It doesn't fully work with plug-socket. That is, every GtkPlug
    has a separate "keyboard mode" setting that Control-F1 in a widget
    in that plug toggles.

 2) It doesn't implement the suggested Escape to get out of keyborad mode
    you have to press Control-F1 again. 

    Implementing the Escape key binding is rather a nuisance - it can't
    be done with a keybinding, since it must have a _higher_ priority
    than the Escape accelerator to close a dialog. The way it would
    need to be done is to define the keybinding with a GtkSetting
    (as in Padraig's patch), then make a signal connection to key-press-event
    when turning on keyboard-mode for a toplevel. (But that wouldn't 
    work at all for plug-socket.)

 3) It breaks the newly introduced propagating-Control-F1 behavior,
    since Control-F1 always simply toggles the keyboard mode.

    If we want to support tooltips for parent widgets, it probably 
    should be done by making "keyboard mode" search for a parent widget
    with a tooltip if the focus widget doesn't have one, and show
    that. This shouldn't be that hard to implement.

It's certainly far from perfect, but I think is a lot more useable than
what is in CVS, and we'll probably have to live with something at
about this level of functionality for GTK+-2.0.

Regards,
                                        Owen

Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/gtk+/ChangeLog,v
retrieving revision 1.2961
diff -u -p -r1.2961 ChangeLog
--- ChangeLog	2002/02/07 18:43:56	1.2961
+++ ChangeLog	2002/02/07 22:14:57
@@ -1,3 +1,21 @@
+Thu Feb  7 17:10:01 2002  Owen Taylor  <otaylor redhat com>
+
+	* gtk/gtktooltips.[ch]: Export _gtk_tooltips_toggle_keyboard_mode()
+	rather than _gtk_tooltips_show_tip(). When in "keyboard mode",
+	show the tip for the currently focused widget rather than
+	than the tip that the mouse is over. Also, fix thread locking
+	bug with keyboard tooltips, and use ::event-after rather than
+	::event to observe events more reliably.
+
+	* gtk/gtkwidget.c: Make Control-F1 toggle the keyboard mode
+	for tooltips for the window.
+
Index: gtk/gtktooltips.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtktooltips.c,v
retrieving revision 1.45
diff -u -p -r1.45 gtktooltips.c
--- gtk/gtktooltips.c	2002/02/07 15:45:17	1.45
+++ gtk/gtktooltips.c	2002/02/07 22:14:57
@@ -49,7 +49,7 @@ static void gtk_tooltips_class_init     
 static void gtk_tooltips_init              (GtkTooltips      *tooltips);
 static void gtk_tooltips_destroy           (GtkObject        *object);
 
-static gint gtk_tooltips_event_handler     (GtkWidget   *widget,
+static void gtk_tooltips_event_handler     (GtkWidget   *widget,
                                             GdkEvent    *event);
 static void gtk_tooltips_widget_unmap      (GtkWidget   *widget,
                                             gpointer     data);
@@ -62,6 +62,8 @@ static gint gtk_tooltips_timeout        
 static gint gtk_tooltips_paint_window      (GtkTooltips *tooltips);
 static void gtk_tooltips_draw_tips         (GtkTooltips *tooltips);
 
+static gboolean get_keyboard_mode          (GtkWidget   *widget);
+
 static GtkObjectClass *parent_class;
 static const gchar  *tooltips_data_key = "_GtkTooltipsData";
 
@@ -293,7 +282,7 @@ gtk_tooltips_set_tip (GtkTooltips *toolt
 
       tooltips->tips_data_list = g_list_append (tooltips->tips_data_list,
                                                 tooltipsdata);
-      gtk_signal_connect_after (GTK_OBJECT (widget), "event",
+      gtk_signal_connect_after (GTK_OBJECT (widget), "event-after",
                                (GtkSignalFunc) gtk_tooltips_event_handler,
                                tooltipsdata);
 
@@ -326,13 +315,14 @@ gtk_tooltips_paint_window (GtkTooltips *
 }
 
 static void
-gtk_tooltips_draw_tips (GtkTooltips * tooltips)
+gtk_tooltips_draw_tips (GtkTooltips *tooltips)
 {
   GtkRequisition requisition;
   GtkWidget *widget;
   GtkStyle *style;
   gint x, y, w, h, scr_w, scr_h;
   GtkTooltipsData *data;
+  gboolean keyboard_mode;
 
   if (!tooltips->tip_window)
     gtk_tooltips_force_window (tooltips);
@@ -344,6 +334,8 @@ gtk_tooltips_draw_tips (GtkTooltips * to
   
   widget = tooltips->active_tips_data->widget;
 
+  keyboard_mode = get_keyboard_mode (widget);
+
   scr_w = gdk_screen_width ();
   scr_h = gdk_screen_height ();
 
@@ -355,10 +347,17 @@ gtk_tooltips_draw_tips (GtkTooltips * to
   w = requisition.width;
   h = requisition.height;
 
-  gdk_window_get_pointer (NULL, &x, NULL, NULL);
-  gdk_window_get_origin (widget->window, NULL, &y);
+  gdk_window_get_origin (widget->window, &x, &y);
   if (GTK_WIDGET_NO_WINDOW (widget))
-    y += widget->allocation.y;
+    {
+      x += widget->allocation.x;
+      y += widget->allocation.y;
+    }
+
+  x += widget->allocation.width / 2;
+    
+  if (!keyboard_mode)
+    gdk_window_get_pointer (NULL, &x, NULL, NULL);
 
   x -= (w / 2 + 4);
 
@@ -434,6 +433,35 @@ gtk_tooltips_set_active_widget (GtkToolt
     }
 }
 
+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);
+}
+
 static gboolean
 gtk_tooltips_recently_shown (GtkTooltips *tooltips)
 {
@@ -446,67 +474,122 @@ gtk_tooltips_recently_shown (GtkTooltips
   return (msec < STICKY_REVERT_DELAY);
 }
 
-static gint
+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;
+      if (focus)
+	gtk_tooltips_show_tip (focus);
+      
+      g_object_set_data (G_OBJECT (toplevel), "gtk-tooltips-keyboard-mode", GUINT_TO_POINTER (TRUE));
+    }
+}
+
+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));
+    }
+}
+
+static void
 gtk_tooltips_event_handler (GtkWidget *widget,
                             GdkEvent  *event)
 {
   GtkTooltips *tooltips;
   GtkTooltipsData *old_tips_data;
   GtkWidget *event_widget;
+  gboolean keyboard_mode = get_keyboard_mode (widget);
 
   if ((event->type == GDK_LEAVE_NOTIFY || event->type == GDK_ENTER_NOTIFY) &&
       event->crossing.detail == GDK_NOTIFY_INFERIOR)
     return FALSE;
 
-  event_widget = gtk_get_event_widget (event);
-  if (event_widget != widget)
-    return FALSE;
-  
   old_tips_data = gtk_tooltips_data_get (widget);
   tooltips = old_tips_data->tooltips;
 
-  switch (event->type)
+  if (keyboard_mode)
     {
-    case GDK_MOTION_NOTIFY:
-    case GDK_EXPOSE:
-      /* do nothing */
-      break;
-      
-    case GDK_ENTER_NOTIFY:
-      old_tips_data = tooltips->active_tips_data;
-      if (tooltips->enabled &&
-	  (!old_tips_data || old_tips_data->widget != widget))
+      switch (event->type)
 	{
-	  guint delay;
-	  
-	  gtk_tooltips_set_active_widget (tooltips, widget);
+	case GDK_FOCUS_CHANGE:
+	  if (event->focus_change.in)
+	    gtk_tooltips_show_tip (widget);
+	  else
+	    gtk_tooltips_hide_tip (widget);
+	  break;
+	default:
+	  break;
+	}
+    }
+  else
+    {
+      event_widget = gtk_get_event_widget (event);
+      if (event_widget != widget)
+	return FALSE;
+  
+      switch (event->type)
+	{
+	case GDK_MOTION_NOTIFY:
+	case GDK_EXPOSE:
+	  /* do nothing */
+	  break;
 	  
-	  if (tooltips->use_sticky_delay  &&
+	case GDK_ENTER_NOTIFY:
+	  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);
+		delay = 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;
 	}
-      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);
-      return FALSE;
-      break;
     }
 
   return FALSE;
@@ -537,25 +620,12 @@ gtk_tooltips_widget_remove (GtkWidget *w
   gtk_tooltips_destroy_data (tooltipsdata);
 }
 
-gboolean
-_gtk_tooltips_show_tip (GtkWidget *widget)
+void
+_gtk_tooltips_toggle_keyboard_mode (GtkWidget *widget)
 {
-  /* Showing the tip from the keyboard */
-
-  /* FIXME this function is completely broken right now,
-   * popdown doesn't occur when it should.
-   */
-  
-  GtkTooltipsData *tooltipsdata;
-
-  tooltipsdata = gtk_tooltips_data_get (widget);
-
-  if (tooltipsdata == NULL)
-    return FALSE;
-
-  gtk_tooltips_set_active_widget (tooltipsdata->tooltips,
-                                  widget);
-
-  gtk_tooltips_timeout (tooltipsdata->tooltips);
-  return TRUE;
+  if (get_keyboard_mode (widget))
+    stop_keyboard_mode (widget);
+  else
+    start_keyboard_mode (widget);
 }
+
Index: gtk/gtktooltips.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtktooltips.h,v
retrieving revision 1.22
diff -u -p -r1.22 gtktooltips.h
--- gtk/gtktooltips.h	2002/02/07 15:45:17	1.22
+++ gtk/gtktooltips.h	2002/02/07 22:14:57
@@ -94,7 +94,7 @@ GtkTooltipsData* gtk_tooltips_data_get	 
 void             gtk_tooltips_force_window (GtkTooltips   *tooltips);
 
 
-gboolean         _gtk_tooltips_show_tip    (GtkWidget    *widget);
+void             _gtk_tooltips_toggle_keyboard_mode (GtkWidget *widget);
 
 #ifdef __cplusplus
 }
Index: gtk/gtkwidget.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwidget.c,v
retrieving revision 1.295
diff -u -p -r1.295 gtkwidget.c
--- gtk/gtkwidget.c	2002/02/07 15:45:17	1.295
+++ gtk/gtkwidget.c	2002/02/07 22:14:58
@@ -3400,9 +3400,12 @@ gtk_widget_real_show_help (GtkWidget    
                            GtkWidgetHelpType help_type)
 {
   if (help_type == GTK_WIDGET_HELP_TOOLTIP)
-     return _gtk_tooltips_show_tip (widget);
+    {
+      _gtk_tooltips_toggle_keyboard_mode (widget);
+      return TRUE;
+    }
   else
-     return FALSE;
+    return FALSE;
 }
 
 static gboolean


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