[metacity/cowbell] copyright notice; rm old code (for now)



commit 86792c838a46892f4e7231dadc107af0a38eb873
Author: Thomas Thurman <tthurman gnome org>
Date:   Wed Oct 28 22:26:15 2009 -0400

    copyright notice; rm old code (for now)

 src/ui/theme.c | 6661 +-------------------------------------------------------
 1 files changed, 22 insertions(+), 6639 deletions(-)
---
diff --git a/src/ui/theme.c b/src/ui/theme.c
index effb335..b2859e1 100644
--- a/src/ui/theme.c
+++ b/src/ui/theme.c
@@ -1,5 +1,27 @@
 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 
+/* Metacity Theme Rendering */
+
+/*
+ * Copyright (C) 2009 Collabora Ltd
+ * Copyright (C) 2009 Thomas Thurman
+ *
+ * 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 "theme.h"
 #include "util.h"
 #include <string.h>
@@ -1336,6642 +1358,3 @@ meta_pango_font_desc_get_text_height (const PangoFontDescription *font_desc,
   
   return retval;
 }
-
-#if 0
-/****************************************************************/
-
-
-
-/* Metacity Theme Rendering */
-
-/*
- * Copyright (C) 2001 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.
- */
-
-/**
- * \file theme.c    Making Metacity look pretty
- *
- * The window decorations drawn by Metacity are described by files on disk
- * known internally as "themes" (externally as "window border themes" on
- * http://art.gnome.org/themes/metacity/ or "Metacity themes"). This file
- * contains most of the code necessary to support themes; it does not
- * contain the XML parser, which is in theme-parser.c.
- *
- * \bug This is a big file with lots of different subsystems, which might
- * be better split out into separate files.
- */
-
-/**
- * \defgroup tokenizer   The theme expression tokenizer
- *
- * Themes can use a simple expression language to represent the values of
- * things. This is the tokeniser used for that language.
- *
- * \bug We could remove almost all this code by using GScanner instead,
- * but we would also have to find every expression in every existing theme
- * we could and make sure the parse trees were the same.
- */
-
-/**
- * \defgroup parser  The theme expression parser
- *
- * Themes can use a simple expression language to represent the values of
- * things. This is the parser used for that language.
- */
-
-#include <config.h>
-#include "theme.h"
-#include "theme-parser.h"
-#include "util.h"
-#include "gradient.h"
-#include <gtk/gtk.h>
-#include <string.h>
-#include <stdlib.h>
-#include <math.h>
-
-#define GDK_COLOR_RGBA(color)                                           \
-                         ((guint32) (0xff                         |     \
-                                     (((color).red / 256) << 24)   |    \
-                                     (((color).green / 256) << 16) |    \
-                                     (((color).blue / 256) << 8)))
-
-#define GDK_COLOR_RGB(color)                                            \
-                         ((guint32) ((((color).red / 256) << 16)   |    \
-                                     (((color).green / 256) << 8)  |    \
-                                     (((color).blue / 256))))
-
-#define ALPHA_TO_UCHAR(d) ((unsigned char) ((d) * 255))
-
-#define DEBUG_FILL_STRUCT(s) memset ((s), 0xef, sizeof (*(s)))
-#define CLAMP_UCHAR(v) ((guchar) (CLAMP (((int)v), (int)0, (int)255)))
-#define INTENSITY(r, g, b) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11)
-
-static void gtk_style_shade		(GdkColor	 *a,
-					 GdkColor	 *b,
-					 gdouble	  k);
-static void rgb_to_hls			(gdouble	 *r,
-					 gdouble	 *g,
-					 gdouble	 *b);
-static void hls_to_rgb			(gdouble	 *h,
-					 gdouble	 *l,
-					 gdouble	 *s);
-
-/**
- * The current theme. (Themes are singleton.)
- */
-static MetaTheme *meta_current_theme = NULL;
-
-static GdkPixbuf *
-colorize_pixbuf (GdkPixbuf *orig,
-                 GdkColor  *new_color)
-{
-  GdkPixbuf *pixbuf;
-  double intensity;
-  int x, y;
-  const guchar *src;
-  guchar *dest;
-  int orig_rowstride;
-  int dest_rowstride;
-  int width, height;
-  gboolean has_alpha;
-  const guchar *src_pixels;
-  guchar *dest_pixels;
-  
-  pixbuf = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (orig), gdk_pixbuf_get_has_alpha (orig),
-			   gdk_pixbuf_get_bits_per_sample (orig),
-			   gdk_pixbuf_get_width (orig), gdk_pixbuf_get_height (orig));
-
-  if (pixbuf == NULL)
-    return NULL;
-  
-  orig_rowstride = gdk_pixbuf_get_rowstride (orig);
-  dest_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
-  width = gdk_pixbuf_get_width (pixbuf);
-  height = gdk_pixbuf_get_height (pixbuf);
-  has_alpha = gdk_pixbuf_get_has_alpha (orig);
-  src_pixels = gdk_pixbuf_get_pixels (orig);
-  dest_pixels = gdk_pixbuf_get_pixels (pixbuf);
-  
-  for (y = 0; y < height; y++)
-    {
-      src = src_pixels + y * orig_rowstride;
-      dest = dest_pixels + y * dest_rowstride;
-
-      for (x = 0; x < width; x++)
-        {
-          double dr, dg, db;
-          
-          intensity = INTENSITY (src[0], src[1], src[2]) / 255.0;
-
-          if (intensity <= 0.5)
-            {
-              /* Go from black at intensity = 0.0 to new_color at intensity = 0.5 */
-              dr = (new_color->red * intensity * 2.0) / 65535.0;
-              dg = (new_color->green * intensity * 2.0) / 65535.0;
-              db = (new_color->blue * intensity * 2.0) / 65535.0;
-            }
-          else
-            {
-              /* Go from new_color at intensity = 0.5 to white at intensity = 1.0 */
-              dr = (new_color->red + (65535 - new_color->red) * (intensity - 0.5) * 2.0) / 65535.0;
-              dg = (new_color->green + (65535 - new_color->green) * (intensity - 0.5) * 2.0) / 65535.0;
-              db = (new_color->blue + (65535 - new_color->blue) * (intensity - 0.5) * 2.0) / 65535.0;
-            }
-          
-          dest[0] = CLAMP_UCHAR (255 * dr);
-          dest[1] = CLAMP_UCHAR (255 * dg);
-          dest[2] = CLAMP_UCHAR (255 * db);
-          
-          if (has_alpha)
-            {
-              dest[3] = src[3];
-              src += 4;
-              dest += 4;
-            }
-          else
-            {
-              src += 3;
-              dest += 3;
-            }
-        }
-    }
-
-  return pixbuf;
-}
-
-static void
-color_composite (const GdkColor *bg,
-                 const GdkColor *fg,
-                 double          alpha_d,
-                 GdkColor       *color)
-{
-  guint16 alpha;
-
-  *color = *bg;
-  alpha = alpha_d * 0xffff;
-  color->red = color->red + (((fg->red - color->red) * alpha + 0x8000) >> 16);
-  color->green = color->green + (((fg->green - color->green) * alpha + 0x8000) >> 16);
-  color->blue = color->blue + (((fg->blue - color->blue) * alpha + 0x8000) >> 16);
-}
-
-/**
- * Sets all the fields of a border to dummy values.
- *
- * \param border The border whose fields should be reset.
- */
-static void
-init_border (GtkBorder *border)
-{
-  border->top = -1;
-  border->bottom = -1;
-  border->left = -1;
-  border->right = -1;
-}
-
-/**
- * Creates a new, empty MetaFrameLayout. The fields will be set to dummy
- * values.
- *
- * \return The newly created MetaFrameLayout.
- */
-MetaFrameLayout*
-meta_frame_layout_new  (void)
-{
-  MetaFrameLayout *layout;
-
-  layout = g_new0 (MetaFrameLayout, 1);
-
-  layout->refcount = 1;
-
-  /* Fill with -1 values to detect invalid themes */
-  layout->left_width = -1;
-  layout->right_width = -1;
-  layout->bottom_height = -1;
-
-  init_border (&layout->title_border);
-
-  layout->title_vertical_pad = -1;
-  
-  layout->right_titlebar_edge = -1;
-  layout->left_titlebar_edge = -1;
-
-  layout->button_sizing = META_BUTTON_SIZING_LAST;
-  layout->button_aspect = 1.0;
-  layout->button_width = -1;
-  layout->button_height = -1;
-
-  layout->has_title = TRUE;
-  layout->title_scale = 1.0;
-  
-  init_border (&layout->button_border);
-
-  return layout;
-}
-
-/**
- *
- */
-static gboolean
-validate_border (const GtkBorder *border,
-                 const char     **bad)
-{
-  *bad = NULL;
-  
-  if (border->top < 0)
-    *bad = _("top");
-  else if (border->bottom < 0)
-    *bad = _("bottom");
-  else if (border->left < 0)
-    *bad = _("left");
-  else if (border->right < 0)
-    *bad = _("right");
-
-  return *bad == NULL;
-}
-
-/**
- * Ensures that the theme supplied a particular dimension. When a
- * MetaFrameLayout is created, all its integer fields are set to -1
- * by meta_frame_layout_new(). After an instance of this type
- * should have been initialised, this function checks that
- * a given field is not still at -1. It is never called directly, but
- * rather via the CHECK_GEOMETRY_VALUE and CHECK_GEOMETRY_BORDER
- * macros.
- *
- * \param      val    The value to check
- * \param      name   The name to use in the error message
- * \param[out] error  Set to an error if val was not initialised
- */
-static gboolean
-validate_geometry_value (int         val,
-                         const char *name,
-                         GError    **error)
-{
-  if (val < 0)
-    {
-      g_set_error (error, META_THEME_ERROR,
-                   META_THEME_ERROR_FRAME_GEOMETRY,
-                   _("frame geometry does not specify \"%s\" dimension"),
-                   name);
-      return FALSE;
-    }
-  else
-    return TRUE;
-}
-
-static gboolean
-validate_geometry_border (const GtkBorder *border,
-                          const char      *name,
-                          GError         **error)
-{
-  const char *bad;
-
-  if (!validate_border (border, &bad))
-    {
-      g_set_error (error, META_THEME_ERROR,
-                   META_THEME_ERROR_FRAME_GEOMETRY,
-                   _("frame geometry does not specify dimension \"%s\" for border \"%s\""),
-                   bad, name);
-      return FALSE;
-    }
-  else
-    return TRUE;
-}
-
-gboolean
-meta_frame_layout_validate (const MetaFrameLayout *layout,
-                            GError               **error)
-{
-  g_return_val_if_fail (layout != NULL, FALSE);
-
-#define CHECK_GEOMETRY_VALUE(vname) if (!validate_geometry_value (layout->vname, #vname, error)) return FALSE
-
-#define CHECK_GEOMETRY_BORDER(bname) if (!validate_geometry_border (&layout->bname, #bname, error)) return FALSE
-
-  CHECK_GEOMETRY_VALUE (left_width);
-  CHECK_GEOMETRY_VALUE (right_width);
-  CHECK_GEOMETRY_VALUE (bottom_height);
-
-  CHECK_GEOMETRY_BORDER (title_border);
-
-  CHECK_GEOMETRY_VALUE (title_vertical_pad);
-
-  CHECK_GEOMETRY_VALUE (right_titlebar_edge);
-  CHECK_GEOMETRY_VALUE (left_titlebar_edge);
-
-  switch (layout->button_sizing)
-    {
-    case META_BUTTON_SIZING_ASPECT:
-      if (layout->button_aspect < (0.1) ||
-          layout->button_aspect > (15.0))
-        {
-          g_set_error (error, META_THEME_ERROR,
-                       META_THEME_ERROR_FRAME_GEOMETRY,
-                       _("Button aspect ratio %g is not reasonable"),
-                       layout->button_aspect);
-          return FALSE;
-        }
-      break;
-    case META_BUTTON_SIZING_FIXED:
-      CHECK_GEOMETRY_VALUE (button_width);
-      CHECK_GEOMETRY_VALUE (button_height);
-      break;
-    case META_BUTTON_SIZING_LAST:
-      g_set_error (error, META_THEME_ERROR,
-                   META_THEME_ERROR_FRAME_GEOMETRY,
-                   _("Frame geometry does not specify size of buttons"));
-      return FALSE;
-    }
-
-  CHECK_GEOMETRY_BORDER (button_border);
-
-  return TRUE;
-}
-
-MetaFrameLayout*
-meta_frame_layout_copy (const MetaFrameLayout *src)
-{
-  MetaFrameLayout *layout;
-
-  layout = g_new0 (MetaFrameLayout, 1);
-
-  *layout = *src;
-
-  layout->refcount = 1;
-
-  return layout;
-}
-
-void
-meta_frame_layout_ref (MetaFrameLayout *layout)
-{
-  g_return_if_fail (layout != NULL);
-
-  layout->refcount += 1;
-}
-
-void
-meta_frame_layout_unref (MetaFrameLayout *layout)
-{
-  g_return_if_fail (layout != NULL);
-  g_return_if_fail (layout->refcount > 0);
-
-  layout->refcount -= 1;
-
-  if (layout->refcount == 0)
-    {
-      DEBUG_FILL_STRUCT (layout);
-      g_free (layout);
-    }
-}
-
-void
-meta_frame_layout_get_borders (const MetaFrameLayout *layout,
-                               int                    text_height,
-                               MetaFrameFlags         flags,
-                               int                   *top_height,
-                               int                   *bottom_height,
-                               int                   *left_width,
-                               int                   *right_width)
-{
-  int buttons_height, title_height;
-  
-  g_return_if_fail (top_height != NULL);
-  g_return_if_fail (bottom_height != NULL);
-  g_return_if_fail (left_width != NULL);
-  g_return_if_fail (right_width != NULL);
-
-  if (!layout->has_title)
-    text_height = 0;
-  
-  buttons_height = layout->button_height +
-    layout->button_border.top + layout->button_border.bottom;
-  title_height = text_height +
-    layout->title_vertical_pad +
-    layout->title_border.top + layout->title_border.bottom;
-
-  if (top_height)
-    {
-      *top_height = MAX (buttons_height, title_height);
-    }
-
-  if (left_width)
-    *left_width = layout->left_width;
-  if (right_width)
-    *right_width = layout->right_width;
-
-  if (bottom_height)
-    {
-      if (flags & META_FRAME_SHADED)
-        *bottom_height = 0;
-      else
-        *bottom_height = layout->bottom_height;
-    }
-
-  if (flags & META_FRAME_FULLSCREEN)
-    {
-      if (top_height)
-        *top_height = 0;
-      if (bottom_height)
-        *bottom_height = 0;
-      if (left_width)
-        *left_width = 0;
-      if (right_width)
-        *right_width = 0;
-    }
-}
-
-static MetaButtonSpace*
-rect_for_function (MetaFrameGeometry *fgeom,
-                   MetaFrameFlags     flags,
-                   MetaButtonFunction function,
-                   MetaTheme         *theme)
-{
-
-  /* Firstly, check version-specific things. */
-  
-  if (META_THEME_ALLOWS(theme, META_THEME_SHADE_STICK_ABOVE_BUTTONS))
-    {
-      switch (function)
-        {
-        case META_BUTTON_FUNCTION_SHADE:
-          if ((flags & META_FRAME_ALLOWS_SHADE) && !(flags & META_FRAME_SHADED))
-            return &fgeom->shade_rect;
-          else
-            return NULL;
-        case META_BUTTON_FUNCTION_ABOVE:
-          if (!(flags & META_FRAME_ABOVE))
-            return &fgeom->above_rect;
-          else
-            return NULL;
-        case META_BUTTON_FUNCTION_STICK:
-          if (!(flags & META_FRAME_STUCK))
-            return &fgeom->stick_rect;
-          else
-            return NULL;
-        case META_BUTTON_FUNCTION_UNSHADE:
-          if ((flags & META_FRAME_ALLOWS_SHADE) && (flags & META_FRAME_SHADED))
-            return &fgeom->unshade_rect;
-          else
-            return NULL;
-        case META_BUTTON_FUNCTION_UNABOVE:
-          if (flags & META_FRAME_ABOVE)
-            return &fgeom->unabove_rect;
-          else
-            return NULL;
-        case META_BUTTON_FUNCTION_UNSTICK:
-          if (flags & META_FRAME_STUCK)
-            return &fgeom->unstick_rect;
-        default:
-          /* just go on to the next switch block */;
-        }
-    }
-
-  /* now consider the buttons which exist in all versions */
-
-  switch (function)
-    {
-    case META_BUTTON_FUNCTION_MENU:
-      if (flags & META_FRAME_ALLOWS_MENU)
-        return &fgeom->menu_rect;
-      else
-        return NULL;
-    case META_BUTTON_FUNCTION_MINIMIZE:
-      if (flags & META_FRAME_ALLOWS_MINIMIZE)
-        return &fgeom->min_rect;
-      else
-        return NULL;
-    case META_BUTTON_FUNCTION_MAXIMIZE:
-      if (flags & META_FRAME_ALLOWS_MAXIMIZE)
-        return &fgeom->max_rect;
-      else
-        return NULL;
-    case META_BUTTON_FUNCTION_CLOSE:
-      if (flags & META_FRAME_ALLOWS_DELETE)
-        return &fgeom->close_rect;
-      else
-        return NULL;
-    case META_BUTTON_FUNCTION_STICK:
-    case META_BUTTON_FUNCTION_SHADE:
-    case META_BUTTON_FUNCTION_ABOVE:
-    case META_BUTTON_FUNCTION_UNSTICK:
-    case META_BUTTON_FUNCTION_UNSHADE:
-    case META_BUTTON_FUNCTION_UNABOVE:
-      /* we are being asked for a >v1 button which hasn't been handled yet,
-       * so obviously we're not in a theme which supports that version.
-       * therefore, we don't show the button. return NULL and all will
-       * be well.
-       */
-      return NULL;
-      
-    case META_BUTTON_FUNCTION_LAST:
-      return NULL;
-    }
-
-  return NULL;
-}
-
-static gboolean
-strip_button (MetaButtonSpace *func_rects[MAX_BUTTONS_PER_CORNER],
-              GdkRectangle    *bg_rects[MAX_BUTTONS_PER_CORNER],
-              int             *n_rects,
-              MetaButtonSpace *to_strip)
-{
-  int i;
-  
-  i = 0;
-  while (i < *n_rects)
-    {
-      if (func_rects[i] == to_strip)
-        {
-          *n_rects -= 1;
-
-          /* shift the other rects back in the array */
-          while (i < *n_rects)
-            {
-              func_rects[i] = func_rects[i+1];
-              bg_rects[i] = bg_rects[i+1];
-
-              ++i;
-            }
-
-          func_rects[i] = NULL;
-          bg_rects[i] = NULL;
-          
-          return TRUE;
-        }
-
-      ++i;
-    }
-
-  return FALSE; /* did not strip anything */
-}
-
-void
-meta_frame_layout_calc_geometry (const MetaFrameLayout  *layout,
-                                 int                     text_height,
-                                 MetaFrameFlags          flags,
-                                 int                     client_width,
-                                 int                     client_height,
-                                 const MetaButtonLayout *button_layout,
-                                 MetaFrameGeometry      *fgeom,
-                                 MetaTheme              *theme)
-{
-  int i, n_left, n_right, n_left_spacers, n_right_spacers;
-  int x;
-  int button_y;
-  int title_right_edge;
-  int width, height;
-  int button_width, button_height;
-  int min_size_for_rounding;
-  
-  /* the left/right rects in order; the max # of rects
-   * is the number of button functions
-   */
-  MetaButtonSpace *left_func_rects[MAX_BUTTONS_PER_CORNER];
-  MetaButtonSpace *right_func_rects[MAX_BUTTONS_PER_CORNER];
-  GdkRectangle *left_bg_rects[MAX_BUTTONS_PER_CORNER];
-  gboolean left_buttons_has_spacer[MAX_BUTTONS_PER_CORNER];
-  GdkRectangle *right_bg_rects[MAX_BUTTONS_PER_CORNER];
-  gboolean right_buttons_has_spacer[MAX_BUTTONS_PER_CORNER];
-  
-  meta_frame_layout_get_borders (layout, text_height,
-                                 flags,
-                                 &fgeom->top_height,
-                                 &fgeom->bottom_height,
-                                 &fgeom->left_width,
-                                 &fgeom->right_width);
-
-  width = client_width + fgeom->left_width + fgeom->right_width;
-
-  height = ((flags & META_FRAME_SHADED) ? 0: client_height) +
-    fgeom->top_height + fgeom->bottom_height;
-
-  fgeom->width = width;
-  fgeom->height = height;
-
-  fgeom->top_titlebar_edge = layout->title_border.top;
-  fgeom->bottom_titlebar_edge = layout->title_border.bottom;
-  fgeom->left_titlebar_edge = layout->left_titlebar_edge;
-  fgeom->right_titlebar_edge = layout->right_titlebar_edge;
-
-  /* gcc warnings */
-  button_width = -1;
-  button_height = -1;
-  
-  switch (layout->button_sizing)
-    {
-    case META_BUTTON_SIZING_ASPECT:
-      button_height = fgeom->top_height - layout->button_border.top - layout->button_border.bottom;
-      button_width = button_height / layout->button_aspect;
-      break;
-    case META_BUTTON_SIZING_FIXED:
-      button_width = layout->button_width;
-      button_height = layout->button_height;
-      break;
-    case META_BUTTON_SIZING_LAST:
-      g_assert_not_reached ();
-      break;
-    }
-
-  /* FIXME all this code sort of pretends that duplicate buttons
-   * with the same function are allowed, but that breaks the
-   * code in frames.c, so isn't really allowed right now.
-   * Would need left_close_rect, right_close_rect, etc.
-   */
-  
-  /* Init all button rects to 0, lame hack */
-  memset (ADDRESS_OF_BUTTON_RECTS (fgeom), '\0',
-          LENGTH_OF_BUTTON_RECTS);
-  
-  n_left = 0;
-  n_right = 0;
-  n_left_spacers = 0;
-  n_right_spacers = 0;
-
-  if (!layout->hide_buttons)
-    {
-      /* Try to fill in rects */
-      for (i = 0; i < MAX_BUTTONS_PER_CORNER && button_layout->left_buttons[i] != META_BUTTON_FUNCTION_LAST; i++)
-        {
-          left_func_rects[n_left] = rect_for_function (fgeom, flags,
-                                                       button_layout->left_buttons[i],
-                                                       theme);
-          if (left_func_rects[n_left] != NULL)
-            {
-              left_buttons_has_spacer[n_left] = button_layout->left_buttons_has_spacer[i];
-              if (button_layout->left_buttons_has_spacer[i])
-                ++n_left_spacers;
-
-              ++n_left;
-            }
-        }
-      
-      for (i = 0; i < MAX_BUTTONS_PER_CORNER && button_layout->right_buttons[i] != META_BUTTON_FUNCTION_LAST; i++)
-        {
-          right_func_rects[n_right] = rect_for_function (fgeom, flags,
-                                                         button_layout->right_buttons[i],
-                                                         theme);
-          if (right_func_rects[n_right] != NULL)
-            {
-              right_buttons_has_spacer[n_right] = button_layout->right_buttons_has_spacer[i];
-              if (button_layout->right_buttons_has_spacer[i])
-                ++n_right_spacers;
-
-              ++n_right;
-            }
-        }
-    }
-
-  for (i = 0; i < MAX_BUTTONS_PER_CORNER; i++)
-    {
-      left_bg_rects[i] = NULL;
-      right_bg_rects[i] = NULL;
-    }
-
-  for (i = 0; i < n_left; i++)
-    {
-      if (i == 0) /* prefer left background if only one button */
-        left_bg_rects[i] = &fgeom->left_left_background;
-      else if (i == (n_left - 1))
-        left_bg_rects[i] = &fgeom->left_right_background;
-      else
-        left_bg_rects[i] = &fgeom->left_middle_backgrounds[i - 1];
-    }
-
-  for (i = 0; i < n_right; i++)
-    {
-      /* prefer right background if only one button */
-      if (i == (n_right - 1))
-        right_bg_rects[i] = &fgeom->right_right_background;
-      else if (i == 0)
-        right_bg_rects[i] = &fgeom->right_left_background;
-      else
-        right_bg_rects[i] = &fgeom->right_middle_backgrounds[i - 1];
-    }
-  
-  /* Be sure buttons fit */
-  while (n_left > 0 || n_right > 0)
-    {
-      int space_used_by_buttons;
-      int space_available;
-
-      space_available = fgeom->width - layout->left_titlebar_edge - layout->right_titlebar_edge;
-      
-      space_used_by_buttons = 0;
-
-      space_used_by_buttons += button_width * n_left;
-      space_used_by_buttons += (button_width * 0.75) * n_left_spacers;
-      space_used_by_buttons += layout->button_border.left * n_left;
-      space_used_by_buttons += layout->button_border.right * n_left;
-
-      space_used_by_buttons += button_width * n_right;
-      space_used_by_buttons += (button_width * 0.75) * n_right_spacers;
-      space_used_by_buttons += layout->button_border.left * n_right;
-      space_used_by_buttons += layout->button_border.right * n_right;
-
-      if (space_used_by_buttons <= space_available)
-        break; /* Everything fits, bail out */
-      
-      /* First try to remove separators */
-      if (n_left_spacers > 0)
-        {
-          left_buttons_has_spacer[--n_left_spacers] = FALSE;
-          continue;
-        }
-      else if (n_right_spacers > 0)
-        {
-          right_buttons_has_spacer[--n_right_spacers] = FALSE;
-          continue;
-        }
-
-      /* Otherwise we need to shave out a button. Shave
-       * above, stick, shade, min, max, close, then menu (menu is most useful);
-       * prefer the default button locations.
-       */
-      if (strip_button (left_func_rects, left_bg_rects,
-                        &n_left, &fgeom->above_rect))
-        continue;
-      else if (strip_button (right_func_rects, right_bg_rects,
-                             &n_right, &fgeom->above_rect))
-        continue;
-      else if (strip_button (left_func_rects, left_bg_rects,
-                        &n_left, &fgeom->stick_rect))
-        continue;
-      else if (strip_button (right_func_rects, right_bg_rects,
-                             &n_right, &fgeom->stick_rect))
-        continue;
-      else if (strip_button (left_func_rects, left_bg_rects,
-                        &n_left, &fgeom->shade_rect))
-        continue;
-      else if (strip_button (right_func_rects, right_bg_rects,
-                             &n_right, &fgeom->shade_rect))
-        continue;
-      else if (strip_button (left_func_rects, left_bg_rects,
-                        &n_left, &fgeom->min_rect))
-        continue;
-      else if (strip_button (right_func_rects, right_bg_rects,
-                             &n_right, &fgeom->min_rect))
-        continue;
-      else if (strip_button (left_func_rects, left_bg_rects,
-                             &n_left, &fgeom->max_rect))
-        continue;
-      else if (strip_button (right_func_rects, right_bg_rects,
-                             &n_right, &fgeom->max_rect))
-        continue;
-      else if (strip_button (left_func_rects, left_bg_rects,
-                             &n_left, &fgeom->close_rect))
-        continue;
-      else if (strip_button (right_func_rects, right_bg_rects,
-                             &n_right, &fgeom->close_rect))
-        continue;
-      else if (strip_button (right_func_rects, right_bg_rects,
-                             &n_right, &fgeom->menu_rect))
-        continue;
-      else if (strip_button (left_func_rects, left_bg_rects,
-                             &n_left, &fgeom->menu_rect))
-        continue;
-      else
-        {
-          meta_bug ("Could not find a button to strip. n_left = %d n_right = %d\n",
-                    n_left, n_right);
-        }
-    }
-  
-  /* center buttons vertically */
-  button_y = (fgeom->top_height -
-              (button_height + layout->button_border.top + layout->button_border.bottom)) / 2 + layout->button_border.top;
-
-  /* right edge of farthest-right button */
-  x = width - layout->right_titlebar_edge;
-  
-  i = n_right - 1;
-  while (i >= 0)
-    {
-      MetaButtonSpace *rect;
-
-      if (x < 0) /* if we go negative, leave the buttons we don't get to as 0-width */
-        break;
-      
-      rect = right_func_rects[i];
-      rect->visible.x = x - layout->button_border.right - button_width;
-      if (right_buttons_has_spacer[i])
-        rect->visible.x -= (button_width * 0.75);
-
-      rect->visible.y = button_y;
-      rect->visible.width = button_width;
-      rect->visible.height = button_height;
-
-      if (flags & META_FRAME_MAXIMIZED)
-        {
-          rect->clickable.x = rect->visible.x;
-          rect->clickable.y = 0;
-          rect->clickable.width = rect->visible.width;
-          rect->clickable.height = button_height + button_y;
-
-          if (i == n_right - 1)
-            rect->clickable.width += layout->right_titlebar_edge + layout->right_width + layout->button_border.right;
-
-        }
-      else
-        g_memmove (&(rect->clickable), &(rect->visible), sizeof(rect->clickable));
-
-      *(right_bg_rects[i]) = rect->visible;
-      
-      x = rect->visible.x - layout->button_border.left;
-      
-      --i;
-    }
-
-  /* save right edge of titlebar for later use */
-  title_right_edge = x - layout->title_border.right;
-
-  /* Now x changes to be position from the left and we go through
-   * the left-side buttons
-   */
-  x = layout->left_titlebar_edge;
-  for (i = 0; i < n_left; i++)
-    {
-      MetaButtonSpace *rect;
-
-      rect = left_func_rects[i];
-      
-      rect->visible.x = x + layout->button_border.left;
-      rect->visible.y = button_y;
-      rect->visible.width = button_width;
-      rect->visible.height = button_height;
-
-      if (flags & META_FRAME_MAXIMIZED)
-        {
-          if (i==0)
-            {
-              rect->clickable.x = 0;
-              rect->clickable.width = button_width + x;
-            }
-          else
-            {
-              rect->clickable.x = rect->visible.x;
-              rect->clickable.width = button_width;
-            }
-
-            rect->clickable.y = 0;
-            rect->clickable.height = button_height + button_y;
-          }
-        else
-          g_memmove (&(rect->clickable), &(rect->visible), sizeof(rect->clickable));
-
-
-      x = rect->visible.x + rect->visible.width + layout->button_border.right;
-      if (left_buttons_has_spacer[i])
-        x += (button_width * 0.75);
-
-      *(left_bg_rects[i]) = rect->visible;
-    }
-
-  /* We always fill as much vertical space as possible with title rect,
-   * rather than centering it like the buttons
-   */
-  fgeom->title_rect.x = x + layout->title_border.left;
-  fgeom->title_rect.y = layout->title_border.top;
-  fgeom->title_rect.width = title_right_edge - fgeom->title_rect.x;
-  fgeom->title_rect.height = fgeom->top_height - layout->title_border.top - layout->title_border.bottom;
-
-  /* Nuke title if it won't fit */
-  if (fgeom->title_rect.width < 0 ||
-      fgeom->title_rect.height < 0)
-    {
-      fgeom->title_rect.width = 0;
-      fgeom->title_rect.height = 0;
-    }
-
-  if (flags & META_FRAME_SHADED)
-    min_size_for_rounding = 0;
-  else
-    min_size_for_rounding = 5;
-  
-  fgeom->top_left_corner_rounded_radius = 0;
-  fgeom->top_right_corner_rounded_radius = 0;
-  fgeom->bottom_left_corner_rounded_radius = 0;
-  fgeom->bottom_right_corner_rounded_radius = 0;
-
-  if (fgeom->top_height + fgeom->left_width >= min_size_for_rounding)
-    fgeom->top_left_corner_rounded_radius = layout->top_left_corner_rounded_radius;
-  if (fgeom->top_height + fgeom->right_width >= min_size_for_rounding)
-    fgeom->top_right_corner_rounded_radius = layout->top_right_corner_rounded_radius;
-
-  if (fgeom->bottom_height + fgeom->left_width >= min_size_for_rounding)
-    fgeom->bottom_left_corner_rounded_radius = layout->bottom_left_corner_rounded_radius;
-  if (fgeom->bottom_height + fgeom->right_width >= min_size_for_rounding)
-    fgeom->bottom_right_corner_rounded_radius = layout->bottom_right_corner_rounded_radius;
-}
-
-MetaGradientSpec*
-meta_gradient_spec_new (MetaGradientType type)
-{
-  MetaGradientSpec *spec;
-
-  spec = g_new (MetaGradientSpec, 1);
-
-  spec->type = type;
-  spec->color_specs = NULL;
-
-  return spec;
-}
-
-static void
-free_color_spec (gpointer spec, gpointer user_data)
-{
-  meta_color_spec_free (spec);
-}
-
-void
-meta_gradient_spec_free (MetaGradientSpec *spec)
-{
-  g_return_if_fail (spec != NULL);
-
-  g_slist_foreach (spec->color_specs, free_color_spec, NULL);
-  g_slist_free (spec->color_specs);
-  
-  DEBUG_FILL_STRUCT (spec);
-  g_free (spec);
-}
-
-GdkPixbuf*
-meta_gradient_spec_render (const MetaGradientSpec *spec,
-                           GtkWidget              *widget,
-                           int                     width,
-                           int                     height)
-{
-  int n_colors;
-  GdkColor *colors;
-  GSList *tmp;
-  int i;
-  GdkPixbuf *pixbuf;
-
-  n_colors = g_slist_length (spec->color_specs);
-
-  if (n_colors == 0)
-    return NULL;
-
-  colors = g_new (GdkColor, n_colors);
-
-  i = 0;
-  tmp = spec->color_specs;
-  while (tmp != NULL)
-    {
-      meta_color_spec_render (tmp->data, widget, &colors[i]);
-
-      tmp = tmp->next;
-      ++i;
-    }
-
-  pixbuf = meta_gradient_create_multi (width, height,
-                                       colors, n_colors,
-                                       spec->type);
-
-  g_free (colors);
-
-  return pixbuf;
-}
-
-gboolean
-meta_gradient_spec_validate (MetaGradientSpec *spec,
-                             GError          **error)
-{
-  g_return_val_if_fail (spec != NULL, FALSE);
-  
-  if (g_slist_length (spec->color_specs) < 2)
-    {
-      g_set_error (error, META_THEME_ERROR,
-                   META_THEME_ERROR_FAILED,
-                   _("Gradients should have at least two colors"));
-      return FALSE;
-    }
-
-  return TRUE;
-}
-
-MetaAlphaGradientSpec*
-meta_alpha_gradient_spec_new (MetaGradientType       type,
-                              int                    n_alphas)
-{
-  MetaAlphaGradientSpec *spec;
-
-  g_return_val_if_fail (n_alphas > 0, NULL);
-  
-  spec = g_new0 (MetaAlphaGradientSpec, 1);
-
-  spec->type = type;
-  spec->alphas = g_new0 (unsigned char, n_alphas);
-  spec->n_alphas = n_alphas;
-
-  return spec;
-}
-
-void
-meta_alpha_gradient_spec_free (MetaAlphaGradientSpec *spec)
-{
-  g_return_if_fail (spec != NULL);
-
-  g_free (spec->alphas);
-  g_free (spec);
-}
-
-MetaColorSpec*
-meta_color_spec_new (MetaColorSpecType type)
-{
-  MetaColorSpec *spec;
-  MetaColorSpec dummy;
-  int size;
-
-  size = G_STRUCT_OFFSET (MetaColorSpec, data);
-
-  switch (type)
-    {
-    case META_COLOR_SPEC_BASIC:
-      size += sizeof (dummy.data.basic);
-      break;
-
-    case META_COLOR_SPEC_GTK:
-      size += sizeof (dummy.data.gtk);
-      break;
-
-    case META_COLOR_SPEC_BLEND:
-      size += sizeof (dummy.data.blend);
-      break;
-
-    case META_COLOR_SPEC_SHADE:
-      size += sizeof (dummy.data.shade);
-      break;
-    }
-
-  spec = g_malloc0 (size);
-
-  spec->type = type;
-
-  return spec;
-}
-
-void
-meta_color_spec_free (MetaColorSpec *spec)
-{
-  g_return_if_fail (spec != NULL);
-
-  switch (spec->type)
-    {
-    case META_COLOR_SPEC_BASIC:
-      DEBUG_FILL_STRUCT (&spec->data.basic);
-      break;
-
-    case META_COLOR_SPEC_GTK:
-      DEBUG_FILL_STRUCT (&spec->data.gtk);
-      break;
-
-    case META_COLOR_SPEC_BLEND:
-      if (spec->data.blend.foreground)
-        meta_color_spec_free (spec->data.blend.foreground);
-      if (spec->data.blend.background)
-        meta_color_spec_free (spec->data.blend.background);
-      DEBUG_FILL_STRUCT (&spec->data.blend);
-      break;
-
-    case META_COLOR_SPEC_SHADE:
-      if (spec->data.shade.base)
-        meta_color_spec_free (spec->data.shade.base);
-      DEBUG_FILL_STRUCT (&spec->data.shade);
-      break;
-    }
-
-  g_free (spec);
-}
-
-MetaColorSpec*
-meta_color_spec_new_from_string (const char *str,
-                                 GError    **err)
-{
-  MetaColorSpec *spec;
-
-  spec = NULL;
-  
-  if (str[0] == 'g' && str[1] == 't' && str[2] == 'k' && str[3] == ':')
-    {
-      /* GTK color */
-      const char *bracket;
-      const char *end_bracket;
-      char *tmp;
-      GtkStateType state;
-      MetaGtkColorComponent component;
-      
-      bracket = str;
-      while (*bracket && *bracket != '[')
-        ++bracket;
-
-      if (*bracket == '\0')
-        {
-          g_set_error (err, META_THEME_ERROR,
-                       META_THEME_ERROR_FAILED,
-                       _("GTK color specification must have the state in brackets, e.g. gtk:fg[NORMAL] where NORMAL is the state; could not parse \"%s\""),
-                       str);
-          return NULL;
-        }
-
-      end_bracket = bracket;
-      ++end_bracket;
-      while (*end_bracket && *end_bracket != ']')
-        ++end_bracket;
-      
-      if (*end_bracket == '\0')
-        {
-          g_set_error (err, META_THEME_ERROR,
-                       META_THEME_ERROR_FAILED,
-                       _("GTK color specification must have a close bracket after the state, e.g. gtk:fg[NORMAL] where NORMAL is the state; could not parse \"%s\""),
-                       str);
-          return NULL;
-        }
-
-      tmp = g_strndup (bracket + 1, end_bracket - bracket - 1);
-      state = meta_gtk_state_from_string (tmp);
-      if (((int) state) == -1)
-        {
-          g_set_error (err, META_THEME_ERROR,
-                       META_THEME_ERROR_FAILED,
-                       _("Did not understand state \"%s\" in color specification"),
-                       tmp);
-          g_free (tmp);
-          return NULL;
-        }
-      g_free (tmp);
-      
-      tmp = g_strndup (str + 4, bracket - str - 4);
-      component = meta_color_component_from_string (tmp);
-      if (component == META_GTK_COLOR_LAST)
-        {
-          g_set_error (err, META_THEME_ERROR,
-                       META_THEME_ERROR_FAILED,
-                       _("Did not understand color component \"%s\" in color specification"),
-                       tmp);
-          g_free (tmp);
-          return NULL;
-        }
-      g_free (tmp);
-
-      spec = meta_color_spec_new (META_COLOR_SPEC_GTK);
-      spec->data.gtk.state = state;
-      spec->data.gtk.component = component;
-      g_assert (spec->data.gtk.state < N_GTK_STATES);
-      g_assert (spec->data.gtk.component < META_GTK_COLOR_LAST);
-    }
-  else if (str[0] == 'b' && str[1] == 'l' && str[2] == 'e' && str[3] == 'n' &&
-           str[4] == 'd' && str[5] == '/')
-    {
-      /* blend */
-      char **split;
-      double alpha;
-      char *end;
-      MetaColorSpec *fg;
-      MetaColorSpec *bg;
-      
-      split = g_strsplit (str, "/", 4);
-      
-      if (split[0] == NULL || split[1] == NULL ||
-          split[2] == NULL || split[3] == NULL)
-        {
-          g_set_error (err, META_THEME_ERROR,
-                       META_THEME_ERROR_FAILED,
-                       _("Blend format is \"blend/bg_color/fg_color/alpha\", \"%s\" does not fit the format"),
-                       str);
-          g_strfreev (split);
-          return NULL;
-        }
-
-      alpha = g_ascii_strtod (split[3], &end);
-      if (end == split[3])
-        {
-          g_set_error (err, META_THEME_ERROR,
-                       META_THEME_ERROR_FAILED,
-                       _("Could not parse alpha value \"%s\" in blended color"),
-                       split[3]);
-          g_strfreev (split);
-          return NULL;
-        }
-
-      if (alpha < (0.0 - 1e6) || alpha > (1.0 + 1e6))
-        {
-          g_set_error (err, META_THEME_ERROR,
-                       META_THEME_ERROR_FAILED,
-                       _("Alpha value \"%s\" in blended color is not between 0.0 and 1.0"),
-                       split[3]);
-          g_strfreev (split);
-          return NULL;
-        }
-      
-      fg = NULL;
-      bg = NULL;
-
-      bg = meta_color_spec_new_from_string (split[1], err);
-      if (bg == NULL)
-        {
-          g_strfreev (split);
-          return NULL;
-        }
-
-      fg = meta_color_spec_new_from_string (split[2], err);
-      if (fg == NULL)
-        {
-          meta_color_spec_free (bg);
-          g_strfreev (split);
-          return NULL;
-        }
-
-      g_strfreev (split);
-      
-      spec = meta_color_spec_new (META_COLOR_SPEC_BLEND);
-      spec->data.blend.alpha = alpha;
-      spec->data.blend.background = bg;
-      spec->data.blend.foreground = fg;
-    }
-  else if (str[0] == 's' && str[1] == 'h' && str[2] == 'a' && str[3] == 'd' &&
-           str[4] == 'e' && str[5] == '/')
-    {
-      /* shade */
-      char **split;
-      double factor;
-      char *end;
-      MetaColorSpec *base;
-      
-      split = g_strsplit (str, "/", 3);
-      
-      if (split[0] == NULL || split[1] == NULL ||
-          split[2] == NULL)
-        {
-          g_set_error (err, META_THEME_ERROR,
-                       META_THEME_ERROR_FAILED,
-                       _("Shade format is \"shade/base_color/factor\", \"%s\" does not fit the format"),
-                       str);
-          g_strfreev (split);
-          return NULL;
-        }
-
-      factor = g_ascii_strtod (split[2], &end);
-      if (end == split[2])
-        {
-          g_set_error (err, META_THEME_ERROR,
-                       META_THEME_ERROR_FAILED,
-                       _("Could not parse shade factor \"%s\" in shaded color"),
-                       split[2]);
-          g_strfreev (split);
-          return NULL;
-        }
-
-      if (factor < (0.0 - 1e6))
-        {
-          g_set_error (err, META_THEME_ERROR,
-                       META_THEME_ERROR_FAILED,
-                       _("Shade factor \"%s\" in shaded color is negative"),
-                       split[2]);
-          g_strfreev (split);
-          return NULL;
-        }
-      
-      base = NULL;
-
-      base = meta_color_spec_new_from_string (split[1], err);
-      if (base == NULL)
-        {
-          g_strfreev (split);
-          return NULL;
-        }
-
-      g_strfreev (split);
-      
-      spec = meta_color_spec_new (META_COLOR_SPEC_SHADE);
-      spec->data.shade.factor = factor;
-      spec->data.shade.base = base;
-    }
-  else
-    {
-      spec = meta_color_spec_new (META_COLOR_SPEC_BASIC);
-      
-      if (!gdk_color_parse (str, &spec->data.basic.color))
-        {
-          g_set_error (err, META_THEME_ERROR,
-                       META_THEME_ERROR_FAILED,
-                       _("Could not parse color \"%s\""),
-                       str);
-          meta_color_spec_free (spec);
-          return NULL;
-        }
-    }
-
-  g_assert (spec);
-  
-  return spec;
-}
-
-MetaColorSpec*
-meta_color_spec_new_gtk (MetaGtkColorComponent component,
-                         GtkStateType          state)
-{
-  MetaColorSpec *spec;
-
-  spec = meta_color_spec_new (META_COLOR_SPEC_GTK);
-
-  spec->data.gtk.component = component;
-  spec->data.gtk.state = state;
-
-  return spec;
-}
-
-void
-meta_color_spec_render (MetaColorSpec *spec,
-                        GtkWidget     *widget,
-                        GdkColor      *color)
-{
-  g_return_if_fail (spec != NULL);
-  g_return_if_fail (GTK_IS_WIDGET (widget));
-  g_return_if_fail (widget->style != NULL);
-
-  switch (spec->type)
-    {
-    case META_COLOR_SPEC_BASIC:
-      *color = spec->data.basic.color;
-      break;
-
-    case META_COLOR_SPEC_GTK:
-      switch (spec->data.gtk.component)
-        {
-        case META_GTK_COLOR_BG:
-          *color = widget->style->bg[spec->data.gtk.state];
-          break;
-        case META_GTK_COLOR_FG:
-          *color = widget->style->fg[spec->data.gtk.state];
-          break;
-        case META_GTK_COLOR_BASE:
-          *color = widget->style->base[spec->data.gtk.state];
-          break;
-        case META_GTK_COLOR_TEXT:
-          *color = widget->style->text[spec->data.gtk.state];
-          break;
-        case META_GTK_COLOR_LIGHT:
-          *color = widget->style->light[spec->data.gtk.state];
-          break;
-        case META_GTK_COLOR_DARK:
-          *color = widget->style->dark[spec->data.gtk.state];
-          break;
-        case META_GTK_COLOR_MID:
-          *color = widget->style->mid[spec->data.gtk.state];
-          break;
-        case META_GTK_COLOR_TEXT_AA:
-          *color = widget->style->text_aa[spec->data.gtk.state];
-          break;
-        case META_GTK_COLOR_LAST:
-          g_assert_not_reached ();
-          break;
-        }
-      break;
-
-    case META_COLOR_SPEC_BLEND:
-      {
-        GdkColor bg, fg;
-
-        meta_color_spec_render (spec->data.blend.background, widget, &bg);
-        meta_color_spec_render (spec->data.blend.foreground, widget, &fg);
-
-        color_composite (&bg, &fg, spec->data.blend.alpha, 
-                         &spec->data.blend.color);
-
-        *color = spec->data.blend.color;
-      }
-      break;
-
-    case META_COLOR_SPEC_SHADE:
-      {
-        meta_color_spec_render (spec->data.shade.base, widget, 
-                                &spec->data.shade.color);
-            
-        gtk_style_shade (&spec->data.shade.color, 
-                         &spec->data.shade.color, spec->data.shade.factor);
-
-        *color = spec->data.shade.color;
-      }
-      break;
-    }
-}
-
-/**
- * Represents an operation as a string.
- *
- * \param type  an operation, such as addition
- * \return  a string, such as "+"
- */
-static const char*
-op_name (PosOperatorType type)
-{
-  switch (type)
-    {
-    case POS_OP_ADD:
-      return "+";
-    case POS_OP_SUBTRACT:
-      return "-";
-    case POS_OP_MULTIPLY:
-      return "*";
-    case POS_OP_DIVIDE:
-      return "/";
-    case POS_OP_MOD:
-      return "%";
-    case POS_OP_MAX:
-      return "`max`";
-    case POS_OP_MIN:
-      return "`min`";
-    case POS_OP_NONE:
-      break;
-    }
-
-  return "<unknown>";
-}
-
-/**
- * Parses a string and returns an operation.
- *
- * \param p  a pointer into a string representing an operation; part of an
- *           expression somewhere, so not null-terminated
- * \param len  set to the length of the string found. Set to 0 if none is.
- * \return  the operation found. If none was, returns POS_OP_NONE.
- */
-static PosOperatorType
-op_from_string (const char *p,
-                int        *len)
-{
-  *len = 0;
-  
-  switch (*p)
-    {
-    case '+':
-      *len = 1;
-      return POS_OP_ADD;
-    case '-':
-      *len = 1;
-      return POS_OP_SUBTRACT;
-    case '*':
-      *len = 1;
-      return POS_OP_MULTIPLY;
-    case '/':
-      *len = 1;
-      return POS_OP_DIVIDE;
-    case '%':
-      *len = 1;
-      return POS_OP_MOD;
-
-    case '`':
-      if (p[0] == '`' &&
-          p[1] == 'm' &&
-          p[2] == 'a' &&
-          p[3] == 'x' &&
-          p[4] == '`')
-        {
-          *len = 5;
-          return POS_OP_MAX;
-        }
-      else if (p[0] == '`' &&
-               p[1] == 'm' &&
-               p[2] == 'i' &&
-               p[3] == 'n' &&
-               p[4] == '`')
-        {
-          *len = 5;
-          return POS_OP_MIN;
-        }
-    }
-
-  return POS_OP_NONE;
-}
-
-/**
- * Frees an array of tokens. All the tokens and their associated memory
- * will be freed.
- *
- * \param tokens  an array of tokens to be freed
- * \param n_tokens  how many tokens are in the array.
- */
-static void
-free_tokens (PosToken *tokens,
-             int       n_tokens)
-{
-  int i;
-
-  /* n_tokens can be 0 since tokens may have been allocated more than
-   * it was initialized
-   */
-
-  for (i = 0; i < n_tokens; i++)
-    if (tokens[i].type == POS_TOKEN_VARIABLE)
-      g_free (tokens[i].d.v.name);
-
-  g_free (tokens);
-}
-
-/**
- * Tokenises a number in an expression.
- *
- * \param p  a pointer into a string representing an operation; part of an
- *           expression somewhere, so not null-terminated
- * \param end_return  set to a pointer to the end of the number found; but
- *                    not updated if no number was found at all
- * \param next  set to either an integer or a float token
- * \param[out] err  set to the problem if there was a problem
- * \return TRUE if a valid number was found, FALSE otherwise (and "err" will
- *         have been set)
- *
- * \bug The "while (*start)..." part: what's wrong with strchr-ish things?
- * \bug The name is wrong: it doesn't parse anything.
- * \ingroup tokenizer
- */
-static gboolean
-parse_number (const char  *p,
-              const char **end_return,
-              PosToken    *next,
-              GError     **err)
-{
-  const char *start = p;
-  char *end;
-  gboolean is_float;
-  char *num_str;
-
-  while (*p && (*p == '.' || g_ascii_isdigit (*p)))
-    ++p;
-
-  if (p == start)
-    {
-      char buf[7] = { '\0' };
-      buf[g_unichar_to_utf8 (g_utf8_get_char (p), buf)] = '\0';
-      g_set_error (err, META_THEME_ERROR,
-                   META_THEME_ERROR_BAD_CHARACTER,
-                   _("Coordinate expression contains character '%s' which is not allowed"),
-                   buf);
-      return FALSE;
-    }
-
-  *end_return = p;
-
-  /* we need this to exclude floats like "1e6" */
-  num_str = g_strndup (start, p - start);
-  start = num_str;
-  is_float = FALSE;
-  while (*start)
-    {
-      if (*start == '.')
-        is_float = TRUE;
-      ++start;
-    }
-
-  if (is_float)
-    {
-      next->type = POS_TOKEN_DOUBLE;
-      next->d.d.val = g_ascii_strtod (num_str, &end);
-
-      if (end == num_str)
-        {
-          g_set_error (err, META_THEME_ERROR,
-                       META_THEME_ERROR_FAILED,
-                       _("Coordinate expression contains floating point number '%s' which could not be parsed"),
-                       num_str);
-          g_free (num_str);
-          return FALSE;
-        }
-    }
-  else
-    {
-      next->type = POS_TOKEN_INT;
-      next->d.i.val = strtol (num_str, &end, 10);
-      if (end == num_str)
-        {
-          g_set_error (err, META_THEME_ERROR,
-                       META_THEME_ERROR_FAILED,
-                       _("Coordinate expression contains integer '%s' which could not be parsed"),
-                       num_str);
-          g_free (num_str);
-          return FALSE;
-        }
-    }
-
-  g_free (num_str);
-
-  g_assert (next->type == POS_TOKEN_INT || next->type == POS_TOKEN_DOUBLE);
-
-  return TRUE;
-}
-
-/**
- * Whether a variable can validly appear as part of the name of a variable.
- */
-#define IS_VARIABLE_CHAR(c) (g_ascii_isalpha ((c)) || (c) == '_')
-
-#if 0
-static void
-debug_print_tokens (PosToken *tokens,
-                    int       n_tokens)
-{
-  int i;
-  
-  for (i = 0; i < n_tokens; i++)
-    {
-      PosToken *t = &tokens[i];
-
-      g_print (" ");
-
-      switch (t->type)
-        {
-        case POS_TOKEN_INT:
-          g_print ("\"%d\"", t->d.i.val);
-          break;
-        case POS_TOKEN_DOUBLE:
-          g_print ("\"%g\"", t->d.d.val);
-          break;
-        case POS_TOKEN_OPEN_PAREN:
-          g_print ("\"(\"");
-          break;
-        case POS_TOKEN_CLOSE_PAREN:
-          g_print ("\")\"");
-          break;
-        case POS_TOKEN_VARIABLE:
-          g_print ("\"%s\"", t->d.v.name);
-          break;
-        case POS_TOKEN_OPERATOR:
-          g_print ("\"%s\"", op_name (t->d.o.op));
-          break;
-        }
-    }
-
-  g_print ("\n");
-}
-#endif
-
-/**
- * Tokenises an expression.
- *
- * \param      expr        The expression
- * \param[out] tokens_p    The resulting tokens
- * \param[out] n_tokens_p  The number of resulting tokens
- * \param[out] err  set to the problem if there was a problem
- *
- * \return  True if the expression was successfully tokenised; false otherwise.
- *
- * \ingroup tokenizer
- */
-static gboolean
-pos_tokenize (const char  *expr,
-              PosToken   **tokens_p,
-              int         *n_tokens_p,
-              GError     **err)
-{
-  PosToken *tokens;
-  int n_tokens;
-  int allocated;
-  const char *p;
-  
-  *tokens_p = NULL;
-  *n_tokens_p = 0;
-
-  allocated = 3;
-  n_tokens = 0;
-  tokens = g_new (PosToken, allocated);
-
-  p = expr;
-  while (*p)
-    {
-      PosToken *next;
-      int len;
-      
-      if (n_tokens == allocated)
-        {
-          allocated *= 2;
-          tokens = g_renew (PosToken, tokens, allocated);
-        }
-
-      next = &tokens[n_tokens];
-
-      switch (*p)
-        {
-        case '*':
-        case '/':
-        case '+':
-        case '-': /* negative numbers aren't allowed so this is easy */
-        case '%':
-        case '`':
-          next->type = POS_TOKEN_OPERATOR;
-          next->d.o.op = op_from_string (p, &len);
-          if (next->d.o.op != POS_OP_NONE)
-            {
-              ++n_tokens;
-              p = p + (len - 1); /* -1 since we ++p later */
-            }
-          else
-            {
-              g_set_error (err, META_THEME_ERROR,
-                           META_THEME_ERROR_FAILED,
-                           _("Coordinate expression contained unknown operator at the start of this text: \"%s\""),
-                           p);
-              
-              goto error;
-            }
-          break;
-
-        case '(':
-          next->type = POS_TOKEN_OPEN_PAREN;
-          ++n_tokens;
-          break;
-
-        case ')':
-          next->type = POS_TOKEN_CLOSE_PAREN;
-          ++n_tokens;
-          break;
-
-        case ' ':
-        case '\t':
-        case '\n':		
-          break;
-
-        default:
-          if (IS_VARIABLE_CHAR (*p))
-            {
-              /* Assume variable */
-              const char *start = p;
-              while (*p && IS_VARIABLE_CHAR (*p))
-                ++p;
-              g_assert (p != start);
-              next->type = POS_TOKEN_VARIABLE;
-              next->d.v.name = g_strndup (start, p - start);
-              ++n_tokens;
-              --p; /* since we ++p again at the end of while loop */
-            }
-          else
-            {
-              /* Assume number */
-              const char *end;
-
-              if (!parse_number (p, &end, next, err))
-                goto error;
-
-              ++n_tokens;
-              p = end - 1; /* -1 since we ++p again at the end of while loop */
-            }
-
-          break;
-        }
-
-      ++p;
-    }
-
-  if (n_tokens == 0)
-    {
-      g_set_error (err, META_THEME_ERROR,
-                   META_THEME_ERROR_FAILED,
-                   _("Coordinate expression was empty or not understood"));
-
-      goto error;
-    }
-
-  *tokens_p = tokens;
-  *n_tokens_p = n_tokens;
-
-  return TRUE;
-
- error:
-  g_assert (err == NULL || *err != NULL);
-
-  free_tokens (tokens, n_tokens);
-  return FALSE;
-}
-
-/**
- * The type of a PosExpr: either integer, double, or an operation.
- * \ingroup parser
- */
-typedef enum
-{
-  POS_EXPR_INT,
-  POS_EXPR_DOUBLE,
-  POS_EXPR_OPERATOR
-} PosExprType;
-
-/**
- * Type and value of an expression in a parsed sequence. We don't
- * keep expressions in a tree; if this is of type POS_EXPR_OPERATOR,
- * the arguments of the operator will be in the array positions
- * immediately preceding and following this operator; they cannot
- * themselves be operators.
- *
- * \bug operator is char; it should really be of PosOperatorType.
- * \ingroup parser
- */
-typedef struct
-{
-  PosExprType type;
-  union
-  {
-    double double_val;
-    int int_val;
-    char operator;
-  } d;
-} PosExpr;
-
-#if 0
-static void
-debug_print_exprs (PosExpr *exprs,
-                   int      n_exprs)
-{
-  int i;
-
-  for (i = 0; i < n_exprs; i++)
-    {
-      switch (exprs[i].type)
-        {
-        case POS_EXPR_INT:
-          g_print (" %d", exprs[i].d.int_val);
-          break;
-        case POS_EXPR_DOUBLE:
-          g_print (" %g", exprs[i].d.double_val);
-          break;
-        case POS_EXPR_OPERATOR:
-          g_print (" %s", op_name (exprs[i].d.operator));
-          break;
-        }
-    }
-  g_print ("\n");
-}
-#endif
-
-static gboolean
-do_operation (PosExpr *a,
-              PosExpr *b,
-              PosOperatorType op,
-              GError **err)
-{
-  /* Promote types to double if required */
-  if (a->type == POS_EXPR_DOUBLE ||
-      b->type == POS_EXPR_DOUBLE)
-    {
-      if (a->type != POS_EXPR_DOUBLE)
-        {
-          a->type = POS_EXPR_DOUBLE;
-          a->d.double_val = a->d.int_val;
-        }
-      if (b->type != POS_EXPR_DOUBLE)
-        {
-          b->type = POS_EXPR_DOUBLE;
-          b->d.double_val = b->d.int_val;
-        }
-    }
-
-  g_assert (a->type == b->type);
-
-  if (a->type == POS_EXPR_INT)
-    {
-      switch (op)
-        {
-        case POS_OP_MULTIPLY:
-          a->d.int_val = a->d.int_val * b->d.int_val;
-          break;
-        case POS_OP_DIVIDE:
-          if (b->d.int_val == 0)
-            {
-              g_set_error (err, META_THEME_ERROR,
-                           META_THEME_ERROR_DIVIDE_BY_ZERO,
-                           _("Coordinate expression results in division by zero"));
-              return FALSE;
-            }
-          a->d.int_val = a->d.int_val / b->d.int_val;
-          break;
-        case POS_OP_MOD:
-          if (b->d.int_val == 0)
-            {
-              g_set_error (err, META_THEME_ERROR,
-                           META_THEME_ERROR_DIVIDE_BY_ZERO,
-                           _("Coordinate expression results in division by zero"));
-              return FALSE;
-            }
-          a->d.int_val = a->d.int_val % b->d.int_val;
-          break;
-        case POS_OP_ADD:
-          a->d.int_val = a->d.int_val + b->d.int_val;
-          break;
-        case POS_OP_SUBTRACT:
-          a->d.int_val = a->d.int_val - b->d.int_val;
-          break;
-        case POS_OP_MAX:
-          a->d.int_val = MAX (a->d.int_val, b->d.int_val);
-          break;
-        case POS_OP_MIN:
-          a->d.int_val = MIN (a->d.int_val, b->d.int_val);
-          break;
-        case POS_OP_NONE:
-          g_assert_not_reached ();
-          break;
-        }
-    }
-  else if (a->type == POS_EXPR_DOUBLE)
-    {
-      switch (op)
-        {
-        case POS_OP_MULTIPLY:
-          a->d.double_val = a->d.double_val * b->d.double_val;
-          break;
-        case POS_OP_DIVIDE:
-          if (b->d.double_val == 0.0)
-            {
-              g_set_error (err, META_THEME_ERROR,
-                           META_THEME_ERROR_DIVIDE_BY_ZERO,
-                           _("Coordinate expression results in division by zero"));
-              return FALSE;
-            }
-          a->d.double_val = a->d.double_val / b->d.double_val;
-          break;
-        case POS_OP_MOD:
-          g_set_error (err, META_THEME_ERROR,
-                       META_THEME_ERROR_MOD_ON_FLOAT,
-                       _("Coordinate expression tries to use mod operator on a floating-point number"));
-          return FALSE;
-        case POS_OP_ADD:
-          a->d.double_val = a->d.double_val + b->d.double_val;
-          break;
-        case POS_OP_SUBTRACT:
-          a->d.double_val = a->d.double_val - b->d.double_val;
-          break;
-        case POS_OP_MAX:
-          a->d.double_val = MAX (a->d.double_val, b->d.double_val);
-          break;
-        case POS_OP_MIN:
-          a->d.double_val = MIN (a->d.double_val, b->d.double_val);
-          break;
-        case POS_OP_NONE:
-          g_assert_not_reached ();
-          break;
-        }
-    }
-  else
-    g_assert_not_reached ();
-
-  return TRUE;
-}
-
-static gboolean
-do_operations (PosExpr *exprs,
-               int     *n_exprs,
-               int      precedence,
-               GError **err)
-{
-  int i;
-
-#if 0
-  g_print ("Doing prec %d ops on %d exprs\n", precedence, *n_exprs);
-  debug_print_exprs (exprs, *n_exprs);
-#endif
-
-  i = 1;
-  while (i < *n_exprs)
-    {
-      gboolean compress;
-
-      /* exprs[i-1] first operand
-       * exprs[i]   operator
-       * exprs[i+1] second operand
-       *
-       * we replace first operand with result of mul/div/mod,
-       * or skip over operator and second operand if we have
-       * an add/subtract
-       */
-
-      if (exprs[i-1].type == POS_EXPR_OPERATOR)
-        {
-          g_set_error (err, META_THEME_ERROR,
-                       META_THEME_ERROR_FAILED,
-                       _("Coordinate expression has an operator \"%s\" where an operand was expected"),
-                       op_name (exprs[i-1].d.operator));
-          return FALSE;
-        }
-
-      if (exprs[i].type != POS_EXPR_OPERATOR)
-        {
-          g_set_error (err, META_THEME_ERROR,
-                       META_THEME_ERROR_FAILED,
-                       _("Coordinate expression had an operand where an operator was expected"));
-          return FALSE;
-        }
-
-      if (i == (*n_exprs - 1))
-        {
-          g_set_error (err, META_THEME_ERROR,
-                       META_THEME_ERROR_FAILED,
-                       _("Coordinate expression ended with an operator instead of an operand"));
-          return FALSE;
-        }
-
-      g_assert ((i+1) < *n_exprs);
-
-      if (exprs[i+1].type == POS_EXPR_OPERATOR)
-        {
-          g_set_error (err, META_THEME_ERROR,
-                       META_THEME_ERROR_FAILED,
-                       _("Coordinate expression has operator \"%c\" following operator \"%c\" with no operand in between"),
-                       exprs[i+1].d.operator,
-                       exprs[i].d.operator);
-          return FALSE;
-        }
-
-      compress = FALSE;
-
-      switch (precedence)
-        {
-        case 2:
-          switch (exprs[i].d.operator)
-            {
-            case POS_OP_DIVIDE:
-            case POS_OP_MOD:
-            case POS_OP_MULTIPLY:
-              compress = TRUE;
-              if (!do_operation (&exprs[i-1], &exprs[i+1],
-                                 exprs[i].d.operator,
-                                 err))
-                return FALSE;
-              break;
-            }
-          break;
-        case 1:
-          switch (exprs[i].d.operator)
-            {
-            case POS_OP_ADD:
-            case POS_OP_SUBTRACT:
-              compress = TRUE;
-              if (!do_operation (&exprs[i-1], &exprs[i+1],
-                                 exprs[i].d.operator,
-                                 err))
-                return FALSE;
-              break;
-            }
-          break;
-          /* I have no rationale at all for making these low-precedence */
-        case 0:
-          switch (exprs[i].d.operator)
-            {
-            case POS_OP_MAX:
-            case POS_OP_MIN:
-              compress = TRUE;
-              if (!do_operation (&exprs[i-1], &exprs[i+1],
-                                 exprs[i].d.operator,
-                                 err))
-                return FALSE;
-              break;
-            }
-          break;
-        }
-
-      if (compress)
-        {
-          /* exprs[i-1] first operand (now result)
-           * exprs[i]   operator
-           * exprs[i+1] second operand
-           * exprs[i+2] new operator
-           *
-           * we move new operator just after first operand
-           */
-          if ((i+2) < *n_exprs)
-            {
-              g_memmove (&exprs[i], &exprs[i+2],
-                         sizeof (PosExpr) * (*n_exprs - i - 2));
-            }
-
-          *n_exprs -= 2;
-        }
-      else
-        {
-          /* Skip operator and next operand */
-          i += 2;
-        }
-    }
-
-  return TRUE;
-}
-
-/**
- * There is a predefined set of variables which can appear in an expression.
- * Here we take a token representing a variable, and return the current value
- * of that variable in a particular environment.
- * (The value is always an integer.)
- *
- * There are supposedly some circumstances in which this function can be
- * called from outside Metacity, in which case env->theme will be NULL, and
- * therefore we can't use it to find out quark values, so we do the comparison
- * using strcmp, which is slower.
- *
- * \param t  The token representing a variable
- * \param[out] result  The value of that variable; not set if the token did
- *                     not represent a known variable
- * \param env  The environment within which t should be evaluated
- * \param[out] err  set to the problem if there was a problem
- *
- * \return true if we found the variable asked for, false if we didn't
- *
- * \bug shouldn't t be const?
- * \bug we should perhaps consider some sort of lookup arrangement into an
- *      array; also, the duplication of code is unlovely; perhaps using glib
- *      string hashes instead of quarks would fix both problems?
- * \ingroup parser
- */
-static gboolean
-pos_eval_get_variable (PosToken                  *t,
-                       int                       *result,
-                       const MetaPositionExprEnv *env,
-                       GError                   **err)
-{
-  if (env->theme)
-    {
-      if (t->d.v.name_quark == env->theme->quark_width)
-        *result = env->rect.width;
-      else if (t->d.v.name_quark == env->theme->quark_height)
-        *result = env->rect.height;
-      else if (env->object_width >= 0 &&
-               t->d.v.name_quark == env->theme->quark_object_width)
-        *result = env->object_width;
-      else if (env->object_height >= 0 &&
-               t->d.v.name_quark == env->theme->quark_object_height)
-        *result = env->object_height;
-      else if (t->d.v.name_quark == env->theme->quark_left_width)
-        *result = env->left_width;
-      else if (t->d.v.name_quark == env->theme->quark_right_width)
-        *result = env->right_width;
-      else if (t->d.v.name_quark == env->theme->quark_top_height)
-        *result = env->top_height;
-      else if (t->d.v.name_quark == env->theme->quark_bottom_height)
-        *result = env->bottom_height;
-      else if (t->d.v.name_quark == env->theme->quark_mini_icon_width)
-        *result = env->mini_icon_width;
-      else if (t->d.v.name_quark == env->theme->quark_mini_icon_height)
-        *result = env->mini_icon_height;
-      else if (t->d.v.name_quark == env->theme->quark_icon_width)
-        *result = env->icon_width;
-      else if (t->d.v.name_quark == env->theme->quark_icon_height)
-        *result = env->icon_height;
-      else if (t->d.v.name_quark == env->theme->quark_title_width)
-        *result = env->title_width;
-      else if (t->d.v.name_quark == env->theme->quark_title_height)
-        *result = env->title_height;
-      else
-        {
-          g_set_error (err, META_THEME_ERROR,
-                       META_THEME_ERROR_UNKNOWN_VARIABLE,
-                       _("Coordinate expression had unknown variable or constant \"%s\""),
-                       t->d.v.name);
-          return FALSE;
-        }
-    }
-  else 
-    {
-      if (strcmp (t->d.v.name, "width") == 0)
-        *result = env->rect.width;
-      else if (strcmp (t->d.v.name, "height") == 0)
-        *result = env->rect.height;
-      else if (env->object_width >= 0 &&
-               strcmp (t->d.v.name, "object_width") == 0)
-        *result = env->object_width;
-      else if (env->object_height >= 0 &&
-               strcmp (t->d.v.name, "object_height") == 0)
-        *result = env->object_height;
-      else if (strcmp (t->d.v.name, "left_width") == 0)
-        *result = env->left_width;
-      else if (strcmp (t->d.v.name, "right_width") == 0)
-        *result = env->right_width;
-      else if (strcmp (t->d.v.name, "top_height") == 0)
-        *result = env->top_height;
-      else if (strcmp (t->d.v.name, "bottom_height") == 0)
-        *result = env->bottom_height;
-      else if (strcmp (t->d.v.name, "mini_icon_width") == 0)
-        *result = env->mini_icon_width;
-      else if (strcmp (t->d.v.name, "mini_icon_height") == 0)
-        *result = env->mini_icon_height;
-      else if (strcmp (t->d.v.name, "icon_width") == 0)
-        *result = env->icon_width;
-      else if (strcmp (t->d.v.name, "icon_height") == 0)
-        *result = env->icon_height;
-      else if (strcmp (t->d.v.name, "title_width") == 0)
-        *result = env->title_width;
-      else if (strcmp (t->d.v.name, "title_height") == 0)
-        *result = env->title_height;
-      else
-        {
-          g_set_error (err, META_THEME_ERROR,
-                       META_THEME_ERROR_UNKNOWN_VARIABLE,
-                       _("Coordinate expression had unknown variable or constant \"%s\""),
-                       t->d.v.name);
-          return FALSE;
-        }
-    }
-
-  return TRUE;
-}
-
-/**
- * Evaluates a sequence of tokens within a particular environment context,
- * and returns the current value. May recur if parantheses are found.
- *
- * \param tokens  A list of tokens to evaluate.
- * \param n_tokens  How many tokens are in the list.
- * \param env  The environment context in which to evaluate the expression.
- * \param[out] result  The current value of the expression
- * 
- * \bug Yes, we really do reparse the expression every time it's evaluated.
- *      We should keep the parse tree around all the time and just
- *      run the new values through it.
- * \ingroup parser
- */
-static gboolean
-pos_eval_helper (PosToken                   *tokens,
-                 int                         n_tokens,
-                 const MetaPositionExprEnv  *env,
-                 PosExpr                    *result,
-                 GError                    **err)
-{
-  /* Lazy-ass hardcoded limit on number of terms in expression */
-#define MAX_EXPRS 32
-  int paren_level;
-  int first_paren;
-  int i;
-  PosExpr exprs[MAX_EXPRS];
-  int n_exprs;
-  int precedence;
-  
-  /* Our first goal is to get a list of PosExpr, essentially
-   * substituting variables and handling parentheses.
-   */
-
-  first_paren = 0;
-  paren_level = 0;
-  n_exprs = 0;
-  for (i = 0; i < n_tokens; i++)
-    {
-      PosToken *t = &tokens[i];
-
-      if (n_exprs >= MAX_EXPRS)
-        {
-          g_set_error (err, META_THEME_ERROR,
-                       META_THEME_ERROR_FAILED,
-                       _("Coordinate expression parser overflowed its buffer."));
-          return FALSE;
-        }
-
-      if (paren_level == 0)
-        {
-          switch (t->type)
-            {
-            case POS_TOKEN_INT:
-              exprs[n_exprs].type = POS_EXPR_INT;
-              exprs[n_exprs].d.int_val = t->d.i.val;
-              ++n_exprs;
-              break;
-
-            case POS_TOKEN_DOUBLE:
-              exprs[n_exprs].type = POS_EXPR_DOUBLE;
-              exprs[n_exprs].d.double_val = t->d.d.val;
-              ++n_exprs;
-              break;
-
-            case POS_TOKEN_OPEN_PAREN:
-              ++paren_level;
-              if (paren_level == 1)
-                first_paren = i;
-              break;
-
-            case POS_TOKEN_CLOSE_PAREN:
-              g_set_error (err, META_THEME_ERROR,
-                           META_THEME_ERROR_BAD_PARENS,
-                           _("Coordinate expression had a close parenthesis with no open parenthesis"));
-              return FALSE;
-
-            case POS_TOKEN_VARIABLE:
-              exprs[n_exprs].type = POS_EXPR_INT;
-
-              /* FIXME we should just dump all this crap
-               * in a hash, maybe keep width/height out
-               * for optimization purposes
-               */
-              if (!pos_eval_get_variable (t, &exprs[n_exprs].d.int_val, env, err))
-                return FALSE;
-                  
-              ++n_exprs;
-              break;
-
-            case POS_TOKEN_OPERATOR:
-              exprs[n_exprs].type = POS_EXPR_OPERATOR;
-              exprs[n_exprs].d.operator = t->d.o.op;
-              ++n_exprs;
-              break;
-            }
-        }
-      else
-        {
-          g_assert (paren_level > 0);
-
-          switch (t->type)
-            {
-            case POS_TOKEN_INT:
-            case POS_TOKEN_DOUBLE:
-            case POS_TOKEN_VARIABLE:
-            case POS_TOKEN_OPERATOR:
-              break;
-
-            case POS_TOKEN_OPEN_PAREN:
-              ++paren_level;
-              break;
-
-            case POS_TOKEN_CLOSE_PAREN:
-              if (paren_level == 1)
-                {
-                  /* We closed a toplevel paren group, so recurse */
-                  if (!pos_eval_helper (&tokens[first_paren+1],
-                                        i - first_paren - 1,
-                                        env,
-                                        &exprs[n_exprs],
-                                        err))
-                    return FALSE;
-
-                  ++n_exprs;
-                }
-
-              --paren_level;
-              break;
-
-            }
-        }
-    }
-
-  if (paren_level > 0)
-    {
-      g_set_error (err, META_THEME_ERROR,
-                   META_THEME_ERROR_BAD_PARENS,
-                   _("Coordinate expression had an open parenthesis with no close parenthesis"));
-      return FALSE;
-    }
-
-  /* Now we have no parens and no vars; so we just do all the multiplies
-   * and divides, then all the add and subtract.
-   */
-  if (n_exprs == 0)
-    {
-      g_set_error (err, META_THEME_ERROR,
-                   META_THEME_ERROR_FAILED,
-                   _("Coordinate expression doesn't seem to have any operators or operands"));
-      return FALSE;
-    }
-
-  /* precedence 1 ops */
-  precedence = 2;
-  while (precedence >= 0)
-    {
-      if (!do_operations (exprs, &n_exprs, precedence, err))
-        return FALSE;
-      --precedence;
-    }
-
-  g_assert (n_exprs == 1);
-
-  *result = *exprs;
-
-  return TRUE;
-}
-
-/*
- *   expr = int | double | expr * expr | expr / expr |
- *          expr + expr | expr - expr | (expr)
- *
- *   so very not worth fooling with bison, yet so very painful by hand.
- */
-/**
- * Evaluates an expression.
- *
- * \param spec  The expression to evaluate.
- * \param env   The environment context to evaluate the expression in.
- * \param[out] val_p  The integer value of the expression; if the expression
- *                    is of type float, this will be rounded. If we return
- *                    FALSE because the expression is invalid, this will be
- *                    zero.
- * \param[out] err    The error, if anything went wrong.
- *
- * \return  True if we evaluated the expression successfully; false otherwise.
- *
- * \bug Shouldn't spec be const?
- * \ingroup parser
- */
-static gboolean
-pos_eval (MetaDrawSpec              *spec,
-          const MetaPositionExprEnv *env,
-          int                       *val_p,
-          GError                   **err)
-{
-  PosExpr expr;
-
-  *val_p = 0;
-
-  if (pos_eval_helper (spec->tokens, spec->n_tokens, env, &expr, err))
-    {
-      switch (expr.type)
-        {
-        case POS_EXPR_INT:
-          *val_p = expr.d.int_val;
-          break;
-        case POS_EXPR_DOUBLE:
-          *val_p = expr.d.double_val;
-          break;
-        case POS_EXPR_OPERATOR:
-          g_assert_not_reached ();
-          break;
-        }
-      return TRUE;
-    }
-  else
-    {
-      return FALSE;
-    }
-}
-
-/* We always return both X and Y, but only one will be meaningful in
- * most contexts.
- */
-
-gboolean
-meta_parse_position_expression (MetaDrawSpec              *spec,
-                                const MetaPositionExprEnv *env,
-                                int                       *x_return,
-                                int                       *y_return,
-                                GError                   **err)
-{
-  /* All positions are in a coordinate system with x, y at the origin.
-   * The expression can have -, +, *, / as operators, floating point
-   * or integer constants, and the variables "width" and "height" and
-   * optionally "object_width" and object_height". Negative numbers
-   * aren't allowed.
-   */
-  int val;
-
-  if (spec->constant)
-    val = spec->value;
-  else
-    {
-      if (pos_eval (spec, env, &spec->value, err) == FALSE)
-        {
-          g_assert (err == NULL || *err != NULL);
-          return FALSE;
-        }
-
-      val = spec->value;
-    }
-
-  if (x_return)
-    *x_return = env->rect.x + val;
-  if (y_return)
-    *y_return = env->rect.y + val;
-
-  return TRUE;
-}
-
-
-gboolean
-meta_parse_size_expression (MetaDrawSpec              *spec,
-                            const MetaPositionExprEnv *env,
-                            int                       *val_return,
-                            GError                   **err)
-{
-  int val;
-
-  if (spec->constant)
-    val = spec->value;
-  else 
-    {
-      if (pos_eval (spec, env, &spec->value, err) == FALSE)
-        {
-          g_assert (err == NULL || *err != NULL);
-          return FALSE;
-        }
-
-      val = spec->value;
-    }
-
-  if (val_return)
-    *val_return = MAX (val, 1); /* require that sizes be at least 1x1 */
-
-  return TRUE;
-}
-
-/* To do this we tokenize, replace variable tokens
- * that are constants, then reassemble. The purpose
- * here is to optimize expressions so we don't do hash
- * lookups to eval them. Obviously it's a tradeoff that
- * slows down theme load times.
- */
-gboolean
-meta_theme_replace_constants (MetaTheme   *theme,
-                              PosToken    *tokens,
-                              int          n_tokens,
-                              GError     **err)
-{
-  int i;
-  double dval;
-  int ival;
-  gboolean is_constant = TRUE;
-  
-  /* Loop through tokenized string looking for variables to replace */
-  for (i = 0; i < n_tokens; i++)
-    {
-      PosToken *t = &tokens[i];      
-
-      if (t->type == POS_TOKEN_VARIABLE)
-        {
-          if (meta_theme_lookup_int_constant (theme, t->d.v.name, &ival))
-            {
-              t->type = POS_TOKEN_INT;
-              t->d.i.val = ival;
-            }
-          else if (meta_theme_lookup_float_constant (theme, t->d.v.name, &dval))
-            {
-              t->type = POS_TOKEN_DOUBLE;
-              t->d.d.val = dval;
-            }
-          else 
-            {
-              /* If we've found a variable that cannot be replaced then the
-                 expression is not a constant expression and we want to 
-                 replace it with a GQuark */
-
-              t->d.v.name_quark = g_quark_from_string (t->d.v.name);
-              is_constant = FALSE;
-            }
-        }
-    }  
-
-  return is_constant;
-}
-
-static int
-parse_x_position_unchecked (MetaDrawSpec              *spec,
-                            const MetaPositionExprEnv *env)
-{
-  int retval;
-  GError *error;
-
-  retval = 0;
-  error = NULL;
-  if (!meta_parse_position_expression (spec, env, &retval, NULL, &error))
-    {
-      meta_warning (_("Theme contained an expression that resulted in an error: %s\n"),
-                    error->message);
-      
-      g_error_free (error);
-    }
-  
-  return retval;
-}
-
-static int
-parse_y_position_unchecked (MetaDrawSpec              *spec,
-                            const MetaPositionExprEnv *env)
-{
-  int retval;
-  GError *error;
-
-  retval = 0;
-  error = NULL;
-  if (!meta_parse_position_expression (spec, env, NULL, &retval, &error))
-    {
-      meta_warning (_("Theme contained an expression that resulted in an error: %s\n"),
-                    error->message);
-
-      g_error_free (error);
-    }
-
-  return retval;
-}
-
-static int
-parse_size_unchecked (MetaDrawSpec        *spec,
-                      MetaPositionExprEnv *env)
-{
-  int retval;
-  GError *error;
-
-  retval = 0;
-  error = NULL;
-  if (!meta_parse_size_expression (spec, env, &retval, &error))
-    {
-      meta_warning (_("Theme contained an expression that resulted in an error: %s\n"),
-                    error->message);
-
-      g_error_free (error);
-    }
-
-  return retval;
-}
-
-void
-meta_draw_spec_free (MetaDrawSpec *spec)
-{
-  if (!spec) return;
-  free_tokens (spec->tokens, spec->n_tokens);
-  g_slice_free (MetaDrawSpec, spec);
-}
-
-MetaDrawSpec *
-meta_draw_spec_new (MetaTheme  *theme,
-                    const char *expr,
-                    GError    **error)
-{
-  MetaDrawSpec *spec;
-
-  spec = g_slice_new0 (MetaDrawSpec);
-
-  pos_tokenize (expr, &spec->tokens, &spec->n_tokens, NULL);
-  
-  spec->constant = meta_theme_replace_constants (theme, spec->tokens, 
-                                                 spec->n_tokens, NULL);
-  if (spec->constant) 
-    {
-      gboolean result;
-
-      result = pos_eval (spec, NULL, &spec->value, error);
-      if (result == FALSE)
-        {
-          meta_draw_spec_free (spec);
-          return NULL;
-        }
-    }
-    
-  return spec;
-}
-
-MetaDrawOp*
-meta_draw_op_new (MetaDrawType type)
-{
-  MetaDrawOp *op;
-  MetaDrawOp dummy;
-  int size;
-
-  size = G_STRUCT_OFFSET (MetaDrawOp, data);
-
-  switch (type)
-    {
-    case META_DRAW_LINE:
-      size += sizeof (dummy.data.line);
-      break;
-
-    case META_DRAW_RECTANGLE:
-      size += sizeof (dummy.data.rectangle);
-      break;
-
-    case META_DRAW_ARC:
-      size += sizeof (dummy.data.arc);
-      break;
-
-    case META_DRAW_CLIP:
-      size += sizeof (dummy.data.clip);
-      break;
-      
-    case META_DRAW_TINT:
-      size += sizeof (dummy.data.tint);
-      break;
-
-    case META_DRAW_GRADIENT:
-      size += sizeof (dummy.data.gradient);
-      break;
-
-    case META_DRAW_IMAGE:
-      size += sizeof (dummy.data.image);
-      break;
-
-    case META_DRAW_GTK_ARROW:
-      size += sizeof (dummy.data.gtk_arrow);
-      break;
-
-    case META_DRAW_GTK_BOX:
-      size += sizeof (dummy.data.gtk_box);
-      break;
-
-    case META_DRAW_GTK_VLINE:
-      size += sizeof (dummy.data.gtk_vline);
-      break;
-
-    case META_DRAW_ICON:
-      size += sizeof (dummy.data.icon);
-      break;
-
-    case META_DRAW_TITLE:
-      size += sizeof (dummy.data.title);
-      break;
-    case META_DRAW_OP_LIST:
-      size += sizeof (dummy.data.op_list);
-      break;
-    case META_DRAW_TILE:
-      size += sizeof (dummy.data.tile);
-      break;
-    }
-
-  op = g_malloc0 (size);
-
-  op->type = type;
-
-  return op;
-}
-
-void
-meta_draw_op_free (MetaDrawOp *op)
-{
-  g_return_if_fail (op != NULL);
-
-  switch (op->type)
-    {
-    case META_DRAW_LINE:
-      if (op->data.line.color_spec)
-        meta_color_spec_free (op->data.line.color_spec);
-
-      meta_draw_spec_free (op->data.line.x1);
-      meta_draw_spec_free (op->data.line.y1);
-      meta_draw_spec_free (op->data.line.x2);
-      meta_draw_spec_free (op->data.line.y2);
-      break;
-
-    case META_DRAW_RECTANGLE:
-      if (op->data.rectangle.color_spec)
-        g_free (op->data.rectangle.color_spec);
-
-      meta_draw_spec_free (op->data.rectangle.x);
-      meta_draw_spec_free (op->data.rectangle.y);
-      meta_draw_spec_free (op->data.rectangle.width);
-      meta_draw_spec_free (op->data.rectangle.height);
-      break;
-
-    case META_DRAW_ARC:
-      if (op->data.arc.color_spec)
-        g_free (op->data.arc.color_spec);
-
-      meta_draw_spec_free (op->data.arc.x);
-      meta_draw_spec_free (op->data.arc.y);
-      meta_draw_spec_free (op->data.arc.width);
-      meta_draw_spec_free (op->data.arc.height);
-      break;
-
-    case META_DRAW_CLIP:
-      meta_draw_spec_free (op->data.clip.x);
-      meta_draw_spec_free (op->data.clip.y);
-      meta_draw_spec_free (op->data.clip.width);
-      meta_draw_spec_free (op->data.clip.height);
-      break;
-      
-    case META_DRAW_TINT:
-      if (op->data.tint.color_spec)
-        meta_color_spec_free (op->data.tint.color_spec);
-
-      if (op->data.tint.alpha_spec)
-        meta_alpha_gradient_spec_free (op->data.tint.alpha_spec);
-
-      meta_draw_spec_free (op->data.tint.x);
-      meta_draw_spec_free (op->data.tint.y);
-      meta_draw_spec_free (op->data.tint.width);
-      meta_draw_spec_free (op->data.tint.height);
-      break;
-
-    case META_DRAW_GRADIENT:
-      if (op->data.gradient.gradient_spec)
-        meta_gradient_spec_free (op->data.gradient.gradient_spec);
-
-      if (op->data.gradient.alpha_spec)
-        meta_alpha_gradient_spec_free (op->data.gradient.alpha_spec);
-
-      meta_draw_spec_free (op->data.gradient.x);
-      meta_draw_spec_free (op->data.gradient.y);
-      meta_draw_spec_free (op->data.gradient.width);
-      meta_draw_spec_free (op->data.gradient.height);
-      break;
-
-    case META_DRAW_IMAGE:
-      if (op->data.image.alpha_spec)
-        meta_alpha_gradient_spec_free (op->data.image.alpha_spec);
-
-      if (op->data.image.pixbuf)
-        g_object_unref (G_OBJECT (op->data.image.pixbuf));
-
-      if (op->data.image.colorize_spec)
-	meta_color_spec_free (op->data.image.colorize_spec);
-
-      if (op->data.image.colorize_cache_pixbuf)
-        g_object_unref (G_OBJECT (op->data.image.colorize_cache_pixbuf));
-
-      meta_draw_spec_free (op->data.image.x);
-      meta_draw_spec_free (op->data.image.y);
-      meta_draw_spec_free (op->data.image.width);
-      meta_draw_spec_free (op->data.image.height);
-      break;
-
-    case META_DRAW_GTK_ARROW:
-      meta_draw_spec_free (op->data.gtk_arrow.x);
-      meta_draw_spec_free (op->data.gtk_arrow.y);
-      meta_draw_spec_free (op->data.gtk_arrow.width);
-      meta_draw_spec_free (op->data.gtk_arrow.height);
-      break;
-
-    case META_DRAW_GTK_BOX:
-      meta_draw_spec_free (op->data.gtk_box.x);
-      meta_draw_spec_free (op->data.gtk_box.y);
-      meta_draw_spec_free (op->data.gtk_box.width);
-      meta_draw_spec_free (op->data.gtk_box.height);
-      break;
-
-    case META_DRAW_GTK_VLINE:
-      meta_draw_spec_free (op->data.gtk_vline.x);
-      meta_draw_spec_free (op->data.gtk_vline.y1);
-      meta_draw_spec_free (op->data.gtk_vline.y2);
-      break;
-
-    case META_DRAW_ICON:
-      if (op->data.icon.alpha_spec)
-        meta_alpha_gradient_spec_free (op->data.icon.alpha_spec);
-
-      meta_draw_spec_free (op->data.icon.x);
-      meta_draw_spec_free (op->data.icon.y);
-      meta_draw_spec_free (op->data.icon.width);
-      meta_draw_spec_free (op->data.icon.height);
-      break;
-
-    case META_DRAW_TITLE:
-      if (op->data.title.color_spec)
-        meta_color_spec_free (op->data.title.color_spec);
-
-      meta_draw_spec_free (op->data.title.x);
-      meta_draw_spec_free (op->data.title.y);
-      break;
-
-    case META_DRAW_OP_LIST:
-      if (op->data.op_list.op_list)
-        meta_draw_op_list_unref (op->data.op_list.op_list);
-
-      meta_draw_spec_free (op->data.op_list.x);
-      meta_draw_spec_free (op->data.op_list.y);
-      meta_draw_spec_free (op->data.op_list.width);
-      meta_draw_spec_free (op->data.op_list.height);
-      break;
-
-    case META_DRAW_TILE:
-      if (op->data.tile.op_list)
-        meta_draw_op_list_unref (op->data.tile.op_list);
-
-      meta_draw_spec_free (op->data.tile.x);
-      meta_draw_spec_free (op->data.tile.y);
-      meta_draw_spec_free (op->data.tile.width);
-      meta_draw_spec_free (op->data.tile.height);
-      meta_draw_spec_free (op->data.tile.tile_xoffset);
-      meta_draw_spec_free (op->data.tile.tile_yoffset);
-      meta_draw_spec_free (op->data.tile.tile_width);
-      meta_draw_spec_free (op->data.tile.tile_height);
-      break;
-    }
-
-  g_free (op);
-}
-
-static GdkGC*
-get_gc_for_primitive (GtkWidget          *widget,
-                      GdkDrawable        *drawable,
-                      MetaColorSpec      *color_spec,
-                      const GdkRectangle *clip,
-                      int                 line_width)
-{
-  GdkGC *gc;
-  GdkGCValues values;
-  GdkColor color;
-
-  meta_color_spec_render (color_spec, widget, &color);
-
-  values.foreground = color;
-
-  gdk_rgb_find_color (gdk_drawable_get_colormap (drawable),
-                      &values.foreground);
-
-  values.line_width = line_width;
-
-  gc = gdk_gc_new_with_values (drawable, &values,
-                               GDK_GC_FOREGROUND | GDK_GC_LINE_WIDTH);
-
-  if (clip)
-    gdk_gc_set_clip_rectangle (gc,
-                               (GdkRectangle*) clip); /* const cast */
-
-  return gc;
-}
-
-static GdkPixbuf*
-apply_alpha (GdkPixbuf             *pixbuf,
-             MetaAlphaGradientSpec *spec,
-             gboolean               force_copy)
-{
-  GdkPixbuf *new_pixbuf;
-  gboolean needs_alpha;
-  
-  g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
-  
-  needs_alpha = spec && (spec->n_alphas > 1 ||
-                         spec->alphas[0] != 0xff);
-
-  if (!needs_alpha)
-    return pixbuf;
-  
-  if (!gdk_pixbuf_get_has_alpha (pixbuf))
-    {
-      new_pixbuf = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0);
-      g_object_unref (G_OBJECT (pixbuf));
-      pixbuf = new_pixbuf;
-    }
-  else if (force_copy)
-    {
-      new_pixbuf = gdk_pixbuf_copy (pixbuf);
-      g_object_unref (G_OBJECT (pixbuf));
-      pixbuf = new_pixbuf;
-    }
-  
-  g_assert (gdk_pixbuf_get_has_alpha (pixbuf));
-
-  meta_gradient_add_alpha (pixbuf, spec->alphas, spec->n_alphas, spec->type);
-  
-  return pixbuf;
-}
-
-static void
-render_pixbuf (GdkDrawable        *drawable,
-               const GdkRectangle *clip,
-               GdkPixbuf          *pixbuf,
-               int                 x,
-               int                 y)
-{
-  /* grumble, render_to_drawable_alpha does not accept a clip
-   * mask, so we have to go through some BS
-   */
-  /* FIXME once GTK 1.3.13 has been out a while we can use
-   * render_to_drawable() which now does alpha with clip.
-   *
-   * Though the gdk_rectangle_intersect() check may be a useful
-   * optimization anyway.
-   */
-  GdkRectangle pixbuf_rect;
-  GdkRectangle draw_rect;
-
-  pixbuf_rect.x = x;
-  pixbuf_rect.y = y;
-  pixbuf_rect.width = gdk_pixbuf_get_width (pixbuf);
-  pixbuf_rect.height = gdk_pixbuf_get_height (pixbuf);
-
-  if (clip)
-    {
-      if (!gdk_rectangle_intersect ((GdkRectangle*)clip,
-                                    &pixbuf_rect, &draw_rect))
-        return;
-    }
-  else
-    {
-      draw_rect = pixbuf_rect;
-    }
-
-  gdk_draw_pixbuf (drawable,
-                   NULL,
-                   pixbuf,
-                   draw_rect.x - pixbuf_rect.x,
-                   draw_rect.y - pixbuf_rect.y,
-                   draw_rect.x, draw_rect.y,
-                   draw_rect.width,
-                   draw_rect.height,
-                   GDK_RGB_DITHER_NORMAL,
-                   draw_rect.x - pixbuf_rect.x,
-                   draw_rect.y - pixbuf_rect.y);
-}
-
-static GdkPixbuf*
-pixbuf_tile (GdkPixbuf *tile,
-             int        width,
-             int        height)
-{
-  GdkPixbuf *pixbuf;
-  int tile_width;
-  int tile_height;
-  int i, j;
-  
-  tile_width = gdk_pixbuf_get_width (tile);
-  tile_height = gdk_pixbuf_get_height (tile);
-  
-  pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
-                           gdk_pixbuf_get_has_alpha (tile),
-                           8, width, height);
-
-  i = 0;
-  while (i < width)
-    {
-      j = 0;
-      while (j < height)
-        {
-          int w, h;
-
-          w = MIN (tile_width, width - i);
-          h = MIN (tile_height, height - j);
-          
-          gdk_pixbuf_copy_area (tile,
-                                0, 0,
-                                w, h,
-                                pixbuf,
-                                i, j);
-
-          j += tile_height;
-        }
-      
-      i += tile_width;
-    }
-  
-  return pixbuf;
-}
-
-static GdkPixbuf *
-replicate_rows (GdkPixbuf  *src,
-                int         src_x,
-                int         src_y,
-                int         width,
-                int         height)
-{
-  unsigned int n_channels = gdk_pixbuf_get_n_channels (src);
-  unsigned int src_rowstride = gdk_pixbuf_get_rowstride (src);
-  unsigned char *pixels = (gdk_pixbuf_get_pixels (src) + src_y * src_rowstride + src_x
-                           * n_channels);
-  unsigned char *dest_pixels;
-  GdkPixbuf *result;
-  unsigned int dest_rowstride;
-  int i;
-
-  result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8,
-                           width, height);
-  dest_rowstride = gdk_pixbuf_get_rowstride (result);
-  dest_pixels = gdk_pixbuf_get_pixels (result);
-  
-  for (i = 0; i < height; i++)
-    memcpy (dest_pixels + dest_rowstride * i, pixels, n_channels * width);
-
-  return result;
-}
-
-static GdkPixbuf *
-replicate_cols (GdkPixbuf  *src,
-                int         src_x,
-                int         src_y,
-                int         width,
-                int         height)
-{
-  unsigned int n_channels = gdk_pixbuf_get_n_channels (src);
-  unsigned int src_rowstride = gdk_pixbuf_get_rowstride (src);
-  unsigned char *pixels = (gdk_pixbuf_get_pixels (src) + src_y * src_rowstride + src_x
-                           * n_channels);
-  unsigned char *dest_pixels;
-  GdkPixbuf *result;
-  unsigned int dest_rowstride;
-  int i, j;
-
-  result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, n_channels == 4, 8,
-                           width, height);
-  dest_rowstride = gdk_pixbuf_get_rowstride (result);
-  dest_pixels = gdk_pixbuf_get_pixels (result);
-
-  for (i = 0; i < height; i++)
-    {
-      unsigned char *p = dest_pixels + dest_rowstride * i;
-      unsigned char *q = pixels + src_rowstride * i;
-
-      unsigned char r = *(q++);
-      unsigned char g = *(q++);
-      unsigned char b = *(q++);
-      
-      if (n_channels == 4)
-        {
-          unsigned char a;
-          
-          a = *(q++);
-          
-          for (j = 0; j < width; j++)
-            {
-              *(p++) = r;
-              *(p++) = g;
-              *(p++) = b;                    
-              *(p++) = a;
-            }
-        }
-      else
-        {
-          for (j = 0; j < width; j++)
-            {
-              *(p++) = r;
-              *(p++) = g;
-              *(p++) = b;
-            }
-        }
-    }
-
-  return result;
-}
-
-static GdkPixbuf*
-scale_and_alpha_pixbuf (GdkPixbuf             *src,
-                        MetaAlphaGradientSpec *alpha_spec,
-                        MetaImageFillType      fill_type,
-                        int                    width,
-                        int                    height,
-                        gboolean               vertical_stripes,
-                        gboolean               horizontal_stripes)
-{
-  GdkPixbuf *pixbuf;
-  GdkPixbuf *temp_pixbuf;
-
-  pixbuf = NULL;
-
-  pixbuf = src;
-
-  if (gdk_pixbuf_get_width (pixbuf) == width &&
-      gdk_pixbuf_get_height (pixbuf) == height)
-    {
-      g_object_ref (G_OBJECT (pixbuf));
-    }
-  else
-    {
-      if (fill_type == META_IMAGE_FILL_TILE)
-        {
-          pixbuf = pixbuf_tile (pixbuf, width, height);
-        }
-      else
-        {
-    	  int src_h, src_w, dest_h, dest_w;
-          src_h = gdk_pixbuf_get_height (src);
-          src_w = gdk_pixbuf_get_width (src);
-
-          /* prefer to replicate_cols if possible, as that
-           * is faster (no memory reads)
-           */
-          if (horizontal_stripes)
-            {
-              dest_w = gdk_pixbuf_get_width (src);
-              dest_h = height;
-            }
-          else if (vertical_stripes)
-            {
-              dest_w = width;
-              dest_h = gdk_pixbuf_get_height (src);
-            }
-
-          else
-            {
-              dest_w = width;
-              dest_h = height;
-            }
-
-          if (dest_w == src_w && dest_h == src_h)
-            {
-              temp_pixbuf = src;
-              g_object_ref (G_OBJECT (temp_pixbuf));
-            }
-          else
-            {
-              temp_pixbuf = gdk_pixbuf_scale_simple (src,
-                                                     dest_w, dest_h,
-                                                     GDK_INTERP_BILINEAR);
-            }
-
-          /* prefer to replicate_cols if possible, as that
-           * is faster (no memory reads)
-           */
-          if (horizontal_stripes)
-            {
-              pixbuf = replicate_cols (temp_pixbuf, 0, 0, width, height);
-              g_object_unref (G_OBJECT (temp_pixbuf));
-            }
-          else if (vertical_stripes)
-            {
-              pixbuf = replicate_rows (temp_pixbuf, 0, 0, width, height);
-              g_object_unref (G_OBJECT (temp_pixbuf));
-            }
-          else 
-            {
-              pixbuf = temp_pixbuf;
-            }
-        }
-    }
-
-  if (pixbuf)
-    pixbuf = apply_alpha (pixbuf, alpha_spec, pixbuf == src);
-  
-  return pixbuf;
-}
-
-static GdkPixbuf*
-draw_op_as_pixbuf (const MetaDrawOp    *op,
-                   GtkWidget           *widget,
-                   const MetaDrawInfo  *info,
-                   int                  width,
-                   int                  height)
-{
-  /* Try to get the op as a pixbuf, assuming w/h in the op
-   * matches the width/height passed in. return NULL
-   * if the op can't be converted to an equivalent pixbuf.
-   */
-  GdkPixbuf *pixbuf;
-
-  pixbuf = NULL;
-
-  switch (op->type)
-    {
-    case META_DRAW_LINE:
-      break;
-
-    case META_DRAW_RECTANGLE:
-      if (op->data.rectangle.filled)
-        {
-          GdkColor color;
-
-          meta_color_spec_render (op->data.rectangle.color_spec,
-                                  widget,
-                                  &color);
-
-          pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
-                                   FALSE,
-                                   8, width, height);
-
-          gdk_pixbuf_fill (pixbuf, GDK_COLOR_RGBA (color));
-        }
-      break;
-
-    case META_DRAW_ARC:
-      break;
-
-    case META_DRAW_CLIP:
-      break;
-      
-    case META_DRAW_TINT:
-      {
-        GdkColor color;
-        guint32 rgba;
-        gboolean has_alpha;
-
-        meta_color_spec_render (op->data.rectangle.color_spec,
-                                widget,
-                                &color);
-
-        has_alpha =
-          op->data.tint.alpha_spec &&
-          (op->data.tint.alpha_spec->n_alphas > 1 ||
-           op->data.tint.alpha_spec->alphas[0] != 0xff);
-        
-        pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
-                                 has_alpha,
-                                 8, width, height);
-
-        if (!has_alpha)
-          {
-            rgba = GDK_COLOR_RGBA (color);
-            
-            gdk_pixbuf_fill (pixbuf, rgba);
-          }
-        else if (op->data.tint.alpha_spec->n_alphas == 1)
-          {
-            rgba = GDK_COLOR_RGBA (color);
-            rgba &= ~0xff;
-            rgba |= op->data.tint.alpha_spec->alphas[0];
-            
-            gdk_pixbuf_fill (pixbuf, rgba);
-          }
-        else
-          {
-            rgba = GDK_COLOR_RGBA (color);
-            
-            gdk_pixbuf_fill (pixbuf, rgba);
-
-            meta_gradient_add_alpha (pixbuf,
-                                     op->data.tint.alpha_spec->alphas,
-                                     op->data.tint.alpha_spec->n_alphas,
-                                     op->data.tint.alpha_spec->type);
-          }
-      }
-      break;
-
-    case META_DRAW_GRADIENT:
-      {
-        pixbuf = meta_gradient_spec_render (op->data.gradient.gradient_spec,
-                                            widget, width, height);
-
-        pixbuf = apply_alpha (pixbuf,
-                              op->data.gradient.alpha_spec,
-                              FALSE);
-      }
-      break;
-
-      
-    case META_DRAW_IMAGE:
-      {
-	if (op->data.image.colorize_spec)
-	  {
-	    GdkColor color;
-
-            meta_color_spec_render (op->data.image.colorize_spec,
-                                    widget, &color);
-            
-            if (op->data.image.colorize_cache_pixbuf == NULL ||
-                op->data.image.colorize_cache_pixel != GDK_COLOR_RGB (color))
-              {
-                if (op->data.image.colorize_cache_pixbuf)
-                  g_object_unref (G_OBJECT (op->data.image.colorize_cache_pixbuf));
-                
-                /* const cast here */
-                ((MetaDrawOp*)op)->data.image.colorize_cache_pixbuf =
-                  colorize_pixbuf (op->data.image.pixbuf,
-                                   &color);
-                ((MetaDrawOp*)op)->data.image.colorize_cache_pixel =
-                  GDK_COLOR_RGB (color);
-              }
-            
-            if (op->data.image.colorize_cache_pixbuf)
-              {
-                pixbuf = scale_and_alpha_pixbuf (op->data.image.colorize_cache_pixbuf,
-                                                 op->data.image.alpha_spec,
-                                                 op->data.image.fill_type,
-                                                 width, height,
-                                                 op->data.image.vertical_stripes,
-                                                 op->data.image.horizontal_stripes);
-              }
-	  }
-	else
-	  {
-	    pixbuf = scale_and_alpha_pixbuf (op->data.image.pixbuf,
-                                             op->data.image.alpha_spec,
-                                             op->data.image.fill_type,
-                                             width, height,
-                                             op->data.image.vertical_stripes,
-                                             op->data.image.horizontal_stripes);
-	  }
-        break;
-      }
-      
-    case META_DRAW_GTK_ARROW:
-    case META_DRAW_GTK_BOX:
-    case META_DRAW_GTK_VLINE:
-      break;
-
-    case META_DRAW_ICON:
-      if (info->mini_icon &&
-          width <= gdk_pixbuf_get_width (info->mini_icon) &&
-          height <= gdk_pixbuf_get_height (info->mini_icon))
-        pixbuf = scale_and_alpha_pixbuf (info->mini_icon,
-                                         op->data.icon.alpha_spec,
-                                         op->data.icon.fill_type,
-                                         width, height,
-                                         FALSE, FALSE);
-      else if (info->icon)
-        pixbuf = scale_and_alpha_pixbuf (info->icon,
-                                         op->data.icon.alpha_spec,
-                                         op->data.icon.fill_type,
-                                         width, height,
-                                         FALSE, FALSE);
-      break;
-
-    case META_DRAW_TITLE:
-      break;
-
-    case META_DRAW_OP_LIST:
-      break;
-
-    case META_DRAW_TILE:
-      break;
-    }
-
-  return pixbuf;
-}
-
-static void
-fill_env (MetaPositionExprEnv *env,
-          const MetaDrawInfo  *info,
-          MetaRectangle        logical_region)
-{
-  /* FIXME this stuff could be raised into draw_op_list_draw() probably
-   */
-  env->rect = logical_region;
-  env->object_width = -1;
-  env->object_height = -1;
-  if (info->fgeom)
-    {
-      env->left_width = info->fgeom->left_width;
-      env->right_width = info->fgeom->right_width;
-      env->top_height = info->fgeom->top_height;
-      env->bottom_height = info->fgeom->bottom_height;
-    }
-  else
-    {
-      env->left_width = 0;
-      env->right_width = 0;
-      env->top_height = 0;
-      env->bottom_height = 0;
-    }
-  
-  env->mini_icon_width = info->mini_icon ? gdk_pixbuf_get_width (info->mini_icon) : 0;
-  env->mini_icon_height = info->mini_icon ? gdk_pixbuf_get_height (info->mini_icon) : 0;
-  env->icon_width = info->icon ? gdk_pixbuf_get_width (info->icon) : 0;
-  env->icon_height = info->icon ? gdk_pixbuf_get_height (info->icon) : 0;
-
-  env->title_width = info->title_layout_width;
-  env->title_height = info->title_layout_height;
-  env->theme = meta_current_theme;
-}
-
-static void
-meta_draw_op_draw_with_env (const MetaDrawOp    *op,
-                            GtkStyle            *style_gtk,
-                            GtkWidget           *widget,
-                            GdkDrawable         *drawable,
-                            const GdkRectangle  *clip,
-                            const MetaDrawInfo  *info,
-                            MetaRectangle        rect,
-                            MetaPositionExprEnv *env)
-{
-  GdkGC *gc;
-  
-  switch (op->type)
-    {
-    case META_DRAW_LINE:
-      {
-        int x1, x2, y1, y2;
-
-        gc = get_gc_for_primitive (widget, drawable,
-                                   op->data.line.color_spec,
-                                   clip,
-                                   op->data.line.width);
-
-        if (op->data.line.dash_on_length > 0 &&
-            op->data.line.dash_off_length > 0)
-          {
-            gint8 dash_list[2];
-            dash_list[0] = op->data.line.dash_on_length;
-            dash_list[1] = op->data.line.dash_off_length;
-            gdk_gc_set_dashes (gc, 0, dash_list, 2);
-          }
-
-        x1 = parse_x_position_unchecked (op->data.line.x1, env);
-        y1 = parse_y_position_unchecked (op->data.line.y1, env); 
-
-        if (!op->data.line.x2 &&
-            !op->data.line.y2 &&
-            op->data.line.width==0)
-          gdk_draw_point (drawable, gc, x1, y1);
-        else
-          {
-            if (op->data.line.x2)
-              x2 = parse_x_position_unchecked (op->data.line.x2, env);
-            else
-              x2 = x1;
-
-            if (op->data.line.y2)
-              y2 = parse_y_position_unchecked (op->data.line.y2, env);
-            else
-              y2 = y1;
-
-            gdk_draw_line (drawable, gc, x1, y1, x2, y2);
-          }
-
-        g_object_unref (G_OBJECT (gc));
-      }
-      break;
-
-    case META_DRAW_RECTANGLE:
-      {
-        int rx, ry, rwidth, rheight;
-
-        gc = get_gc_for_primitive (widget, drawable,
-                                   op->data.rectangle.color_spec,
-                                   clip, 0);
-
-        rx = parse_x_position_unchecked (op->data.rectangle.x, env);
-        ry = parse_y_position_unchecked (op->data.rectangle.y, env);
-        rwidth = parse_size_unchecked (op->data.rectangle.width, env);
-        rheight = parse_size_unchecked (op->data.rectangle.height, env);
-
-        gdk_draw_rectangle (drawable, gc,
-                            op->data.rectangle.filled,
-                            rx, ry, rwidth, rheight);
-
-        g_object_unref (G_OBJECT (gc));
-      }
-      break;
-
-    case META_DRAW_ARC:
-      {
-        int rx, ry, rwidth, rheight;
-
-        gc = get_gc_for_primitive (widget, drawable,
-                                   op->data.arc.color_spec,
-                                   clip, 0);
-
-        rx = parse_x_position_unchecked (op->data.arc.x, env);
-        ry = parse_y_position_unchecked (op->data.arc.y, env);
-        rwidth = parse_size_unchecked (op->data.arc.width, env);
-        rheight = parse_size_unchecked (op->data.arc.height, env);
-
-        gdk_draw_arc (drawable,
-                      gc,
-                      op->data.arc.filled,
-                      rx, ry, rwidth, rheight,
-                      op->data.arc.start_angle * (360.0 * 64.0) -
-                      (90.0 * 64.0), /* start at 12 instead of 3 oclock */
-                      op->data.arc.extent_angle * (360.0 * 64.0));
-
-        g_object_unref (G_OBJECT (gc));
-      }
-      break;
-
-    case META_DRAW_CLIP:
-      break;
-      
-    case META_DRAW_TINT:
-      {
-        int rx, ry, rwidth, rheight;
-        gboolean needs_alpha;
-        
-        needs_alpha = op->data.tint.alpha_spec &&
-          (op->data.tint.alpha_spec->n_alphas > 1 ||
-           op->data.tint.alpha_spec->alphas[0] != 0xff);
-        
-        rx = parse_x_position_unchecked (op->data.tint.x, env);
-        ry = parse_y_position_unchecked (op->data.tint.y, env);
-        rwidth = parse_size_unchecked (op->data.tint.width, env);
-        rheight = parse_size_unchecked (op->data.tint.height, env);
-
-        if (!needs_alpha)
-          {
-            gc = get_gc_for_primitive (widget, drawable,
-                                       op->data.tint.color_spec,
-                                       clip, 0);
-
-            gdk_draw_rectangle (drawable, gc,
-                                TRUE,
-                                rx, ry, rwidth, rheight);
-
-            g_object_unref (G_OBJECT (gc));
-          }
-        else
-          {
-            GdkPixbuf *pixbuf;
-
-            pixbuf = draw_op_as_pixbuf (op, widget, info,
-                                        rwidth, rheight);
-
-            if (pixbuf)
-              {
-                render_pixbuf (drawable, clip, pixbuf, rx, ry);
-
-                g_object_unref (G_OBJECT (pixbuf));
-              }
-          }
-      }
-      break;
-
-    case META_DRAW_GRADIENT:
-      {
-        int rx, ry, rwidth, rheight;
-        GdkPixbuf *pixbuf;
-
-        rx = parse_x_position_unchecked (op->data.gradient.x, env);
-        ry = parse_y_position_unchecked (op->data.gradient.y, env);
-        rwidth = parse_size_unchecked (op->data.gradient.width, env);
-        rheight = parse_size_unchecked (op->data.gradient.height, env);
-
-        pixbuf = draw_op_as_pixbuf (op, widget, info,
-                                    rwidth, rheight);
-
-        if (pixbuf)
-          {
-            render_pixbuf (drawable, clip, pixbuf, rx, ry);
-
-            g_object_unref (G_OBJECT (pixbuf));
-          }
-      }
-      break;
-
-    case META_DRAW_IMAGE:
-      {
-        int rx, ry, rwidth, rheight;
-        GdkPixbuf *pixbuf;
-
-        if (op->data.image.pixbuf)
-          {
-            env->object_width = gdk_pixbuf_get_width (op->data.image.pixbuf);
-            env->object_height = gdk_pixbuf_get_height (op->data.image.pixbuf);
-          }
-
-        rwidth = parse_size_unchecked (op->data.image.width, env);
-        rheight = parse_size_unchecked (op->data.image.height, env);
-        
-        pixbuf = draw_op_as_pixbuf (op, widget, info,
-                                    rwidth, rheight);
-
-        if (pixbuf)
-          {
-            rx = parse_x_position_unchecked (op->data.image.x, env);
-            ry = parse_y_position_unchecked (op->data.image.y, env);
-
-            render_pixbuf (drawable, clip, pixbuf, rx, ry);
-
-            g_object_unref (G_OBJECT (pixbuf));
-          }
-      }
-      break;
-
-    case META_DRAW_GTK_ARROW:
-      {
-        int rx, ry, rwidth, rheight;
-
-        rx = parse_x_position_unchecked (op->data.gtk_arrow.x, env);
-        ry = parse_y_position_unchecked (op->data.gtk_arrow.y, env);
-        rwidth = parse_size_unchecked (op->data.gtk_arrow.width, env);
-        rheight = parse_size_unchecked (op->data.gtk_arrow.height, env);
-
-        gtk_paint_arrow (style_gtk,
-                         drawable,
-                         op->data.gtk_arrow.state,
-                         op->data.gtk_arrow.shadow,
-                         (GdkRectangle*) clip,
-                         widget,
-                         "metacity",
-                         op->data.gtk_arrow.arrow,
-                         op->data.gtk_arrow.filled,
-                         rx, ry, rwidth, rheight);
-      }
-      break;
-
-    case META_DRAW_GTK_BOX:
-      {
-        int rx, ry, rwidth, rheight;
-
-        rx = parse_x_position_unchecked (op->data.gtk_box.x, env);
-        ry = parse_y_position_unchecked (op->data.gtk_box.y, env);
-        rwidth = parse_size_unchecked (op->data.gtk_box.width, env);
-        rheight = parse_size_unchecked (op->data.gtk_box.height, env);
-
-        gtk_paint_box (style_gtk,
-                       drawable,
-                       op->data.gtk_box.state,
-                       op->data.gtk_box.shadow,
-                       (GdkRectangle*) clip,
-                       widget,
-                       "metacity",
-                       rx, ry, rwidth, rheight);
-      }
-      break;
-
-    case META_DRAW_GTK_VLINE:
-      {
-        int rx, ry1, ry2;
-
-        rx = parse_x_position_unchecked (op->data.gtk_vline.x, env);
-        ry1 = parse_y_position_unchecked (op->data.gtk_vline.y1, env);
-        ry2 = parse_y_position_unchecked (op->data.gtk_vline.y2, env);
-        
-        gtk_paint_vline (style_gtk,
-                         drawable,
-                         op->data.gtk_vline.state,
-                         (GdkRectangle*) clip,
-                         widget,
-                         "metacity",
-                         ry1, ry2, rx);
-      }
-      break;
-
-    case META_DRAW_ICON:
-      {
-        int rx, ry, rwidth, rheight;
-        GdkPixbuf *pixbuf;
-
-        rwidth = parse_size_unchecked (op->data.icon.width, env);
-        rheight = parse_size_unchecked (op->data.icon.height, env);
-        
-        pixbuf = draw_op_as_pixbuf (op, widget, info,
-                                    rwidth, rheight);
-
-        if (pixbuf)
-          {
-            rx = parse_x_position_unchecked (op->data.icon.x, env);
-            ry = parse_y_position_unchecked (op->data.icon.y, env);
-
-            render_pixbuf (drawable, clip, pixbuf, rx, ry);
-
-            g_object_unref (G_OBJECT (pixbuf));
-          }
-      }
-      break;
-
-    case META_DRAW_TITLE:
-      if (info->title_layout)
-        {
-          int rx, ry;
-
-          gc = get_gc_for_primitive (widget, drawable,
-                                     op->data.title.color_spec,
-                                     clip, 0);
-
-          rx = parse_x_position_unchecked (op->data.title.x, env);
-          ry = parse_y_position_unchecked (op->data.title.y, env);
-
-          gdk_draw_layout (drawable, gc,
-                           rx, ry,
-                           info->title_layout);
-
-          g_object_unref (G_OBJECT (gc));
-        }
-      break;
-
-    case META_DRAW_OP_LIST:
-      {
-        MetaRectangle d_rect;
-
-        d_rect.x = parse_x_position_unchecked (op->data.op_list.x, env);
-        d_rect.y = parse_y_position_unchecked (op->data.op_list.y, env);
-        d_rect.width = parse_size_unchecked (op->data.op_list.width, env);
-        d_rect.height = parse_size_unchecked (op->data.op_list.height, env);
-
-        meta_draw_op_list_draw_with_style (op->data.op_list.op_list,
-                                           style_gtk, widget, drawable, clip, info,
-                                           d_rect);
-      }
-      break;
-
-    case META_DRAW_TILE:
-      {
-        int rx, ry, rwidth, rheight;
-        int tile_xoffset, tile_yoffset; 
-        GdkRectangle new_clip;
-        MetaRectangle tile;
-        
-        rx = parse_x_position_unchecked (op->data.tile.x, env);
-        ry = parse_y_position_unchecked (op->data.tile.y, env);
-        rwidth = parse_size_unchecked (op->data.tile.width, env);
-        rheight = parse_size_unchecked (op->data.tile.height, env);
-
-        new_clip.x = rx;
-        new_clip.y = ry;
-        new_clip.width = rwidth;
-        new_clip.height = rheight;
-
-        if (clip == NULL || gdk_rectangle_intersect ((GdkRectangle*)clip, &new_clip,
-                                                     &new_clip))
-          {
-            tile_xoffset = parse_x_position_unchecked (op->data.tile.tile_xoffset, env);
-            tile_yoffset = parse_y_position_unchecked (op->data.tile.tile_yoffset, env);
-            /* tile offset should not include x/y */
-            tile_xoffset -= rect.x;
-            tile_yoffset -= rect.y;
-            
-            tile.width = parse_size_unchecked (op->data.tile.tile_width, env);
-            tile.height = parse_size_unchecked (op->data.tile.tile_height, env);
-
-            tile.x = rx - tile_xoffset;
-        
-            while (tile.x < (rx + rwidth))
-              {
-                tile.y = ry - tile_yoffset;
-                while (tile.y < (ry + rheight))
-                  {
-                    meta_draw_op_list_draw_with_style (op->data.tile.op_list,
-                                                       style_gtk, widget, drawable, &new_clip, info,
-                                                       tile);
-
-                    tile.y += tile.height;
-                  }
-
-                tile.x += tile.width;
-              }
-          }
-      }
-      break;
-    }
-}
-
-void
-meta_draw_op_draw_with_style (const MetaDrawOp    *op,
-                              GtkStyle            *style_gtk,
-                              GtkWidget           *widget,
-                              GdkDrawable         *drawable,
-                              const GdkRectangle  *clip,
-                              const MetaDrawInfo  *info,
-                              MetaRectangle        logical_region)
-{
-  MetaPositionExprEnv env;
-
-  g_return_if_fail (style_gtk->colormap == gdk_drawable_get_colormap (drawable));
-
-  fill_env (&env, info, logical_region);
-
-  meta_draw_op_draw_with_env (op, style_gtk, widget, drawable, clip,
-                              info, logical_region,
-                              &env);
-
-}
-
-void
-meta_draw_op_draw (const MetaDrawOp    *op,
-                   GtkWidget           *widget,
-                   GdkDrawable         *drawable,
-                   const GdkRectangle  *clip,
-                   const MetaDrawInfo  *info,
-                   MetaRectangle        logical_region)
-{
-  meta_draw_op_draw_with_style (op, widget->style, widget,
-                                drawable, clip, info, logical_region);
-}
-
-MetaDrawOpList*
-meta_draw_op_list_new (int n_preallocs)
-{
-  MetaDrawOpList *op_list;
-
-  g_return_val_if_fail (n_preallocs >= 0, NULL);
-
-  op_list = g_new (MetaDrawOpList, 1);
-
-  op_list->refcount = 1;
-  op_list->n_allocated = n_preallocs;
-  op_list->ops = g_new (MetaDrawOp*, op_list->n_allocated);
-  op_list->n_ops = 0;
-
-  return op_list;
-}
-
-void
-meta_draw_op_list_ref (MetaDrawOpList *op_list)
-{
-  g_return_if_fail (op_list != NULL);
-
-  op_list->refcount += 1;
-}
-
-void
-meta_draw_op_list_unref (MetaDrawOpList *op_list)
-{
-  g_return_if_fail (op_list != NULL);
-  g_return_if_fail (op_list->refcount > 0);
-
-  op_list->refcount -= 1;
-
-  if (op_list->refcount == 0)
-    {
-      int i;
-
-      for (i = 0; i < op_list->n_ops; i++)
-        meta_draw_op_free (op_list->ops[i]);
-
-      g_free (op_list->ops);
-
-      DEBUG_FILL_STRUCT (op_list);
-      g_free (op_list);
-    }
-}
-
-void
-meta_draw_op_list_draw_with_style  (const MetaDrawOpList *op_list,
-                                    GtkStyle             *style_gtk,
-                                    GtkWidget            *widget,
-                                    GdkDrawable          *drawable,
-                                    const GdkRectangle   *clip,
-                                    const MetaDrawInfo   *info,
-                                    MetaRectangle         rect)
-{
-  int i;
-  GdkRectangle active_clip;
-  GdkRectangle orig_clip;
-  MetaPositionExprEnv env;
-
-  g_return_if_fail (style_gtk->colormap == gdk_drawable_get_colormap (drawable));
-
-  if (op_list->n_ops == 0)
-    return;
-  
-  fill_env (&env, info, rect);
-  
-  /* FIXME this can be optimized, potentially a lot, by
-   * compressing multiple ops when possible. For example,
-   * anything convertible to a pixbuf can be composited
-   * client-side, and putting a color tint over a pixbuf
-   * can be done without creating the solid-color pixbuf.
-   *
-   * To implement this my plan is to have the idea of a
-   * compiled draw op (with the string expressions already
-   * evaluated), we make an array of those, and then fold
-   * adjacent items when possible.
-   */
-  if (clip)
-    {
-      orig_clip = *clip;
-    }
-  else
-    {
-      orig_clip.x = rect.x;
-      orig_clip.y = rect.y;
-      orig_clip.width = rect.width;
-      orig_clip.height = rect.height;
-    }
-
-  active_clip = orig_clip;
-
-  for (i = 0; i < op_list->n_ops; i++)
-    {
-      MetaDrawOp *op = op_list->ops[i];
-      
-      if (op->type == META_DRAW_CLIP)
-        {
-          active_clip.x = parse_x_position_unchecked (op->data.clip.x, &env);
-          active_clip.y = parse_y_position_unchecked (op->data.clip.y, &env);
-          active_clip.width = parse_size_unchecked (op->data.clip.width, &env);
-          active_clip.height = parse_size_unchecked (op->data.clip.height, &env);
-          
-          gdk_rectangle_intersect (&orig_clip, &active_clip, &active_clip);
-        }
-      else if (active_clip.width > 0 &&
-               active_clip.height > 0)
-        {
-          meta_draw_op_draw_with_env (op,
-                                      style_gtk, widget, drawable, &active_clip, info,
-                                      rect,
-                                      &env);
-        }
-    }
-}
-
-void
-meta_draw_op_list_draw  (const MetaDrawOpList *op_list,
-                         GtkWidget            *widget,
-                         GdkDrawable          *drawable,
-                         const GdkRectangle   *clip,
-                         const MetaDrawInfo   *info,
-                         MetaRectangle         rect)
-
-{
-  meta_draw_op_list_draw_with_style (op_list, widget->style, widget,
-                                     drawable, clip, info, rect);
-}
-
-void
-meta_draw_op_list_append (MetaDrawOpList       *op_list,
-                          MetaDrawOp           *op)
-{
-  if (op_list->n_ops == op_list->n_allocated)
-    {
-      op_list->n_allocated *= 2;
-      op_list->ops = g_renew (MetaDrawOp*, op_list->ops, op_list->n_allocated);
-    }
-
-  op_list->ops[op_list->n_ops] = op;
-  op_list->n_ops += 1;
-}
-
-gboolean
-meta_draw_op_list_validate (MetaDrawOpList    *op_list,
-                            GError           **error)
-{
-  g_return_val_if_fail (op_list != NULL, FALSE);
-
-  /* empty lists are OK, nothing else to check really */
-
-  return TRUE;
-}
-
-/* This is not done in validate, since we wouldn't know the name
- * of the list to report the error. It might be nice to
- * store names inside the list sometime.
- */
-gboolean
-meta_draw_op_list_contains (MetaDrawOpList    *op_list,
-                            MetaDrawOpList    *child)
-{
-  int i;
-
-  /* mmm, huge tree recursion */
-
-  for (i = 0; i < op_list->n_ops; i++)
-    {
-      if (op_list->ops[i]->type == META_DRAW_OP_LIST)
-        {
-          if (op_list->ops[i]->data.op_list.op_list == child)
-            return TRUE;
-          
-          if (meta_draw_op_list_contains (op_list->ops[i]->data.op_list.op_list,
-                                          child))
-            return TRUE;
-        }
-      else if (op_list->ops[i]->type == META_DRAW_TILE)
-        {
-          if (op_list->ops[i]->data.tile.op_list == child)
-            return TRUE;
-          
-          if (meta_draw_op_list_contains (op_list->ops[i]->data.tile.op_list,
-                                          child))
-            return TRUE;
-        }
-    }
-
-  return FALSE;
-}
-
-/**
- * Constructor for a MetaFrameStyle.
- *
- * \param parent  The parent style. Data not filled in here will be
- *                looked for in the parent style, and in its parent
- *                style, and so on.
- *
- * \return The newly-constructed style.
- */
-MetaFrameStyle*
-meta_frame_style_new (MetaFrameStyle *parent)
-{
-  MetaFrameStyle *style;
-
-  style = g_new0 (MetaFrameStyle, 1);
-
-  style->refcount = 1;
-
-  /* Default alpha is fully opaque */
-  style->window_background_alpha = 255;
-
-  style->parent = parent;
-  if (parent)
-    meta_frame_style_ref (parent);
-
-  return style;
-}
-
-/**
- * Increases the reference count of a frame style.
- * If the style is NULL, this is a no-op.
- *
- * \param style  The style.
- */
-void
-meta_frame_style_ref (MetaFrameStyle *style)
-{
-  g_return_if_fail (style != NULL);
-
-  style->refcount += 1;
-}
-
-static void
-free_button_ops (MetaDrawOpList *op_lists[META_BUTTON_TYPE_LAST][META_BUTTON_STATE_LAST])
-{
-  int i, j;
-
-  for (i = 0; i < META_BUTTON_TYPE_LAST; i++)
-    for (j = 0; j < META_BUTTON_STATE_LAST; j++)
-      if (op_lists[i][j])
-        meta_draw_op_list_unref (op_lists[i][j]);
-}
-
-void
-meta_frame_style_unref (MetaFrameStyle *style)
-{
-  g_return_if_fail (style != NULL);
-  g_return_if_fail (style->refcount > 0);
-
-  style->refcount -= 1;
-
-  if (style->refcount == 0)
-    {
-      int i;
-
-      free_button_ops (style->buttons);
-
-      for (i = 0; i < META_FRAME_PIECE_LAST; i++)
-        if (style->pieces[i])
-          meta_draw_op_list_unref (style->pieces[i]);
-
-      if (style->layout)
-        meta_frame_layout_unref (style->layout);
-
-      if (style->window_background_color)
-        meta_color_spec_free (style->window_background_color);
-
-      /* we hold a reference to any parent style */
-      if (style->parent)
-        meta_frame_style_unref (style->parent);
-
-      DEBUG_FILL_STRUCT (style);
-      g_free (style);
-    }
-}
-
-static MetaDrawOpList*
-get_button (MetaFrameStyle *style,
-            MetaButtonType  type,
-            MetaButtonState state)
-{
-  MetaDrawOpList *op_list;
-  MetaFrameStyle *parent;
-  
-  parent = style;
-  op_list = NULL;
-  while (parent && op_list == NULL)
-    {
-      op_list = parent->buttons[type][state];
-      parent = parent->parent;
-    }
-
-  /* We fall back to middle button backgrounds if we don't
-   * have the ones on the sides
-   */
-
-  if (op_list == NULL &&
-      (type == META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND ||
-       type == META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND))
-    return get_button (style, META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND,
-                       state);
-
-  if (op_list == NULL &&
-      (type == META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND ||
-       type == META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND))
-    return get_button (style, META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND,
-                       state);
-  
-  /* We fall back to normal if no prelight */
-  if (op_list == NULL &&
-      state == META_BUTTON_STATE_PRELIGHT)
-    return get_button (style, type, META_BUTTON_STATE_NORMAL);
-
-  return op_list;
-}
-
-gboolean
-meta_frame_style_validate (MetaFrameStyle    *style,
-                           guint              current_theme_version,
-                           GError           **error)
-{
-  int i, j;
-  
-  g_return_val_if_fail (style != NULL, FALSE);
-  g_return_val_if_fail (style->layout != NULL, FALSE);
-
-  for (i = 0; i < META_BUTTON_TYPE_LAST; i++)
-    {
-      /* for now the "positional" buttons are optional */
-      if (i >= META_BUTTON_TYPE_CLOSE)
-        {
-          for (j = 0; j < META_BUTTON_STATE_LAST; j++)
-            {
-              if (get_button (style, i, j) == NULL &&
-                  meta_theme_earliest_version_with_button (i) <= current_theme_version
-                  )
-                {
-                  g_set_error (error, META_THEME_ERROR,
-                               META_THEME_ERROR_FAILED,
-                               _("<button function=\"%s\" state=\"%s\" draw_ops=\"whatever\"/> must be specified for this frame style"),
-                               meta_button_type_to_string (i),
-                               meta_button_state_to_string (j));
-                  return FALSE;
-                }
-            }
-        }
-    }
-  
-  return TRUE;
-}
-
-static void
-button_rect (MetaButtonType           type,
-             const MetaFrameGeometry *fgeom,
-             int                      middle_background_offset,
-             GdkRectangle            *rect)
-{
-  switch (type)
-    {
-    case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
-      *rect = fgeom->left_left_background;
-      break;
-
-    case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND:
-      *rect = fgeom->left_middle_backgrounds[middle_background_offset];
-      break;
-      
-    case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
-      *rect = fgeom->left_right_background;
-      break;
-      
-    case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
-      *rect = fgeom->right_left_background;
-      break;
-      
-    case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND:
-      *rect = fgeom->right_middle_backgrounds[middle_background_offset];
-      break;
-      
-    case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND:
-      *rect = fgeom->right_right_background;
-      break;
-      
-    case META_BUTTON_TYPE_CLOSE:
-      *rect = fgeom->close_rect.visible;
-      break;
-
-    case META_BUTTON_TYPE_SHADE:
-      *rect = fgeom->shade_rect.visible;
-      break;
-
-    case META_BUTTON_TYPE_UNSHADE:
-      *rect = fgeom->unshade_rect.visible;
-      break;
-
-    case META_BUTTON_TYPE_ABOVE:
-      *rect = fgeom->above_rect.visible;
-      break;
-
-    case META_BUTTON_TYPE_UNABOVE:
-      *rect = fgeom->unabove_rect.visible;
-      break;
-
-    case META_BUTTON_TYPE_STICK:
-      *rect = fgeom->stick_rect.visible;
-      break;
-
-    case META_BUTTON_TYPE_UNSTICK:
-      *rect = fgeom->unstick_rect.visible;
-      break;
-
-    case META_BUTTON_TYPE_MAXIMIZE:
-      *rect = fgeom->max_rect.visible;
-      break;
-
-    case META_BUTTON_TYPE_MINIMIZE:
-      *rect = fgeom->min_rect.visible;
-      break;
-
-    case META_BUTTON_TYPE_MENU:
-      *rect = fgeom->menu_rect.visible;
-      break;
-      
-    case META_BUTTON_TYPE_LAST:
-      g_assert_not_reached ();
-      break;
-    }
-}
-
-void
-meta_frame_style_draw_with_style (MetaFrameStyle          *style,
-                                  GtkStyle                *style_gtk,
-                                  GtkWidget               *widget,
-                                  GdkDrawable             *drawable,
-                                  int                      x_offset,
-                                  int                      y_offset,
-                                  const GdkRectangle      *clip,
-                                  const MetaFrameGeometry *fgeom,
-                                  int                      client_width,
-                                  int                      client_height,
-                                  PangoLayout             *title_layout,
-                                  int                      text_height,
-                                  MetaButtonState          button_states[META_BUTTON_TYPE_LAST],
-                                  GdkPixbuf               *mini_icon,
-                                  GdkPixbuf               *icon)
-{
-  int i, j;
-  GdkRectangle titlebar_rect;
-  GdkRectangle left_titlebar_edge;
-  GdkRectangle right_titlebar_edge;
-  GdkRectangle bottom_titlebar_edge;
-  GdkRectangle top_titlebar_edge;
-  GdkRectangle left_edge, right_edge, bottom_edge;
-  PangoRectangle extents;
-  MetaDrawInfo draw_info;
-  
-  g_return_if_fail (style_gtk->colormap == gdk_drawable_get_colormap (drawable));
-
-  titlebar_rect.x = 0;
-  titlebar_rect.y = 0;
-  titlebar_rect.width = fgeom->width;
-  titlebar_rect.height = fgeom->top_height;
-
-  left_titlebar_edge.x = titlebar_rect.x;
-  left_titlebar_edge.y = titlebar_rect.y + fgeom->top_titlebar_edge;
-  left_titlebar_edge.width = fgeom->left_titlebar_edge;
-  left_titlebar_edge.height = titlebar_rect.height - fgeom->top_titlebar_edge - fgeom->bottom_titlebar_edge;
-
-  right_titlebar_edge.y = left_titlebar_edge.y;
-  right_titlebar_edge.height = left_titlebar_edge.height;
-  right_titlebar_edge.width = fgeom->right_titlebar_edge;
-  right_titlebar_edge.x = titlebar_rect.x + titlebar_rect.width - right_titlebar_edge.width;
-
-  top_titlebar_edge.x = titlebar_rect.x;
-  top_titlebar_edge.y = titlebar_rect.y;
-  top_titlebar_edge.width = titlebar_rect.width;
-  top_titlebar_edge.height = fgeom->top_titlebar_edge;
-
-  bottom_titlebar_edge.x = titlebar_rect.x;
-  bottom_titlebar_edge.width = titlebar_rect.width;
-  bottom_titlebar_edge.height = fgeom->bottom_titlebar_edge;
-  bottom_titlebar_edge.y = titlebar_rect.y + titlebar_rect.height - bottom_titlebar_edge.height;
-
-  left_edge.x = 0;
-  left_edge.y = fgeom->top_height;
-  left_edge.width = fgeom->left_width;
-  left_edge.height = fgeom->height - fgeom->top_height - fgeom->bottom_height;
-
-  right_edge.x = fgeom->width - fgeom->right_width;
-  right_edge.y = fgeom->top_height;
-  right_edge.width = fgeom->right_width;
-  right_edge.height = fgeom->height - fgeom->top_height - fgeom->bottom_height;
-
-  bottom_edge.x = 0;
-  bottom_edge.y = fgeom->height - fgeom->bottom_height;
-  bottom_edge.width = fgeom->width;
-  bottom_edge.height = fgeom->bottom_height;
-
-  if (title_layout)
-    pango_layout_get_pixel_extents (title_layout,
-                                    NULL, &extents);
-
-  draw_info.mini_icon = mini_icon;
-  draw_info.icon = icon;
-  draw_info.title_layout = title_layout;
-  draw_info.title_layout_width = title_layout ? extents.width : 0;
-  draw_info.title_layout_height = title_layout ? extents.height : 0;
-  draw_info.fgeom = fgeom;
-  
-  /* The enum is in the order the pieces should be rendered. */
-  i = 0;
-  while (i < META_FRAME_PIECE_LAST)
-    {
-      GdkRectangle rect;
-      GdkRectangle combined_clip;
-      
-      switch ((MetaFramePiece) i)
-        {
-        case META_FRAME_PIECE_ENTIRE_BACKGROUND:
-          rect.x = 0;
-          rect.y = 0;
-          rect.width = fgeom->width;
-          rect.height = fgeom->height;
-          break;
-
-        case META_FRAME_PIECE_TITLEBAR:
-          rect = titlebar_rect;
-          break;
-
-        case META_FRAME_PIECE_LEFT_TITLEBAR_EDGE:
-          rect = left_titlebar_edge;
-          break;
-
-        case META_FRAME_PIECE_RIGHT_TITLEBAR_EDGE:
-          rect = right_titlebar_edge;
-          break;
-
-        case META_FRAME_PIECE_TOP_TITLEBAR_EDGE:
-          rect = top_titlebar_edge;
-          break;
-
-        case META_FRAME_PIECE_BOTTOM_TITLEBAR_EDGE:
-          rect = bottom_titlebar_edge;
-          break;
-
-        case META_FRAME_PIECE_TITLEBAR_MIDDLE:
-          rect.x = left_titlebar_edge.x + left_titlebar_edge.width;
-          rect.y = top_titlebar_edge.y + top_titlebar_edge.height;
-          rect.width = titlebar_rect.width - left_titlebar_edge.width -
-            right_titlebar_edge.width;
-          rect.height = titlebar_rect.height - top_titlebar_edge.height - bottom_titlebar_edge.height;
-          break;
-
-        case META_FRAME_PIECE_TITLE:
-          rect = fgeom->title_rect;
-          break;
-
-        case META_FRAME_PIECE_LEFT_EDGE:
-          rect = left_edge;
-          break;
-
-        case META_FRAME_PIECE_RIGHT_EDGE:
-          rect = right_edge;
-          break;
-
-        case META_FRAME_PIECE_BOTTOM_EDGE:
-          rect = bottom_edge;
-          break;
-
-        case META_FRAME_PIECE_OVERLAY:
-          rect.x = 0;
-          rect.y = 0;
-          rect.width = fgeom->width;
-          rect.height = fgeom->height;
-          break;
-
-        case META_FRAME_PIECE_LAST:
-          g_assert_not_reached ();
-          break;
-        }
-
-      rect.x += x_offset;
-      rect.y += y_offset;
-
-      if (clip == NULL)
-        combined_clip = rect;
-      else
-        gdk_rectangle_intersect ((GdkRectangle*) clip, /* const cast */
-                                 &rect,
-                                 &combined_clip);
-
-      if (combined_clip.width > 0 && combined_clip.height > 0)
-        {
-          MetaDrawOpList *op_list;
-          MetaFrameStyle *parent;
-
-          parent = style;
-          op_list = NULL;
-          while (parent && op_list == NULL)
-            {
-              op_list = parent->pieces[i];
-              parent = parent->parent;
-            }
-
-          if (op_list)
-            {
-              MetaRectangle m_rect;
-              m_rect = meta_rect (rect.x, rect.y, rect.width, rect.height);
-              meta_draw_op_list_draw_with_style (op_list,
-                                                 style_gtk,
-                                                 widget,
-                                                 drawable,
-                                                 &combined_clip,
-                                                 &draw_info,
-                                                 m_rect);
-            }
-        }
-
-
-      /* Draw buttons just before overlay */
-      if ((i + 1) == META_FRAME_PIECE_OVERLAY)
-        {
-          int middle_bg_offset;
-
-          middle_bg_offset = 0;
-          j = 0;
-          while (j < META_BUTTON_TYPE_LAST)
-            {
-              button_rect (j, fgeom, middle_bg_offset, &rect);
-              
-              rect.x += x_offset;
-              rect.y += y_offset;
-              
-              if (clip == NULL)
-                combined_clip = rect;
-              else
-                gdk_rectangle_intersect ((GdkRectangle*) clip, /* const cast */
-                                         &rect,
-                                         &combined_clip);
-              
-              if (combined_clip.width > 0 && combined_clip.height > 0)
-                {
-                  MetaDrawOpList *op_list;
-                  
-                  op_list = get_button (style, j, button_states[j]);
-                  
-                  if (op_list)
-                    {
-                      MetaRectangle m_rect;
-                      m_rect = meta_rect (rect.x, rect.y,
-                                          rect.width, rect.height);
-                      meta_draw_op_list_draw_with_style (op_list,
-                                                         style_gtk,
-                                                         widget,
-                                                         drawable,
-                                                         &combined_clip,
-                                                         &draw_info,
-                                                         m_rect);
-                    }
-                }
-
-              /* MIDDLE_BACKGROUND type may get drawn more than once */
-              if ((j == META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND ||
-                   j == META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND) &&
-                  middle_bg_offset < MAX_MIDDLE_BACKGROUNDS)
-                {
-                  ++middle_bg_offset;
-                }
-              else
-                {
-                  middle_bg_offset = 0;
-                  ++j;
-                }
-            }
-        }
-      
-      ++i;
-    }
-}
-
-void
-meta_frame_style_draw (MetaFrameStyle          *style,
-                       GtkWidget               *widget,
-                       GdkDrawable             *drawable,
-                       int                      x_offset,
-                       int                      y_offset,
-                       const GdkRectangle      *clip,
-                       const MetaFrameGeometry *fgeom,
-                       int                      client_width,
-                       int                      client_height,
-                       PangoLayout             *title_layout,
-                       int                      text_height,
-                       MetaButtonState          button_states[META_BUTTON_TYPE_LAST],
-                       GdkPixbuf               *mini_icon,
-                       GdkPixbuf               *icon)
-{
-  meta_frame_style_draw_with_style (style, widget->style, widget,
-                                    drawable, x_offset, y_offset,
-                                    clip, fgeom, client_width, client_height,
-                                    title_layout, text_height,
-                                    button_states, mini_icon, icon);
-}
-
-MetaFrameStyleSet*
-meta_frame_style_set_new (MetaFrameStyleSet *parent)
-{
-  MetaFrameStyleSet *style_set;
-
-  style_set = g_new0 (MetaFrameStyleSet, 1);
-
-  style_set->parent = parent;
-  if (parent)
-    meta_frame_style_set_ref (parent);
-
-  style_set->refcount = 1;
-  
-  return style_set;
-}
-
-static void
-free_focus_styles (MetaFrameStyle *focus_styles[META_FRAME_FOCUS_LAST])
-{
-  int i;
-
-  for (i = 0; i < META_FRAME_FOCUS_LAST; i++)
-    if (focus_styles[i])
-      meta_frame_style_unref (focus_styles[i]);
-}
-
-void
-meta_frame_style_set_ref (MetaFrameStyleSet *style_set)
-{
-  g_return_if_fail (style_set != NULL);
-
-  style_set->refcount += 1;
-}
-
-void
-meta_frame_style_set_unref (MetaFrameStyleSet *style_set)
-{
-  g_return_if_fail (style_set != NULL);
-  g_return_if_fail (style_set->refcount > 0);
-
-  style_set->refcount -= 1;
-
-  if (style_set->refcount == 0)
-    {
-      int i;
-
-      for (i = 0; i < META_FRAME_RESIZE_LAST; i++)
-        {
-          free_focus_styles (style_set->normal_styles[i]);
-          free_focus_styles (style_set->shaded_styles[i]);
-        }
-
-      free_focus_styles (style_set->maximized_styles);
-      free_focus_styles (style_set->maximized_and_shaded_styles);
-
-      if (style_set->parent)
-        meta_frame_style_set_unref (style_set->parent);
-
-      DEBUG_FILL_STRUCT (style_set);
-      g_free (style_set);
-    }
-}
-
-
-static MetaFrameStyle*
-get_style (MetaFrameStyleSet *style_set,
-           MetaFrameState     state,
-           MetaFrameResize    resize,
-           MetaFrameFocus     focus)
-{
-  MetaFrameStyle *style;  
-  
-  style = NULL;
-
-  switch (state)
-    {
-    case META_FRAME_STATE_NORMAL:
-    case META_FRAME_STATE_SHADED:
-      {
-        if (state == META_FRAME_STATE_SHADED)
-          style = style_set->shaded_styles[resize][focus];
-        else
-          style = style_set->normal_styles[resize][focus];
-
-        /* Try parent if we failed here */
-        if (style == NULL && style_set->parent)
-          style = get_style (style_set->parent, state, resize, focus);
-      
-        /* Allow people to omit the vert/horz/none resize modes */
-        if (style == NULL &&
-            resize != META_FRAME_RESIZE_BOTH)
-          style = get_style (style_set, state, META_FRAME_RESIZE_BOTH, focus);
-      }
-      break;
-    default:
-      {
-        MetaFrameStyle **styles;
-
-        styles = NULL;
-      
-        switch (state)
-          {
-          case META_FRAME_STATE_MAXIMIZED:
-            styles = style_set->maximized_styles;
-            break;
-          case META_FRAME_STATE_MAXIMIZED_AND_SHADED:
-            styles = style_set->maximized_and_shaded_styles;
-            break;
-          case META_FRAME_STATE_NORMAL:
-          case META_FRAME_STATE_SHADED:
-          case META_FRAME_STATE_LAST:
-            g_assert_not_reached ();
-            break;
-          }
-
-        style = styles[focus];
-
-        /* Try parent if we failed here */
-        if (style == NULL && style_set->parent)
-          style = get_style (style_set->parent, state, resize, focus);      
-      }
-    }
-
-  return style;
-}
-
-static gboolean
-check_state  (MetaFrameStyleSet *style_set,
-              MetaFrameState     state,
-              GError           **error)
-{
-  int i;
-
-  for (i = 0; i < META_FRAME_FOCUS_LAST; i++)
-    {
-      if (get_style (style_set, state,
-                     META_FRAME_RESIZE_NONE, i) == NULL)
-        {
-          /* Translators: This error occurs when a <frame> tag is missing
-           * in theme XML.  The "<frame ...>" is intended as a noun phrase,
-           * and the "missing" qualifies it.  You should translate "whatever".
-           */
-          g_set_error (error, META_THEME_ERROR,
-                       META_THEME_ERROR_FAILED,
-                       _("Missing <frame state=\"%s\" resize=\"%s\" focus=\"%s\" style=\"whatever\"/>"),
-                       meta_frame_state_to_string (state),
-                       meta_frame_resize_to_string (META_FRAME_RESIZE_NONE),
-                       meta_frame_focus_to_string (i));
-          return FALSE;
-        }
-    }
-
-  return TRUE;
-}
-
-gboolean
-meta_frame_style_set_validate  (MetaFrameStyleSet *style_set,
-                                GError           **error)
-{
-  int i, j;
-  
-  g_return_val_if_fail (style_set != NULL, FALSE);
-
-  for (i = 0; i < META_FRAME_RESIZE_LAST; i++)
-    for (j = 0; j < META_FRAME_FOCUS_LAST; j++)
-      if (get_style (style_set, META_FRAME_STATE_NORMAL, i, j) == NULL)
-        {
-          g_set_error (error, META_THEME_ERROR,
-                       META_THEME_ERROR_FAILED,
-                       _("Missing <frame state=\"%s\" resize=\"%s\" focus=\"%s\" style=\"whatever\"/>"),
-                       meta_frame_state_to_string (META_FRAME_STATE_NORMAL),
-                       meta_frame_resize_to_string (i),
-                       meta_frame_focus_to_string (j));
-          return FALSE;
-        }
-
-  if (!check_state (style_set, META_FRAME_STATE_SHADED, error))
-    return FALSE;
-  
-  if (!check_state (style_set, META_FRAME_STATE_MAXIMIZED, error))
-    return FALSE;
-
-  if (!check_state (style_set, META_FRAME_STATE_MAXIMIZED_AND_SHADED, error))
-    return FALSE;
-  
-  return TRUE;
-}
-
-MetaTheme*
-meta_theme_get_current (void)
-{
-  return meta_current_theme;
-}
-
-void
-meta_theme_set_current (const char *name,
-                        gboolean    force_reload)
-{
-  MetaTheme *new_theme;
-  GError *err;
-
-  meta_topic (META_DEBUG_THEMES, "Setting current theme to \"%s\"\n", name);
-  
-  if (!force_reload &&
-      meta_current_theme &&
-      strcmp (name, meta_current_theme->name) == 0)
-    return;
-  
-  err = NULL;
-  new_theme = meta_theme_load (name, &err);
-
-  if (new_theme == NULL)
-    {
-      meta_warning (_("Failed to load theme \"%s\": %s\n"),
-                    name, err->message);
-      g_error_free (err);
-    }
-  else
-    {
-      if (meta_current_theme)
-        meta_theme_free (meta_current_theme);
-
-      meta_current_theme = new_theme;
-
-      meta_topic (META_DEBUG_THEMES, "New theme is \"%s\"\n", meta_current_theme->name);
-    }
-}
-
-MetaTheme*
-meta_theme_new (void)
-{
-  MetaTheme *theme;
-
-  theme = g_new0 (MetaTheme, 1);
-
-  theme->images_by_filename =
-    g_hash_table_new_full (g_str_hash,
-                           g_str_equal,
-                           g_free,
-                           (GDestroyNotify) g_object_unref);
-  
-  theme->layouts_by_name =
-    g_hash_table_new_full (g_str_hash,
-                           g_str_equal,
-                           g_free,
-                           (GDestroyNotify) meta_frame_layout_unref);
-
-  theme->draw_op_lists_by_name =
-    g_hash_table_new_full (g_str_hash,
-                           g_str_equal,
-                           g_free,
-                           (GDestroyNotify) meta_draw_op_list_unref);
-
-  theme->styles_by_name =
-    g_hash_table_new_full (g_str_hash,
-                           g_str_equal,
-                           g_free,
-                           (GDestroyNotify) meta_frame_style_unref);
-
-  theme->style_sets_by_name =
-    g_hash_table_new_full (g_str_hash,
-                           g_str_equal,
-                           g_free,
-                           (GDestroyNotify) meta_frame_style_set_unref);
-  
-  /* Create our variable quarks so we can look up variables without
-     having to strcmp for the names */
-  theme->quark_width = g_quark_from_static_string ("width");
-  theme->quark_height = g_quark_from_static_string ("height");
-  theme->quark_object_width = g_quark_from_static_string ("object_width");
-  theme->quark_object_height = g_quark_from_static_string ("object_height");
-  theme->quark_left_width = g_quark_from_static_string ("left_width");
-  theme->quark_right_width = g_quark_from_static_string ("right_width");
-  theme->quark_top_height = g_quark_from_static_string ("top_height");
-  theme->quark_bottom_height = g_quark_from_static_string ("bottom_height");
-  theme->quark_mini_icon_width = g_quark_from_static_string ("mini_icon_width");
-  theme->quark_mini_icon_height = g_quark_from_static_string ("mini_icon_height");
-  theme->quark_icon_width = g_quark_from_static_string ("icon_width");
-  theme->quark_icon_height = g_quark_from_static_string ("icon_height");
-  theme->quark_title_width = g_quark_from_static_string ("title_width");
-  theme->quark_title_height = g_quark_from_static_string ("title_height");
-  return theme;
-}
-
-
-void
-meta_theme_free (MetaTheme *theme)
-{
-  int i;
-
-  g_return_if_fail (theme != NULL);
-
-  g_free (theme->name);
-  g_free (theme->dirname);
-  g_free (theme->filename);
-  g_free (theme->readable_name);
-  g_free (theme->date);
-  g_free (theme->description);
-  g_free (theme->author);
-  g_free (theme->copyright);
-
-  /* be more careful when destroying the theme hash tables,
-     since they are only constructed as needed, and may be NULL. */
-  if (theme->integer_constants)
-    g_hash_table_destroy (theme->integer_constants);
-  if (theme->images_by_filename)
-    g_hash_table_destroy (theme->images_by_filename);
-  if (theme->layouts_by_name)
-    g_hash_table_destroy (theme->layouts_by_name);
-  if (theme->draw_op_lists_by_name)  
-    g_hash_table_destroy (theme->draw_op_lists_by_name);
-  if (theme->styles_by_name)  
-    g_hash_table_destroy (theme->styles_by_name);
-  if (theme->style_sets_by_name)  
-    g_hash_table_destroy (theme->style_sets_by_name);
-
-  for (i = 0; i < META_FRAME_TYPE_LAST; i++)
-    if (theme->style_sets_by_type[i])
-      meta_frame_style_set_unref (theme->style_sets_by_type[i]);
-
-  DEBUG_FILL_STRUCT (theme);
-  g_free (theme);
-}
-
-gboolean
-meta_theme_validate (MetaTheme *theme,
-                     GError   **error)
-{
-  int i;
-  
-  g_return_val_if_fail (theme != NULL, FALSE);
-
-  /* FIXME what else should be checked? */
-
-  g_assert (theme->name);
-  
-  if (theme->readable_name == NULL)
-    {
-      /* Translators: This error means that a necessary XML tag (whose name
-       * is given in angle brackets) was not found in a given theme (whose
-       * name is given second, in quotation marks).
-       */
-      g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FAILED,
-                   _("No <%s> set for theme \"%s\""), "name", theme->name);
-      return FALSE;
-    }
-
-  if (theme->author == NULL)
-    {
-      g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FAILED,
-                   _("No <%s> set for theme \"%s\""), "author", theme->name);
-      return FALSE;
-    }
-
-  if (theme->date == NULL)
-    {
-      g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FAILED,
-                   _("No <%s> set for theme \"%s\""), "date", theme->name);
-      return FALSE;
-    }
-
-  if (theme->description == NULL)
-    {
-      g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FAILED,
-                   _("No <%s> set for theme \"%s\""), "description", theme->name);
-      return FALSE;
-    }
-
-  if (theme->copyright == NULL)
-    {
-      g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FAILED,
-                   _("No <%s> set for theme \"%s\""), "copyright", theme->name);
-      return FALSE;
-    }
-
-  for (i = 0; i < (int)META_FRAME_TYPE_LAST; i++)
-    if (theme->style_sets_by_type[i] == NULL)
-      {
-        g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FAILED,
-                     _("No frame style set for window type \"%s\" in theme \"%s\", add a <window type=\"%s\" style_set=\"whatever\"/> element"),
-                     meta_frame_type_to_string (i),
-                     theme->name,
-                     meta_frame_type_to_string (i));
-        
-        return FALSE;          
-      }
-
-  return TRUE;
-}
-
-GdkPixbuf*
-meta_theme_load_image (MetaTheme  *theme,
-                       const char *filename,
-                       guint size_of_theme_icons,
-                       GError    **error)
-{
-  GdkPixbuf *pixbuf;
-
-  pixbuf = g_hash_table_lookup (theme->images_by_filename,
-                                filename);
-
-  if (pixbuf == NULL)
-    {
-       
-      if (g_str_has_prefix (filename, "theme:") &&
-          META_THEME_ALLOWS (theme, META_THEME_IMAGES_FROM_ICON_THEMES))
-        {
-          pixbuf = gtk_icon_theme_load_icon (
-              gtk_icon_theme_get_default (),
-              filename+6,
-              size_of_theme_icons,
-              0,
-              error);
-          if (pixbuf == NULL) return NULL;
-         }
-      else
-        {
-          char *full_path;
-          full_path = g_build_filename (theme->dirname, filename, NULL);
-      
-          pixbuf = gdk_pixbuf_new_from_file (full_path, error);
-          if (pixbuf == NULL)
-            {
-              g_free (full_path);
-              return NULL;
-            }
-      
-          g_free (full_path);
-        }      
-      g_hash_table_replace (theme->images_by_filename,
-                            g_strdup (filename),
-                            pixbuf);
-    }
-
-  g_assert (pixbuf);
-  
-  g_object_ref (G_OBJECT (pixbuf));
-
-  return pixbuf;
-}
-
-static MetaFrameStyle*
-theme_get_style (MetaTheme     *theme,
-                 MetaFrameType  type,
-                 MetaFrameFlags flags)
-{
-  MetaFrameState state;
-  MetaFrameResize resize;
-  MetaFrameFocus focus;
-  MetaFrameStyle *style;
-  MetaFrameStyleSet *style_set;
-
-  style_set = theme->style_sets_by_type[type];
-
-  /* Right now the parser forces a style set for all types,
-   * but this fallback code is here in case I take that out.
-   */
-  if (style_set == NULL)
-    style_set = theme->style_sets_by_type[META_FRAME_TYPE_NORMAL];
-  if (style_set == NULL)
-    return NULL;
-  
-  switch (flags & (META_FRAME_MAXIMIZED | META_FRAME_SHADED))
-    {
-    case 0:
-      state = META_FRAME_STATE_NORMAL;
-      break;
-    case META_FRAME_MAXIMIZED:
-      state = META_FRAME_STATE_MAXIMIZED;
-      break;
-    case META_FRAME_SHADED:
-      state = META_FRAME_STATE_SHADED;
-      break;
-    case (META_FRAME_MAXIMIZED | META_FRAME_SHADED):
-      state = META_FRAME_STATE_MAXIMIZED_AND_SHADED;
-      break;
-    default:
-      g_assert_not_reached ();
-      state = META_FRAME_STATE_LAST; /* compiler */
-      break;
-    }
-
-  switch (flags & (META_FRAME_ALLOWS_VERTICAL_RESIZE | META_FRAME_ALLOWS_HORIZONTAL_RESIZE))
-    {
-    case 0:
-      resize = META_FRAME_RESIZE_NONE;
-      break;
-    case META_FRAME_ALLOWS_VERTICAL_RESIZE:
-      resize = META_FRAME_RESIZE_VERTICAL;
-      break;
-    case META_FRAME_ALLOWS_HORIZONTAL_RESIZE:
-      resize = META_FRAME_RESIZE_HORIZONTAL;
-      break;
-    case (META_FRAME_ALLOWS_VERTICAL_RESIZE | META_FRAME_ALLOWS_HORIZONTAL_RESIZE):
-      resize = META_FRAME_RESIZE_BOTH;
-      break;
-    default:
-      g_assert_not_reached ();
-      resize = META_FRAME_RESIZE_LAST; /* compiler */
-      break;
-    }
-  
-  /* re invert the styles used for focus/unfocussed while flashing a frame */
-  if (((flags & META_FRAME_HAS_FOCUS) && !(flags & META_FRAME_IS_FLASHING))
-      || (!(flags & META_FRAME_HAS_FOCUS) && (flags & META_FRAME_IS_FLASHING)))
-    focus = META_FRAME_FOCUS_YES;
-  else
-    focus = META_FRAME_FOCUS_NO;
-
-  style = get_style (style_set, state, resize, focus);
-
-  return style;
-}
-
-MetaFrameStyle*
-meta_theme_get_frame_style (MetaTheme     *theme,
-                            MetaFrameType  type,
-                            MetaFrameFlags flags)
-{
-  MetaFrameStyle *style;
-
-  g_return_val_if_fail (type < META_FRAME_TYPE_LAST, NULL);
-  
-  style = theme_get_style (theme, type, flags);
-
-  return style;
-}
-
-double
-meta_theme_get_title_scale (MetaTheme     *theme,
-                            MetaFrameType  type,
-                            MetaFrameFlags flags)
-{
-  MetaFrameStyle *style;
-
-  g_return_val_if_fail (type < META_FRAME_TYPE_LAST, 1.0);
-  
-  style = theme_get_style (theme, type, flags);
-  
-  /* Parser is not supposed to allow this currently */
-  if (style == NULL)
-    return 1.0;
-
-  return style->layout->title_scale;
-}
-
-void
-meta_theme_draw_frame_with_style (MetaTheme              *theme,
-                                  GtkStyle               *style_gtk,
-                                  GtkWidget              *widget,
-                                  GdkDrawable            *drawable,
-                                  const GdkRectangle     *clip,
-                                  int                     x_offset,
-                                  int                     y_offset,
-                                  MetaFrameType           type,
-                                  MetaFrameFlags          flags,
-                                  int                     client_width,
-                                  int                     client_height,
-                                  PangoLayout            *title_layout,
-                                  int                     text_height,
-                                  const MetaButtonLayout *button_layout,
-                                  MetaButtonState         button_states[META_BUTTON_TYPE_LAST],
-                                  GdkPixbuf              *mini_icon,
-                                  GdkPixbuf              *icon)
-{
-  MetaFrameGeometry fgeom;
-  MetaFrameStyle *style;
-
-  g_return_if_fail (type < META_FRAME_TYPE_LAST);
-  
-  style = theme_get_style (theme, type, flags);
-  
-  /* Parser is not supposed to allow this currently */
-  if (style == NULL)
-    return;
-  
-  meta_frame_layout_calc_geometry (style->layout,
-                                   text_height,
-                                   flags,
-                                   client_width, client_height,
-                                   button_layout,
-                                   &fgeom,
-                                   theme);  
-
-  meta_frame_style_draw_with_style (style,
-                                    style_gtk,
-                                    widget,
-                                    drawable,
-                                    x_offset, y_offset,
-                                    clip,
-                                    &fgeom,
-                                    client_width, client_height,
-                                    title_layout,
-                                    text_height,
-                                    button_states,
-                                    mini_icon, icon);
-}
-
-void
-meta_theme_draw_frame (MetaTheme              *theme,
-                       GtkWidget              *widget,
-                       GdkDrawable            *drawable,
-                       const GdkRectangle     *clip,
-                       int                     x_offset,
-                       int                     y_offset,
-                       MetaFrameType           type,
-                       MetaFrameFlags          flags,
-                       int                     client_width,
-                       int                     client_height,
-                       PangoLayout            *title_layout,
-                       int                     text_height,
-                       const MetaButtonLayout *button_layout,
-                       MetaButtonState         button_states[META_BUTTON_TYPE_LAST],
-                       GdkPixbuf              *mini_icon,
-                       GdkPixbuf              *icon)
-{
-  meta_theme_draw_frame_with_style (theme, widget->style, widget,
-                                    drawable, clip, x_offset, y_offset, type,flags,
-                                    client_width, client_height,
-                                    title_layout, text_height,
-                                    button_layout, button_states,
-                                    mini_icon, icon);
-}
-
-void
-meta_theme_draw_frame_by_name (MetaTheme              *theme,
-                               GtkWidget              *widget,
-                               GdkDrawable            *drawable,
-                               const GdkRectangle     *clip,
-                               int                     x_offset,
-                               int                     y_offset,
-                               const gchar             *style_name,
-                               MetaFrameFlags          flags,
-                               int                     client_width,
-                               int                     client_height,
-                               PangoLayout            *title_layout,
-                               int                     text_height,
-                               const MetaButtonLayout *button_layout,
-                               MetaButtonState         button_states[META_BUTTON_TYPE_LAST],
-                               GdkPixbuf              *mini_icon,
-                               GdkPixbuf              *icon)
-{
-  MetaFrameGeometry fgeom;
-  MetaFrameStyle *style;
-
-  style = meta_theme_lookup_style (theme, style_name);
-  
-  /* Parser is not supposed to allow this currently */
-  if (style == NULL)
-    return;
-  
-  meta_frame_layout_calc_geometry (style->layout,
-                                   text_height,
-                                   flags,
-                                   client_width, client_height,
-                                   button_layout,
-                                   &fgeom,
-                                   theme);  
-
-  meta_frame_style_draw (style,
-                         widget,
-                         drawable,
-                         x_offset, y_offset,
-                         clip,
-                         &fgeom,
-                         client_width, client_height,
-                         title_layout,
-                         text_height,
-                         button_states,
-                         mini_icon, icon);
-}
-
-void
-meta_theme_get_frame_borders (MetaTheme      *theme,
-                              MetaFrameType   type,
-                              int             text_height,
-                              MetaFrameFlags  flags,
-                              int            *top_height,
-                              int            *bottom_height,
-                              int            *left_width,
-                              int            *right_width)
-{
-  MetaFrameStyle *style;
-
-  g_return_if_fail (type < META_FRAME_TYPE_LAST);
-  
-  if (top_height)
-    *top_height = 0;
-  if (bottom_height)
-    *bottom_height = 0;
-  if (left_width)
-    *left_width = 0;
-  if (right_width)
-    *right_width = 0;
-  
-  style = theme_get_style (theme, type, flags);
-  
-  /* Parser is not supposed to allow this currently */
-  if (style == NULL)
-    return;
-
-  meta_frame_layout_get_borders (style->layout,
-                                 text_height,
-                                 flags,
-                                 top_height, bottom_height,
-                                 left_width, right_width);
-}
-
-void
-meta_theme_calc_geometry (MetaTheme              *theme,
-                          MetaFrameType           type,
-                          int                     text_height,
-                          MetaFrameFlags          flags,
-                          int                     client_width,
-                          int                     client_height,
-                          const MetaButtonLayout *button_layout,
-                          MetaFrameGeometry      *fgeom)
-{
-  MetaFrameStyle *style;
-
-  g_return_if_fail (type < META_FRAME_TYPE_LAST);
-  
-  style = theme_get_style (theme, type, flags);
-  
-  /* Parser is not supposed to allow this currently */
-  if (style == NULL)
-    return;
-
-  meta_frame_layout_calc_geometry (style->layout,
-                                   text_height,
-                                   flags,
-                                   client_width, client_height,
-                                   button_layout,
-                                   fgeom,
-                                   theme);
-}
-
-MetaFrameLayout*
-meta_theme_lookup_layout (MetaTheme         *theme,
-                          const char        *name)
-{
-  return g_hash_table_lookup (theme->layouts_by_name, name);
-}
-
-void
-meta_theme_insert_layout (MetaTheme         *theme,
-                          const char        *name,
-                          MetaFrameLayout   *layout)
-{
-  meta_frame_layout_ref (layout);
-  g_hash_table_replace (theme->layouts_by_name, g_strdup (name), layout);
-}
-
-MetaDrawOpList*
-meta_theme_lookup_draw_op_list (MetaTheme         *theme,
-                                const char        *name)
-{
-  return g_hash_table_lookup (theme->draw_op_lists_by_name, name);
-}
-
-void
-meta_theme_insert_draw_op_list (MetaTheme         *theme,
-                                const char        *name,
-                                MetaDrawOpList    *op_list)
-{
-  meta_draw_op_list_ref (op_list);
-  g_hash_table_replace (theme->draw_op_lists_by_name, g_strdup (name), op_list);
-}
-
-MetaFrameStyle*
-meta_theme_lookup_style (MetaTheme         *theme,
-                         const char        *name)
-{
-  return g_hash_table_lookup (theme->styles_by_name, name);
-}
-
-void
-meta_theme_insert_style (MetaTheme         *theme,
-                         const char        *name,
-                         MetaFrameStyle    *style)
-{
-  meta_frame_style_ref (style);
-  g_hash_table_replace (theme->styles_by_name, g_strdup (name), style);
-}
-
-MetaFrameStyleSet*
-meta_theme_lookup_style_set (MetaTheme         *theme,
-                             const char        *name)
-{
-  return g_hash_table_lookup (theme->style_sets_by_name, name);
-}
-
-void
-meta_theme_insert_style_set    (MetaTheme         *theme,
-                                const char        *name,
-                                MetaFrameStyleSet *style_set)
-{
-  meta_frame_style_set_ref (style_set);
-  g_hash_table_replace (theme->style_sets_by_name, g_strdup (name), style_set);
-}
-
-static gboolean
-first_uppercase (const char *str)
-{  
-  return g_ascii_isupper (*str);
-}
-
-gboolean
-meta_theme_define_int_constant (MetaTheme   *theme,
-                                const char  *name,
-                                int          value,
-                                GError     **error)
-{
-  if (theme->integer_constants == NULL)
-    theme->integer_constants = g_hash_table_new_full (g_str_hash,
-                                                      g_str_equal,
-                                                      g_free,
-                                                      NULL);
-
-  if (!first_uppercase (name))
-    {
-      g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FAILED,
-                   _("User-defined constants must begin with a capital letter; \"%s\" does not"),
-                   name);
-      return FALSE;
-    }
-  
-  if (g_hash_table_lookup_extended (theme->integer_constants, name, NULL, NULL))
-    {
-      g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FAILED,
-                   _("Constant \"%s\" has already been defined"),
-                   name);
-      
-      return FALSE;
-    }
-
-  g_hash_table_insert (theme->integer_constants,
-                       g_strdup (name),
-                       GINT_TO_POINTER (value));
-
-  return TRUE;
-}
-
-gboolean
-meta_theme_lookup_int_constant (MetaTheme   *theme,
-                                const char  *name,
-                                int         *value)
-{
-  gpointer old_value;
-
-  *value = 0;
-  
-  if (theme->integer_constants == NULL)
-    return FALSE;
-  
-  if (g_hash_table_lookup_extended (theme->integer_constants,
-                                    name, NULL, &old_value))
-    {
-      *value = GPOINTER_TO_INT (old_value);
-      return TRUE;
-    }
-  else
-    {
-      return FALSE;
-    }
-}
-
-gboolean
-meta_theme_define_float_constant (MetaTheme   *theme,
-                                  const char  *name,
-                                  double       value,
-                                  GError     **error)
-{
-  double *d;
-  
-  if (theme->float_constants == NULL)
-    theme->float_constants = g_hash_table_new_full (g_str_hash,
-                                                    g_str_equal,
-                                                    g_free,
-                                                    g_free);
-
-  if (!first_uppercase (name))
-    {
-      g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FAILED,
-                   _("User-defined constants must begin with a capital letter; \"%s\" does not"),
-                   name);
-      return FALSE;
-    }
-  
-  if (g_hash_table_lookup_extended (theme->float_constants, name, NULL, NULL))
-    {
-      g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FAILED,
-                   _("Constant \"%s\" has already been defined"),
-                   name);
-      
-      return FALSE;
-    }
-
-  d = g_new (double, 1);
-  *d = value;
-  
-  g_hash_table_insert (theme->float_constants,
-                       g_strdup (name), d);
-
-  return TRUE;
-}
-
-gboolean
-meta_theme_lookup_float_constant (MetaTheme   *theme,
-                                  const char  *name,
-                                  double      *value)
-{
-  double *d;
-
-  *value = 0.0;
-  
-  if (theme->float_constants == NULL)
-    return FALSE;
-
-  d = g_hash_table_lookup (theme->float_constants, name);
-
-  if (d)
-    {
-      *value = *d;
-      return TRUE;
-    }
-  else
-    {
-      return FALSE;
-    }
-}
-
-gboolean
-meta_theme_define_color_constant (MetaTheme   *theme,
-                                  const char  *name,
-                                  const char  *value,
-                                  GError     **error)
-{
-  if (theme->color_constants == NULL)
-    theme->color_constants = g_hash_table_new_full (g_str_hash,
-                                                    g_str_equal,
-                                                    g_free,
-                                                    NULL);
-
-  if (!first_uppercase (name))
-    {
-      g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FAILED,
-                   _("User-defined constants must begin with a capital letter; \"%s\" does not"),
-                   name);
-      return FALSE;
-    }
-  
-  if (g_hash_table_lookup_extended (theme->color_constants, name, NULL, NULL))
-    {
-      g_set_error (error, META_THEME_ERROR, META_THEME_ERROR_FAILED,
-                   _("Constant \"%s\" has already been defined"),
-                   name);
-      
-      return FALSE;
-    }
-
-  g_hash_table_insert (theme->color_constants,
-                       g_strdup (name),
-                       g_strdup (value));
-
-  return TRUE;
-}
-
-/**
- * Looks up a colour constant.
- *
- * \param theme  the theme containing the constant
- * \param name  the name of the constant
- * \param value  [out] the string representation of the colour, or NULL if it
- *               doesn't exist
- * \return  TRUE if it exists, FALSE otherwise
- */
-gboolean
-meta_theme_lookup_color_constant (MetaTheme   *theme,
-                                  const char  *name,
-                                  char       **value)
-{
-  char *result;
-
-  *value = NULL;
-  
-  if (theme->color_constants == NULL)
-    return FALSE;
-
-  result = g_hash_table_lookup (theme->color_constants, name);
-
-  if (result)
-    {
-      *value = result;
-      return TRUE;
-    }
-  else
-    {
-      return FALSE;
-    }
-}
-
-
-PangoFontDescription*
-meta_gtk_widget_get_font_desc (GtkWidget *widget,
-                               double     scale,
-			       const PangoFontDescription *override)
-{
-  PangoFontDescription *font_desc;
-  
-  g_return_val_if_fail (GTK_WIDGET_REALIZED (widget), NULL);
-
-  font_desc = pango_font_description_copy (widget->style->font_desc);
-
-  if (override)
-    pango_font_description_merge (font_desc, override, TRUE);
-
-  pango_font_description_set_size (font_desc,
-                                   MAX (pango_font_description_get_size (font_desc) * scale, 1));
-
-  return font_desc;
-}
-
-/**
- * Returns the height of the letters in a particular font.
- *
- * \param font_desc  the font
- * \param context  the context of the font
- * \return  the height of the letters
- */
-int
-meta_pango_font_desc_get_text_height (const PangoFontDescription *font_desc,
-                                      PangoContext         *context)
-{
-  PangoFontMetrics *metrics;
-  PangoLanguage *lang;
-  int retval;
-
-  lang = pango_context_get_language (context);
-  metrics = pango_context_get_metrics (context, font_desc, lang);
-
-  retval = PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) + 
-                         pango_font_metrics_get_descent (metrics));
-  
-  pango_font_metrics_unref (metrics);
-  
-  return retval;
-}
-
-MetaGtkColorComponent
-meta_color_component_from_string (const char *str)
-{
-  if (strcmp ("fg", str) == 0)
-    return META_GTK_COLOR_FG;
-  else if (strcmp ("bg", str) == 0)
-    return META_GTK_COLOR_BG;
-  else if (strcmp ("light", str) == 0)
-    return META_GTK_COLOR_LIGHT;
-  else if (strcmp ("dark", str) == 0)
-    return META_GTK_COLOR_DARK;
-  else if (strcmp ("mid", str) == 0)
-    return META_GTK_COLOR_MID;
-  else if (strcmp ("text", str) == 0)
-    return META_GTK_COLOR_TEXT;
-  else if (strcmp ("base", str) == 0)
-    return META_GTK_COLOR_BASE;
-  else if (strcmp ("text_aa", str) == 0)
-    return META_GTK_COLOR_TEXT_AA;
-  else
-    return META_GTK_COLOR_LAST;
-}
-
-const char*
-meta_color_component_to_string (MetaGtkColorComponent component)
-{
-  switch (component)
-    {
-    case META_GTK_COLOR_FG:
-      return "fg";
-    case META_GTK_COLOR_BG:
-      return "bg";
-    case META_GTK_COLOR_LIGHT:
-      return "light";
-    case META_GTK_COLOR_DARK:
-      return "dark";
-    case META_GTK_COLOR_MID:
-      return "mid";
-    case META_GTK_COLOR_TEXT:
-      return "text";
-    case META_GTK_COLOR_BASE:
-      return "base";
-    case META_GTK_COLOR_TEXT_AA:
-      return "text_aa";
-    case META_GTK_COLOR_LAST:
-      break;
-    }
-
-  return "<unknown>";
-}
-
-MetaButtonState
-meta_button_state_from_string (const char *str)
-{
-  if (strcmp ("normal", str) == 0)
-    return META_BUTTON_STATE_NORMAL;
-  else if (strcmp ("pressed", str) == 0)
-    return META_BUTTON_STATE_PRESSED;
-  else if (strcmp ("prelight", str) == 0)
-    return META_BUTTON_STATE_PRELIGHT;
-  else
-    return META_BUTTON_STATE_LAST;
-}
-
-const char*
-meta_button_state_to_string (MetaButtonState state)
-{
-  switch (state)
-    {
-    case META_BUTTON_STATE_NORMAL:
-      return "normal";
-    case META_BUTTON_STATE_PRESSED:
-      return "pressed";
-    case META_BUTTON_STATE_PRELIGHT:
-      return "prelight";
-    case META_BUTTON_STATE_LAST:
-      break;
-    }
-
-  return "<unknown>";
-}
-
-MetaButtonType
-meta_button_type_from_string (const char *str, MetaTheme *theme)
-{
-  if (META_THEME_ALLOWS(theme, META_THEME_SHADE_STICK_ABOVE_BUTTONS))
-    {
-      if (strcmp ("shade", str) == 0)
-        return META_BUTTON_TYPE_SHADE;
-      else if (strcmp ("above", str) == 0)
-        return META_BUTTON_TYPE_ABOVE;
-      else if (strcmp ("stick", str) == 0)
-        return META_BUTTON_TYPE_STICK;
-      else if (strcmp ("unshade", str) == 0)
-        return META_BUTTON_TYPE_UNSHADE;
-      else if (strcmp ("unabove", str) == 0)
-        return META_BUTTON_TYPE_UNABOVE;
-      else if (strcmp ("unstick", str) == 0)
-        return META_BUTTON_TYPE_UNSTICK;
-     }
-
-  if (strcmp ("close", str) == 0)
-    return META_BUTTON_TYPE_CLOSE;
-  else if (strcmp ("maximize", str) == 0)
-    return META_BUTTON_TYPE_MAXIMIZE;
-  else if (strcmp ("minimize", str) == 0)
-    return META_BUTTON_TYPE_MINIMIZE;
-  else if (strcmp ("menu", str) == 0)
-    return META_BUTTON_TYPE_MENU;
-  else if (strcmp ("left_left_background", str) == 0)
-    return META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND;
-  else if (strcmp ("left_middle_background", str) == 0)
-    return META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND;
-  else if (strcmp ("left_right_background", str) == 0)
-    return META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND;
-  else if (strcmp ("right_left_background", str) == 0)
-    return META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND;
-  else if (strcmp ("right_middle_background", str) == 0)
-    return META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND;
-  else if (strcmp ("right_right_background", str) == 0)
-    return META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND;
-  else
-    return META_BUTTON_TYPE_LAST;
-}
-
-const char*
-meta_button_type_to_string (MetaButtonType type)
-{
-  switch (type)
-    {
-    case META_BUTTON_TYPE_CLOSE:
-      return "close";
-    case META_BUTTON_TYPE_MAXIMIZE:
-      return "maximize";
-    case META_BUTTON_TYPE_MINIMIZE:
-      return "minimize";
-    case META_BUTTON_TYPE_SHADE:
-     return "shade";
-    case META_BUTTON_TYPE_ABOVE:
-      return "above";
-    case META_BUTTON_TYPE_STICK:
-      return "stick";
-    case META_BUTTON_TYPE_UNSHADE:
-      return "unshade";
-    case META_BUTTON_TYPE_UNABOVE:
-      return "unabove";
-    case META_BUTTON_TYPE_UNSTICK:
-      return "unstick";
-     case META_BUTTON_TYPE_MENU:
-      return "menu";
-    case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
-      return "left_left_background";
-    case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND:
-      return "left_middle_background";
-    case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
-      return "left_right_background";
-    case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
-      return "right_left_background";
-    case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND:
-      return "right_middle_background";
-    case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND:
-      return "right_right_background";      
-    case META_BUTTON_TYPE_LAST:
-      break;
-    }
-
-  return "<unknown>";
-}
-
-MetaFramePiece
-meta_frame_piece_from_string (const char *str)
-{
-  if (strcmp ("entire_background", str) == 0)
-    return META_FRAME_PIECE_ENTIRE_BACKGROUND;
-  else if (strcmp ("titlebar", str) == 0)
-    return META_FRAME_PIECE_TITLEBAR;
-  else if (strcmp ("titlebar_middle", str) == 0)
-    return META_FRAME_PIECE_TITLEBAR_MIDDLE;
-  else if (strcmp ("left_titlebar_edge", str) == 0)
-    return META_FRAME_PIECE_LEFT_TITLEBAR_EDGE;
-  else if (strcmp ("right_titlebar_edge", str) == 0)
-    return META_FRAME_PIECE_RIGHT_TITLEBAR_EDGE;
-  else if (strcmp ("top_titlebar_edge", str) == 0)
-    return META_FRAME_PIECE_TOP_TITLEBAR_EDGE;
-  else if (strcmp ("bottom_titlebar_edge", str) == 0)
-    return META_FRAME_PIECE_BOTTOM_TITLEBAR_EDGE;
-  else if (strcmp ("title", str) == 0)
-    return META_FRAME_PIECE_TITLE;
-  else if (strcmp ("left_edge", str) == 0)
-    return META_FRAME_PIECE_LEFT_EDGE;
-  else if (strcmp ("right_edge", str) == 0)
-    return META_FRAME_PIECE_RIGHT_EDGE;
-  else if (strcmp ("bottom_edge", str) == 0)
-    return META_FRAME_PIECE_BOTTOM_EDGE;
-  else if (strcmp ("overlay", str) == 0)
-    return META_FRAME_PIECE_OVERLAY;
-  else
-    return META_FRAME_PIECE_LAST;
-}
-
-const char*
-meta_frame_piece_to_string (MetaFramePiece piece)
-{
-  switch (piece)
-    {
-    case META_FRAME_PIECE_ENTIRE_BACKGROUND:
-      return "entire_background";
-    case META_FRAME_PIECE_TITLEBAR:
-      return "titlebar";
-    case META_FRAME_PIECE_TITLEBAR_MIDDLE:
-      return "titlebar_middle";
-    case META_FRAME_PIECE_LEFT_TITLEBAR_EDGE:
-      return "left_titlebar_edge";
-    case META_FRAME_PIECE_RIGHT_TITLEBAR_EDGE:
-      return "right_titlebar_edge";
-    case META_FRAME_PIECE_TOP_TITLEBAR_EDGE:
-      return "top_titlebar_edge";
-    case META_FRAME_PIECE_BOTTOM_TITLEBAR_EDGE:
-      return "bottom_titlebar_edge";
-    case META_FRAME_PIECE_TITLE:
-      return "title";
-    case META_FRAME_PIECE_LEFT_EDGE:
-      return "left_edge";
-    case META_FRAME_PIECE_RIGHT_EDGE:
-      return "right_edge";
-    case META_FRAME_PIECE_BOTTOM_EDGE:
-      return "bottom_edge";
-    case META_FRAME_PIECE_OVERLAY:
-      return "overlay";
-    case META_FRAME_PIECE_LAST:
-      break;
-    }
-
-  return "<unknown>";
-}
-
-MetaFrameState
-meta_frame_state_from_string (const char *str)
-{
-  if (strcmp ("normal", str) == 0)
-    return META_FRAME_STATE_NORMAL;
-  else if (strcmp ("maximized", str) == 0)
-    return META_FRAME_STATE_MAXIMIZED;
-  else if (strcmp ("shaded", str) == 0)
-    return META_FRAME_STATE_SHADED;
-  else if (strcmp ("maximized_and_shaded", str) == 0)
-    return META_FRAME_STATE_MAXIMIZED_AND_SHADED;
-  else
-    return META_FRAME_STATE_LAST;
-}
-
-const char*
-meta_frame_state_to_string (MetaFrameState state)
-{
-  switch (state)
-    {
-    case META_FRAME_STATE_NORMAL:
-      return "normal";
-    case META_FRAME_STATE_MAXIMIZED:
-      return "maximized";
-    case META_FRAME_STATE_SHADED:
-      return "shaded";
-    case META_FRAME_STATE_MAXIMIZED_AND_SHADED:
-      return "maximized_and_shaded";
-    case META_FRAME_STATE_LAST:
-      break;
-    }
-
-  return "<unknown>";
-}
-
-MetaFrameResize
-meta_frame_resize_from_string (const char *str)
-{
-  if (strcmp ("none", str) == 0)
-    return META_FRAME_RESIZE_NONE;
-  else if (strcmp ("vertical", str) == 0)
-    return META_FRAME_RESIZE_VERTICAL;
-  else if (strcmp ("horizontal", str) == 0)
-    return META_FRAME_RESIZE_HORIZONTAL;
-  else if (strcmp ("both", str) == 0)
-    return META_FRAME_RESIZE_BOTH;
-  else
-    return META_FRAME_RESIZE_LAST;
-}
-
-const char*
-meta_frame_resize_to_string (MetaFrameResize resize)
-{
-  switch (resize)
-    {
-    case META_FRAME_RESIZE_NONE:
-      return "none";
-    case META_FRAME_RESIZE_VERTICAL:
-      return "vertical";
-    case META_FRAME_RESIZE_HORIZONTAL:
-      return "horizontal";
-    case META_FRAME_RESIZE_BOTH:
-      return "both";
-    case META_FRAME_RESIZE_LAST:
-      break;
-    }
-
-  return "<unknown>";
-}
-
-MetaFrameFocus
-meta_frame_focus_from_string (const char *str)
-{
-  if (strcmp ("no", str) == 0)
-    return META_FRAME_FOCUS_NO;
-  else if (strcmp ("yes", str) == 0)
-    return META_FRAME_FOCUS_YES;
-  else
-    return META_FRAME_FOCUS_LAST;
-}
-
-const char*
-meta_frame_focus_to_string (MetaFrameFocus focus)
-{
-  switch (focus)
-    {
-    case META_FRAME_FOCUS_NO:
-      return "no";
-    case META_FRAME_FOCUS_YES:
-      return "yes";
-    case META_FRAME_FOCUS_LAST:
-      break;
-    }
-
-  return "<unknown>";
-}
-
-MetaFrameType
-meta_frame_type_from_string (const char *str)
-{
-  if (strcmp ("normal", str) == 0)
-    return META_FRAME_TYPE_NORMAL;
-  else if (strcmp ("dialog", str) == 0)
-    return META_FRAME_TYPE_DIALOG;
-  else if (strcmp ("modal_dialog", str) == 0)
-    return META_FRAME_TYPE_MODAL_DIALOG;
-  else if (strcmp ("utility", str) == 0)
-    return META_FRAME_TYPE_UTILITY;
-  else if (strcmp ("menu", str) == 0)
-    return META_FRAME_TYPE_MENU;
-  else if (strcmp ("border", str) == 0)
-    return META_FRAME_TYPE_BORDER;
-#if 0
-  else if (strcmp ("toolbar", str) == 0)
-    return META_FRAME_TYPE_TOOLBAR;
-#endif
-  else
-    return META_FRAME_TYPE_LAST;
-}
-
-const char*
-meta_frame_type_to_string (MetaFrameType type)
-{
-  switch (type)
-    {
-    case META_FRAME_TYPE_NORMAL:
-      return "normal";
-    case META_FRAME_TYPE_DIALOG:
-      return "dialog";
-    case META_FRAME_TYPE_MODAL_DIALOG:
-      return "modal_dialog";
-    case META_FRAME_TYPE_UTILITY:
-      return "utility";
-    case META_FRAME_TYPE_MENU:
-      return "menu";
-    case META_FRAME_TYPE_BORDER:
-      return "border";
-#if 0
-    case META_FRAME_TYPE_TOOLBAR:
-      return "toolbar";
-#endif
-    case  META_FRAME_TYPE_LAST:
-      break;
-    }
-
-  return "<unknown>";
-}
-
-MetaGradientType
-meta_gradient_type_from_string (const char *str)
-{
-  if (strcmp ("vertical", str) == 0)
-    return META_GRADIENT_VERTICAL;
-  else if (strcmp ("horizontal", str) == 0)
-    return META_GRADIENT_HORIZONTAL;
-  else if (strcmp ("diagonal", str) == 0)
-    return META_GRADIENT_DIAGONAL;
-  else
-    return META_GRADIENT_LAST;
-}
-
-const char*
-meta_gradient_type_to_string (MetaGradientType type)
-{
-  switch (type)
-    {
-    case META_GRADIENT_VERTICAL:
-      return "vertical";
-    case META_GRADIENT_HORIZONTAL:
-      return "horizontal";
-    case META_GRADIENT_DIAGONAL:
-      return "diagonal";
-    case META_GRADIENT_LAST:
-      break;
-    }
-
-  return "<unknown>";
-}
-
-GtkStateType
-meta_gtk_state_from_string (const char *str)
-{
-  if (strcmp ("normal", str) == 0 || strcmp ("NORMAL", str) == 0)
-    return GTK_STATE_NORMAL;
-  else if (strcmp ("prelight", str) == 0 || strcmp ("PRELIGHT", str) == 0)
-    return GTK_STATE_PRELIGHT;
-  else if (strcmp ("active", str) == 0 || strcmp ("ACTIVE", str) == 0)
-    return GTK_STATE_ACTIVE;
-  else if (strcmp ("selected", str) == 0 || strcmp ("SELECTED", str) == 0)
-    return GTK_STATE_SELECTED;
-  else if (strcmp ("insensitive", str) == 0 || strcmp ("INSENSITIVE", str) == 0)
-    return GTK_STATE_INSENSITIVE;
-  else
-    return -1; /* hack */
-}
-
-const char*
-meta_gtk_state_to_string (GtkStateType state)
-{
-  switch (state)
-    {
-    case GTK_STATE_NORMAL:
-      return "NORMAL";
-    case GTK_STATE_PRELIGHT:
-      return "PRELIGHT";
-    case GTK_STATE_ACTIVE:
-      return "ACTIVE";
-    case GTK_STATE_SELECTED:
-      return "SELECTED";
-    case GTK_STATE_INSENSITIVE:
-      return "INSENSITIVE";
-    }
-
-  return "<unknown>";
-}
-
-GtkShadowType
-meta_gtk_shadow_from_string (const char *str)
-{
-  if (strcmp ("none", str) == 0)
-    return GTK_SHADOW_NONE;
-  else if (strcmp ("in", str) == 0)
-    return GTK_SHADOW_IN;
-  else if (strcmp ("out", str) == 0)
-    return GTK_SHADOW_OUT;
-  else if (strcmp ("etched_in", str) == 0)
-    return GTK_SHADOW_ETCHED_IN;
-  else if (strcmp ("etched_out", str) == 0)
-    return GTK_SHADOW_ETCHED_OUT;
-  else
-    return -1;
-}
-
-const char*
-meta_gtk_shadow_to_string (GtkShadowType shadow)
-{
-  switch (shadow)
-    {
-    case GTK_SHADOW_NONE:
-      return "none";
-    case GTK_SHADOW_IN:
-      return "in";
-    case GTK_SHADOW_OUT:
-      return "out";
-    case GTK_SHADOW_ETCHED_IN:
-      return "etched_in";
-    case GTK_SHADOW_ETCHED_OUT:
-      return "etched_out";
-    }
-
-  return "<unknown>";
-}
-
-GtkArrowType
-meta_gtk_arrow_from_string (const char *str)
-{
-  if (strcmp ("up", str) == 0)
-    return GTK_ARROW_UP;
-  else if (strcmp ("down", str) == 0)
-    return GTK_ARROW_DOWN;
-  else if (strcmp ("left", str) == 0)
-    return GTK_ARROW_LEFT;
-  else if (strcmp ("right", str) == 0)
-    return GTK_ARROW_RIGHT;
-  else if (strcmp ("none", str) == 0)
-    return GTK_ARROW_NONE;
-  else
-    return -1;
-}
-
-const char*
-meta_gtk_arrow_to_string (GtkArrowType arrow)
-{
-  switch (arrow)
-    {
-    case GTK_ARROW_UP:
-      return "up";
-    case GTK_ARROW_DOWN:
-      return "down";
-    case GTK_ARROW_LEFT:
-      return "left";
-    case GTK_ARROW_RIGHT:
-      return "right";
-    case GTK_ARROW_NONE:
-      return "none";
-    }
-
-  return "<unknown>";
-}
-
-/**
- * Returns a fill_type from a string.  The inverse of
- * meta_image_fill_type_to_string().
- *
- * \param str  a string representing a fill_type
- * \result  the fill_type, or -1 if it represents no fill_type.
- */
-MetaImageFillType
-meta_image_fill_type_from_string (const char *str)
-{
-  if (strcmp ("tile", str) == 0)
-    return META_IMAGE_FILL_TILE;
-  else if (strcmp ("scale", str) == 0)
-    return META_IMAGE_FILL_SCALE;
-  else
-    return -1;
-}
-
-/**
- * Returns a string representation of a fill_type.  The inverse of
- * meta_image_fill_type_from_string().
- *
- * \param fill_type  the fill type
- * \result  a string representing that type
- */
-const char*
-meta_image_fill_type_to_string (MetaImageFillType fill_type)
-{
-  switch (fill_type)
-    {
-    case META_IMAGE_FILL_TILE:
-      return "tile";
-    case META_IMAGE_FILL_SCALE:
-      return "scale";
-    }
-  
-  return "<unknown>";
-}
-
-/**
- * Takes a colour "a", scales the lightness and saturation by a certain amount,
- * and sets "b" to the resulting colour.
- * gtkstyle.c cut-and-pastage.
- *
- * \param a  the starting colour
- * \param b  [out] the resulting colour
- * \param k  amount to scale lightness and saturation by
- */ 
-static void
-gtk_style_shade (GdkColor *a,
-                 GdkColor *b,
-                 gdouble   k)
-{
-  gdouble red;
-  gdouble green;
-  gdouble blue;
-  
-  red = (gdouble) a->red / 65535.0;
-  green = (gdouble) a->green / 65535.0;
-  blue = (gdouble) a->blue / 65535.0;
-  
-  rgb_to_hls (&red, &green, &blue);
-  
-  green *= k;
-  if (green > 1.0)
-    green = 1.0;
-  else if (green < 0.0)
-    green = 0.0;
-  
-  blue *= k;
-  if (blue > 1.0)
-    blue = 1.0;
-  else if (blue < 0.0)
-    blue = 0.0;
-  
-  hls_to_rgb (&red, &green, &blue);
-  
-  b->red = red * 65535.0;
-  b->green = green * 65535.0;
-  b->blue = blue * 65535.0;
-}
-
-/**
- * Converts a red/green/blue triplet to a hue/lightness/saturation triplet.
- *
- * \param r  on input, red; on output, hue
- * \param g  on input, green; on output, lightness
- * \param b  on input, blue; on output, saturation
- */
-static void
-rgb_to_hls (gdouble *r,
-            gdouble *g,
-            gdouble *b)
-{
-  gdouble min;
-  gdouble max;
-  gdouble red;
-  gdouble green;
-  gdouble blue;
-  gdouble h, l, s;
-  gdouble delta;
-  
-  red = *r;
-  green = *g;
-  blue = *b;
-  
-  if (red > green)
-    {
-      if (red > blue)
-        max = red;
-      else
-        max = blue;
-      
-      if (green < blue)
-        min = green;
-      else
-        min = blue;
-    }
-  else
-    {
-      if (green > blue)
-        max = green;
-      else
-        max = blue;
-      
-      if (red < blue)
-        min = red;
-      else
-        min = blue;
-    }
-  
-  l = (max + min) / 2;
-  s = 0;
-  h = 0;
-  
-  if (max != min)
-    {
-      if (l <= 0.5)
-        s = (max - min) / (max + min);
-      else
-        s = (max - min) / (2 - max - min);
-      
-      delta = max -min;
-      if (red == max)
-        h = (green - blue) / delta;
-      else if (green == max)
-        h = 2 + (blue - red) / delta;
-      else if (blue == max)
-        h = 4 + (red - green) / delta;
-      
-      h *= 60;
-      if (h < 0.0)
-        h += 360;
-    }
-  
-  *r = h;
-  *g = l;
-  *b = s;
-}
-
-/**
- * Converts a hue/lightness/saturation triplet to a red/green/blue triplet.
- *
- * \param h  on input, hue; on output, red
- * \param l  on input, lightness; on output, green
- * \param s  on input, saturation; on output, blue
- */
-static void
-hls_to_rgb (gdouble *h,
-            gdouble *l,
-            gdouble *s)
-{
-  gdouble hue;
-  gdouble lightness;
-  gdouble saturation;
-  gdouble m1, m2;
-  gdouble r, g, b;
-  
-  lightness = *l;
-  saturation = *s;
-  
-  if (lightness <= 0.5)
-    m2 = lightness * (1 + saturation);
-  else
-    m2 = lightness + saturation - lightness * saturation;
-  m1 = 2 * lightness - m2;
-  
-  if (saturation == 0)
-    {
-      *h = lightness;
-      *l = lightness;
-      *s = lightness;
-    }
-  else
-    {
-      hue = *h + 120;
-      while (hue > 360)
-        hue -= 360;
-      while (hue < 0)
-        hue += 360;
-      
-      if (hue < 60)
-        r = m1 + (m2 - m1) * hue / 60;
-      else if (hue < 180)
-        r = m2;
-      else if (hue < 240)
-        r = m1 + (m2 - m1) * (240 - hue) / 60;
-      else
-        r = m1;
-      
-      hue = *h;
-      while (hue > 360)
-        hue -= 360;
-      while (hue < 0)
-        hue += 360;
-      
-      if (hue < 60)
-        g = m1 + (m2 - m1) * hue / 60;
-      else if (hue < 180)
-        g = m2;
-      else if (hue < 240)
-        g = m1 + (m2 - m1) * (240 - hue) / 60;
-      else
-        g = m1;
-      
-      hue = *h - 120;
-      while (hue > 360)
-        hue -= 360;
-      while (hue < 0)
-        hue += 360;
-      
-      if (hue < 60)
-        b = m1 + (m2 - m1) * hue / 60;
-      else if (hue < 180)
-        b = m2;
-      else if (hue < 240)
-        b = m1 + (m2 - m1) * (240 - hue) / 60;
-      else
-        b = m1;
-      
-      *h = r;
-      *l = g;
-      *s = b;
-    }
-}
-
-#if 0
-/* These are some functions I'm saving to use in optimizing
- * MetaDrawOpList, namely to pre-composite pixbufs on client side
- * prior to rendering to the server
- */
-static void
-draw_bg_solid_composite (const MetaTextureSpec *bg,
-                         const MetaTextureSpec *fg,
-                         double                 alpha,
-                         GtkWidget             *widget,
-                         GdkDrawable           *drawable,
-                         const GdkRectangle    *clip,
-                         MetaTextureDrawMode    mode,
-                         double                 xalign,
-                         double                 yalign,
-                         int                    x,
-                         int                    y,
-                         int                    width,
-                         int                    height)
-{
-  GdkColor bg_color;
-
-  g_assert (bg->type == META_TEXTURE_SOLID);
-  g_assert (fg->type != META_TEXTURE_COMPOSITE);
-  g_assert (fg->type != META_TEXTURE_SHAPE_LIST);
-
-  meta_color_spec_render (bg->data.solid.color_spec,
-                          widget,
-                          &bg_color);
-
-  switch (fg->type)
-    {
-    case META_TEXTURE_SOLID:
-      {
-        GdkColor fg_color;
-
-        meta_color_spec_render (fg->data.solid.color_spec,
-                                widget,
-                                &fg_color);
-
-        color_composite (&bg_color, &fg_color,
-                         alpha, &fg_color);
-
-        draw_color_rectangle (widget, drawable, &fg_color, clip,
-                              x, y, width, height);
-      }
-      break;
-
-    case META_TEXTURE_GRADIENT:
-      /* FIXME I think we could just composite all the colors in
-       * the gradient prior to generating the gradient?
-       */
-      /* FALL THRU */
-    case META_TEXTURE_IMAGE:
-      {
-        GdkPixbuf *pixbuf;
-        GdkPixbuf *composited;
-
-        pixbuf = meta_texture_spec_render (fg, widget, mode, 255,
-                                           width, height);
-
-        if (pixbuf == NULL)
-          return;
-
-        composited = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
-                                     gdk_pixbuf_get_has_alpha (pixbuf), 8,
-                                     gdk_pixbuf_get_width (pixbuf),
-                                     gdk_pixbuf_get_height (pixbuf));
-
-        if (composited == NULL)
-          {
-            g_object_unref (G_OBJECT (pixbuf));
-            return;
-          }
-
-        gdk_pixbuf_composite_color (pixbuf,
-                                    composited,
-                                    0, 0,
-                                    gdk_pixbuf_get_width (pixbuf),
-                                    gdk_pixbuf_get_height (pixbuf),
-                                    0.0, 0.0, /* offsets */
-                                    1.0, 1.0, /* scale */
-                                    GDK_INTERP_BILINEAR,
-                                    255 * alpha,
-                                    0, 0,     /* check offsets */
-                                    0,        /* check size */
-                                    GDK_COLOR_RGB (bg_color),
-                                    GDK_COLOR_RGB (bg_color));
-
-        /* Need to draw background since pixbuf is not
-         * necessarily covering the whole thing
-         */
-        draw_color_rectangle (widget, drawable, &bg_color, clip,
-                              x, y, width, height);
-
-        render_pixbuf_aligned (drawable, clip, composited,
-                               xalign, yalign,
-                               x, y, width, height);
-
-        g_object_unref (G_OBJECT (pixbuf));
-        g_object_unref (G_OBJECT (composited));
-      }
-      break;
-
-    case META_TEXTURE_BLANK:
-    case META_TEXTURE_COMPOSITE:
-    case META_TEXTURE_SHAPE_LIST:
-      g_assert_not_reached ();
-      break;
-    }
-}
-
-static void
-draw_bg_gradient_composite (const MetaTextureSpec *bg,
-                            const MetaTextureSpec *fg,
-                            double                 alpha,
-                            GtkWidget             *widget,
-                            GdkDrawable           *drawable,
-                            const GdkRectangle    *clip,
-                            MetaTextureDrawMode    mode,
-                            double                 xalign,
-                            double                 yalign,
-                            int                    x,
-                            int                    y,
-                            int                    width,
-                            int                    height)
-{
-  g_assert (bg->type == META_TEXTURE_GRADIENT);
-  g_assert (fg->type != META_TEXTURE_COMPOSITE);
-  g_assert (fg->type != META_TEXTURE_SHAPE_LIST);
-
-  switch (fg->type)
-    {
-    case META_TEXTURE_SOLID:
-    case META_TEXTURE_GRADIENT:
-    case META_TEXTURE_IMAGE:
-      {
-        GdkPixbuf *bg_pixbuf;
-        GdkPixbuf *fg_pixbuf;
-        GdkPixbuf *composited;
-        int fg_width, fg_height;
-
-        bg_pixbuf = meta_texture_spec_render (bg, widget, mode, 255,
-                                              width, height);
-
-        if (bg_pixbuf == NULL)
-          return;
-
-        fg_pixbuf = meta_texture_spec_render (fg, widget, mode, 255,
-                                              width, height);
-
-        if (fg_pixbuf == NULL)
-          {
-            g_object_unref (G_OBJECT (bg_pixbuf));
-            return;
-          }
-
-        /* gradients always fill the entire target area */
-        g_assert (gdk_pixbuf_get_width (bg_pixbuf) == width);
-        g_assert (gdk_pixbuf_get_height (bg_pixbuf) == height);
-
-        composited = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
-                                     gdk_pixbuf_get_has_alpha (bg_pixbuf), 8,
-                                     gdk_pixbuf_get_width (bg_pixbuf),
-                                     gdk_pixbuf_get_height (bg_pixbuf));
-
-        if (composited == NULL)
-          {
-            g_object_unref (G_OBJECT (bg_pixbuf));
-            g_object_unref (G_OBJECT (fg_pixbuf));
-            return;
-          }
-
-        fg_width = gdk_pixbuf_get_width (fg_pixbuf);
-        fg_height = gdk_pixbuf_get_height (fg_pixbuf);
-
-        /* If we wanted to be all cool we could deal with the
-         * offsets and try to composite only in the clip rectangle,
-         * but I just don't care enough to figure it out.
-         */
-
-        gdk_pixbuf_composite (fg_pixbuf,
-                              composited,
-                              x + (width - fg_width) * xalign,
-                              y + (height - fg_height) * yalign,
-                              gdk_pixbuf_get_width (fg_pixbuf),
-                              gdk_pixbuf_get_height (fg_pixbuf),
-                              0.0, 0.0, /* offsets */
-                              1.0, 1.0, /* scale */
-                              GDK_INTERP_BILINEAR,
-                              255 * alpha);
-
-        render_pixbuf (drawable, clip, composited, x, y);
-
-        g_object_unref (G_OBJECT (bg_pixbuf));
-        g_object_unref (G_OBJECT (fg_pixbuf));
-        g_object_unref (G_OBJECT (composited));
-      }
-      break;
-
-    case META_TEXTURE_BLANK:
-    case META_TEXTURE_SHAPE_LIST:
-    case META_TEXTURE_COMPOSITE:
-      g_assert_not_reached ();
-      break;
-    }
-}
-#endif
-
-/**
- * Returns the earliest version of the theme format which required support
- * for a particular button.  (For example, "shade" first appeared in v2, and
- * "close" in v1.)
- *
- * \param type  the button type
- * \return  the number of the theme format
- */
-guint
-meta_theme_earliest_version_with_button (MetaButtonType type)
-{
-  switch (type)
-    {
-    case META_BUTTON_TYPE_CLOSE:
-    case META_BUTTON_TYPE_MAXIMIZE:
-    case META_BUTTON_TYPE_MINIMIZE:
-    case META_BUTTON_TYPE_MENU:
-    case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
-    case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND:
-    case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
-    case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
-    case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND:
-    case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND:
-      return 1;
-      
-    case META_BUTTON_TYPE_SHADE:
-    case META_BUTTON_TYPE_ABOVE:
-    case META_BUTTON_TYPE_STICK:
-    case META_BUTTON_TYPE_UNSHADE:
-    case META_BUTTON_TYPE_UNABOVE:
-    case META_BUTTON_TYPE_UNSTICK:
-      return 2;
-
-    default:
-      meta_warning("Unknown button %d\n", type);
-      return 1; 
-    }
-}
-#endif



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]