summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog10
-rw-r--r--src/Makefile.am8
-rw-r--r--src/frames.c67
-rw-r--r--src/gradient.c853
-rw-r--r--src/gradient.h53
-rw-r--r--src/testgradient.c246
-rw-r--r--src/theme.c62
-rw-r--r--src/theme.h6
8 files changed, 1250 insertions, 55 deletions
diff --git a/ChangeLog b/ChangeLog
index 5f11457..4a36e01 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2002-01-06 Havoc Pennington <hp@pobox.com>
+
+ * src/theme.c (meta_theme_get_gradient): change to use spiffy
+ gradient code.
+
+ * src/gradient.c: copy lovely gradient code from WindowMaker,
+ as usual Dan and Alfredo have very nice code
+
2002-01-06 Fatih Demir <kabalak@gtranslator.org>
* configure.in: Added "tr" to the languages list.
@@ -9,7 +17,7 @@
dumb-looking
* src/theme.c: replace old theme.[hc] contents with newer stuff
- that doesn't do anything
+ that doesn't do anything
2002-01-05 Havoc Pennington <hp@pobox.com>
diff --git a/src/Makefile.am b/src/Makefile.am
index 7bca75d..81f2543 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -21,6 +21,8 @@ metacity_SOURCES= \
frame.h \
frames.c \
frames.h \
+ gradient.c \
+ gradient.h \
inlinepixbufs.h \
keybindings.c \
keybindings.h \
@@ -57,6 +59,12 @@ bin_PROGRAMS=metacity
metacity_LDADD= @METACITY_LIBS@
+testgradient_SOURCES=gradient.h gradient.c testgradient.c
+
+noinst_PROGRAMS=testgradient
+
+testgradient_LDADD= @METACITY_LIBS@
+
desktopfilesdir=$(datadir)/gnome/wm-properties
desktopfiles_DATA=metacity.desktop
diff --git a/src/frames.c b/src/frames.c
index 6a6549a..10dd5af 100644
--- a/src/frames.c
+++ b/src/frames.c
@@ -1758,41 +1758,42 @@ meta_frames_expose_event (GtkWidget *widget,
layout_gc = widget->style->fg_gc[GTK_STATE_NORMAL];
if (flags & META_FRAME_HAS_FOCUS)
{
+ GdkPixbuf *gradient;
+
layout_gc = widget->style->fg_gc[GTK_STATE_SELECTED];
-#if 0
- /* Draw blue background */
- gdk_draw_rectangle (frame->window,
- widget->style->bg_gc[GTK_STATE_SELECTED],
- TRUE,
- fgeom.title_rect.x,
- fgeom.title_rect.y,
- fgeom.title_rect.width,
- fgeom.title_rect.height);
-#else
- {
- GdkPixbuf *gradient;
-
- gradient = meta_theme_get_gradient (META_GRADIENT_HORIZONTAL,
- &widget->style->bg[GTK_STATE_SELECTED],
- &widget->style->bg[GTK_STATE_NORMAL],
- fgeom.title_rect.width,
- fgeom.title_rect.height);
-
- gdk_pixbuf_render_to_drawable (gradient,
- frame->window,
- widget->style->bg_gc[GTK_STATE_SELECTED],
- 0, 0,
- fgeom.title_rect.x,
- fgeom.title_rect.y,
- fgeom.title_rect.width,
- fgeom.title_rect.height,
- GDK_RGB_DITHER_NORMAL,
- 0, 0);
-
- g_object_unref (G_OBJECT (gradient));
- }
-#endif
+ gradient = meta_theme_get_gradient (META_GRADIENT_DIAGONAL,
+ &widget->style->bg[GTK_STATE_SELECTED],
+ &widget->style->bg[GTK_STATE_NORMAL],
+ fgeom.title_rect.width,
+ fgeom.title_rect.height);
+
+ if (gradient != NULL)
+ {
+ gdk_pixbuf_render_to_drawable (gradient,
+ frame->window,
+ widget->style->bg_gc[GTK_STATE_SELECTED],
+ 0, 0,
+ fgeom.title_rect.x,
+ fgeom.title_rect.y,
+ fgeom.title_rect.width,
+ fgeom.title_rect.height,
+ GDK_RGB_DITHER_NORMAL,
+ 0, 0);
+
+ g_object_unref (G_OBJECT (gradient));
+ }
+ else
+ {
+ /* Fallback to plain selection color */
+ gdk_draw_rectangle (frame->window,
+ widget->style->bg_gc[GTK_STATE_SELECTED],
+ TRUE,
+ fgeom.title_rect.x,
+ fgeom.title_rect.y,
+ fgeom.title_rect.width,
+ fgeom.title_rect.height);
+ }
}
if (frame->layout)
diff --git a/src/gradient.c b/src/gradient.c
new file mode 100644
index 0000000..61cb32b
--- /dev/null
+++ b/src/gradient.c
@@ -0,0 +1,853 @@
+/* Metacity gradient rendering */
+
+/*
+ * Copyright (C) 2001 Havoc Pennington, 99% copied from wrlib in
+ * WindowMaker, Copyright (C) 1997-2000 Dan Pascu and Alfredo Kojima
+ *
+ * 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 <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);
+ }
+ 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);
+ }
+ }
+ 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 rr, gg, bb;
+ 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)
+ {
+ rr = r1>>16;
+ gg = g1>>16;
+ bb = b1>>16;
+ }
+ else
+ {
+ rr = r2>>16;
+ gg = g2>>16;
+ bb = b2>>16;
+ }
+ for (j=0; j<width/8; j++)
+ {
+ *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
+ *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
+ *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
+ *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
+ *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
+ *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
+ *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
+ *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
+ }
+ switch (width%8)
+ {
+ case 7: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
+ case 6: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
+ case 5: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
+ case 4: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
+ case 3: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
+ case 2: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
+ case 1: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
+ }
+ 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;
+
+ /* FIXME the no_padding = TRUE here is a workaround for a problem
+ * create_diagonal that can't handle a funky rowstride
+ */
+ pixbuf = blank_pixbuf (width, height, TRUE);
+ 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;
+ unsigned char rr, gg, bb;
+ 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;
+
+ rr = r>>16;
+ gg = g>>16;
+ bb = b>>16;
+ for (j=0; j<width/8; j++)
+ {
+ *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
+ *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
+ *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
+ *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
+ *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
+ *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
+ *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
+ *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
+ }
+ switch (width%8)
+ {
+ case 7: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
+ case 6: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
+ case 5: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
+ case 4: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
+ case 3: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
+ case 2: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
+ case 1: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
+ }
+ 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;
+ int r0, g0, b0;
+ int rf, gf, bf;
+ 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);
+
+ /* FIXME here is the pixbuf that we require to have width == rowstride
+ * resulting in no_padding = TRUE in create_horizontal
+ */
+ tmp = meta_gradient_create_horizontal (2*width-1, 1, from, to);
+ if (!tmp)
+ {
+ g_object_unref (G_OBJECT (pixbuf));
+ return NULL;
+ }
+
+ 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);
+
+ 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)
+ {
+ /* FIXME this algorithm assumes rowstride == width in the source
+ * pixbuf, because otherwise we'd accidentally copy junk pixels.
+ */
+ 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;
+ unsigned char rr, gg, bb;
+ int rowstride;
+ int pad;
+
+ 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);
+ pad = rowstride - (width * 3);
+ 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++)
+ {
+ rr = r>>16;
+ gg = g>>16;
+ bb = b>>16;
+
+ for (x=0; x<width/4; x++)
+ {
+ *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
+ *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
+ *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
+ *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
+ }
+ switch (width%4)
+ {
+ case 3: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
+ case 2: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
+ case 1: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
+ }
+
+ ptr += pad;
+
+ r += dr;
+ g += dg;
+ b += db;
+ k++;
+ }
+ r = colors[i].red << 8;
+ g = colors[i].green << 8;
+ b = colors[i].blue << 8;
+ }
+
+ rr = r>>16;
+ gg = g>>16;
+ bb = b>>16;
+
+ if (k<height)
+ {
+ tmp = ptr;
+ for (x=0; x<width/4; x++)
+ {
+ *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
+ *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
+ *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
+ *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
+ }
+ switch (width%4)
+ {
+ case 3: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
+ case 2: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
+ case 1: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
+ default: break;
+ }
+
+ ptr += pad;
+
+ 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;
+
+ /* FIXME here again is a bug that requires multi_horizontal
+ * to have width == rowstride
+ */
+ 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;
+}
+
+#ifdef META_TEST_GRADIENTS
+#include <gtk/gtk.h>
+
+typedef void (* RenderGradientFunc) (GdkDrawable *drawable,
+ GdkGC *gc,
+ int width,
+ int height);
+
+static void
+render_simple (GdkDrawable *drawable,
+ GdkGC *gc,
+ int width, int height,
+ MetaGradientType type)
+{
+ GdkPixbuf *pixbuf;
+ GdkColor from, to;
+
+ gdk_color_parse ("blue", &from);
+ gdk_color_parse ("green", &to);
+
+ pixbuf = meta_gradient_create_simple (width, height,
+ &from, &to,
+ type);
+
+ gdk_pixbuf_render_to_drawable (pixbuf,
+ drawable,
+ gc,
+ 0, 0,
+ 0, 0, width, height,
+ GDK_RGB_DITHER_NORMAL,
+ 0, 0);
+
+ g_object_unref (G_OBJECT (pixbuf));
+}
+
+static void
+render_vertical_func (GdkDrawable *drawable,
+ GdkGC *gc,
+ int width, int height)
+{
+ render_simple (drawable, gc, width, height, META_GRADIENT_VERTICAL);
+}
+
+static void
+render_horizontal_func (GdkDrawable *drawable,
+ GdkGC *gc,
+ int width, int height)
+{
+ render_simple (drawable, gc, width, height, META_GRADIENT_HORIZONTAL);
+}
+
+static void
+render_diagonal_func (GdkDrawable *drawable,
+ GdkGC *gc,
+ int width, int height)
+{
+ render_simple (drawable, gc, width, height, META_GRADIENT_DIAGONAL);
+}
+
+static gboolean
+expose_callback (GtkWidget *widget,
+ GdkEventExpose *event,
+ gpointer data)
+{
+ RenderGradientFunc func = data;
+
+ (* func) (widget->window,
+ widget->style->fg_gc[widget->state],
+ widget->allocation.width,
+ widget->allocation.height);
+
+ return TRUE;
+}
+
+static GtkWidget*
+create_gradient_window (RenderGradientFunc func)
+{
+ GtkWidget *window;
+ GtkWidget *drawing_area;
+
+ window = gtk_window_new (GTK_WINDOW_POPUP);
+
+ drawing_area = gtk_drawing_area_new ();
+
+ gtk_widget_set_size_request (drawing_area, 175, 175);
+
+ g_signal_connect (G_OBJECT (drawing_area),
+ "expose_event",
+ G_CALLBACK (expose_callback),
+ func);
+
+ gtk_container_add (GTK_CONTAINER (window), drawing_area);
+
+ return window;
+}
+
+void
+meta_gradient_test (void)
+{
+ GtkWidget *window;
+
+ window = create_gradient_window (render_vertical_func);
+ gtk_window_move (GTK_WINDOW (window), 0, 0);
+ gtk_widget_show_all (window);
+
+ window = create_gradient_window (render_horizontal_func);
+ gtk_window_move (GTK_WINDOW (window), 0, 200);
+ gtk_widget_show_all (window);
+
+ window = create_gradient_window (render_diagonal_func);
+ gtk_window_move (GTK_WINDOW (window), 200, 0);
+ gtk_widget_show_all (window);
+}
+#endif
+
diff --git a/src/gradient.h b/src/gradient.h
new file mode 100644
index 0000000..079150c
--- /dev/null
+++ b/src/gradient.h
@@ -0,0 +1,53 @@
+/* Metacity gradient rendering */
+
+/*
+ * Copyright (C) 2001 Havoc Pennington, 99% copied from wrlib in
+ * WindowMaker, Copyright (C) 1997-2000 Dan Pascu and Alfredo Kojima
+ *
+ * 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. */
+
+#ifndef META_GRADIENT_H
+#define META_GRADIENT_H
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gdk/gdkcolor.h>
+
+typedef enum
+{
+ META_GRADIENT_VERTICAL,
+ META_GRADIENT_HORIZONTAL,
+ META_GRADIENT_DIAGONAL
+} MetaGradientType;
+
+
+GdkPixbuf* meta_gradient_create_simple (int width,
+ int height,
+ const GdkColor *from,
+ const GdkColor *to,
+ MetaGradientType style);
+GdkPixbuf* meta_gradient_create_multi (int width,
+ int height,
+ const GdkColor *colors,
+ int n_colors,
+ MetaGradientType style);
+GdkPixbuf* meta_gradient_create_interwoven (int width,
+ int height,
+ const GdkColor colors1[2],
+ int thickness1,
+ const GdkColor colors2[2],
+ int thickness2);
+
+#endif
diff --git a/src/testgradient.c b/src/testgradient.c
new file mode 100644
index 0000000..aac882a
--- /dev/null
+++ b/src/testgradient.c
@@ -0,0 +1,246 @@
+/* Metacity gradient test program */
+
+/*
+ * Copyright (C) 2002 Havoc Pennington
+ *
+ * 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 <gtk/gtk.h>
+
+typedef void (* RenderGradientFunc) (GdkDrawable *drawable,
+ GdkGC *gc,
+ int width,
+ int height);
+
+static void
+render_simple (GdkDrawable *drawable,
+ GdkGC *gc,
+ int width, int height,
+ MetaGradientType type)
+{
+ GdkPixbuf *pixbuf;
+ GdkColor from, to;
+
+ gdk_color_parse ("blue", &from);
+ gdk_color_parse ("green", &to);
+
+ pixbuf = meta_gradient_create_simple (width, height,
+ &from, &to,
+ type);
+
+ gdk_pixbuf_render_to_drawable (pixbuf,
+ drawable,
+ gc,
+ 0, 0,
+ 0, 0, width, height,
+ GDK_RGB_DITHER_NORMAL,
+ 0, 0);
+
+ g_object_unref (G_OBJECT (pixbuf));
+}
+
+static void
+render_vertical_func (GdkDrawable *drawable,
+ GdkGC *gc,
+ int width, int height)
+{
+ render_simple (drawable, gc, width, height, META_GRADIENT_VERTICAL);
+}
+
+static void
+render_horizontal_func (GdkDrawable *drawable,
+ GdkGC *gc,
+ int width, int height)
+{
+ render_simple (drawable, gc, width, height, META_GRADIENT_HORIZONTAL);
+}
+
+static void
+render_diagonal_func (GdkDrawable *drawable,
+ GdkGC *gc,
+ int width, int height)
+{
+ render_simple (drawable, gc, width, height, META_GRADIENT_DIAGONAL);
+}
+
+static void
+render_multi (GdkDrawable *drawable,
+ GdkGC *gc,
+ int width, int height,
+ MetaGradientType type)
+{
+ GdkPixbuf *pixbuf;
+#define N_COLORS 5
+ GdkColor colors[N_COLORS];
+
+ gdk_color_parse ("red", &colors[0]);
+ gdk_color_parse ("blue", &colors[1]);
+ gdk_color_parse ("orange", &colors[2]);
+ gdk_color_parse ("pink", &colors[3]);
+ gdk_color_parse ("green", &colors[4]);
+
+ pixbuf = meta_gradient_create_multi (width, height,
+ colors, N_COLORS,
+ type);
+
+ gdk_pixbuf_render_to_drawable (pixbuf,
+ drawable,
+ gc,
+ 0, 0,
+ 0, 0, width, height,
+ GDK_RGB_DITHER_NORMAL,
+ 0, 0);
+
+ g_object_unref (G_OBJECT (pixbuf));
+}
+
+static void
+render_vertical_multi_func (GdkDrawable *drawable,
+ GdkGC *gc,
+ int width, int height)
+{
+ render_multi (drawable, gc, width, height, META_GRADIENT_VERTICAL);
+}
+
+static void
+render_horizontal_multi_func (GdkDrawable *drawable,
+ GdkGC *gc,
+ int width, int height)
+{
+ render_multi (drawable, gc, width, height, META_GRADIENT_HORIZONTAL);
+}
+
+static void
+render_diagonal_multi_func (GdkDrawable *drawable,
+ GdkGC *gc,
+ int width, int height)
+{
+ render_multi (drawable, gc, width, height, META_GRADIENT_DIAGONAL);
+}
+
+static void
+render_interwoven_func (GdkDrawable *drawable,
+ GdkGC *gc,
+ int width, int height)
+{
+ GdkPixbuf *pixbuf;
+#define N_COLORS 4
+ GdkColor colors[N_COLORS];
+
+ gdk_color_parse ("red", &colors[0]);
+ gdk_color_parse ("blue", &colors[1]);
+ gdk_color_parse ("pink", &colors[2]);
+ gdk_color_parse ("green", &colors[3]);
+
+ pixbuf = meta_gradient_create_interwoven (width, height,
+ colors, height / 10,
+ colors + 2, height / 14);
+
+ gdk_pixbuf_render_to_drawable (pixbuf,
+ drawable,
+ gc,
+ 0, 0,
+ 0, 0, width, height,
+ GDK_RGB_DITHER_NORMAL,
+ 0, 0);
+
+ g_object_unref (G_OBJECT (pixbuf));
+}
+
+static gboolean
+expose_callback (GtkWidget *widget,
+ GdkEventExpose *event,
+ gpointer data)
+{
+ RenderGradientFunc func = data;
+
+ (* func) (widget->window,
+ widget->style->fg_gc[widget->state],
+ widget->allocation.width,
+ widget->allocation.height);
+
+ return TRUE;
+}
+
+static GtkWidget*
+create_gradient_window (const char *title,
+ RenderGradientFunc func)
+{
+ GtkWidget *window;
+ GtkWidget *drawing_area;
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+ gtk_window_set_title (GTK_WINDOW (window), title);
+
+ drawing_area = gtk_drawing_area_new ();
+
+ gtk_widget_set_size_request (drawing_area, 1, 1);
+
+ gtk_window_set_default_size (GTK_WINDOW (window), 175, 175);
+
+ g_signal_connect (G_OBJECT (drawing_area),
+ "expose_event",
+ G_CALLBACK (expose_callback),
+ func);
+
+ gtk_container_add (GTK_CONTAINER (window), drawing_area);
+
+ gtk_widget_show_all (window);
+
+ return window;
+}
+
+static void
+meta_gradient_test (void)
+{
+ GtkWidget *window;
+
+ window = create_gradient_window ("Simple vertical",
+ render_vertical_func);
+
+ window = create_gradient_window ("Simple horizontal",
+ render_horizontal_func);
+
+ window = create_gradient_window ("Simple diagonal",
+ render_diagonal_func);
+
+ window = create_gradient_window ("Multi vertical",
+ render_vertical_multi_func);
+
+ window = create_gradient_window ("Multi horizontal",
+ render_horizontal_multi_func);
+
+ window = create_gradient_window ("Multi diagonal",
+ render_diagonal_multi_func);
+
+ window = create_gradient_window ("Interwoven",
+ render_interwoven_func);
+}
+
+int
+main (int argc, char **argv)
+{
+ gtk_init (&argc, &argv);
+
+ meta_gradient_test ();
+
+ gtk_main ();
+
+ return 0;
+}
+
diff --git a/src/theme.c b/src/theme.c
index ada597a..c42a336 100644
--- a/src/theme.c
+++ b/src/theme.c
@@ -21,8 +21,10 @@
#include "theme.h"
#include "util.h"
+#include "gradient.h"
#include <string.h>
+#if 0
/* fill_gradient routine from GNOME background-properties, CVS says
* Michael Fulbright checked it in, Copyright 1998 Red Hat Inc.
*/
@@ -101,6 +103,7 @@ fill_gradient (GdkPixbuf *pixbuf,
g_free (row);
}
+#endif
typedef struct _CachedGradient CachedGradient;
@@ -236,8 +239,8 @@ meta_theme_get_gradient (MetaGradientType type,
"Requesting %s gradient one %d/%d/%d two %d/%d/%d "
"%d x %d\n",
type == META_GRADIENT_VERTICAL ? "vertical" : "horizontal",
- color_one->red / 255, color_one->green / 255, color_one->blue / 255,
- color_two->red / 255, color_two->green / 255, color_two->blue / 255,
+ color_one->red / 256, color_one->green / 256, color_one->blue / 256,
+ color_two->red / 256, color_two->green / 256, color_two->blue / 256,
width, height);
if (gradient_cache == NULL)
@@ -266,6 +269,7 @@ meta_theme_get_gradient (MetaGradientType type,
return cached->pixbuf;
}
+#if 0
gradient.pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8,
gradient.width, gradient.height);
@@ -276,24 +280,50 @@ meta_theme_get_gradient (MetaGradientType type,
gradient.width,
gradient.height,
0, 0);
-
- cached = g_new (CachedGradient, 1);
- *cached = gradient;
+#else
+ gradient.pixbuf = meta_gradient_create_simple (gradient.width,
+ gradient.height,
+ &gradient.color_one,
+ &gradient.color_two,
+ type);
+
+ if (gradient.pixbuf == NULL)
+ {
+ meta_topic (META_DEBUG_GRADIENT_CACHE,
+ "Not enough memory to create gradient of size %d bytes\n",
+ GRADIENT_SIZE (&gradient));
+ return NULL;
+ }
+#endif
- g_hash_table_insert (gradient_cache, cached, cached);
+ if (GRADIENT_SIZE (&gradient) > MAX_CACHE_SIZE)
+ {
+ cached = g_new (CachedGradient, 1);
+ *cached = gradient;
+
+ g_hash_table_insert (gradient_cache, cached, cached);
- meta_topic (META_DEBUG_GRADIENT_CACHE,
- "Caching newly-created gradient, size is %d bytes, total cache size %d bytes %d gradients, maximum %d bytes\n",
- GRADIENT_SIZE (cached),
- cache_size, g_hash_table_size (gradient_cache), MAX_CACHE_SIZE);
+ meta_topic (META_DEBUG_GRADIENT_CACHE,
+ "Caching newly-created gradient, size is %d bytes, total cache size %d bytes %d gradients, maximum %d bytes\n",
+ GRADIENT_SIZE (cached),
+ cache_size, g_hash_table_size (gradient_cache), MAX_CACHE_SIZE);
- cache_size += GRADIENT_SIZE (cached);
+ cache_size += GRADIENT_SIZE (cached);
+
+ g_object_ref (G_OBJECT (cached->pixbuf)); /* to return to caller */
+ retval = cached->pixbuf;
- g_object_ref (G_OBJECT (cached->pixbuf)); /* to return to caller */
- retval = cached->pixbuf;
-
- if (cache_size > MAX_CACHE_SIZE)
- expire_some_old_gradients (); /* may unref "cached->pixbuf" and free "cached" */
+ if (cache_size > MAX_CACHE_SIZE)
+ expire_some_old_gradients (); /* may unref "cached->pixbuf" and free "cached" */
+ }
+ else
+ {
+ meta_topic (META_DEBUG_GRADIENT_CACHE,
+ "Gradient of size %d bytes is too large to cache\n",
+ GRADIENT_SIZE (&gradient));
+
+ retval = gradient.pixbuf;
+ }
return retval;
}
diff --git a/src/theme.h b/src/theme.h
index ee27367..8a3cbae 100644
--- a/src/theme.h
+++ b/src/theme.h
@@ -23,16 +23,12 @@
#define META_THEME_H
#include "frames.h"
+#include "gradient.h"
/* theme.[hc] is basically responsible for drawing parts of the UI using
* theme data
*/
-typedef enum
-{
- META_GRADIENT_VERTICAL,
- META_GRADIENT_HORIZONTAL
-} MetaGradientType;
GdkPixbuf* meta_theme_get_gradient (MetaGradientType type,
const GdkColor *color_one,