summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHavoc Pennington <hp@redhat.com>2002-05-31 21:18:11 +0000
committerHavoc Pennington <hp@src.gnome.org>2002-05-31 21:18:11 +0000
commitd4b91dc6540e438cf4bda1dac647caa31df7856d (patch)
tree18940a46594ef754db48c8f4dafd2090915c2649
parent8da3b943a9fda038ab5113a7f093faea96aef66e (diff)
downloadmetacity-d4b91dc6540e438cf4bda1dac647caa31df7856d.tar.gz
metacity-d4b91dc6540e438cf4bda1dac647caa31df7856d.tar.bz2
now just uses meta_gradient_add_alpha (draw_op_as_pixbuf): implement alpha
2002-05-31 Havoc Pennington <hp@redhat.com> * 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
-rw-r--r--ChangeLog10
-rw-r--r--src/gradient.c173
-rw-r--r--src/gradient.h9
-rw-r--r--src/testgradient.c109
-rw-r--r--src/theme-parser.c124
-rw-r--r--src/theme.c161
-rw-r--r--src/theme.h19
7 files changed, 504 insertions, 101 deletions
diff --git a/ChangeLog b/ChangeLog
index b66ed5a..35b01b2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2002-05-31 Havoc Pennington <hp@redhat.com>
+
+ * 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 <hp@redhat.com>
* src/main.c (main): verbose-log on startup whether we were
diff --git a/src/gradient.c b/src/gradient.c
index ee1f921..a188364 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 206c6e4..d441b16 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 007b441..7d16b42 100644
--- a/src/testgradient.c
+++ b/src/testgradient.c
@@ -27,14 +27,81 @@ typedef void (* RenderGradientFunc) (GdkDrawable *drawable,
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 cb68e7c..0a1ba22 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 c54e9ff..ac6f411 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));
-
- 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;
- }
+ meta_gradient_add_alpha (pixbuf, spec->alphas, spec->n_alphas, spec->type);
+
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 6345a2e..f93157a 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);