tooltip: add tooltip-radius and tooltip-alpha style properties

This allows themes to change the tooltip opacity and radius. Based on a
downstream Fedora patch by Matthias Clasen.

https://bugzilla.gnome.org/show_bug.cgi?id=683070
This commit is contained in:
Cosimo Cecchi 2012-08-30 16:07:18 -04:00
parent 3d5cd6e055
commit af26ec6a73
2 changed files with 226 additions and 10 deletions

View File

@ -97,6 +97,7 @@ static void gtk_tooltip_display_closed (GdkDisplay *display,
GtkTooltip *tooltip); GtkTooltip *tooltip);
static void gtk_tooltip_set_last_window (GtkTooltip *tooltip, static void gtk_tooltip_set_last_window (GtkTooltip *tooltip,
GdkWindow *window); GdkWindow *window);
static void update_shape (GtkTooltip *tooltip);
G_DEFINE_TYPE (GtkTooltip, gtk_tooltip, G_TYPE_OBJECT); G_DEFINE_TYPE (GtkTooltip, gtk_tooltip, G_TYPE_OBJECT);
@ -111,6 +112,39 @@ gtk_tooltip_class_init (GtkTooltipClass *klass)
object_class->dispose = gtk_tooltip_dispose; object_class->dispose = gtk_tooltip_dispose;
} }
static void
on_composited_changed (GtkWidget *window,
GtkTooltip *tooltip)
{
update_shape (tooltip);
}
static void
on_screen_changed (GtkWidget *window,
GdkScreen *previous,
GtkTooltip *tooltip)
{
GdkScreen *screen;
GdkColormap *cmap;
screen = gtk_widget_get_screen (window);
cmap = NULL;
if (gdk_screen_is_composited (screen))
cmap = gdk_screen_get_rgba_colormap (screen);
if (cmap == NULL)
cmap = gdk_screen_get_rgb_colormap (screen);
gtk_widget_set_colormap (window, cmap);
}
static void
on_realized (GtkWidget *window,
GtkTooltip *tooltip)
{
update_shape (tooltip);
}
static void static void
gtk_tooltip_init (GtkTooltip *tooltip) gtk_tooltip_init (GtkTooltip *tooltip)
{ {
@ -129,8 +163,12 @@ gtk_tooltip_init (GtkTooltip *tooltip)
tooltip->last_window = NULL; tooltip->last_window = NULL;
tooltip->window = g_object_ref (gtk_window_new (GTK_WINDOW_POPUP)); tooltip->window = g_object_ref (gtk_window_new (GTK_WINDOW_POPUP));
on_screen_changed (tooltip->window, NULL, tooltip);
gtk_window_set_type_hint (GTK_WINDOW (tooltip->window), gtk_window_set_type_hint (GTK_WINDOW (tooltip->window),
GDK_WINDOW_TYPE_HINT_TOOLTIP); GDK_WINDOW_TYPE_HINT_TOOLTIP);
gtk_widget_set_app_paintable (tooltip->window, TRUE); gtk_widget_set_app_paintable (tooltip->window, TRUE);
gtk_window_set_resizable (GTK_WINDOW (tooltip->window), FALSE); gtk_window_set_resizable (GTK_WINDOW (tooltip->window), FALSE);
gtk_widget_set_name (tooltip->window, "gtk-tooltip"); gtk_widget_set_name (tooltip->window, "gtk-tooltip");
@ -164,6 +202,13 @@ gtk_tooltip_init (GtkTooltip *tooltip)
gtk_box_pack_start (GTK_BOX (tooltip->box), tooltip->label, gtk_box_pack_start (GTK_BOX (tooltip->box), tooltip->label,
FALSE, FALSE, 0); FALSE, FALSE, 0);
g_signal_connect (tooltip->window, "composited-changed",
G_CALLBACK (on_composited_changed), tooltip);
g_signal_connect (tooltip->window, "screen-changed",
G_CALLBACK (on_screen_changed), tooltip);
g_signal_connect (tooltip->window, "realize",
G_CALLBACK (on_realized), tooltip);
tooltip->custom_widget = NULL; tooltip->custom_widget = NULL;
} }
@ -510,9 +555,153 @@ gtk_tooltip_window_style_set (GtkTooltip *tooltip)
gtk_widget_queue_draw (tooltip->window); gtk_widget_queue_draw (tooltip->window);
} }
static void
draw_round_rect (cairo_t *cr,
gdouble aspect,
gdouble x,
gdouble y,
gdouble corner_radius,
gdouble width,
gdouble height)
{
gdouble radius = corner_radius / aspect;
cairo_move_to (cr, x + radius, y);
/* top-right, left of the corner */
cairo_line_to (cr, x + width - radius, y);
/* top-right, below the corner */
cairo_arc (cr,
x + width - radius, y + radius, radius,
-90.0f * G_PI / 180.0f, 0.0f * G_PI / 180.0f);
/* bottom-right, above the corner */
cairo_line_to (cr, x + width, y + height - radius);
/* bottom-right, left of the corner */
cairo_arc (cr,
x + width - radius, y + height - radius, radius,
0.0f * G_PI / 180.0f, 90.0f * G_PI / 180.0f);
/* bottom-left, right of the corner */
cairo_line_to (cr, x + radius, y + height);
/* bottom-left, above the corner */
cairo_arc (cr,
x + radius, y + height - radius, radius,
90.0f * G_PI / 180.0f, 180.0f * G_PI / 180.0f);
/* top-left, below the corner */
cairo_line_to (cr, x, y + radius);
/* top-left, right of the corner */
cairo_arc (cr,
x + radius, y + radius, radius,
180.0f * G_PI / 180.0f, 270.0f * G_PI / 180.0f);
cairo_close_path (cr);
}
static void
fill_background (GtkWidget *widget,
cairo_t *cr,
GdkColor *bg_color,
GdkColor *border_color,
guchar alpha)
{
gint tooltip_radius;
if (!gtk_widget_is_composited (widget))
alpha = 255;
gtk_widget_style_get (widget,
"tooltip-radius", &tooltip_radius,
NULL);
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
cairo_paint (cr);
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
draw_round_rect (cr,
1.0, 0.5, 0.5, tooltip_radius,
widget->allocation.width - 1,
widget->allocation.height - 1);
cairo_set_source_rgba (cr,
(float) bg_color->red / 65535.0,
(float) bg_color->green / 65535.0,
(float) bg_color->blue / 65535.0,
(float) alpha / 255.0);
cairo_fill_preserve (cr);
cairo_set_source_rgba (cr,
(float) border_color->red / 65535.0,
(float) border_color->green / 65535.0,
(float) border_color->blue / 65535.0,
(float) alpha / 255.0);
cairo_set_line_width (cr, 1.0);
cairo_stroke (cr);
}
static void
update_shape (GtkTooltip *tooltip)
{
GdkBitmap *mask;
cairo_t *cr;
gint width, height, tooltip_radius;
gtk_widget_style_get (tooltip->window,
"tooltip-radius", &tooltip_radius,
NULL);
if (tooltip_radius == 0 ||
gtk_widget_is_composited (tooltip->window))
{
gtk_widget_shape_combine_mask (tooltip->window, NULL, 0, 0);
return;
}
gtk_window_get_size (GTK_WINDOW (tooltip->window), &width, &height);
mask = (GdkBitmap *) gdk_pixmap_new (NULL, width, height, 1);
cr = gdk_cairo_create (mask);
fill_background (tooltip->window, cr,
&tooltip->window->style->black,
&tooltip->window->style->black,
255);
gtk_widget_shape_combine_mask (tooltip->window, mask, 0, 0);
cairo_destroy (cr);
g_object_unref (mask);
}
static gboolean static gboolean
gtk_tooltip_paint_window (GtkTooltip *tooltip) gtk_tooltip_paint_window (GtkTooltip *tooltip)
{ {
guchar tooltip_alpha;
gint tooltip_radius;
gtk_widget_style_get (tooltip->window,
"tooltip-alpha", &tooltip_alpha,
"tooltip-radius", &tooltip_radius,
NULL);
if (tooltip_alpha != 255 || tooltip_radius != 0)
{
cairo_t *cr;
cr = gdk_cairo_create (tooltip->window->window);
fill_background (tooltip->window, cr,
&tooltip->window->style->bg [GTK_STATE_NORMAL],
&tooltip->window->style->bg [GTK_STATE_SELECTED],
tooltip_alpha);
cairo_destroy (cr);
update_shape (tooltip);
}
else
{
gtk_paint_flat_box (tooltip->window->style, gtk_paint_flat_box (tooltip->window->style,
tooltip->window->window, tooltip->window->window,
GTK_STATE_NORMAL, GTK_STATE_NORMAL,
@ -523,6 +712,7 @@ gtk_tooltip_paint_window (GtkTooltip *tooltip)
0, 0, 0, 0,
tooltip->window->allocation.width, tooltip->window->allocation.width,
tooltip->window->allocation.height); tooltip->window->allocation.height);
}
return FALSE; return FALSE;
} }

View File

@ -2586,6 +2586,32 @@ gtk_widget_class_init (GtkWidgetClass *klass)
P_("The length of vertical scroll arrows"), P_("The length of vertical scroll arrows"),
1, G_MAXINT, 16, 1, G_MAXINT, 16,
GTK_PARAM_READABLE)); GTK_PARAM_READABLE));
/**
* GtkWidget:tooltip-alpha:
*
* The "tooltip-alpha" style property defines the opacity of
* widget tooltips.
*/
gtk_widget_class_install_style_property (klass,
g_param_spec_uchar ("tooltip-alpha",
P_("Tooltips opacity"),
P_("The opacity to be used when drawing tooltips"),
0, 255, 255,
GTK_PARAM_READABLE));
/**
* GtkWidget:tooltip-radius:
*
* The "tooltip-radius" style property defines the radius of
* widget tooltips.
*/
gtk_widget_class_install_style_property (klass,
g_param_spec_uint ("tooltip-radius",
P_("Tooltips radius"),
P_("The radius to be used when drawing tooltips"),
0, G_MAXINT, 0,
GTK_PARAM_READABLE));
} }
static void static void