New tooltips API.

2007-02-06  Kristian Rietveld  <kris@imendio.com>

	New tooltips API.

	* gtk/Makefile.am
	* gtk/gtk.h
	* gtk/gtk.symbols: build system foo.

	* gtk/gtkmain.c (gtk_main_do_event): call tooltip event handler
	hook for appropriate events.

	* gtk/gtkmarshalers.list: add BOOLEAN:INT,INT,BOOLEAN,OBJECT.

	* gtk/gtkrc.c: add style for gtk-tooltip.

	* gtk/gtksettings.c (gtk_settings_class_init): make the
	different tooltip timeouts configurable.

	* gtk/gtkwidget.[ch]: add new properties, signals, make sure
	tooltips are hidden on unmap, destroy, update window event
	mask on realize, hook into focus change and show help
	handlers.

	* gtk/gtkwindow.h: move GtkWindow typdef to gtkwidget.h ...

	* gtk/gtktooltip.[ch]: new files.

	* tests/Makefile.am
	* tests/testtooltips.c: add test application.


svn path=/trunk/; revision=17264
This commit is contained in:
Kristian Rietveld 2007-02-06 10:25:21 +00:00 committed by Kristian Rietveld
parent 47b8d98aba
commit 0ef946ed64
15 changed files with 1928 additions and 7 deletions

View File

@ -1,3 +1,33 @@
2007-02-06 Kristian Rietveld <kris@imendio.com>
New tooltips API.
* gtk/Makefile.am
* gtk/gtk.h
* gtk/gtk.symbols: build system foo.
* gtk/gtkmain.c (gtk_main_do_event): call tooltip event handler
hook for appropriate events.
* gtk/gtkmarshalers.list: add BOOLEAN:INT,INT,BOOLEAN,OBJECT.
* gtk/gtkrc.c: add style for gtk-tooltip.
* gtk/gtksettings.c (gtk_settings_class_init): make the
different tooltip timeouts configurable.
* gtk/gtkwidget.[ch]: add new properties, signals, make sure
tooltips are hidden on unmap, destroy, update window event
mask on realize, hook into focus change and show help
handlers.
* gtk/gtkwindow.h: move GtkWindow typdef to gtkwidget.h ...
* gtk/gtktooltip.[ch]: new files.
* tests/Makefile.am
* tests/testtooltips.c: add test application.
2007-02-05 Dom Lachowicz <domlachowicz@gmail.com>
* modules/engines/ms-windows/msw_style.c: Fix bug 404506, caused

View File

@ -292,6 +292,7 @@ gtk_public_h_sources = \
gtktoolbar.h \
gtktoolbutton.h \
gtktoolitem.h \
gtktooltip.h \
gtktooltips.h \
gtktree.h \
gtktreednd.h \
@ -559,6 +560,7 @@ gtk_base_c_sources = \
gtktoolbar.c \
gtktoolbutton.c \
gtktoolitem.c \
gtktooltip.c \
gtktooltips.c \
gtktree.c \
gtktreedatalist.c \

View File

@ -177,6 +177,7 @@
#include <gtk/gtktoolbar.h>
#include <gtk/gtktoolbutton.h>
#include <gtk/gtktoolitem.h>
#include <gtk/gtktooltip.h>
#include <gtk/gtktooltips.h>
#include <gtk/gtktree.h>
#include <gtk/gtktreednd.h>

View File

@ -3961,6 +3961,17 @@ gtk_tool_item_set_visible_vertical
#endif
#endif
#if IN_HEADER(__GTK_TOOLTIP_H__)
#if IN_FILE(__GTK_TOOLTIP_C__)
gtk_tooltip_get_type G_GNUC_CONST
gtk_tooltip_set_custom
gtk_tooltip_set_icon
gtk_tooltip_set_icon_from_stock
gtk_tooltip_set_markup
gtk_tooltip_trigger_tooltip_query
#endif
#endif
#if IN_HEADER(__GTK_TOOLTIPS_H__)
#if IN_FILE(__GTK_TOOLTIPS_C__)
gtk_tooltips_data_get
@ -4508,6 +4519,7 @@ gtk_widget_get_screen
gtk_widget_get_settings
gtk_widget_get_size_request
gtk_widget_get_style
gtk_widget_get_tooltip_window
gtk_widget_get_toplevel
gtk_widget_get_type G_GNUC_CONST
gtk_widget_get_visual
@ -4580,6 +4592,7 @@ gtk_widget_set_sensitive
gtk_widget_set_size_request
gtk_widget_set_state
gtk_widget_set_style
gtk_widget_set_tooltip_window
gtk_widget_shape_combine_mask
gtk_widget_input_shape_combine_mask
gtk_widget_show
@ -4592,6 +4605,7 @@ gtk_widget_style_get_property
gtk_widget_style_get_valist
gtk_widget_thaw_child_notify
gtk_widget_translate_coordinates
gtk_widget_trigger_tooltip_query
gtk_widget_unmap
gtk_widget_unparent
gtk_widget_unrealize

View File

@ -65,6 +65,7 @@
#include "gtksettings.h"
#include "gtkwidget.h"
#include "gtkwindow.h"
#include "gtktooltip.h"
#include "gtkprivate.h"
#include "gtkdebug.h"
#include "gtkalias.h"
@ -1593,6 +1594,20 @@ gtk_main_do_event (GdkEvent *event)
g_assert_not_reached ();
break;
}
if (event->type == GDK_ENTER_NOTIFY
|| event->type == GDK_LEAVE_NOTIFY
|| event->type == GDK_BUTTON_PRESS
|| event->type == GDK_2BUTTON_PRESS
|| event->type == GDK_3BUTTON_PRESS
|| event->type == GDK_KEY_PRESS
|| event->type == GDK_DRAG_ENTER
|| event->type == GDK_GRAB_BROKEN
|| event->type == GDK_MOTION_NOTIFY
|| event->type == GDK_SCROLL)
{
_gtk_tooltip_handle_event (event);
}
tmp_list = current_events;
current_events = g_list_remove_link (current_events, tmp_list);

View File

@ -39,6 +39,7 @@ BOOLEAN:OBJECT,ENUM
BOOLEAN:INT
BOOLEAN:INT,INT
BOOLEAN:INT,INT,INT
BOOLEAN:INT,INT,BOOLEAN,OBJECT
BOOLEAN:UINT
BOOLEAN:VOID
BOOLEAN:BOOLEAN

View File

@ -893,7 +893,7 @@ _gtk_rc_init (void)
"\n"
"class \"GtkProgressBar\" style : gtk \"gtk-default-progress-bar-style\"\n"
"class \"GtkTrayIcon\" style : gtk \"gtk-default-tray-icon-style\"\n"
"widget \"gtk-tooltips*\" style : gtk \"gtk-default-tooltips-style\"\n"
"widget \"gtk-tooltip*\" style : gtk \"gtk-default-tooltips-style\"\n"
"widget_class \"*<GtkMenuItem>*\" style : gtk \"gtk-default-menu-item-style\"\n"
"widget_class \"*<GtkMenuBar>*<GtkMenuItem>\" style : gtk \"gtk-default-menu-bar-item-style\"\n"
"class \"GtkLabel\" style : gtk \"gtk-default-label-style\"\n"

View File

@ -94,6 +94,9 @@ enum {
PROP_COLOR_SCHEME,
PROP_ENABLE_ANIMATIONS,
PROP_TOUCHSCREEN_MODE,
PROP_TOOLTIP_TIMEOUT,
PROP_TOOLTIP_BROWSE_TIMEOUT,
PROP_TOOLTIP_BROWSE_MODE_TIMEOUT,
PROP_KEYNAV_CURSOR_ONLY,
PROP_KEYNAV_WRAP_AROUND,
PROP_ERROR_BELL,
@ -556,6 +559,73 @@ gtk_settings_class_init (GtkSettingsClass *class)
g_assert (result == PROP_TOUCHSCREEN_MODE);
/**
* GtkSettings:gtk-tooltip-timeout:
*
* Time, in milliseconds, after which a tooltip could appear if the
* cursor is hovering on top of a widget.
*
* Since: 2.12
*/
result = settings_install_property_parser (class,
g_param_spec_int ("gtk-tooltip-timeout",
P_("Tooltip timeout"),
P_("Timeout before tooltip is shown"),
0, G_MAXINT,
1500,
GTK_PARAM_READWRITE),
NULL);
g_assert (result == PROP_TOOLTIP_TIMEOUT);
/**
* GtkSettings:gtk-tooltip-browse-timeout:
*
* Controls the time after which tooltips will appear when
* browse mode is enabled, in milliseconds.
*
* Browse mode is enabled when the mouse pointer moves off an object
* where a tooltip was currently being displayed. If the mouse pointer
* hits another object before the browse mode timeout expires (see
* gtk-tooltip-browse-mode-timeout), it will take the amount of
* milliseconds specified by this setting to popup the tooltip
* for the new object.
*
* Since: 2.12
*/
result = settings_install_property_parser (class,
g_param_spec_int ("gtk-tooltip-browse-timeout",
P_("Tooltip browse timeout"),
P_("Timeout before tooltip is shown when browse mode is enabled"),
0, G_MAXINT,
100,
GTK_PARAM_READWRITE),
NULL);
g_assert (result == PROP_TOOLTIP_BROWSE_TIMEOUT);
/**
* GtkSettings:gtk-tooltip-browse-mode-timeout:
*
* Amount of time, in milliseconds, after which the browse mode
* will be disabled.
*
* See GtkSettings:gtk-tooltip-browse-timeout for more information
* about browse mode.
*
* Since: 2.12
*/
result = settings_install_property_parser (class,
g_param_spec_int ("gtk-tooltip-browse-mode-timeout",
P_("Tooltip browse mode timeout"),
P_("Timeout after which browse mode is disabled"),
0, G_MAXINT,
500,
GTK_PARAM_READWRITE),
NULL);
g_assert (result == PROP_TOOLTIP_BROWSE_MODE_TIMEOUT);
/**
* GtkSettings:gtk-keynav-cursor-only:
*

1064
gtk/gtktooltip.c Normal file

File diff suppressed because it is too large Load Diff

55
gtk/gtktooltip.h Normal file
View File

@ -0,0 +1,55 @@
/* gtktooltip.h
*
* Copyright (C) 2006-2007 Imendio AB
* Contact: Kristian Rietveld <kris@imendio.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GTK_TOOLTIP__
#define __GTK_TOOLTIP__
#include "gtkwidget.h"
#include "gtkwindow.h"
G_BEGIN_DECLS
#define GTK_TYPE_TOOLTIP (gtk_tooltip_get_type ())
GType gtk_tooltip_get_type (void);
void gtk_tooltip_set_markup (GtkTooltip *tooltip,
const gchar *markup);
void gtk_tooltip_set_icon (GtkTooltip *tooltip,
GdkPixbuf *pixbuf);
void gtk_tooltip_set_icon_from_stock (GtkTooltip *tooltip,
const gchar *stock_id,
GtkIconSize size);
void gtk_tooltip_set_custom (GtkTooltip *tooltip,
GtkWidget *custom_widget);
void gtk_tooltip_trigger_tooltip_query (GdkDisplay *display);
void _gtk_tooltip_focus_in (GtkWidget *widget);
void _gtk_tooltip_focus_out (GtkWidget *widget);
void _gtk_tooltip_toggle_keyboard_mode (GtkWidget *widget);
void _gtk_tooltip_handle_event (GdkEvent *event);
void _gtk_tooltip_hide (GtkWidget *widget);
G_END_DECLS
#endif /* __GTK_TOOLTIP__ */

View File

@ -50,6 +50,7 @@
#include "gdk/gdkkeysyms.h"
#include "gtkaccessible.h"
#include "gtktooltips.h"
#include "gtktooltip.h"
#include "gtkinvisible.h"
#include "gtkalias.h"
@ -121,6 +122,7 @@ enum {
CAN_ACTIVATE_ACCEL,
GRAB_BROKEN,
COMPOSITED_CHANGED,
QUERY_TOOLTIP,
KEYNAV_FAILED,
DRAG_FAILED,
LAST_SIGNAL
@ -145,7 +147,9 @@ enum {
PROP_STYLE,
PROP_EVENTS,
PROP_EXTENSION_EVENTS,
PROP_NO_SHOW_ALL
PROP_NO_SHOW_ALL,
PROP_HAS_TOOLTIP,
PROP_TOOLTIP_MARKUP
};
typedef struct _GtkStateData GtkStateData;
@ -158,7 +162,6 @@ struct _GtkStateData
guint use_forall : 1;
};
/* --- prototypes --- */
static void gtk_widget_class_init (GtkWidgetClass *klass);
static void gtk_widget_base_class_finalize (GtkWidgetClass *klass);
@ -190,6 +193,11 @@ static void gtk_widget_direction_changed (GtkWidget *widget,
GtkTextDirection previous_direction);
static void gtk_widget_real_grab_focus (GtkWidget *focus_widget);
static gboolean gtk_widget_real_query_tooltip (GtkWidget *widget,
gint x,
gint y,
gboolean keyboard_tip,
GtkTooltip *tooltip);
static gboolean gtk_widget_real_show_help (GtkWidget *widget,
GtkWidgetHelpType help_type);
@ -230,6 +238,10 @@ static GdkScreen * gtk_widget_get_screen_unchecked (GtkWidget
static void gtk_widget_queue_shallow_draw (GtkWidget *widget);
static gboolean gtk_widget_real_can_activate_accel (GtkWidget *widget,
guint signal_id);
static void gtk_widget_set_has_tooltip (GtkWidget *widget,
gboolean has_tooltip,
gboolean force);
static void gtk_widget_set_usize_internal (GtkWidget *widget,
gint width,
@ -261,6 +273,9 @@ static GQuark quark_pango_context = 0;
static GQuark quark_rc_style = 0;
static GQuark quark_accessible_object = 0;
static GQuark quark_mnemonic_labels = 0;
static GQuark quark_tooltip_markup = 0;
static GQuark quark_has_tooltip = 0;
static GQuark quark_tooltip_window = 0;
GParamSpecPool *_gtk_widget_child_property_pool = NULL;
GObjectNotifyContext *_gtk_widget_child_property_notify_context = NULL;
@ -336,6 +351,9 @@ gtk_widget_class_init (GtkWidgetClass *klass)
quark_rc_style = g_quark_from_static_string ("gtk-rc-style");
quark_accessible_object = g_quark_from_static_string ("gtk-accessible-object");
quark_mnemonic_labels = g_quark_from_static_string ("gtk-mnemonic-labels");
quark_tooltip_markup = g_quark_from_static_string ("gtk-tooltip-markup");
quark_has_tooltip = g_quark_from_static_string ("gtk-has-tooltip");
quark_tooltip_window = g_quark_from_static_string ("gtk-tooltip-window");
style_property_spec_pool = g_param_spec_pool_new (FALSE);
_gtk_widget_child_property_pool = g_param_spec_pool_new (TRUE);
@ -407,6 +425,7 @@ gtk_widget_class_init (GtkWidgetClass *klass)
klass->screen_changed = NULL;
klass->can_activate_accel = gtk_widget_real_can_activate_accel;
klass->grab_broken_event = NULL;
klass->query_tooltip = gtk_widget_real_query_tooltip;
klass->show_help = gtk_widget_real_show_help;
@ -548,6 +567,47 @@ gtk_widget_class_init (GtkWidgetClass *klass)
P_("Whether gtk_widget_show_all() should not affect this widget"),
FALSE,
GTK_PARAM_READWRITE));
/**
* GtkWidget:has-tooltip:
*
* Enables or disables the emission of GtkWidget::query-tooltip on @widget. A
* value of %TRUE indicates that @widget can have a tooltip, in this case
* the widget will be queried using GtkWidget::query-tooltip to determine
* whether it will provide a tooltip or not.
*
* Since: 2.12
*/
g_object_class_install_property (gobject_class,
PROP_HAS_TOOLTIP,
g_param_spec_boolean ("has-tooltip",
P_("Has tooltip"),
P_("Whether this widget has a tooltip"),
FALSE,
GTK_PARAM_READWRITE));
/**
* GtkWidget:tooltip-markup:
*
* Sets the text of tooltip to be the given string, which is marked up
* with the <link linkend="PangoMarkupFormat">Pango text markup language</link>.
* Also see gtk_tooltip_set_markup().
*
* This is a convenience property which will take care of getting the
* tooltip shown if the given string is not %NULL: GtkWidget:has-tooltip
* will automatically be set to %TRUE and there will be taken care of
* GtkWidget::query-tooltip in the default signal handler.
*
* Since: 2.12
*/
g_object_class_install_property (gobject_class,
PROP_TOOLTIP_MARKUP,
g_param_spec_string ("tooltip-markup",
P_("Tooltip markup"),
P_("The contents of the tooltip for this widget"),
NULL,
GTK_PARAM_READWRITE));
widget_signals[SHOW] =
g_signal_new (I_("show"),
G_TYPE_FROM_CLASS (gobject_class),
@ -1450,6 +1510,45 @@ gtk_widget_class_init (GtkWidgetClass *klass)
_gtk_marshal_BOOLEAN__BOXED,
G_TYPE_BOOLEAN, 1,
GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
/**
* GtkWidget::query-tooltip:
* @widget: the object which received the signal
* @x: the x coordinate of the cursor position where the request has been
* emitted, relative to the widget's allocation
* @y: the y coordinate of the cursor position where the request has been
* emitted, relative to the widget's allocation
* @keyboard_mode: %TRUE if the tooltip was trigged using the keyboard
* @tooltip: a #GtkTooltip
*
* Emitted when the gtk-tooltip-timeout has expired with the cursor
* hovering "above" @widget; or emitted when @widget got focus in
* keyboard mode.
*
* Using the given coordinates, the signal handler should determine
* whether a tooltip should be shown for @widget. If this is the case
* %TRUE should be returned, %FALSE otherwise. Note that if
* @keyboard_mode is %TRUE, the values of @x and @y are undefined and
* should not be used.
*
* The signal handler is free to manipulate @tooltip with the therefore
* destined function calls.
*
* Returns: %TRUE if @tooltip should be shown right now, %FALSE otherwise.
*
* Since: 2.12
*/
widget_signals[QUERY_TOOLTIP] =
g_signal_new (I_("query-tooltip"),
G_TYPE_FROM_CLASS (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkWidgetClass, query_tooltip),
_gtk_boolean_handled_accumulator, NULL,
_gtk_marshal_BOOLEAN__INT_INT_BOOLEAN_OBJECT,
G_TYPE_BOOLEAN, 4,
G_TYPE_INT,
G_TYPE_INT,
G_TYPE_BOOLEAN,
GTK_TYPE_TOOLTIP);
/**
* GtkWidget::popup-menu
* @widget: the object which received the signal
@ -1730,7 +1829,10 @@ gtk_widget_set_property (GObject *object,
switch (prop_id)
{
gboolean tmp;
guint32 saved_flags;
gchar *tooltip_markup;
GtkWindow *tooltip_window;
case PROP_NAME:
gtk_widget_set_name (widget, g_value_get_string (value));
@ -1805,6 +1907,21 @@ gtk_widget_set_property (GObject *object,
case PROP_NO_SHOW_ALL:
gtk_widget_set_no_show_all (widget, g_value_get_boolean (value));
break;
case PROP_HAS_TOOLTIP:
gtk_widget_set_has_tooltip (widget, g_value_get_boolean (value), FALSE);
break;
case PROP_TOOLTIP_MARKUP:
tooltip_markup = g_object_get_qdata (object, quark_tooltip_markup);
tooltip_window = g_object_get_qdata (object, quark_tooltip_window);
tooltip_markup = g_value_dup_string (value);
g_object_set_qdata_full (object, quark_tooltip_markup,
tooltip_markup, g_free);
tmp = (tooltip_window != NULL || tooltip_markup != NULL);
gtk_widget_set_has_tooltip (widget, tmp, FALSE);
break;
default:
break;
}
@ -1899,6 +2016,12 @@ gtk_widget_get_property (GObject *object,
case PROP_NO_SHOW_ALL:
g_value_set_boolean (value, gtk_widget_get_no_show_all (widget));
break;
case PROP_HAS_TOOLTIP:
g_value_set_boolean (value, GPOINTER_TO_UINT (g_object_get_qdata (object, quark_has_tooltip)));
break;
case PROP_TOOLTIP_MARKUP:
g_value_set_string (value, g_object_get_qdata (object, quark_tooltip_markup));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -2490,6 +2613,7 @@ gtk_widget_unmap (GtkWidget *widget)
{
if (GTK_WIDGET_NO_WINDOW (widget))
gdk_window_invalidate_rect (widget->window, &widget->allocation, FALSE);
_gtk_tooltip_hide (widget);
g_signal_emit (widget, widget_signals[UNMAP], 0);
}
}
@ -2548,7 +2672,9 @@ gtk_widget_realize (GtkWidget *widget)
gtk_widget_ensure_style (widget);
g_signal_emit (widget, widget_signals[REALIZE], 0);
gtk_widget_set_has_tooltip (widget, GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (widget), quark_has_tooltip)), TRUE);
if (GTK_WIDGET_HAS_SHAPE_MASK (widget))
{
shape_info = g_object_get_qdata (G_OBJECT (widget), quark_shape_info);
@ -2601,6 +2727,7 @@ gtk_widget_unrealize (GtkWidget *widget)
if (GTK_WIDGET_REALIZED (widget))
{
g_object_ref (widget);
_gtk_tooltip_hide (widget);
g_signal_emit (widget, widget_signals[UNREALIZE], 0);
GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED | GTK_MAPPED);
g_object_unref (widget);
@ -3897,6 +4024,7 @@ gtk_widget_event_internal (GtkWidget *widget,
break;
case GDK_DESTROY:
signal_num = DESTROY_EVENT;
_gtk_tooltip_hide (widget);
break;
case GDK_KEY_PRESS:
signal_num = KEY_PRESS_EVENT;
@ -3912,6 +4040,10 @@ gtk_widget_event_internal (GtkWidget *widget,
break;
case GDK_FOCUS_CHANGE:
signal_num = event->focus_change.in ? FOCUS_IN_EVENT : FOCUS_OUT_EVENT;
if (event->focus_change.in)
_gtk_tooltip_focus_in (widget);
else
_gtk_tooltip_focus_out (widget);
break;
case GDK_CONFIGURE:
signal_num = CONFIGURE_EVENT;
@ -4354,6 +4486,28 @@ gtk_widget_real_grab_focus (GtkWidget *focus_widget)
}
}
static gboolean
gtk_widget_real_query_tooltip (GtkWidget *widget,
gint x,
gint y,
gboolean keyboard_tip,
GtkTooltip *tooltip)
{
gchar *tooltip_markup;
gboolean has_tooltip;
tooltip_markup = g_object_get_qdata (G_OBJECT (widget), quark_tooltip_markup);
has_tooltip = GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (widget), quark_has_tooltip));
if (has_tooltip && tooltip_markup)
{
gtk_tooltip_set_markup (tooltip, tooltip_markup);
return TRUE;
}
return FALSE;
}
static gboolean
gtk_widget_real_show_help (GtkWidget *widget,
GtkWidgetHelpType help_type)
@ -4361,6 +4515,8 @@ gtk_widget_real_show_help (GtkWidget *widget,
if (help_type == GTK_WIDGET_HELP_TOOLTIP)
{
_gtk_tooltips_toggle_keyboard_mode (widget);
_gtk_tooltip_toggle_keyboard_mode (widget);
return TRUE;
}
else
@ -5256,6 +5412,7 @@ do_screen_change (GtkWidget *widget,
g_object_set_qdata (G_OBJECT (widget), quark_pango_context, NULL);
}
_gtk_tooltip_hide (widget);
g_signal_emit (widget, widget_signals[SCREEN_CHANGED], 0, old_screen);
}
}
@ -8219,5 +8376,122 @@ gtk_widget_set_no_show_all (GtkWidget *widget,
g_object_notify (G_OBJECT (widget), "no-show-all");
}
static void
gtk_widget_set_has_tooltip (GtkWidget *widget,
gboolean has_tooltip,
gboolean force)
{
gboolean priv_has_tooltip;
priv_has_tooltip = GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (widget),
quark_has_tooltip));
if (priv_has_tooltip != has_tooltip || force)
{
priv_has_tooltip = has_tooltip;
if (priv_has_tooltip)
{
if (GTK_WIDGET_REALIZED (widget) && GTK_WIDGET_NO_WINDOW (widget))
gdk_window_set_events (widget->window,
gdk_window_get_events (widget->window) |
GDK_LEAVE_NOTIFY_MASK |
GDK_POINTER_MOTION_MASK |
GDK_POINTER_MOTION_HINT_MASK);
if (!GTK_WIDGET_NO_WINDOW (widget))
gtk_widget_add_events (widget,
GDK_LEAVE_NOTIFY_MASK |
GDK_POINTER_MOTION_MASK |
GDK_POINTER_MOTION_HINT_MASK);
}
g_object_set_qdata (G_OBJECT (widget), quark_has_tooltip,
GUINT_TO_POINTER (priv_has_tooltip));
}
}
/**
* gtk_widget_set_tooltip_window:
* @widget: a #GtkWidget
* @custom_window: a #GtkWindow, or %NULL
*
* Replaces the default, usually yellow, window used for displaying
* tooltips with @custom_window. GTK+ will take care of showing and
* hiding @custom_window at the right moment, to behave likewise as
* the default tooltip window. If @custom_window is %NULL, the default
* tooltip window will be used.
*
* Since: 2.12
*/
void
gtk_widget_set_tooltip_window (GtkWidget *widget,
GtkWindow *custom_window)
{
gboolean tmp;
gchar *tooltip_markup;
GtkWindow *tooltip_window;
g_return_if_fail (GTK_IS_WIDGET (widget));
if (custom_window)
g_return_if_fail (GTK_IS_WINDOW (custom_window));
tooltip_window = g_object_get_qdata (G_OBJECT (widget), quark_tooltip_window);
tooltip_markup = g_object_get_qdata (G_OBJECT (widget), quark_tooltip_markup);
if (custom_window)
g_object_ref (custom_window);
if (tooltip_window)
g_object_unref (tooltip_window);
tooltip_window = custom_window;
g_object_set_qdata_full (G_OBJECT (widget), quark_tooltip_window,
tooltip_window, g_object_unref);
tmp = (tooltip_window != NULL || tooltip_markup != NULL);
gtk_widget_set_has_tooltip (widget, tmp, FALSE);
if (tmp)
gtk_widget_trigger_tooltip_query (widget);
}
/**
* gtk_widget_get_tooltip_window:
* @widget: a #GtkWidget
*
* Returns the #GtkWindow of the current tooltip. This can be the
* GtkWindow created by default, or the custom tooltip window set
* using gtk_widget_set_tooltip_window().
*
* Return value: The #GtkWindow of the current tooltip.
*
* Since: 2.12
*/
GtkWindow *
gtk_widget_get_tooltip_window (GtkWidget *widget)
{
g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
return g_object_get_qdata (G_OBJECT (widget), quark_tooltip_window);
}
/**
* gtk_widget_trigger_tooltip_query:
* @widget: a #GtkWidget
*
* Triggers a tooltip query on the display where the toplevel of @widget
* is located. See gtk_tooltip_trigger_tooltip_query() for more
* information.
*
* Since: 2.12
*/
void
gtk_widget_trigger_tooltip_query (GtkWidget *widget)
{
gtk_tooltip_trigger_tooltip_query (gtk_widget_get_display (widget));
}
#define __GTK_WIDGET_C__
#include "gtkaliasdef.c"

View File

@ -140,6 +140,8 @@ typedef struct _GtkWidgetClass GtkWidgetClass;
typedef struct _GtkWidgetAuxInfo GtkWidgetAuxInfo;
typedef struct _GtkWidgetShapeInfo GtkWidgetShapeInfo;
typedef struct _GtkClipboard GtkClipboard;
typedef struct _GtkTooltip GtkTooltip;
typedef struct _GtkWindow GtkWindow;
typedef void (*GtkCallback) (GtkWidget *widget,
gpointer data);
@ -409,8 +411,13 @@ struct _GtkWidgetClass
void (* composited_changed) (GtkWidget *widget);
gboolean (* query_tooltip) (GtkWidget *widget,
gint x,
gint y,
gboolean keyboard_tooltip,
GtkTooltip *tooltip);
/* Padding for future expansion */
void (*_gtk_reserved4) (void);
void (*_gtk_reserved5) (void);
void (*_gtk_reserved6) (void);
void (*_gtk_reserved7) (void);
@ -777,6 +784,12 @@ void gtk_widget_add_mnemonic_label (GtkWidget *widget,
void gtk_widget_remove_mnemonic_label (GtkWidget *widget,
GtkWidget *label);
void gtk_widget_set_tooltip_window (GtkWidget *widget,
GtkWindow *custom_window);
GtkWindow *gtk_widget_get_tooltip_window (GtkWidget *widget);
void gtk_widget_trigger_tooltip_query (GtkWidget *widget);
GType gtk_requisition_get_type (void) G_GNUC_CONST;
GtkRequisition *gtk_requisition_copy (const GtkRequisition *requisition);
void gtk_requisition_free (GtkRequisition *requisition);

View File

@ -44,7 +44,6 @@ G_BEGIN_DECLS
#define GTK_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_WINDOW, GtkWindowClass))
typedef struct _GtkWindow GtkWindow;
typedef struct _GtkWindowClass GtkWindowClass;
typedef struct _GtkWindowGeometryInfo GtkWindowGeometryInfo;
typedef struct _GtkWindowGroup GtkWindowGroup;

View File

@ -82,7 +82,8 @@ noinst_PROGRAMS = \
pixbuf-threads \
testmerge \
testactions \
testgrouping
testgrouping \
testtooltips
autotestfilechooser_DEPENDENCIES = $(TEST_DEPS)
simple_DEPENDENCIES = $(TEST_DEPS)
@ -134,6 +135,7 @@ testxinerama_DEPENDENCIES = $(TEST_DEPS)
testmerge_DEPENDENCIES = $(TEST_DEPS)
testactions_DEPENDENCIES = $(TEST_DEPS)
testgrouping_DEPENDENCIES = $(TEST_DEPS)
testtooltips_DEPENDENCIES = $(TEST_DEPS)
autotestfilechooser_LDADD = $(LDADDS)
simple_LDADD = $(LDADDS)
@ -192,6 +194,7 @@ pixbuf_threads_LDADD = $(LDADDS) $(GLIB_LIBS)
testmerge_LDADD = $(LDADDS)
testactions_LDADD = $(LDADDS)
testgrouping_LDADD = $(LDADDS)
testtooltips_LDADD = $(LDADDS)
autotestfilechooser_SOURCES = \
autotestfilechooser.c
@ -267,6 +270,9 @@ testrecentchooser_SOURCES = \
testgrouping_SOURCES = \
testgrouping.c
testtoooltips_SOURCES = \
testtooltips.c
EXTRA_DIST = \
prop-editor.h \
testgtk.1 \

377
tests/testtooltips.c Normal file
View File

@ -0,0 +1,377 @@
/* testtooltips.c: Test application for GTK+ >= 2.12 tooltips code
*
* Copyright (C) 2006-2007 Imendio AB
* Contact: Kristian Rietveld <kris@imendio.com>
*
* This work is provided "as is"; redistribution and modification
* in whole or in part, in any medium, physical or electronic is
* permitted without restriction.
*
* This work 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.
*
* In no event shall the authors or contributors be liable for any
* direct, indirect, incidental, special, exemplary, or consequential
* damages (including, but not limited to, procurement of substitute
* goods or services; loss of use, data, or profits; or business
* interruption) however caused and on any theory of liability, whether
* in contract, strict liability, or tort (including negligence or
* otherwise) arising in any way out of the use of this software, even
* if advised of the possibility of such damage.
*/
#include <gtk/gtk.h>
static gboolean
query_tooltip_cb (GtkWidget *widget,
gint x,
gint y,
gboolean keyboard_tip,
GtkTooltip *tooltip,
gpointer data)
{
gtk_tooltip_set_markup (tooltip, gtk_button_get_label (GTK_BUTTON (widget)));
gtk_tooltip_set_icon_from_stock (tooltip, GTK_STOCK_DELETE,
GTK_ICON_SIZE_MENU);
return TRUE;
}
static gboolean
query_tooltip_custom_cb (GtkWidget *widget,
gint x,
gint y,
gboolean keyboard_tip,
GtkTooltip *tooltip,
gpointer data)
{
GdkColor color = { 0, 0, 65535 };
GtkWindow *window = gtk_widget_get_tooltip_window (widget);
gtk_widget_modify_bg (GTK_WIDGET (window), GTK_STATE_NORMAL, &color);
return TRUE;
}
static gboolean
query_tooltip_text_view_cb (GtkWidget *widget,
gint x,
gint y,
gboolean keyboard_tip,
GtkTooltip *tooltip,
gpointer data)
{
gint bx, by, trailing;
GtkTextTag *tag = data;
GtkTextIter iter;
GtkTextView *text_view = GTK_TEXT_VIEW (widget);
gtk_text_view_window_to_buffer_coords (text_view, GTK_TEXT_WINDOW_TEXT,
x, y, &bx, &by);
gtk_text_view_get_iter_at_position (text_view, &iter, &trailing, bx, by);
if (gtk_text_iter_has_tag (&iter, tag))
gtk_tooltip_set_markup (tooltip, "Tooltip on text tag");
else
return FALSE;
return TRUE;
}
static gboolean
query_tooltip_tree_view_cb (GtkWidget *widget,
gint x,
gint y,
gboolean keyboard_tip,
GtkTooltip *tooltip,
gpointer data)
{
GtkTreeIter iter;
GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
GtkTreePath *path = NULL;
gchar *tmp;
gchar *pathstring;
char buffer[512];
if (keyboard_tip)
{
/* Keyboard mode */
gtk_tree_view_get_cursor (tree_view, &path, NULL);
if (!path)
return FALSE;
}
else
{
/* Mouse mode */
if (!gtk_tree_view_get_path_at_pos (tree_view, x, y, &path, NULL, NULL, NULL))
return FALSE;
}
gtk_tree_model_get_iter (model, &iter, path);
gtk_tree_model_get (model, &iter, 0, &tmp, -1);
pathstring = gtk_tree_path_to_string (path);
snprintf (buffer, 511, "<b>Path %s:</b> %s", pathstring, tmp);
gtk_tooltip_set_markup (tooltip, buffer);
gtk_tree_path_free (path);
g_free (pathstring);
g_free (tmp);
return TRUE;
}
static GtkTreeModel *
create_model (void)
{
GtkTreeStore *store;
GtkTreeIter iter;
store = gtk_tree_store_new (1, G_TYPE_STRING);
/* A tree store with some random words ... */
gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
0, "File Manager", -1);
gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
0, "Gossip", -1);
gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
0, "System Settings", -1);
gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
0, "The GIMP", -1);
gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
0, "Terminal", -1);
gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
0, "Word Processor", -1);
return GTK_TREE_MODEL (store);
}
static void
selection_changed_cb (GtkTreeSelection *selection,
GtkWidget *tree_view)
{
gtk_widget_trigger_tooltip_query (tree_view);
}
static struct Rectangle
{
gint x;
gint y;
gfloat r;
gfloat g;
gfloat b;
const char *tooltip;
}
rectangles[] =
{
{ 10, 10, 0.0, 0.0, 0.9, "Blue box!" },
{ 200, 170, 1.0, 0.0, 0.0, "Red thing" },
{ 100, 50, 0.8, 0.8, 0.0, "Yellow thing" }
};
static gboolean
query_tooltip_drawing_area_cb (GtkWidget *widget,
gint x,
gint y,
gboolean keyboard_tip,
GtkTooltip *tooltip,
gpointer data)
{
gint i;
if (keyboard_tip)
return FALSE;
for (i = 0; i < G_N_ELEMENTS (rectangles); i++)
{
struct Rectangle *r = &rectangles[i];
if (r->x < x && x < r->x + 50
&& r->y < y && y < r->y + 50)
{
gtk_tooltip_set_markup (tooltip, r->tooltip);
return TRUE;
}
}
return FALSE;
}
static gboolean
drawing_area_expose (GtkWidget *drawing_area,
GdkEventExpose *event,
gpointer data)
{
gint i;
cairo_t *cr;
gdk_window_get_pointer (drawing_area->window, NULL, NULL, NULL);
cr = gdk_cairo_create (drawing_area->window);
cairo_rectangle (cr, 0, 0,
drawing_area->allocation.width,
drawing_area->allocation.height);
cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
cairo_fill (cr);
for (i = 0; i < G_N_ELEMENTS (rectangles); i++)
{
struct Rectangle *r = &rectangles[i];
cairo_rectangle (cr, r->x, r->y, 50, 50);
cairo_set_source_rgb (cr, r->r, r->g, r->b);
cairo_stroke (cr);
cairo_rectangle (cr, r->x, r->y, 50, 50);
cairo_set_source_rgba (cr, r->r, r->g, r->b, 0.5);
cairo_fill (cr);
}
cairo_destroy (cr);
return FALSE;
}
int
main (int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *box;
GtkWidget *drawing_area;
GtkWidget *button;
GtkWidget *tooltip_window;
GtkWidget *tooltip_button;
GtkWidget *tree_view;
GtkTreeViewColumn *column;
GtkWidget *text_view;
GtkTextBuffer *buffer;
GtkTextIter iter;
GtkTextTag *tag;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Tooltips test");
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
g_signal_connect (window, "delete_event",
G_CALLBACK (gtk_main_quit), NULL);
box = gtk_vbox_new (FALSE, 3);
gtk_container_add (GTK_CONTAINER (window), box);
/* A check button using the tooltip-markup property */
button = gtk_check_button_new_with_label ("This one uses the tooltip-markup property");
g_object_set (button, "tooltip-markup", "Hello, I am a static tooltip.", NULL);
gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
/* A check button using the query-tooltip signal */
button = gtk_check_button_new_with_label ("I use the query-tooltip signal");
g_object_set (button, "has-tooltip", TRUE, NULL);
g_signal_connect (button, "query-tooltip",
G_CALLBACK (query_tooltip_cb), NULL);
gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
/* A label */
button = gtk_label_new ("I am just a label");
gtk_label_set_selectable (GTK_LABEL (button), FALSE);
g_object_set (button, "tooltip-markup", "Label tooltip", NULL);
gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
/* A selectable label */
button = gtk_label_new ("I am a selectable label");
gtk_label_set_selectable (GTK_LABEL (button), TRUE);
g_object_set (button, "tooltip-markup", "Another Label tooltip", NULL);
gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
/* Another one, with a custom tooltip window */
button = gtk_check_button_new_with_label ("This one has a custom tooltip window!");
gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
tooltip_window = gtk_window_new (GTK_WINDOW_POPUP);
tooltip_button = gtk_label_new ("blaat!");
gtk_container_add (GTK_CONTAINER (tooltip_window), tooltip_button);
gtk_widget_show (tooltip_button);
gtk_widget_set_tooltip_window (button, GTK_WINDOW (tooltip_window));
g_signal_connect (button, "query-tooltip",
G_CALLBACK (query_tooltip_custom_cb), NULL);
g_object_set (button, "has-tooltip", TRUE, NULL);
/* An insensitive button */
button = gtk_button_new_with_label ("This one is insensitive");
gtk_widget_set_sensitive (button, FALSE);
g_object_set (button, "tooltip-markup", "Insensitive!", NULL);
gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
/* Testcases from Kris without a tree view don't exist. */
tree_view = gtk_tree_view_new_with_model (create_model ());
gtk_widget_set_size_request (tree_view, 200, 240);
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree_view),
0, "Test",
gtk_cell_renderer_text_new (),
"text", 0,
NULL);
g_object_set (tree_view, "has-tooltip", TRUE, NULL);
g_signal_connect (tree_view, "query-tooltip",
G_CALLBACK (query_tooltip_tree_view_cb), NULL);
g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)),
"changed", G_CALLBACK (selection_changed_cb), tree_view);
/* Set a tooltip on the column */
column = gtk_tree_view_get_column (GTK_TREE_VIEW (tree_view), 0);
gtk_tree_view_column_set_clickable (column, TRUE);
g_object_set (column->button, "tooltip-markup", "Header", NULL);
gtk_box_pack_start (GTK_BOX (box), tree_view, FALSE, FALSE, 2);
/* And a text view for Matthias */
buffer = gtk_text_buffer_new (NULL);
gtk_text_buffer_get_end_iter (buffer, &iter);
gtk_text_buffer_insert (buffer, &iter, "Hello, the text ", -1);
tag = gtk_text_buffer_create_tag (buffer, "bold", NULL);
g_object_set (tag, "weight", PANGO_WEIGHT_BOLD, NULL);
gtk_text_buffer_get_end_iter (buffer, &iter);
gtk_text_buffer_insert_with_tags (buffer, &iter, "in bold", -1, tag, NULL);
gtk_text_buffer_get_end_iter (buffer, &iter);
gtk_text_buffer_insert (buffer, &iter, " has a tooltip!", -1);
text_view = gtk_text_view_new_with_buffer (buffer);
gtk_widget_set_size_request (text_view, 200, 50);
g_object_set (text_view, "has-tooltip", TRUE, NULL);
g_signal_connect (text_view, "query-tooltip",
G_CALLBACK (query_tooltip_text_view_cb), tag);
gtk_box_pack_start (GTK_BOX (box), text_view, FALSE, FALSE, 2);
/* Drawing area */
drawing_area = gtk_drawing_area_new ();
gtk_widget_set_size_request (drawing_area, 320, 240);
g_object_set (drawing_area, "has-tooltip", TRUE, NULL);
g_signal_connect (drawing_area, "expose_event",
G_CALLBACK (drawing_area_expose), NULL);
g_signal_connect (drawing_area, "query-tooltip",
G_CALLBACK (query_tooltip_drawing_area_cb), NULL);
gtk_box_pack_start (GTK_BOX (box), drawing_area, FALSE, FALSE, 2);
/* Done! */
gtk_widget_show_all (window);
gtk_main ();
return 0;
}