From a1797ff49005fe18a3ae55f763f5a58ade66b480 Mon Sep 17 00:00:00 2001
From: Victor Kareh <vkareh@redhat.com>
Date: Thu, 30 May 2019 16:27:59 -0400
Subject: gradient: sync code with mutter before it was removed

upstream commits:
https://gitlab.gnome.org/GNOME/metacity/commit/3932dca0
https://gitlab.gnome.org/GNOME/metacity/commit/10240013
https://gitlab.gnome.org/GNOME/metacity/commit/3fa97193
---
 src/ui/gradient.c | 496 +++++++++++++++++++++++++++++-------------------------
 src/ui/gradient.h |   9 +
 2 files changed, 280 insertions(+), 225 deletions(-)

(limited to 'src/ui')

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
  */
-- 
cgit v1.2.1