Tooltips keynav patch
- From: Owen Taylor <otaylor redhat com>
- To: gtk-devel-list gnome org
- Cc: padraig obriain sun com
- Subject: Tooltips keynav patch
- Date: Thu, 7 Feb 2002 17:49:54 -0500 (EST)
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]