summaryrefslogtreecommitdiff
path: root/src/ui/gradient.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/gradient.c')
-rw-r--r--src/ui/gradient.c842
1 files changed, 842 insertions, 0 deletions
diff --git a/src/ui/gradient.c b/src/ui/gradient.c
new file mode 100644
index 00000000..0e739817
--- /dev/null
+++ b/src/ui/gradient.c
@@ -0,0 +1,842 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+/* Marco gradient rendering */
+
+/*
+ * Copyright (C) 2001 Havoc Pennington, 99% copied from wrlib in
+ * WindowMaker, Copyright (C) 1997-2000 Dan Pascu and Alfredo Kojima
+ * Copyright (C) 2005 Elijah Newren
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA. */
+
+#include "gradient.h"
+#include "util.h"
+#include <string.h>
+
+/* This is all Alfredo's and Dan's usual very nice WindowMaker code,
+ * slightly GTK-ized
+ */
+static GdkPixbuf* meta_gradient_create_horizontal (int width,
+ int height,
+ const GdkColor *from,
+ const GdkColor *to);
+static GdkPixbuf* meta_gradient_create_vertical (int width,
+ int height,
+ const GdkColor *from,
+ const GdkColor *to);
+static GdkPixbuf* meta_gradient_create_diagonal (int width,
+ int height,
+ const GdkColor *from,
+ const GdkColor *to);
+static GdkPixbuf* meta_gradient_create_multi_horizontal (int width,
+ int height,
+ const GdkColor *colors,
+ int count);
+static GdkPixbuf* meta_gradient_create_multi_vertical (int width,
+ int height,
+ const GdkColor *colors,
+ int count);
+static GdkPixbuf* meta_gradient_create_multi_diagonal (int width,
+ int height,
+ const GdkColor *colors,
+ int count);
+
+
+/* Used as the destroy notification function for gdk_pixbuf_new() */
+static void
+free_buffer (guchar *pixels, gpointer data)
+{
+ g_free (pixels);
+}
+
+static GdkPixbuf*
+blank_pixbuf (int width, int height, gboolean no_padding)
+{
+ guchar *buf;
+ int rowstride;
+
+ g_return_val_if_fail (width > 0, NULL);
+ g_return_val_if_fail (height > 0, NULL);
+
+ if (no_padding)
+ rowstride = width * 3;
+ else
+ /* Always align rows to 32-bit boundaries */
+ rowstride = 4 * ((3 * width + 3) / 4);
+
+ buf = g_try_malloc (height * rowstride);
+ if (!buf)
+ return NULL;
+
+ return gdk_pixbuf_new_from_data (buf, GDK_COLORSPACE_RGB,
+ FALSE, 8,
+ width, height, rowstride,
+ free_buffer, NULL);
+}
+
+GdkPixbuf*
+meta_gradient_create_simple (int width,
+ int height,
+ const GdkColor *from,
+ const GdkColor *to,
+ MetaGradientType style)
+{
+ switch (style)
+ {
+ case META_GRADIENT_HORIZONTAL:
+ return meta_gradient_create_horizontal (width, height,
+ from, to);
+ case META_GRADIENT_VERTICAL:
+ return meta_gradient_create_vertical (width, height,
+ from, to);
+
+ case META_GRADIENT_DIAGONAL:
+ return meta_gradient_create_diagonal (width, height,
+ from, to);
+ case META_GRADIENT_LAST:
+ break;
+ }
+ g_assert_not_reached ();
+ return NULL;
+}
+
+GdkPixbuf*
+meta_gradient_create_multi (int width,
+ int height,
+ const GdkColor *colors,
+ int n_colors,
+ MetaGradientType style)
+{
+
+ if (n_colors > 2)
+ {
+ switch (style)
+ {
+ case META_GRADIENT_HORIZONTAL:
+ return meta_gradient_create_multi_horizontal (width, height, colors, n_colors);
+ case META_GRADIENT_VERTICAL:
+ return meta_gradient_create_multi_vertical (width, height, colors, n_colors);
+ case META_GRADIENT_DIAGONAL:
+ return meta_gradient_create_multi_diagonal (width, height, colors, n_colors);
+ case META_GRADIENT_LAST:
+ g_assert_not_reached ();
+ break;
+ }
+ }
+ else if (n_colors > 1)
+ {
+ return meta_gradient_create_simple (width, height, &colors[0], &colors[1],
+ style);
+ }
+ else if (n_colors > 0)
+ {
+ return meta_gradient_create_simple (width, height, &colors[0], &colors[0],
+ style);
+ }
+ g_assert_not_reached ();
+ return NULL;
+}
+
+/* Interwoven essentially means we have two vertical gradients,
+ * cut into horizontal strips of the given thickness, and then the strips
+ * are alternated. I'm not sure what it's good for, just copied since
+ * WindowMaker had it.
+ */
+GdkPixbuf*
+meta_gradient_create_interwoven (int width,
+ int height,
+ const GdkColor colors1[2],
+ int thickness1,
+ const GdkColor colors2[2],
+ int thickness2)
+{
+
+ int i, j, k, l, ll;
+ long r1, g1, b1, dr1, dg1, db1;
+ long r2, g2, b2, dr2, dg2, db2;
+ GdkPixbuf *pixbuf;
+ unsigned char *ptr;
+ unsigned char *pixels;
+ int rowstride;
+
+ pixbuf = blank_pixbuf (width, height, FALSE);
+ if (pixbuf == NULL)
+ return NULL;
+
+ pixels = gdk_pixbuf_get_pixels (pixbuf);
+ rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+
+ r1 = colors1[0].red<<8;
+ g1 = colors1[0].green<<8;
+ b1 = colors1[0].blue<<8;
+
+ r2 = colors2[0].red<<8;
+ g2 = colors2[0].green<<8;
+ b2 = colors2[0].blue<<8;
+
+ dr1 = ((colors1[1].red-colors1[0].red)<<8)/(int)height;
+ dg1 = ((colors1[1].green-colors1[0].green)<<8)/(int)height;
+ db1 = ((colors1[1].blue-colors1[0].blue)<<8)/(int)height;
+
+ dr2 = ((colors2[1].red-colors2[0].red)<<8)/(int)height;
+ dg2 = ((colors2[1].green-colors2[0].green)<<8)/(int)height;
+ db2 = ((colors2[1].blue-colors2[0].blue)<<8)/(int)height;
+
+ for (i=0,k=0,l=0,ll=thickness1; i<height; i++)
+ {
+ ptr = pixels + i * rowstride;
+
+ if (k == 0)
+ {
+ ptr[0] = (unsigned char) (r1>>16);
+ ptr[1] = (unsigned char) (g1>>16);
+ ptr[2] = (unsigned char) (b1>>16);
+ }
+ else
+ {
+ ptr[0] = (unsigned char) (r2>>16);
+ ptr[1] = (unsigned char) (g2>>16);
+ ptr[2] = (unsigned char) (b2>>16);
+ }
+
+ for (j=1; j <= width/2; j *= 2)
+ memcpy (&(ptr[j*3]), ptr, j*3);
+ memcpy (&(ptr[j*3]), ptr, (width - j)*3);
+
+ if (++l == ll)
+ {
+ if (k == 0)
+ {
+ k = 1;
+ ll = thickness2;
+ }
+ else
+ {
+ k = 0;
+ ll = thickness1;
+ }
+ l = 0;
+ }
+ r1+=dr1;
+ g1+=dg1;
+ b1+=db1;
+
+ r2+=dr2;
+ g2+=dg2;
+ b2+=db2;
+ }
+
+ return pixbuf;
+}
+
+/*
+ *----------------------------------------------------------------------
+ * meta_gradient_create_horizontal--
+ * Renders a horizontal linear gradient of the specified size in the
+ * GdkPixbuf format with a border of the specified type.
+ *
+ * Returns:
+ * A 24bit GdkPixbuf with the gradient (no alpha channel).
+ *
+ * Side effects:
+ * None
+ *----------------------------------------------------------------------
+ */
+static GdkPixbuf*
+meta_gradient_create_horizontal (int width, int height,
+ const GdkColor *from,
+ const GdkColor *to)
+{
+ int i;
+ long r, g, b, dr, dg, db;
+ GdkPixbuf *pixbuf;
+ unsigned char *ptr;
+ unsigned char *pixels;
+ int r0, g0, b0;
+ int rf, gf, bf;
+ int rowstride;
+
+ pixbuf = blank_pixbuf (width, height, FALSE);
+ if (pixbuf == NULL)
+ return NULL;
+
+ pixels = gdk_pixbuf_get_pixels (pixbuf);
+ ptr = pixels;
+ rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+
+ r0 = (guchar) (from->red / 256.0);
+ g0 = (guchar) (from->green / 256.0);
+ b0 = (guchar) (from->blue / 256.0);
+ rf = (guchar) (to->red / 256.0);
+ gf = (guchar) (to->green / 256.0);
+ bf = (guchar) (to->blue / 256.0);
+
+ r = r0 << 16;
+ g = g0 << 16;
+ b = b0 << 16;
+
+ dr = ((rf-r0)<<16)/(int)width;
+ dg = ((gf-g0)<<16)/(int)width;
+ db = ((bf-b0)<<16)/(int)width;
+ /* render the first line */
+ for (i=0; i<width; i++)
+ {
+ *(ptr++) = (unsigned char)(r>>16);
+ *(ptr++) = (unsigned char)(g>>16);
+ *(ptr++) = (unsigned char)(b>>16);
+ r += dr;
+ g += dg;
+ b += db;
+ }
+
+ /* copy the first line to the other lines */
+ for (i=1; i<height; i++)
+ {
+ memcpy (&(pixels[i*rowstride]), pixels, rowstride);
+ }
+ return pixbuf;
+}
+
+/*
+ *----------------------------------------------------------------------
+ * meta_gradient_create_vertical--
+ * Renders a vertical linear gradient of the specified size in the
+ * GdkPixbuf format with a border of the specified type.
+ *
+ * Returns:
+ * A 24bit GdkPixbuf with the gradient (no alpha channel).
+ *
+ * Side effects:
+ * None
+ *----------------------------------------------------------------------
+ */
+static GdkPixbuf*
+meta_gradient_create_vertical (int width, int height,
+ const GdkColor *from,
+ const GdkColor *to)
+{
+ int i, j;
+ long r, g, b, dr, dg, db;
+ GdkPixbuf *pixbuf;
+ unsigned char *ptr;
+ int r0, g0, b0;
+ int rf, gf, bf;
+ int rowstride;
+ unsigned char *pixels;
+
+ pixbuf = blank_pixbuf (width, height, FALSE);
+ if (pixbuf == NULL)
+ return NULL;
+
+ pixels = gdk_pixbuf_get_pixels (pixbuf);
+ rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+
+ r0 = (guchar) (from->red / 256.0);
+ g0 = (guchar) (from->green / 256.0);
+ b0 = (guchar) (from->blue / 256.0);
+ rf = (guchar) (to->red / 256.0);
+ gf = (guchar) (to->green / 256.0);
+ bf = (guchar) (to->blue / 256.0);
+
+ r = r0<<16;
+ g = g0<<16;
+ b = b0<<16;
+
+ dr = ((rf-r0)<<16)/(int)height;
+ dg = ((gf-g0)<<16)/(int)height;
+ db = ((bf-b0)<<16)/(int)height;
+
+ for (i=0; i<height; i++)
+ {
+ ptr = pixels + i * rowstride;
+
+ ptr[0] = (unsigned char)(r>>16);
+ ptr[1] = (unsigned char)(g>>16);
+ ptr[2] = (unsigned char)(b>>16);
+
+ for (j=1; j <= width/2; j *= 2)
+ memcpy (&(ptr[j*3]), ptr, j*3);
+ memcpy (&(ptr[j*3]), ptr, (width - j)*3);
+
+ r+=dr;
+ g+=dg;
+ b+=db;
+ }
+ return pixbuf;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ * meta_gradient_create_diagonal--
+ * Renders a diagonal linear gradient of the specified size in the
+ * GdkPixbuf format with a border of the specified type.
+ *
+ * Returns:
+ * A 24bit GdkPixbuf with the gradient (no alpha channel).
+ *
+ * Side effects:
+ * None
+ *----------------------------------------------------------------------
+ */
+
+
+static GdkPixbuf*
+meta_gradient_create_diagonal (int width, int height,
+ const GdkColor *from,
+ const GdkColor *to)
+{
+ GdkPixbuf *pixbuf, *tmp;
+ int j;
+ float a, offset;
+ unsigned char *ptr;
+ unsigned char *pixels;
+ int rowstride;
+
+ if (width == 1)
+ return meta_gradient_create_vertical (width, height, from, to);
+ else if (height == 1)
+ return meta_gradient_create_horizontal (width, height, from, to);
+
+ pixbuf = blank_pixbuf (width, height, FALSE);
+ if (pixbuf == NULL)
+ return NULL;
+
+ pixels = gdk_pixbuf_get_pixels (pixbuf);
+ rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+
+ tmp = meta_gradient_create_horizontal (2*width-1, 1, from, to);
+ if (!tmp)
+ {
+ g_object_unref (G_OBJECT (pixbuf));
+ return NULL;
+ }
+
+ ptr = gdk_pixbuf_get_pixels (tmp);
+
+ a = ((float)(width - 1))/((float)(height - 1));
+ width = width * 3;
+
+ /* copy the first line to the other lines with corresponding offset */
+ for (j=0, offset=0.0; j<rowstride*height; j += rowstride)
+ {
+ memcpy (&(pixels[j]), &ptr[3*(int)offset], width);
+ offset += a;
+ }
+
+ g_object_unref (G_OBJECT (tmp));
+ return pixbuf;
+}
+
+
+static GdkPixbuf*
+meta_gradient_create_multi_horizontal (int width, int height,
+ const GdkColor *colors,
+ int count)
+{
+ int i, j, k;
+ long r, g, b, dr, dg, db;
+ GdkPixbuf *pixbuf;
+ unsigned char *ptr;
+ unsigned char *pixels;
+ int width2;
+ int rowstride;
+
+ g_return_val_if_fail (count > 2, NULL);
+
+ pixbuf = blank_pixbuf (width, height, FALSE);
+ if (pixbuf == NULL)
+ return NULL;
+
+ pixels = gdk_pixbuf_get_pixels (pixbuf);
+ rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+ ptr = pixels;
+
+ if (count > width)
+ count = width;
+
+ if (count > 1)
+ width2 = width/(count-1);
+ else
+ width2 = width;
+
+ k = 0;
+
+ r = colors[0].red << 8;
+ g = colors[0].green << 8;
+ b = colors[0].blue << 8;
+
+ /* render the first line */
+ for (i=1; i<count; i++)
+ {
+ dr = ((int)(colors[i].red - colors[i-1].red) <<8)/(int)width2;
+ dg = ((int)(colors[i].green - colors[i-1].green)<<8)/(int)width2;
+ db = ((int)(colors[i].blue - colors[i-1].blue) <<8)/(int)width2;
+ for (j=0; j<width2; j++)
+ {
+ *ptr++ = (unsigned char)(r>>16);
+ *ptr++ = (unsigned char)(g>>16);
+ *ptr++ = (unsigned char)(b>>16);
+ r += dr;
+ g += dg;
+ b += db;
+ k++;
+ }
+ r = colors[i].red << 8;
+ g = colors[i].green << 8;
+ b = colors[i].blue << 8;
+ }
+ for (j=k; j<width; j++)
+ {
+ *ptr++ = (unsigned char)(r>>16);
+ *ptr++ = (unsigned char)(g>>16);
+ *ptr++ = (unsigned char)(b>>16);
+ }
+
+ /* copy the first line to the other lines */
+ for (i=1; i<height; i++)
+ {
+ memcpy (&(pixels[i*rowstride]), pixels, rowstride);
+ }
+ return pixbuf;
+}
+
+static GdkPixbuf*
+meta_gradient_create_multi_vertical (int width, int height,
+ const GdkColor *colors,
+ int count)
+{
+ int i, j, k;
+ long r, g, b, dr, dg, db;
+ GdkPixbuf *pixbuf;
+ unsigned char *ptr, *tmp, *pixels;
+ int height2;
+ int x;
+ int rowstride;
+
+ g_return_val_if_fail (count > 2, NULL);
+
+ pixbuf = blank_pixbuf (width, height, FALSE);
+ if (pixbuf == NULL)
+ return NULL;
+
+ pixels = gdk_pixbuf_get_pixels (pixbuf);
+ rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+ ptr = pixels;
+
+ if (count > height)
+ count = height;
+
+ if (count > 1)
+ height2 = height/(count-1);
+ else
+ height2 = height;
+
+ k = 0;
+
+ r = colors[0].red << 8;
+ g = colors[0].green << 8;
+ b = colors[0].blue << 8;
+
+ for (i=1; i<count; i++)
+ {
+ dr = ((int)(colors[i].red - colors[i-1].red) <<8)/(int)height2;
+ dg = ((int)(colors[i].green - colors[i-1].green)<<8)/(int)height2;
+ db = ((int)(colors[i].blue - colors[i-1].blue) <<8)/(int)height2;
+
+ for (j=0; j<height2; j++)
+ {
+ ptr[0] = (unsigned char)(r>>16);
+ ptr[1] = (unsigned char)(g>>16);
+ ptr[2] = (unsigned char)(b>>16);
+
+ for (x=1; x <= width/2; x *= 2)
+ memcpy (&(ptr[x*3]), ptr, x*3);
+ memcpy (&(ptr[x*3]), ptr, (width - x)*3);
+
+ ptr += rowstride;
+
+ r += dr;
+ g += dg;
+ b += db;
+ k++;
+ }
+ r = colors[i].red << 8;
+ g = colors[i].green << 8;
+ b = colors[i].blue << 8;
+ }
+
+ if (k<height)
+ {
+ tmp = ptr;
+
+ ptr[0] = (unsigned char) (r>>16);
+ ptr[1] = (unsigned char) (g>>16);
+ ptr[2] = (unsigned char) (b>>16);
+
+ for (x=1; x <= width/2; x *= 2)
+ memcpy (&(ptr[x*3]), ptr, x*3);
+ memcpy (&(ptr[x*3]), ptr, (width - x)*3);
+
+ ptr += rowstride;
+
+ for (j=k+1; j<height; j++)
+ {
+ memcpy (ptr, tmp, rowstride);
+ ptr += rowstride;
+ }
+ }
+
+ return pixbuf;
+}
+
+
+static GdkPixbuf*
+meta_gradient_create_multi_diagonal (int width, int height,
+ const GdkColor *colors,
+ int count)
+{
+ GdkPixbuf *pixbuf, *tmp;
+ float a, offset;
+ int j;
+ unsigned char *ptr;
+ unsigned char *pixels;
+ int rowstride;
+
+ g_return_val_if_fail (count > 2, NULL);
+
+ if (width == 1)
+ return meta_gradient_create_multi_vertical (width, height, colors, count);
+ else if (height == 1)
+ return meta_gradient_create_multi_horizontal (width, height, colors, count);
+
+ pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8,
+ width, height);
+ if (pixbuf == NULL)
+ return NULL;
+
+ pixels = gdk_pixbuf_get_pixels (pixbuf);
+ rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+
+ if (count > width)
+ count = width;
+ if (count > height)
+ count = height;
+
+ if (count > 2)
+ tmp = meta_gradient_create_multi_horizontal (2*width-1, 1, colors, count);
+ else
+ /* wrlib multiplies these colors by 256 before passing them in, but
+ * I think it's a bug in wrlib, so changed here. I could be wrong
+ * though, if we notice two-color multi diagonals not working.
+ */
+ tmp = meta_gradient_create_horizontal (2*width-1, 1,
+ &colors[0], &colors[1]);
+
+ if (!tmp)
+ {
+ g_object_unref (G_OBJECT (pixbuf));
+ return NULL;
+ }
+ ptr = gdk_pixbuf_get_pixels (tmp);
+
+ a = ((float)(width - 1))/((float)(height - 1));
+ width = width * 3;
+
+ /* copy the first line to the other lines with corresponding offset */
+ for (j=0, offset=0; j<rowstride*height; j += rowstride)
+ {
+ memcpy (&(pixels[j]), &ptr[3*(int)offset], width);
+ offset += a;
+ }
+
+ g_object_unref (G_OBJECT (tmp));
+ 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 ("marco: vertical alpha channel gradient not implemented yet\n");
+ break;
+
+ case META_GRADIENT_DIAGONAL:
+ g_printerr ("marco: diagonal alpha channel gradient not implemented yet\n");
+ break;
+
+ case META_GRADIENT_LAST:
+ g_assert_not_reached ();
+ break;
+ }
+}