From d4b91dc6540e438cf4bda1dac647caa31df7856d Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Fri, 31 May 2002 21:18:11 +0000 Subject: [PATCH] now just uses meta_gradient_add_alpha (draw_op_as_pixbuf): implement alpha 2002-05-31 Havoc Pennington * src/theme.c (multiply_alpha): now just uses meta_gradient_add_alpha (draw_op_as_pixbuf): implement alpha gradients for tint, gradient, and image draw ops, so I can implement garrett's stuff. * src/gradient.c (meta_gradient_add_alpha): new function to multiply the alpha channel of a pixbuf by an alpha gradient --- ChangeLog | 10 +++ src/gradient.c | 173 +++++++++++++++++++++++++++++++++++++++++++++ src/gradient.h | 9 +++ src/testgradient.c | 109 ++++++++++++++++++++++++++-- src/theme-parser.c | 124 ++++++++++++++++++++++++-------- src/theme.c | 161 ++++++++++++++++++++++++----------------- src/theme.h | 19 ++++- 7 files changed, 504 insertions(+), 101 deletions(-) diff --git a/ChangeLog b/ChangeLog index b66ed5a43..35b01b258 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2002-05-31 Havoc Pennington + + * src/theme.c (multiply_alpha): now just uses + meta_gradient_add_alpha + (draw_op_as_pixbuf): implement alpha gradients for tint, gradient, + and image draw ops, so I can implement garrett's stuff. + + * src/gradient.c (meta_gradient_add_alpha): new function to + multiply the alpha channel of a pixbuf by an alpha gradient + 2002-05-30 Havoc Pennington * src/main.c (main): verbose-log on startup whether we were diff --git a/src/gradient.c b/src/gradient.c index ee1f9215e..a18836462 100644 --- a/src/gradient.c +++ b/src/gradient.c @@ -730,3 +730,176 @@ meta_gradient_create_multi_diagonal (int width, int height, return pixbuf; } +static void +simple_multiply_alpha (GdkPixbuf *pixbuf, + guchar alpha) +{ + guchar *pixels; + int rowstride; + int height; + int row; + + g_return_if_fail (GDK_IS_PIXBUF (pixbuf)); + + if (alpha == 255) + return; + + g_assert (gdk_pixbuf_get_has_alpha (pixbuf)); + + pixels = gdk_pixbuf_get_pixels (pixbuf); + rowstride = gdk_pixbuf_get_rowstride (pixbuf); + height = gdk_pixbuf_get_height (pixbuf); + + row = 0; + while (row < height) + { + guchar *p; + guchar *end; + + p = pixels + row * rowstride; + end = p + rowstride; + + while (p != end) + { + p += 3; /* skip RGB */ + + /* multiply the two alpha channels. not sure this is right. + * but some end cases are that if the pixbuf contains 255, + * then it should be modified to contain "alpha"; if the + * pixbuf contains 0, it should remain 0. + */ + /* ((*p / 255.0) * (alpha / 255.0)) * 255; */ + *p = (guchar) (((int) *p * (int) alpha) / (int) 255); + + ++p; /* skip A */ + } + + ++row; + } +} + +static void +meta_gradient_add_alpha_horizontal (GdkPixbuf *pixbuf, + const unsigned char *alphas, + int n_alphas) +{ + int i, j; + long a, da; + unsigned char *p; + unsigned char *pixels; + int width2; + int rowstride; + int width, height; + unsigned char *gradient; + unsigned char *gradient_p; + unsigned char *gradient_end; + + g_return_if_fail (n_alphas > 0); + + if (n_alphas == 1) + { + /* Optimize this */ + simple_multiply_alpha (pixbuf, alphas[0]); + return; + } + + width = gdk_pixbuf_get_width (pixbuf); + height = gdk_pixbuf_get_height (pixbuf); + + gradient = g_new (unsigned char, width); + gradient_end = gradient + width; + + if (n_alphas > width) + n_alphas = width; + + if (n_alphas > 1) + width2 = width / (n_alphas - 1); + else + width2 = width; + + a = alphas[0] << 8; + gradient_p = gradient; + + /* render the gradient into an array */ + for (i = 1; i < n_alphas; i++) + { + da = (((int)(alphas[i] - (int) alphas[i-1])) << 8) / (int) width2; + + for (j = 0; j < width2; j++) + { + *gradient_p++ = (a >> 8); + + a += da; + } + + a = alphas[i] << 8; + } + + /* get leftover pixels */ + while (gradient_p != gradient_end) + { + *gradient_p++ = a >> 8; + } + + /* Now for each line of the pixbuf, fill in with the gradient */ + pixels = gdk_pixbuf_get_pixels (pixbuf); + rowstride = gdk_pixbuf_get_rowstride (pixbuf); + + p = pixels; + i = 0; + while (i < height) + { + unsigned char *row_end = p + rowstride; + gradient_p = gradient; + + p += 3; + while (gradient_p != gradient_end) + { + /* multiply the two alpha channels. not sure this is right. + * but some end cases are that if the pixbuf contains 255, + * then it should be modified to contain "alpha"; if the + * pixbuf contains 0, it should remain 0. + */ + /* ((*p / 255.0) * (alpha / 255.0)) * 255; */ + *p = (guchar) (((int) *p * (int) *gradient_p) / (int) 255); + + p += 4; + ++gradient_p; + } + + p = row_end; + ++i; + } + + g_free (gradient); +} + +void +meta_gradient_add_alpha (GdkPixbuf *pixbuf, + const guchar *alphas, + int n_alphas, + MetaGradientType type) +{ + g_return_if_fail (GDK_IS_PIXBUF (pixbuf)); + g_return_if_fail (gdk_pixbuf_get_has_alpha (pixbuf)); + g_return_if_fail (n_alphas > 0); + + switch (type) + { + case META_GRADIENT_HORIZONTAL: + meta_gradient_add_alpha_horizontal (pixbuf, alphas, n_alphas); + break; + + case META_GRADIENT_VERTICAL: + g_printerr ("metacity: vertical alpha channel gradient not implemented yet\n"); + break; + + case META_GRADIENT_DIAGONAL: + g_printerr ("metacity: diagonal alpha channel gradient not implemented yet\n"); + break; + + case META_GRADIENT_LAST: + g_assert_not_reached (); + break; + } +} diff --git a/src/gradient.h b/src/gradient.h index 206c6e4e3..d441b16ad 100644 --- a/src/gradient.h +++ b/src/gradient.h @@ -51,4 +51,13 @@ GdkPixbuf* meta_gradient_create_interwoven (int width, int thickness2); +/* Generate an alpha gradient and multiply it with the existing alpha + * channel of the given pixbuf + */ +void meta_gradient_add_alpha (GdkPixbuf *pixbuf, + const guchar *alphas, + int n_alphas, + MetaGradientType type); + + #endif diff --git a/src/testgradient.c b/src/testgradient.c index 007b441df..7d16b427c 100644 --- a/src/testgradient.c +++ b/src/testgradient.c @@ -26,15 +26,82 @@ typedef void (* RenderGradientFunc) (GdkDrawable *drawable, int width, int height); +static void +draw_checkerboard (GdkDrawable *drawable, + int width, + int height) +{ + gint i, j, xcount, ycount; + GdkGC *gc1, *gc2; + GdkColor color; + +#define CHECK_SIZE 10 +#define SPACING 2 + + /* It would be a bit more efficient to keep these + * GC's around instead of recreating on each expose, but + * this is the lazy/slow way. + */ + gc1 = gdk_gc_new (drawable); + color.red = 30000; + color.green = 30000; + color.blue = 30000; + gdk_gc_set_rgb_fg_color (gc1, &color); + + gc2 = gdk_gc_new (drawable); + color.red = 50000; + color.green = 50000; + color.blue = 50000; + gdk_gc_set_rgb_fg_color (gc2, &color); + + xcount = 0; + i = SPACING; + while (i < width) + { + j = SPACING; + ycount = xcount % 2; /* start with even/odd depending on row */ + while (j < height) + { + GdkGC *gc; + + if (ycount % 2) + gc = gc1; + else + gc = gc2; + + /* If we're outside event->area, this will do nothing. + * It might be mildly more efficient if we handled + * the clipping ourselves, but again we're feeling lazy. + */ + gdk_draw_rectangle (drawable, + gc, + TRUE, + i, j, + CHECK_SIZE, + CHECK_SIZE); + + j += CHECK_SIZE + SPACING; + ++ycount; + } + + i += CHECK_SIZE + SPACING; + ++xcount; + } + + g_object_unref (G_OBJECT (gc1)); + g_object_unref (G_OBJECT (gc2)); +} + static void render_simple (GdkDrawable *drawable, GdkGC *gc, int width, int height, - MetaGradientType type) + MetaGradientType type, + gboolean with_alpha) { GdkPixbuf *pixbuf; GdkColor from, to; - + gdk_color_parse ("blue", &from); gdk_color_parse ("green", &to); @@ -42,6 +109,26 @@ render_simple (GdkDrawable *drawable, &from, &to, type); + if (with_alpha) + { + const unsigned char alphas[] = { 0xff, 0xaa, 0x2f, 0x0, 0xcc, 0xff, 0xff }; + + if (!gdk_pixbuf_get_has_alpha (pixbuf)) + { + GdkPixbuf *new_pixbuf; + + new_pixbuf = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0); + g_object_unref (G_OBJECT (pixbuf)); + pixbuf = new_pixbuf; + } + + meta_gradient_add_alpha (pixbuf, + alphas, G_N_ELEMENTS (alphas), + META_GRADIENT_HORIZONTAL); + + draw_checkerboard (drawable, width, height); + } + gdk_pixbuf_render_to_drawable (pixbuf, drawable, gc, @@ -58,7 +145,7 @@ render_vertical_func (GdkDrawable *drawable, GdkGC *gc, int width, int height) { - render_simple (drawable, gc, width, height, META_GRADIENT_VERTICAL); + render_simple (drawable, gc, width, height, META_GRADIENT_VERTICAL, FALSE); } static void @@ -66,7 +153,7 @@ render_horizontal_func (GdkDrawable *drawable, GdkGC *gc, int width, int height) { - render_simple (drawable, gc, width, height, META_GRADIENT_HORIZONTAL); + render_simple (drawable, gc, width, height, META_GRADIENT_HORIZONTAL, FALSE); } static void @@ -74,7 +161,15 @@ render_diagonal_func (GdkDrawable *drawable, GdkGC *gc, int width, int height) { - render_simple (drawable, gc, width, height, META_GRADIENT_DIAGONAL); + render_simple (drawable, gc, width, height, META_GRADIENT_DIAGONAL, FALSE); +} + +static void +render_diagonal_alpha_func (GdkDrawable *drawable, + GdkGC *gc, + int width, int height) +{ + render_simple (drawable, gc, width, height, META_GRADIENT_DIAGONAL, TRUE); } static void @@ -230,6 +325,10 @@ meta_gradient_test (void) window = create_gradient_window ("Interwoven", render_interwoven_func); + + window = create_gradient_window ("Simple diagonal with horizontal multi alpha", + render_diagonal_alpha_func); + } int diff --git a/src/theme-parser.c b/src/theme-parser.c index cb68e7cf9..0a1ba225e 100644 --- a/src/theme-parser.c +++ b/src/theme-parser.c @@ -577,22 +577,81 @@ parse_angle (const char *str, } static gboolean -parse_alpha (const char *str, - double *val, - GMarkupParseContext *context, - GError **error) +parse_alpha (const char *str, + MetaAlphaGradientSpec **spec_ret, + GMarkupParseContext *context, + GError **error) { - if (!parse_double (str, val, context, error)) - return FALSE; + char **split; + int i; + int n_alphas; + MetaAlphaGradientSpec *spec; - if (*val < (0.0 - 1e6) || *val > (1.0 + 1e6)) + *spec_ret = NULL; + + split = g_strsplit (str, ":", -1); + + i = 0; + while (split[i]) + ++i; + + if (i == 0) { set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Alpha must be between 0.0 (invisible) and 1.0 (fully opaque), was %g\n"), - *val); + _("Could not parse \"%s\" as a floating point number"), + str); + + g_strfreev (split); + return FALSE; } + n_alphas = i; + + /* FIXME allow specifying horizontal/vertical/diagonal in theme format, + * once we implement vertical/diagonal in gradient.c + */ + spec = meta_alpha_gradient_spec_new (META_GRADIENT_HORIZONTAL, + n_alphas); + + i = 0; + while (i < n_alphas) + { + double v; + + if (!parse_double (split[i], &v, context, error)) + { + set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, + _("Could not parse \"%s\" as a floating point number"), + split[i]); + + g_strfreev (split); + meta_alpha_gradient_spec_free (spec); + + return FALSE; + } + + if (v < (0.0 - 1e6) || v > (1.0 + 1e6)) + { + set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, + _("Alpha must be between 0.0 (invisible) and 1.0 (fully opaque), was %g\n"), + v); + + g_strfreev (split); + meta_alpha_gradient_spec_free (spec); + + return FALSE; + } + + spec->alphas[i] = (unsigned char) (v * 255); + + ++i; + } + + g_strfreev (split); + + *spec_ret = spec; + return TRUE; } @@ -1886,7 +1945,7 @@ parse_draw_op_element (GMarkupParseContext *context, const char *width; const char *height; const char *alpha; - double alpha_val; + MetaAlphaGradientSpec *alpha_spec; MetaColorSpec *color_spec; if (!locate_attributes (context, element_name, attribute_names, attribute_values, @@ -1952,7 +2011,8 @@ parse_draw_op_element (GMarkupParseContext *context, if (!check_expression (height, FALSE, info->theme, context, error)) return; - if (!parse_alpha (alpha, &alpha_val, context, error)) + alpha_spec = NULL; + if (!parse_alpha (alpha, &alpha_spec, context, error)) return; /* Check last so we don't have to free it when other @@ -1961,6 +2021,9 @@ parse_draw_op_element (GMarkupParseContext *context, color_spec = meta_color_spec_new_from_string (color, error); if (color_spec == NULL) { + if (alpha_spec) + meta_alpha_gradient_spec_free (alpha_spec); + add_context_to_error (error, context); return; } @@ -1968,11 +2031,11 @@ parse_draw_op_element (GMarkupParseContext *context, op = meta_draw_op_new (META_DRAW_TINT); op->data.tint.color_spec = color_spec; + op->data.tint.alpha_spec = alpha_spec; op->data.tint.x = optimize_expression (info->theme, x); op->data.tint.y = optimize_expression (info->theme, y); op->data.tint.width = optimize_expression (info->theme, width); op->data.tint.height = optimize_expression (info->theme, height); - op->data.tint.alpha = alpha_val; g_assert (info->op_list); @@ -1988,7 +2051,7 @@ parse_draw_op_element (GMarkupParseContext *context, const char *height; const char *type; const char *alpha; - double alpha_val; + MetaAlphaGradientSpec *alpha_spec; MetaGradientType type_val; if (!locate_attributes (context, element_name, attribute_names, attribute_values, @@ -2046,10 +2109,6 @@ parse_draw_op_element (GMarkupParseContext *context, if (!check_expression (height, FALSE, info->theme, context, error)) return; - - alpha_val = 1.0; - if (alpha && !parse_alpha (alpha, &alpha_val, context, error)) - return; type_val = meta_gradient_type_from_string (type); if (type_val == META_GRADIENT_LAST) @@ -2060,6 +2119,10 @@ parse_draw_op_element (GMarkupParseContext *context, return; } + alpha_spec = NULL; + if (alpha && !parse_alpha (alpha, &alpha_spec, context, error)) + return; + g_assert (info->op == NULL); info->op = meta_draw_op_new (META_DRAW_GRADIENT); @@ -2068,10 +2131,9 @@ parse_draw_op_element (GMarkupParseContext *context, info->op->data.gradient.width = optimize_expression (info->theme, width); info->op->data.gradient.height = optimize_expression (info->theme, height); - info->op->data.gradient.gradient_spec = - meta_gradient_spec_new (type_val); + info->op->data.gradient.gradient_spec = meta_gradient_spec_new (type_val); - info->op->data.gradient.alpha = alpha_val; + info->op->data.gradient.alpha_spec = alpha_spec; push_state (info, STATE_GRADIENT); @@ -2087,7 +2149,7 @@ parse_draw_op_element (GMarkupParseContext *context, const char *height; const char *alpha; const char *colorize; - double alpha_val; + MetaAlphaGradientSpec *alpha_spec; GdkPixbuf *pixbuf; MetaColorSpec *colorize_spec = NULL; @@ -2147,9 +2209,6 @@ parse_draw_op_element (GMarkupParseContext *context, if (!check_expression (height, TRUE, info->theme, context, error)) return; - alpha_val = 1.0; - if (alpha && !parse_alpha (alpha, &alpha_val, context, error)) - return; /* Check last so we don't have to free it when other * stuff fails @@ -2173,6 +2232,13 @@ parse_draw_op_element (GMarkupParseContext *context, return; } } + + alpha_spec = NULL; + if (alpha && !parse_alpha (alpha, &alpha_spec, context, error)) + { + g_object_unref (G_OBJECT (pixbuf)); + return; + } op = meta_draw_op_new (META_DRAW_IMAGE); @@ -2182,7 +2248,7 @@ parse_draw_op_element (GMarkupParseContext *context, op->data.image.y = optimize_expression (info->theme, y); op->data.image.width = optimize_expression (info->theme, width); op->data.image.height = optimize_expression (info->theme, height); - op->data.image.alpha = alpha_val; + op->data.image.alpha_spec = alpha_spec; g_assert (info->op_list); @@ -2523,7 +2589,7 @@ parse_draw_op_element (GMarkupParseContext *context, const char *width; const char *height; const char *alpha; - double alpha_val; + MetaAlphaGradientSpec *alpha_spec; if (!locate_attributes (context, element_name, attribute_names, attribute_values, error, @@ -2573,8 +2639,8 @@ parse_draw_op_element (GMarkupParseContext *context, if (!check_expression (height, FALSE, info->theme, context, error)) return; - alpha_val = 1.0; - if (alpha && !parse_alpha (alpha, &alpha_val, context, error)) + alpha_spec = NULL; + if (alpha && !parse_alpha (alpha, &alpha_spec, context, error)) return; op = meta_draw_op_new (META_DRAW_ICON); @@ -2583,7 +2649,7 @@ parse_draw_op_element (GMarkupParseContext *context, op->data.icon.y = optimize_expression (info->theme, y); op->data.icon.width = optimize_expression (info->theme, width); op->data.icon.height = optimize_expression (info->theme, height); - op->data.icon.alpha = alpha_val; + op->data.icon.alpha_spec = alpha_spec; g_assert (info->op_list); diff --git a/src/theme.c b/src/theme.c index c54e9ffbc..ac6f411c1 100644 --- a/src/theme.c +++ b/src/theme.c @@ -753,6 +753,32 @@ meta_gradient_spec_validate (MetaGradientSpec *spec, return TRUE; } +MetaAlphaGradientSpec* +meta_alpha_gradient_spec_new (MetaGradientType type, + int n_alphas) +{ + MetaAlphaGradientSpec *spec; + + g_return_val_if_fail (n_alphas > 0, NULL); + + spec = g_new0 (MetaAlphaGradientSpec, 1); + + spec->type = type; + spec->alphas = g_new0 (unsigned char, n_alphas); + spec->n_alphas = n_alphas; + + return spec; +} + +void +meta_alpha_gradient_spec_free (MetaAlphaGradientSpec *spec) +{ + g_return_if_fail (spec != NULL); + + g_free (spec->alphas); + g_free (spec); +} + MetaColorSpec* meta_color_spec_new (MetaColorSpecType type) { @@ -2347,6 +2373,8 @@ meta_draw_op_free (MetaDrawOp *op) case META_DRAW_TINT: if (op->data.tint.color_spec) meta_color_spec_free (op->data.tint.color_spec); + if (op->data.tint.alpha_spec) + meta_alpha_gradient_spec_free (op->data.tint.alpha_spec); g_free (op->data.tint.x); g_free (op->data.tint.y); g_free (op->data.tint.width); @@ -2356,6 +2384,8 @@ meta_draw_op_free (MetaDrawOp *op) case META_DRAW_GRADIENT: if (op->data.gradient.gradient_spec) meta_gradient_spec_free (op->data.gradient.gradient_spec); + if (op->data.gradient.alpha_spec) + meta_alpha_gradient_spec_free (op->data.gradient.alpha_spec); g_free (op->data.gradient.x); g_free (op->data.gradient.y); g_free (op->data.gradient.width); @@ -2363,6 +2393,8 @@ meta_draw_op_free (MetaDrawOp *op) break; case META_DRAW_IMAGE: + if (op->data.image.alpha_spec) + meta_alpha_gradient_spec_free (op->data.image.alpha_spec); if (op->data.image.pixbuf) g_object_unref (G_OBJECT (op->data.image.pixbuf)); if (op->data.image.colorize_spec) @@ -2375,7 +2407,6 @@ meta_draw_op_free (MetaDrawOp *op) g_free (op->data.image.height); break; - case META_DRAW_GTK_ARROW: g_free (op->data.gtk_arrow.x); g_free (op->data.gtk_arrow.y); @@ -2397,6 +2428,8 @@ meta_draw_op_free (MetaDrawOp *op) break; case META_DRAW_ICON: + if (op->data.icon.alpha_spec) + meta_alpha_gradient_spec_free (op->data.icon.alpha_spec); g_free (op->data.icon.x); g_free (op->data.icon.y); g_free (op->data.icon.width); @@ -2464,21 +2497,21 @@ get_gc_for_primitive (GtkWidget *widget, } static GdkPixbuf* -multiply_alpha (GdkPixbuf *pixbuf, - guchar alpha, - gboolean force_copy) +apply_alpha (GdkPixbuf *pixbuf, + MetaAlphaGradientSpec *spec, + gboolean force_copy) { GdkPixbuf *new_pixbuf; - guchar *pixels; - int rowstride; - int height; - int row; - + gboolean needs_alpha; + g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL); - if (alpha == 255) - return pixbuf; + needs_alpha = spec && (spec->n_alphas > 1 || + spec->alphas[0] != 0xff); + if (!needs_alpha) + return pixbuf; + if (!gdk_pixbuf_get_has_alpha (pixbuf)) { new_pixbuf = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0); @@ -2493,38 +2526,9 @@ multiply_alpha (GdkPixbuf *pixbuf, } g_assert (gdk_pixbuf_get_has_alpha (pixbuf)); + + meta_gradient_add_alpha (pixbuf, spec->alphas, spec->n_alphas, spec->type); - pixels = gdk_pixbuf_get_pixels (pixbuf); - rowstride = gdk_pixbuf_get_rowstride (pixbuf); - height = gdk_pixbuf_get_height (pixbuf); - - row = 0; - while (row < height) - { - guchar *p; - guchar *end; - - p = pixels + row * rowstride; - end = p + rowstride; - - while (p != end) - { - p += 3; /* skip RGB */ - - /* multiply the two alpha channels. not sure this is right. - * but some end cases are that if the pixbuf contains 255, - * then it should be modified to contain "alpha"; if the - * pixbuf contains 0, it should remain 0. - */ - /* ((*p / 255.0) * (alpha / 255.0)) * 255; */ - *p = (guchar) (((int) *p * (int) alpha) / (int) 255); - - ++p; /* skip A */ - } - - ++row; - } - return pixbuf; } @@ -2578,10 +2582,10 @@ render_pixbuf (GdkDrawable *drawable, } static GdkPixbuf* -scale_and_alpha_pixbuf (GdkPixbuf *src, - double alpha, - int width, - int height) +scale_and_alpha_pixbuf (GdkPixbuf *src, + MetaAlphaGradientSpec *alpha_spec, + int width, + int height) { GdkPixbuf *pixbuf; @@ -2611,9 +2615,7 @@ scale_and_alpha_pixbuf (GdkPixbuf *src, } if (pixbuf) - pixbuf = multiply_alpha (pixbuf, - ALPHA_TO_UCHAR (alpha), - pixbuf == src); + pixbuf = apply_alpha (pixbuf, alpha_spec, pixbuf == src); return pixbuf; } @@ -2665,20 +2667,46 @@ draw_op_as_pixbuf (const MetaDrawOp *op, { GdkColor color; guint32 rgba; + gboolean has_alpha; meta_color_spec_render (op->data.rectangle.color_spec, widget, &color); + has_alpha = + op->data.tint.alpha_spec && + (op->data.tint.alpha_spec->n_alphas > 1 || + op->data.tint.alpha_spec->alphas[0] != 0xff); + pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, - ALPHA_TO_UCHAR (op->data.tint.alpha) < 255, + has_alpha, 8, width, height); - rgba = GDK_COLOR_RGBA (color); - rgba &= ~0xff; - rgba |= ALPHA_TO_UCHAR (op->data.tint.alpha); + if (!has_alpha) + { + rgba = GDK_COLOR_RGBA (color); + + gdk_pixbuf_fill (pixbuf, rgba); + } + else if (op->data.tint.alpha_spec->n_alphas == 1) + { + rgba = GDK_COLOR_RGBA (color); + rgba &= ~0xff; + rgba |= op->data.tint.alpha_spec->alphas[0]; + + gdk_pixbuf_fill (pixbuf, rgba); + } + else + { + rgba = GDK_COLOR_RGBA (color); + + gdk_pixbuf_fill (pixbuf, rgba); - gdk_pixbuf_fill (pixbuf, rgba); + meta_gradient_add_alpha (pixbuf, + op->data.tint.alpha_spec->alphas, + op->data.tint.alpha_spec->n_alphas, + op->data.tint.alpha_spec->type); + } } break; @@ -2687,9 +2715,9 @@ draw_op_as_pixbuf (const MetaDrawOp *op, pixbuf = meta_gradient_spec_render (op->data.gradient.gradient_spec, widget, width, height); - pixbuf = multiply_alpha (pixbuf, - ALPHA_TO_UCHAR (op->data.gradient.alpha), - FALSE); + pixbuf = apply_alpha (pixbuf, + op->data.gradient.alpha_spec, + FALSE); } break; @@ -2720,17 +2748,17 @@ draw_op_as_pixbuf (const MetaDrawOp *op, if (op->data.image.colorize_cache_pixbuf) { pixbuf = scale_and_alpha_pixbuf (op->data.image.colorize_cache_pixbuf, - op->data.image.alpha, + op->data.image.alpha_spec, width, height); } } else { pixbuf = scale_and_alpha_pixbuf (op->data.image.pixbuf, - op->data.image.alpha, + op->data.image.alpha_spec, width, height); } - break; + break; } case META_DRAW_GTK_ARROW: @@ -2743,11 +2771,11 @@ draw_op_as_pixbuf (const MetaDrawOp *op, width <= gdk_pixbuf_get_width (info->mini_icon) && height <= gdk_pixbuf_get_height (info->mini_icon)) pixbuf = scale_and_alpha_pixbuf (info->mini_icon, - op->data.icon.alpha, + op->data.icon.alpha_spec, width, height); else if (info->icon) pixbuf = scale_and_alpha_pixbuf (info->icon, - op->data.icon.alpha, + op->data.icon.alpha_spec, width, height); break; @@ -2902,13 +2930,18 @@ meta_draw_op_draw_with_env (const MetaDrawOp *op, case META_DRAW_TINT: { int rx, ry, rwidth, rheight; - + gboolean needs_alpha; + + needs_alpha = op->data.tint.alpha_spec && + (op->data.tint.alpha_spec->n_alphas > 1 || + op->data.tint.alpha_spec->alphas[0] != 0xff); + rx = parse_x_position_unchecked (op->data.tint.x, env); ry = parse_y_position_unchecked (op->data.tint.y, env); rwidth = parse_size_unchecked (op->data.tint.width, env); rheight = parse_size_unchecked (op->data.tint.height, env); - if (ALPHA_TO_UCHAR (op->data.tint.alpha) == 255) + if (!needs_alpha) { gc = get_gc_for_primitive (widget, drawable, op->data.tint.color_spec, diff --git a/src/theme.h b/src/theme.h index 6345a2e9b..f93157a2e 100644 --- a/src/theme.h +++ b/src/theme.h @@ -31,6 +31,7 @@ typedef struct _MetaFrameStyleSet MetaFrameStyleSet; typedef struct _MetaDrawOp MetaDrawOp; typedef struct _MetaDrawOpList MetaDrawOpList; typedef struct _MetaGradientSpec MetaGradientSpec; +typedef struct _MetaAlphaGradientSpec MetaAlphaGradientSpec; typedef struct _MetaColorSpec MetaColorSpec; typedef struct _MetaFrameLayout MetaFrameLayout; typedef struct _MetaFrameGeometry MetaFrameGeometry; @@ -169,6 +170,13 @@ struct _MetaGradientSpec GSList *color_specs; }; +struct _MetaAlphaGradientSpec +{ + MetaGradientType type; + unsigned char *alphas; + int n_alphas; +}; + struct _MetaDrawInfo { GdkPixbuf *mini_icon; @@ -256,7 +264,7 @@ struct _MetaDrawOp struct { MetaColorSpec *color_spec; - double alpha; + MetaAlphaGradientSpec *alpha_spec; char *x; char *y; char *width; @@ -265,7 +273,7 @@ struct _MetaDrawOp struct { MetaGradientSpec *gradient_spec; - double alpha; + MetaAlphaGradientSpec *alpha_spec; char *x; char *y; char *width; @@ -274,6 +282,7 @@ struct _MetaDrawOp struct { MetaColorSpec *colorize_spec; + MetaAlphaGradientSpec *alpha_spec; GdkPixbuf *pixbuf; double alpha; char *x; @@ -312,7 +321,7 @@ struct _MetaDrawOp } gtk_vline; struct { - double alpha; + MetaAlphaGradientSpec *alpha_spec; char *x; char *y; char *width; @@ -618,6 +627,10 @@ GdkPixbuf* meta_gradient_spec_render (const MetaGradientSpec *desc, gboolean meta_gradient_spec_validate (MetaGradientSpec *spec, GError **error); +MetaAlphaGradientSpec* meta_alpha_gradient_spec_new (MetaGradientType type, + int n_alphas); +void meta_alpha_gradient_spec_free (MetaAlphaGradientSpec *spec); + MetaFrameStyle* meta_frame_style_new (MetaFrameStyle *parent); void meta_frame_style_ref (MetaFrameStyle *style);