diff options
-rw-r--r-- | src/ui/gradient.c | 496 | ||||
-rw-r--r-- | src/ui/gradient.h | 9 |
2 files changed, 280 insertions, 225 deletions
diff --git a/src/ui/gradient.c b/src/ui/gradient.c index 550017e1..d9bbb3f5 100644 --- a/src/ui/gradient.c +++ b/src/ui/gradient.c @@ -22,40 +22,17 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301, USA. */ -#include "gradient.h" -#include "util.h" -#include <string.h> +/** + * SECTION: gradient + * @title: Gradients + * @short_description: Metacity gradient rendering + */ -#include <gdk/gdk.h> +#include "config.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 GdkRGBA *from, - const GdkRGBA *to); -static GdkPixbuf* meta_gradient_create_vertical (int width, - int height, - const GdkRGBA *from, - const GdkRGBA *to); -static GdkPixbuf* meta_gradient_create_diagonal (int width, - int height, - const GdkRGBA *from, - const GdkRGBA *to); -static GdkPixbuf* meta_gradient_create_multi_horizontal (int width, - int height, - const GdkRGBA *colors, - int count); -static GdkPixbuf* meta_gradient_create_multi_vertical (int width, - int height, - const GdkRGBA *colors, - int count); -static GdkPixbuf* meta_gradient_create_multi_diagonal (int width, - int height, - const GdkRGBA *colors, - int count); +#include <string.h> +#include "gradient.h" /* Used as the destroy notification function for gdk_pixbuf_new() */ static void @@ -65,7 +42,7 @@ free_buffer (guchar *pixels, gpointer data) } static GdkPixbuf* -blank_pixbuf (int width, int height, gboolean no_padding) +blank_pixbuf (int width, int height) { guchar *buf; int rowstride; @@ -73,175 +50,19 @@ blank_pixbuf (int width, int height, gboolean no_padding) 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); + /* Always align rows to 32-bit boundaries */ + rowstride = 4 * ((4 * width + 4) / 4); buf = g_try_malloc (height * rowstride); if (!buf) return NULL; return gdk_pixbuf_new_from_data (buf, GDK_COLORSPACE_RGB, - FALSE, 8, + TRUE, 8, width, height, rowstride, free_buffer, NULL); } -GdkPixbuf* -meta_gradient_create_simple (int width, - int height, - const GdkRGBA *from, - const GdkRGBA *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 GdkRGBA *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 GdkRGBA colors1[2], - int thickness1, - const GdkRGBA 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 = (long)(colors1[0].red*0xffffff); - g1 = (long)(colors1[0].green*0xffffff); - b1 = (long)(colors1[0].blue*0xffffff); - - r2 = (long)(colors2[0].red*0xffffff); - g2 = (long)(colors2[0].green*0xffffff); - b2 = (long)(colors2[0].blue*0xffffff); - - dr1 = ((colors1[1].red-colors1[0].red)*0xffffff)/(int)height; - dg1 = ((colors1[1].green-colors1[0].green)*0xffffff)/(int)height; - db1 = ((colors1[1].blue-colors1[0].blue)*0xffffff)/(int)height; - - dr2 = ((colors2[1].red-colors2[0].red)*0xffffff)/(int)height; - dg2 = ((colors2[1].green-colors2[0].green)*0xffffff)/(int)height; - db2 = ((colors2[1].blue-colors2[0].blue)*0xffffff)/(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-- @@ -257,19 +78,19 @@ meta_gradient_create_interwoven (int width, */ static GdkPixbuf* meta_gradient_create_horizontal (int width, int height, - const GdkRGBA *from, - const GdkRGBA *to) + const GdkRGBA *from, + const GdkRGBA *to) { int i; - long r, g, b, dr, dg, db; + long r, g, b, a, dr, dg, db, da; GdkPixbuf *pixbuf; unsigned char *ptr; unsigned char *pixels; - int r0, g0, b0; - int rf, gf, bf; + int r0, g0, b0, a0; + int rf, gf, bf, af; int rowstride; - pixbuf = blank_pixbuf (width, height, FALSE); + pixbuf = blank_pixbuf (width, height); if (pixbuf == NULL) return NULL; @@ -280,26 +101,32 @@ meta_gradient_create_horizontal (int width, int height, r0 = (guchar) (from->red * 0xff); g0 = (guchar) (from->green * 0xff); b0 = (guchar) (from->blue * 0xff); + a0 = (guchar) (from->alpha * 0xff); rf = (guchar) (to->red * 0xff); gf = (guchar) (to->green * 0xff); bf = (guchar) (to->blue * 0xff); + af = (guchar) (to->alpha * 0xff); r = r0 << 16; g = g0 << 16; b = b0 << 16; + a = a0 << 16; dr = ((rf-r0)<<16)/(int)width; dg = ((gf-g0)<<16)/(int)width; db = ((bf-b0)<<16)/(int)width; + da = ((af-a0)<<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); + *(ptr++) = (unsigned char)(a>>16); r += dr; g += dg; b += db; + a += da; } /* copy the first line to the other lines */ @@ -325,19 +152,19 @@ meta_gradient_create_horizontal (int width, int height, */ static GdkPixbuf* meta_gradient_create_vertical (int width, int height, - const GdkRGBA *from, - const GdkRGBA *to) + const GdkRGBA *from, + const GdkRGBA *to) { int i, j; - long r, g, b, dr, dg, db; + long r, g, b, a, dr, dg, db, da; GdkPixbuf *pixbuf; unsigned char *ptr; - int r0, g0, b0; - int rf, gf, bf; + int r0, g0, b0, a0; + int rf, gf, bf, af; int rowstride; unsigned char *pixels; - pixbuf = blank_pixbuf (width, height, FALSE); + pixbuf = blank_pixbuf (width, height); if (pixbuf == NULL) return NULL; @@ -347,17 +174,21 @@ meta_gradient_create_vertical (int width, int height, r0 = (guchar) (from->red * 0xff); g0 = (guchar) (from->green * 0xff); b0 = (guchar) (from->blue * 0xff); + a0 = (guchar) (from->alpha * 0xff); rf = (guchar) (to->red * 0xff); gf = (guchar) (to->green * 0xff); bf = (guchar) (to->blue * 0xff); + af = (guchar) (to->alpha * 0xff); r = r0<<16; g = g0<<16; b = b0<<16; + a = a0<<16; dr = ((rf-r0)<<16)/(int)height; dg = ((gf-g0)<<16)/(int)height; db = ((bf-b0)<<16)/(int)height; + da = ((af-a0)<<16)/(int)height; for (i=0; i<height; i++) { @@ -366,14 +197,16 @@ meta_gradient_create_vertical (int width, int height, ptr[0] = (unsigned char)(r>>16); ptr[1] = (unsigned char)(g>>16); ptr[2] = (unsigned char)(b>>16); + ptr[3] = (unsigned char)(a>>16); for (j=1; j <= width/2; j *= 2) - memcpy (&(ptr[j*3]), ptr, j*3); - memcpy (&(ptr[j*3]), ptr, (width - j)*3); + memcpy (&(ptr[j*4]), ptr, j*4); + memcpy (&(ptr[j*4]), ptr, (width - j)*4); r+=dr; g+=dg; b+=db; + a+=da; } return pixbuf; } @@ -393,10 +226,11 @@ meta_gradient_create_vertical (int width, int height, *---------------------------------------------------------------------- */ + static GdkPixbuf* meta_gradient_create_diagonal (int width, int height, - const GdkRGBA *from, - const GdkRGBA *to) + const GdkRGBA *from, + const GdkRGBA *to) { GdkPixbuf *pixbuf, *tmp; int j; @@ -410,7 +244,7 @@ meta_gradient_create_diagonal (int width, int height, else if (height == 1) return meta_gradient_create_horizontal (width, height, from, to); - pixbuf = blank_pixbuf (width, height, FALSE); + pixbuf = blank_pixbuf (width, height); if (pixbuf == NULL) return NULL; @@ -427,12 +261,12 @@ meta_gradient_create_diagonal (int width, int height, ptr = gdk_pixbuf_get_pixels (tmp); a = ((float)(width - 1))/((float)(height - 1)); - width = width * 3; + width = width * 4; /* 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); + memcpy (&(pixels[j]), &ptr[4*(int)offset], width); offset += a; } @@ -440,13 +274,14 @@ meta_gradient_create_diagonal (int width, int height, return pixbuf; } + static GdkPixbuf* meta_gradient_create_multi_horizontal (int width, int height, - const GdkRGBA *colors, + const GdkRGBA *colors, int count) { int i, j, k; - long r, g, b, dr, dg, db; + long r, g, b, a, dr, dg, db, da; GdkPixbuf *pixbuf; unsigned char *ptr; unsigned char *pixels; @@ -455,7 +290,7 @@ meta_gradient_create_multi_horizontal (int width, int height, g_return_val_if_fail (count > 2, NULL); - pixbuf = blank_pixbuf (width, height, FALSE); + pixbuf = blank_pixbuf (width, height); if (pixbuf == NULL) return NULL; @@ -476,6 +311,7 @@ meta_gradient_create_multi_horizontal (int width, int height, r = (long)(colors[0].red * 0xffffff); g = (long)(colors[0].green * 0xffffff); b = (long)(colors[0].blue * 0xffffff); + a = (long)(colors[0].alpha * 0xffffff); /* render the first line */ for (i=1; i<count; i++) @@ -483,28 +319,30 @@ meta_gradient_create_multi_horizontal (int width, int height, dr = (int)((colors[i].red - colors[i-1].red) *0xffffff)/(int)width2; dg = (int)((colors[i].green - colors[i-1].green)*0xffffff)/(int)width2; db = (int)((colors[i].blue - colors[i-1].blue) *0xffffff)/(int)width2; - + da = (int)((colors[i].alpha - colors[i-1].alpha) *0xffffff)/(int)width2; for (j=0; j<width2; j++) { *ptr++ = (unsigned char)(r>>16); *ptr++ = (unsigned char)(g>>16); *ptr++ = (unsigned char)(b>>16); + *ptr++ = (unsigned char)(a>>16); r += dr; g += dg; b += db; + a += da; k++; } - r = (long)(colors[i].red * 0xffffff); g = (long)(colors[i].green * 0xffffff); b = (long)(colors[i].blue * 0xffffff); + a = (long)(colors[i].alpha * 0xffffff); } - for (j=k; j<width; j++) { *ptr++ = (unsigned char)(r>>16); *ptr++ = (unsigned char)(g>>16); *ptr++ = (unsigned char)(b>>16); + *ptr++ = (unsigned char)(a>>16); } /* copy the first line to the other lines */ @@ -517,11 +355,11 @@ meta_gradient_create_multi_horizontal (int width, int height, static GdkPixbuf* meta_gradient_create_multi_vertical (int width, int height, - const GdkRGBA *colors, + const GdkRGBA *colors, int count) { int i, j, k; - long r, g, b, dr, dg, db; + long r, g, b, a, dr, dg, db, da; GdkPixbuf *pixbuf; unsigned char *ptr, *tmp, *pixels; int height2; @@ -530,7 +368,7 @@ meta_gradient_create_multi_vertical (int width, int height, g_return_val_if_fail (count > 2, NULL); - pixbuf = blank_pixbuf (width, height, FALSE); + pixbuf = blank_pixbuf (width, height); if (pixbuf == NULL) return NULL; @@ -551,34 +389,38 @@ meta_gradient_create_multi_vertical (int width, int height, r = (long)(colors[0].red * 0xffffff); g = (long)(colors[0].green * 0xffffff); b = (long)(colors[0].blue * 0xffffff); + a = (long)(colors[0].alpha * 0xffffff); for (i=1; i<count; i++) { dr = (int)((colors[i].red - colors[i-1].red) *0xffffff)/(int)height2; dg = (int)((colors[i].green - colors[i-1].green)*0xffffff)/(int)height2; db = (int)((colors[i].blue - colors[i-1].blue) *0xffffff)/(int)height2; + da = (int)((colors[i].alpha - colors[i-1].alpha) *0xffffff)/(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); + ptr[3] = (unsigned char)(a>>16); for (x=1; x <= width/2; x *= 2) - memcpy (&(ptr[x*3]), ptr, x*3); - memcpy (&(ptr[x*3]), ptr, (width - x)*3); + memcpy (&(ptr[x*4]), ptr, x*4); + memcpy (&(ptr[x*4]), ptr, (width - x)*4); ptr += rowstride; r += dr; g += dg; b += db; + a += da; k++; } - r = (long)(colors[i].red * 0xffffff); g = (long)(colors[i].green * 0xffffff); b = (long)(colors[i].blue * 0xffffff); + a = (long)(colors[i].alpha * 0xffffff); } if (k<height) @@ -588,10 +430,11 @@ meta_gradient_create_multi_vertical (int width, int height, ptr[0] = (unsigned char) (r>>16); ptr[1] = (unsigned char) (g>>16); ptr[2] = (unsigned char) (b>>16); + ptr[3] = (unsigned char) (a>>16); for (x=1; x <= width/2; x *= 2) - memcpy (&(ptr[x*3]), ptr, x*3); - memcpy (&(ptr[x*3]), ptr, (width - x)*3); + memcpy (&(ptr[x*4]), ptr, x*4); + memcpy (&(ptr[x*4]), ptr, (width - x)*4); ptr += rowstride; @@ -605,9 +448,10 @@ meta_gradient_create_multi_vertical (int width, int height, return pixbuf; } + static GdkPixbuf* meta_gradient_create_multi_diagonal (int width, int height, - const GdkRGBA *colors, + const GdkRGBA *colors, int count) { GdkPixbuf *pixbuf, *tmp; @@ -812,6 +656,204 @@ meta_gradient_add_alpha_horizontal (GdkPixbuf *pixbuf, g_free (gradient); } +/** + * meta_gradient_create_simple: + * @width: Width in pixels + * @height: Height in pixels + * @from: Starting color + * @to: Ending color + * @style: Gradient style + * + * Returns: (transfer full): A new linear gradient + */ +GdkPixbuf* +meta_gradient_create_simple (int width, + int height, + const GdkRGBA *from, + const GdkRGBA *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; + + default: + break; + } + g_assert_not_reached (); + return NULL; +} + +/** + * meta_gradient_create_multi: + * @width: Width in pixels + * @height: Height in pixels + * @colors: (array length=n_colors): Array of colors + * @n_colors: Number of colors + * @style: Gradient style + * + * Returns: (transfer full): A new multi-step linear gradient + */ +GdkPixbuf* +meta_gradient_create_multi (int width, + int height, + const GdkRGBA *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; + default: + 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; +} + +/** + * meta_gradient_create_interwoven: (skip) + * @width: Width in pixels + * @height: Height in pixels + * @colors1: Array of colors + * @thickness1: Thickness + * @colors2: Array of colors + * @thickness2: Thickness + * + * 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 GdkRGBA colors1[2], + int thickness1, + const GdkRGBA colors2[2], + int thickness2) +{ + + int i, j, k, l, ll; + long r1, g1, b1, a1, dr1, dg1, db1, da1; + long r2, g2, b2, a2, dr2, dg2, db2, da2; + GdkPixbuf *pixbuf; + unsigned char *ptr; + unsigned char *pixels; + int rowstride; + + pixbuf = blank_pixbuf (width, height); + if (pixbuf == NULL) + return NULL; + + pixels = gdk_pixbuf_get_pixels (pixbuf); + rowstride = gdk_pixbuf_get_rowstride (pixbuf); + + r1 = (long)(colors1[0].red*0xffffff); + g1 = (long)(colors1[0].green*0xffffff); + b1 = (long)(colors1[0].blue*0xffffff); + a1 = (long)(colors1[0].alpha*0xffffff); + + r2 = (long)(colors2[0].red*0xffffff); + g2 = (long)(colors2[0].green*0xffffff); + b2 = (long)(colors2[0].blue*0xffffff); + a2 = (long)(colors2[0].alpha*0xffffff); + + dr1 = ((colors1[1].red-colors1[0].red)*0xffffff)/(int)height; + dg1 = ((colors1[1].green-colors1[0].green)*0xffffff)/(int)height; + db1 = ((colors1[1].blue-colors1[0].blue)*0xffffff)/(int)height; + da1 = ((colors1[1].alpha-colors1[0].alpha)*0xffffff)/(int)height; + + dr2 = ((colors2[1].red-colors2[0].red)*0xffffff)/(int)height; + dg2 = ((colors2[1].green-colors2[0].green)*0xffffff)/(int)height; + db2 = ((colors2[1].blue-colors2[0].blue)*0xffffff)/(int)height; + da2 = ((colors2[1].alpha-colors2[0].alpha)*0xffffff)/(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); + ptr[3] = (unsigned char) (a1>>16); + } + else + { + ptr[0] = (unsigned char) (r2>>16); + ptr[1] = (unsigned char) (g2>>16); + ptr[2] = (unsigned char) (b2>>16); + ptr[3] = (unsigned char) (a2>>16); + } + + for (j=1; j <= width/2; j *= 2) + memcpy (&(ptr[j*4]), ptr, j*4); + memcpy (&(ptr[j*4]), ptr, (width - j)*4); + + if (++l == ll) + { + if (k == 0) + { + k = 1; + ll = thickness2; + } + else + { + k = 0; + ll = thickness1; + } + l = 0; + } + r1+=dr1; + g1+=dg1; + b1+=db1; + a1+=da1; + + r2+=dr2; + g2+=dg2; + b2+=db2; + a2+=da2; + } + + return pixbuf; +} + void meta_gradient_add_alpha (GdkPixbuf *pixbuf, const guchar *alphas, @@ -839,5 +881,9 @@ meta_gradient_add_alpha (GdkPixbuf *pixbuf, case META_GRADIENT_LAST: g_assert_not_reached (); break; + + default: + g_assert_not_reached (); + break; } } diff --git a/src/ui/gradient.h b/src/ui/gradient.h index e40ba8eb..8da20485 100644 --- a/src/ui/gradient.h +++ b/src/ui/gradient.h @@ -27,6 +27,14 @@ #include <gdk-pixbuf/gdk-pixbuf.h> #include <gdk/gdk.h> +/** + * MetaGradientType: + * @META_GRADIENT_VERTICAL: Vertical gradient + * @META_GRADIENT_HORIZONTAL: Horizontal gradient + * @META_GRADIENT_DIAGONAL: Diagonal gradient + * @META_GRADIENT_LAST: Marks the end of the #MetaGradientType enumeration + * + */ typedef enum { META_GRADIENT_VERTICAL, @@ -52,6 +60,7 @@ GdkPixbuf* meta_gradient_create_interwoven (int width, const GdkRGBA colors2[2], int thickness2); + /* Generate an alpha gradient and multiply it with the existing alpha * channel of the given pixbuf */ |