/* GTK - The GIMP Toolkit
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

/*
 * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
 */

#include "config.h"
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <gobject/gvaluecollector.h>
#include "gtkmarshalers.h"
#include "gtkpango.h"
#include "gtkrc.h"
#include "gtkspinbutton.h"
#include "gtkstyle.h"
#include "gtkstylecontextprivate.h"
#include "gtkwidget.h"
#include "gtkiconfactory.h"
#include "gtkintl.h"
#include "gtkdebug.h"
#include "gtkspinner.h"
#include "gtkborder.h"

/**
 * SECTION:gtkstyle
 * @Short_description: Deprecated object that holds style information
 *     for widgets
 * @Title: GtkStyle
 *
 * A #GtkStyle object encapsulates the information that provides the look and
 * feel for a widget.
 *
 * <warning>
 * In GTK+ 3.0, GtkStyle has been deprecated and replaced by #GtkStyleContext.
 * </warning>
 *
 * Each #GtkWidget has an associated #GtkStyle object that is used when
 * rendering that widget. Also, a #GtkStyle holds information for the five
 * possible widget states though not every widget supports all five
 * states; see #GtkStateType.
 *
 * Usually the #GtkStyle for a widget is the same as the default style that
 * is set by GTK+ and modified the theme engine.
 *
 * Usually applications should not need to use or modify the #GtkStyle of
 * their widgets.
 */


#define LIGHTNESS_MULT  1.3
#define DARKNESS_MULT   0.7

/* --- typedefs & structures --- */
typedef struct {
  GType       widget_type;
  GParamSpec *pspec;
  GValue      value;
} PropertyValue;

#define GTK_STYLE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_STYLE, GtkStylePrivate))

typedef struct _GtkStylePrivate GtkStylePrivate;

struct _GtkStylePrivate {
  GtkStyleContext *context;
  gulong context_changed_id;
};

enum {
  PROP_0,
  PROP_CONTEXT
};

/* --- prototypes --- */
static void	 gtk_style_finalize		(GObject	*object);
static void	 gtk_style_constructed		(GObject	*object);
static void      gtk_style_set_property         (GObject        *object,
                                                 guint           prop_id,
                                                 const GValue   *value,
                                                 GParamSpec     *pspec);
static void      gtk_style_get_property         (GObject        *object,
                                                 guint           prop_id,
                                                 GValue         *value,
                                                 GParamSpec     *pspec);

static void      gtk_style_real_realize        (GtkStyle	*style);
static void      gtk_style_real_unrealize      (GtkStyle	*style);
static void      gtk_style_real_copy           (GtkStyle	*style,
						GtkStyle	*src);
static void      gtk_style_real_set_background (GtkStyle	*style,
						GdkWindow	*window,
						GtkStateType	 state_type);
static GtkStyle *gtk_style_real_clone          (GtkStyle	*style);
static void      gtk_style_real_init_from_rc   (GtkStyle	*style,
                                                GtkRcStyle	*rc_style);
static GdkPixbuf *gtk_default_render_icon      (GtkStyle            *style,
                                                const GtkIconSource *source,
                                                GtkTextDirection     direction,
                                                GtkStateType         state,
                                                GtkIconSize          size,
                                                GtkWidget           *widget,
                                                const gchar         *detail);
static void gtk_default_draw_hline      (GtkStyle        *style,
					 cairo_t         *cr,
					 GtkStateType     state_type,
					 GtkWidget       *widget,
					 const gchar     *detail,
					 gint             x1,
					 gint             x2,
					 gint             y);
static void gtk_default_draw_vline      (GtkStyle        *style,
					 cairo_t         *cr,
					 GtkStateType     state_type,
					 GtkWidget       *widget,
					 const gchar     *detail,
					 gint             y1,
					 gint             y2,
					 gint             x);
static void gtk_default_draw_shadow     (GtkStyle        *style,
					 cairo_t         *cr,
					 GtkStateType     state_type,
					 GtkShadowType    shadow_type,
					 GtkWidget       *widget,
					 const gchar     *detail,
					 gint             x,
					 gint             y,
					 gint             width,
					 gint             height);
static void gtk_default_draw_arrow      (GtkStyle        *style,
					 cairo_t         *cr,
					 GtkStateType     state_type,
					 GtkShadowType    shadow_type,
					 GtkWidget       *widget,
					 const gchar     *detail,
					 GtkArrowType     arrow_type,
					 gboolean         fill,
					 gint             x,
					 gint             y,
					 gint             width,
					 gint             height);
static void gtk_default_draw_diamond    (GtkStyle        *style,
					 cairo_t         *cr,
					 GtkStateType     state_type,
					 GtkShadowType    shadow_type,
					 GtkWidget       *widget,
					 const gchar     *detail,
					 gint             x,
					 gint             y,
					 gint             width,
					 gint             height);
static void gtk_default_draw_box        (GtkStyle        *style,
					 cairo_t         *cr,
					 GtkStateType     state_type,
					 GtkShadowType    shadow_type,
					 GtkWidget       *widget,
					 const gchar     *detail,
					 gint             x,
					 gint             y,
					 gint             width,
					 gint             height);
static void gtk_default_draw_flat_box   (GtkStyle        *style,
					 cairo_t         *cr,
					 GtkStateType     state_type,
					 GtkShadowType    shadow_type,
					 GtkWidget       *widget,
					 const gchar     *detail,
					 gint             x,
					 gint             y,
					 gint             width,
					 gint             height);
static void gtk_default_draw_check      (GtkStyle        *style,
					 cairo_t         *cr,
					 GtkStateType     state_type,
					 GtkShadowType    shadow_type,
					 GtkWidget       *widget,
					 const gchar     *detail,
					 gint             x,
					 gint             y,
					 gint             width,
					 gint             height);
static void gtk_default_draw_option     (GtkStyle        *style,
					 cairo_t         *cr,
					 GtkStateType     state_type,
					 GtkShadowType    shadow_type,
					 GtkWidget       *widget,
					 const gchar     *detail,
					 gint             x,
					 gint             y,
					 gint             width,
					 gint             height);
static void gtk_default_draw_tab        (GtkStyle        *style,
					 cairo_t         *cr,
					 GtkStateType     state_type,
					 GtkShadowType    shadow_type,
					 GtkWidget       *widget,
					 const gchar     *detail,
					 gint             x,
					 gint             y,
					 gint             width,
					 gint             height);
static void gtk_default_draw_shadow_gap (GtkStyle        *style,
					 cairo_t         *cr,
					 GtkStateType     state_type,
					 GtkShadowType    shadow_type,
					 GtkWidget       *widget,
					 const gchar     *detail,
					 gint             x,
					 gint             y,
					 gint             width,
					 gint             height,
					 GtkPositionType  gap_side,
					 gint             gap_x,
					 gint             gap_width);
static void gtk_default_draw_box_gap    (GtkStyle        *style,
					 cairo_t         *cr,
					 GtkStateType     state_type,
					 GtkShadowType    shadow_type,
					 GtkWidget       *widget,
					 const gchar     *detail,
					 gint             x,
					 gint             y,
					 gint             width,
					 gint             height,
					 GtkPositionType  gap_side,
					 gint             gap_x,
					 gint             gap_width);
static void gtk_default_draw_extension  (GtkStyle        *style,
					 cairo_t         *cr,
					 GtkStateType     state_type,
					 GtkShadowType    shadow_type,
					 GtkWidget       *widget,
					 const gchar     *detail,
					 gint             x,
					 gint             y,
					 gint             width,
					 gint             height,
					 GtkPositionType  gap_side);
static void gtk_default_draw_focus      (GtkStyle        *style,
					 cairo_t         *cr,
					 GtkStateType     state_type,
					 GtkWidget       *widget,
					 const gchar     *detail,
					 gint             x,
					 gint             y,
					 gint             width,
					 gint             height);
static void gtk_default_draw_slider     (GtkStyle        *style,
					 cairo_t         *cr,
					 GtkStateType     state_type,
					 GtkShadowType    shadow_type,
					 GtkWidget       *widget,
					 const gchar     *detail,
					 gint             x,
					 gint             y,
					 gint             width,
					 gint             height,
					 GtkOrientation   orientation);
static void gtk_default_draw_handle     (GtkStyle        *style,
					 cairo_t         *cr,
					 GtkStateType     state_type,
					 GtkShadowType    shadow_type,
					 GtkWidget       *widget,
					 const gchar     *detail,
					 gint             x,
					 gint             y,
					 gint             width,
					 gint             height,
					 GtkOrientation   orientation);
static void gtk_default_draw_expander   (GtkStyle        *style,
                                         cairo_t         *cr,
                                         GtkStateType     state_type,
                                         GtkWidget       *widget,
                                         const gchar     *detail,
                                         gint             x,
                                         gint             y,
					 GtkExpanderStyle expander_style);
static void gtk_default_draw_layout     (GtkStyle        *style,
                                         cairo_t         *cr,
                                         GtkStateType     state_type,
					 gboolean         use_text,
                                         GtkWidget       *widget,
                                         const gchar     *detail,
                                         gint             x,
                                         gint             y,
                                         PangoLayout     *layout);
static void gtk_default_draw_resize_grip (GtkStyle       *style,
                                          cairo_t        *cr,
                                          GtkStateType    state_type,
                                          GtkWidget      *widget,
                                          const gchar    *detail,
                                          GdkWindowEdge   edge,
                                          gint            x,
                                          gint            y,
                                          gint            width,
                                          gint            height);
static void gtk_default_draw_spinner     (GtkStyle       *style,
                                          cairo_t        *cr,
					  GtkStateType    state_type,
                                          GtkWidget      *widget,
                                          const gchar    *detail,
					  guint           step,
					  gint            x,
					  gint            y,
					  gint            width,
					  gint            height);

static void rgb_to_hls			(gdouble	 *r,
					 gdouble	 *g,
					 gdouble	 *b);
static void hls_to_rgb			(gdouble	 *h,
					 gdouble	 *l,
					 gdouble	 *s);

static void transform_detail_string (const gchar     *detail,
                                     GtkStyleContext *context);

/*
 * Data for default check and radio buttons
 */

static const GtkRequisition default_option_indicator_size = { 7, 13 };
static const GtkBorder default_option_indicator_spacing = { 7, 5, 2, 2 };

#define GTK_GRAY		0xdcdc, 0xdada, 0xd5d5
#define GTK_DARK_GRAY		0xc4c4, 0xc2c2, 0xbdbd
#define GTK_LIGHT_GRAY		0xeeee, 0xebeb, 0xe7e7
#define GTK_WHITE		0xffff, 0xffff, 0xffff
#define GTK_BLUE		0x4b4b, 0x6969, 0x8383
#define GTK_VERY_DARK_GRAY	0x9c9c, 0x9a9a, 0x9494
#define GTK_BLACK		0x0000, 0x0000, 0x0000
#define GTK_WEAK_GRAY		0x7530, 0x7530, 0x7530

/* --- variables --- */
static const GdkColor gtk_default_normal_fg =      { 0, GTK_BLACK };
static const GdkColor gtk_default_active_fg =      { 0, GTK_BLACK };
static const GdkColor gtk_default_prelight_fg =    { 0, GTK_BLACK };
static const GdkColor gtk_default_selected_fg =    { 0, GTK_WHITE };
static const GdkColor gtk_default_insensitive_fg = { 0, GTK_WEAK_GRAY };

static const GdkColor gtk_default_normal_bg =      { 0, GTK_GRAY };
static const GdkColor gtk_default_active_bg =      { 0, GTK_DARK_GRAY };
static const GdkColor gtk_default_prelight_bg =    { 0, GTK_LIGHT_GRAY };
static const GdkColor gtk_default_selected_bg =    { 0, GTK_BLUE };
static const GdkColor gtk_default_insensitive_bg = { 0, GTK_GRAY };
static const GdkColor gtk_default_selected_base =  { 0, GTK_BLUE };
static const GdkColor gtk_default_active_base =    { 0, GTK_VERY_DARK_GRAY };

/* --- signals --- */
static guint realize_signal = 0;
static guint unrealize_signal = 0;

G_DEFINE_TYPE (GtkStyle, gtk_style, G_TYPE_OBJECT)

/* --- functions --- */

static void
gtk_style_init (GtkStyle *style)
{
  gint i;

  style->font_desc = pango_font_description_from_string ("Sans 10");

  style->attach_count = 0;
  
  style->black.red = 0;
  style->black.green = 0;
  style->black.blue = 0;
  
  style->white.red = 65535;
  style->white.green = 65535;
  style->white.blue = 65535;
  
  style->fg[GTK_STATE_NORMAL] = gtk_default_normal_fg;
  style->fg[GTK_STATE_ACTIVE] = gtk_default_active_fg;
  style->fg[GTK_STATE_PRELIGHT] = gtk_default_prelight_fg;
  style->fg[GTK_STATE_SELECTED] = gtk_default_selected_fg;
  style->fg[GTK_STATE_INSENSITIVE] = gtk_default_insensitive_fg;
  
  style->bg[GTK_STATE_NORMAL] = gtk_default_normal_bg;
  style->bg[GTK_STATE_ACTIVE] = gtk_default_active_bg;
  style->bg[GTK_STATE_PRELIGHT] = gtk_default_prelight_bg;
  style->bg[GTK_STATE_SELECTED] = gtk_default_selected_bg;
  style->bg[GTK_STATE_INSENSITIVE] = gtk_default_insensitive_bg;
  
  for (i = 0; i < 4; i++)
    {
      style->text[i] = style->fg[i];
      style->base[i] = style->white;
    }

  style->base[GTK_STATE_SELECTED] = gtk_default_selected_base;
  style->text[GTK_STATE_SELECTED] = style->white;
  style->base[GTK_STATE_ACTIVE] = gtk_default_active_base;
  style->text[GTK_STATE_ACTIVE] = style->white;
  style->base[GTK_STATE_INSENSITIVE] = gtk_default_prelight_bg;
  style->text[GTK_STATE_INSENSITIVE] = gtk_default_insensitive_fg;
  
  style->rc_style = NULL;
  
  style->xthickness = 2;
  style->ythickness = 2;

  style->property_cache = NULL;
}

static void
gtk_style_class_init (GtkStyleClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
  
  object_class->finalize = gtk_style_finalize;
  object_class->set_property = gtk_style_set_property;
  object_class->get_property = gtk_style_get_property;
  object_class->constructed = gtk_style_constructed;

  klass->clone = gtk_style_real_clone;
  klass->copy = gtk_style_real_copy;
  klass->init_from_rc = gtk_style_real_init_from_rc;
  klass->realize = gtk_style_real_realize;
  klass->unrealize = gtk_style_real_unrealize;
  klass->set_background = gtk_style_real_set_background;
  klass->render_icon = gtk_default_render_icon;

  klass->draw_hline = gtk_default_draw_hline;
  klass->draw_vline = gtk_default_draw_vline;
  klass->draw_shadow = gtk_default_draw_shadow;
  klass->draw_arrow = gtk_default_draw_arrow;
  klass->draw_diamond = gtk_default_draw_diamond;
  klass->draw_box = gtk_default_draw_box;
  klass->draw_flat_box = gtk_default_draw_flat_box;
  klass->draw_check = gtk_default_draw_check;
  klass->draw_option = gtk_default_draw_option;
  klass->draw_tab = gtk_default_draw_tab;
  klass->draw_shadow_gap = gtk_default_draw_shadow_gap;
  klass->draw_box_gap = gtk_default_draw_box_gap;
  klass->draw_extension = gtk_default_draw_extension;
  klass->draw_focus = gtk_default_draw_focus;
  klass->draw_slider = gtk_default_draw_slider;
  klass->draw_handle = gtk_default_draw_handle;
  klass->draw_expander = gtk_default_draw_expander;
  klass->draw_layout = gtk_default_draw_layout;
  klass->draw_resize_grip = gtk_default_draw_resize_grip;
  klass->draw_spinner = gtk_default_draw_spinner;

  g_type_class_add_private (object_class, sizeof (GtkStylePrivate));

  g_object_class_install_property (object_class,
				   PROP_CONTEXT,
				   g_param_spec_object ("context",
 							P_("Style context"),
							P_("GtkStyleContext to get style from"),
                                                        GTK_TYPE_STYLE_CONTEXT,
                                                        G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));

  /**
   * GtkStyle::realize:
   * @style: the object which received the signal
   *
   * Emitted when the style has been initialized for a particular
   * visual. Connecting to this signal is probably seldom
   * useful since most of the time applications and widgets only
   * deal with styles that have been already realized.
   *
   * Since: 2.4
   */
  realize_signal = g_signal_new (I_("realize"),
				 G_TYPE_FROM_CLASS (object_class),
				 G_SIGNAL_RUN_FIRST,
				 G_STRUCT_OFFSET (GtkStyleClass, realize),
				 NULL, NULL,
				 _gtk_marshal_VOID__VOID,
				 G_TYPE_NONE, 0);
  /**
   * GtkStyle::unrealize:
   * @style: the object which received the signal
   *
   * Emitted when the aspects of the style specific to a particular visual
   * is being cleaned up. A connection to this signal can be useful
   * if a widget wants to cache objects as object data on #GtkStyle.
   * This signal provides a convenient place to free such cached objects.
   *
   * Since: 2.4
   */
  unrealize_signal = g_signal_new (I_("unrealize"),
				   G_TYPE_FROM_CLASS (object_class),
				   G_SIGNAL_RUN_FIRST,
				   G_STRUCT_OFFSET (GtkStyleClass, unrealize),
				   NULL, NULL,
				   _gtk_marshal_VOID__VOID,
				   G_TYPE_NONE, 0);
}

static void
gtk_style_finalize (GObject *object)
{
  GtkStyle *style = GTK_STYLE (object);
  GtkStylePrivate *priv = GTK_STYLE_GET_PRIVATE (style);
  gint i;

  g_return_if_fail (style->attach_count == 0);

  /* All the styles in the list have the same 
   * style->styles pointer. If we delete the 
   * *first* style from the list, we need to update
   * the style->styles pointers from all the styles.
   * Otherwise we simply remove the node from
   * the list.
   */
  if (style->styles)
    {
      if (style->styles->data != style)
        style->styles = g_slist_remove (style->styles, style);
      else
        {
          GSList *tmp_list = style->styles->next;
	  
          while (tmp_list)
            {
              GTK_STYLE (tmp_list->data)->styles = style->styles->next;
              tmp_list = tmp_list->next;
            }
          g_slist_free_1 (style->styles);
        }
    }

  g_slist_foreach (style->icon_factories, (GFunc) g_object_unref, NULL);
  g_slist_free (style->icon_factories);

  pango_font_description_free (style->font_desc);

  if (style->private_font_desc)
    pango_font_description_free (style->private_font_desc);

  if (style->rc_style)
    g_object_unref (style->rc_style);

  if (priv->context)
    {
      if (priv->context_changed_id)
        g_signal_handler_disconnect (priv->context, priv->context_changed_id);

      g_object_unref (priv->context);
    }

  for (i = 0; i < 5; i++)
    {
      if (style->background[i])
        cairo_pattern_destroy (style->background[i]);
    }

  G_OBJECT_CLASS (gtk_style_parent_class)->finalize (object);
}

static void
gtk_style_set_property (GObject      *object,
                        guint         prop_id,
                        const GValue *value,
                        GParamSpec   *pspec)
{
  GtkStylePrivate *priv;

  priv = GTK_STYLE_GET_PRIVATE (object);

  switch (prop_id)
    {
    case PROP_CONTEXT:
      priv->context = g_value_dup_object (value);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
gtk_style_get_property (GObject      *object,
                        guint         prop_id,
                        GValue       *value,
                        GParamSpec   *pspec)
{
  GtkStylePrivate *priv;

  priv = GTK_STYLE_GET_PRIVATE (object);

  switch (prop_id)
    {
    case PROP_CONTEXT:
      g_value_set_object (value, priv->context);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
set_color (GtkStyle        *style,
           GtkStyleContext *context,
           GtkStateType     state,
           GtkRcFlags       prop)
{
  GtkStateFlags flags;
  GdkRGBA *color = NULL;
  GdkColor *dest = { 0 }; /* Shut up gcc */

  switch (state)
    {
    case GTK_STATE_ACTIVE:
      flags = GTK_STATE_FLAG_ACTIVE;
      break;
    case GTK_STATE_PRELIGHT:
      flags = GTK_STATE_FLAG_PRELIGHT;
      break;
    case GTK_STATE_SELECTED:
      flags = GTK_STATE_FLAG_SELECTED;
      break;
    case GTK_STATE_INSENSITIVE:
      flags = GTK_STATE_FLAG_INSENSITIVE;
      break;
    default:
      flags = 0;
    }

  switch (prop)
    {
    case GTK_RC_BG:
      gtk_style_context_get (context, flags,
                             "background-color", &color,
                             NULL);
      dest = &style->bg[state];
      break;
    case GTK_RC_FG:
      gtk_style_context_get (context, flags,
                             "color", &color,
                             NULL);
      dest = &style->fg[state];
      break;
    case GTK_RC_TEXT:
      gtk_style_context_get (context, flags,
                             "color", &color,
                             NULL);
      dest = &style->text[state];
      break;
    case GTK_RC_BASE:
      gtk_style_context_get (context, flags,
                             "background-color", &color,
                             NULL);
      dest = &style->base[state];
      break;
    }

  if (color)
    {
      dest->pixel = 0;
      dest->red = CLAMP ((guint) (color->red * 65535), 0, 65535);
      dest->green = CLAMP ((guint) (color->green * 65535), 0, 65535);
      dest->blue = CLAMP ((guint) (color->blue * 65535), 0, 65535);
      gdk_rgba_free (color);
    }
}

static void
gtk_style_update_from_context (GtkStyle *style)
{
  GtkStylePrivate *priv;
  GtkStateType state;
  GtkBorder padding;
  gint i;

  priv = GTK_STYLE_GET_PRIVATE (style);

  for (state = GTK_STATE_NORMAL; state <= GTK_STATE_INSENSITIVE; state++)
    {
      if (gtk_style_context_has_class (priv->context, "entry"))
        {
          gtk_style_context_save (priv->context);
          gtk_style_context_remove_class (priv->context, "entry");
          set_color (style, priv->context, state, GTK_RC_BG);
          set_color (style, priv->context, state, GTK_RC_FG);
          gtk_style_context_restore (priv->context);

          set_color (style, priv->context, state, GTK_RC_BASE);
          set_color (style, priv->context, state, GTK_RC_TEXT);
        }
      else
        {
          gtk_style_context_save (priv->context);
          gtk_style_context_add_class (priv->context, "entry");
          set_color (style, priv->context, state, GTK_RC_BASE);
          set_color (style, priv->context, state, GTK_RC_TEXT);
          gtk_style_context_restore (priv->context);

          set_color (style, priv->context, state, GTK_RC_BG);
          set_color (style, priv->context, state, GTK_RC_FG);
        }
    }

  if (style->font_desc)
    pango_font_description_free (style->font_desc);

  gtk_style_context_get (priv->context, 0,
                         "font", &style->font_desc,
                         NULL);
  gtk_style_context_get_padding (priv->context, 0, &padding);

  style->xthickness = padding.left;
  style->ythickness = padding.top;

  for (i = 0; i < 5; i++)
    {
      _gtk_style_shade (&style->bg[i], &style->light[i], LIGHTNESS_MULT);
      _gtk_style_shade (&style->bg[i], &style->dark[i], DARKNESS_MULT);

      style->mid[i].red = (style->light[i].red + style->dark[i].red) / 2;
      style->mid[i].green = (style->light[i].green + style->dark[i].green) / 2;
      style->mid[i].blue = (style->light[i].blue + style->dark[i].blue) / 2;

      style->text_aa[i].red = (style->text[i].red + style->base[i].red) / 2;
      style->text_aa[i].green = (style->text[i].green + style->base[i].green) / 2;
      style->text_aa[i].blue = (style->text[i].blue + style->base[i].blue) / 2;
    }

  style->black.red = 0x0000;
  style->black.green = 0x0000;
  style->black.blue = 0x0000;

  style->white.red = 0xffff;
  style->white.green = 0xffff;
  style->white.blue = 0xffff;

  for (i = 0; i < 5; i++)
    {
      if (style->background[i])
        cairo_pattern_destroy (style->background[i]);

      style->background[i] = cairo_pattern_create_rgb (style->bg[i].red / 65535.0,
                                                       style->bg[i].green / 65535.0,
                                                       style->bg[i].blue / 65535.0);
    }
}

static void
style_context_changed (GtkStyleContext *context,
                       gpointer         user_data)
{
  gtk_style_update_from_context (GTK_STYLE (user_data));
}

static void
gtk_style_constructed (GObject *object)
{
  GtkStylePrivate *priv;

  priv = GTK_STYLE_GET_PRIVATE (object);

  if (priv->context)
    {
      gtk_style_update_from_context (GTK_STYLE (object));

      priv->context_changed_id = g_signal_connect (priv->context, "changed",
                                                   G_CALLBACK (style_context_changed), object);
    }
}

/**
 * gtk_style_copy:
 * @style: a #GtkStyle
 *
 * Creates a copy of the passed in #GtkStyle object.
 *
 * Returns: (transfer full): a copy of @style
 *
 * Deprecated:3.0: Use #GtkStyleContext instead
 */
GtkStyle*
gtk_style_copy (GtkStyle *style)
{
  GtkStyle *new_style;
  
  g_return_val_if_fail (GTK_IS_STYLE (style), NULL);
  
  new_style = GTK_STYLE_GET_CLASS (style)->clone (style);
  GTK_STYLE_GET_CLASS (style)->copy (new_style, style);

  return new_style;
}

GtkStyle*
_gtk_style_new_for_path (GdkScreen     *screen,
                         GtkWidgetPath *path)
{
  GtkStyleContext *context;
  GtkStyle *style;

  context = gtk_style_context_new ();

  if (screen)
    gtk_style_context_set_screen (context, screen);

  gtk_style_context_set_path (context, path);

  style = g_object_new (GTK_TYPE_STYLE,
                        "context", context,
                        NULL);

  g_object_unref (context);

  return style;
}

/**
 * gtk_style_new:
 * @returns: a new #GtkStyle.
 *
 * Creates a new #GtkStyle.
 *
 * Deprecated: 3.0: Use #GtkStyleContext
 **/
GtkStyle*
gtk_style_new (void)
{
  GtkWidgetPath *path;
  GtkStyle *style;

  path = gtk_widget_path_new ();
  gtk_widget_path_append_type (path, GTK_TYPE_WIDGET);

  style = _gtk_style_new_for_path (gdk_screen_get_default (), path);

  gtk_widget_path_free (path);

  return style;
}

/**
 * gtk_style_has_context:
 * @style: a #GtkStyle
 *
 * Returns whether @style has an associated #GtkStyleContext.
 *
 * Returns: %TRUE if @style has a #GtkStyleContext
 *
 * Since: 3.0
 */
gboolean
gtk_style_has_context (GtkStyle *style)
{
  GtkStylePrivate *priv;

  priv = GTK_STYLE_GET_PRIVATE (style);

  return priv->context != NULL;
}

/**
 * gtk_style_attach: (skip)
 * @style: a #GtkStyle.
 * @window: a #GdkWindow.
 *
 * Attaches a style to a window; this process allocates the
 * colors and creates the GC's for the style - it specializes
 * it to a particular visual. The process may involve the creation
 * of a new style if the style has already been attached to a
 * window with a different style and visual.
 *
 * Since this function may return a new object, you have to use it
 * in the following way:
 * <literal>style = gtk_style_attach (style, window)</literal>
 *
 * Returns: Either @style, or a newly-created #GtkStyle.
 *   If the style is newly created, the style parameter
 *   will be unref'ed, and the new style will have
 *   a reference count belonging to the caller.
 *
 * Deprecated:3.0: Use gtk_widget_style_attach() instead
 */
GtkStyle*
gtk_style_attach (GtkStyle  *style,
                  GdkWindow *window)
{
  g_return_val_if_fail (GTK_IS_STYLE (style), NULL);
  g_return_val_if_fail (window != NULL, NULL);

  return style;
}

/**
 * gtk_style_detach:
 * @style: a #GtkStyle
 *
 * Detaches a style from a window. If the style is not attached
 * to any windows anymore, it is unrealized. See gtk_style_attach().
 *
 * Deprecated:3.0: Use #GtkStyleContext instead
 */
void
gtk_style_detach (GtkStyle *style)
{
  g_return_if_fail (GTK_IS_STYLE (style));
}

/**
 * gtk_style_lookup_icon_set:
 * @style: a #GtkStyle
 * @stock_id: an icon name
 *
 * Looks up @stock_id in the icon factories associated with @style
 * and the default icon factory, returning an icon set if found,
 * otherwise %NULL.
 *
 * Return value: (transfer none): icon set of @stock_id
 *
 * Deprecated:3.0: Use gtk_style_context_lookup_icon_set() instead
 */
GtkIconSet*
gtk_style_lookup_icon_set (GtkStyle   *style,
                           const char *stock_id)
{
  GtkStylePrivate *priv;

  g_return_val_if_fail (GTK_IS_STYLE (style), NULL);
  g_return_val_if_fail (stock_id != NULL, NULL);

  priv = GTK_STYLE_GET_PRIVATE (style);

  if (priv->context)
    return gtk_style_context_lookup_icon_set (priv->context, stock_id);

  return gtk_icon_factory_lookup_default (stock_id);
}

/**
 * gtk_style_lookup_color:
 * @style: a #GtkStyle
 * @color_name: the name of the logical color to look up
 * @color: (out): the #GdkColor to fill in
 *
 * Looks up @color_name in the style's logical color mappings,
 * filling in @color and returning %TRUE if found, otherwise
 * returning %FALSE. Do not cache the found mapping, because
 * it depends on the #GtkStyle and might change when a theme
 * switch occurs.
 *
 * Return value: %TRUE if the mapping was found.
 *
 * Since: 2.10
 *
 * Deprecated:3.0: Use gtk_style_context_lookup_color() instead
 **/
gboolean
gtk_style_lookup_color (GtkStyle   *style,
                        const char *color_name,
                        GdkColor   *color)
{
  GtkStylePrivate *priv;
  gboolean result;
  GdkRGBA rgba;

  g_return_val_if_fail (GTK_IS_STYLE (style), FALSE);
  g_return_val_if_fail (color_name != NULL, FALSE);
  g_return_val_if_fail (color != NULL, FALSE);

  priv = GTK_STYLE_GET_PRIVATE (style);

  if (!priv->context)
    return FALSE;

  result = gtk_style_context_lookup_color (priv->context, color_name, &rgba);

  if (color)
    {
      color->red = (guint16) (rgba.red * 65535);
      color->green = (guint16) (rgba.green * 65535);
      color->blue = (guint16) (rgba.blue * 65535);
      color->pixel = 0;
    }

  return result;
}

/**
 * gtk_style_set_background:
 * @style: a #GtkStyle
 * @window: a #GdkWindow
 * @state_type: a state
 * 
 * Sets the background of @window to the background color or pixmap
 * specified by @style for the given state.
 *
 * Deprecated:3.0: Use gtk_style_context_set_background() instead
 */
void
gtk_style_set_background (GtkStyle    *style,
                          GdkWindow   *window,
                          GtkStateType state_type)
{
  g_return_if_fail (GTK_IS_STYLE (style));
  g_return_if_fail (window != NULL);
  
  GTK_STYLE_GET_CLASS (style)->set_background (style, window, state_type);
}

/* Default functions */
static GtkStyle *
gtk_style_real_clone (GtkStyle *style)
{
  GtkStylePrivate *priv;

  priv = GTK_STYLE_GET_PRIVATE (style);

  return g_object_new (G_OBJECT_TYPE (style),
                       "context", priv->context,
                       NULL);
}

static void
gtk_style_real_copy (GtkStyle *style,
		     GtkStyle *src)
{
  gint i;
  
  for (i = 0; i < 5; i++)
    {
      style->fg[i] = src->fg[i];
      style->bg[i] = src->bg[i];
      style->text[i] = src->text[i];
      style->base[i] = src->base[i];

      if (style->background[i])
	cairo_pattern_destroy (style->background[i]),
      style->background[i] = src->background[i];
      if (style->background[i])
	cairo_pattern_reference (style->background[i]);
    }

  if (style->font_desc)
    pango_font_description_free (style->font_desc);
  if (src->font_desc)
    style->font_desc = pango_font_description_copy (src->font_desc);
  else
    style->font_desc = NULL;
  
  style->xthickness = src->xthickness;
  style->ythickness = src->ythickness;

  if (style->rc_style)
    g_object_unref (style->rc_style);
  style->rc_style = src->rc_style;
  if (src->rc_style)
    g_object_ref (src->rc_style);

  g_slist_foreach (style->icon_factories, (GFunc) g_object_unref, NULL);
  g_slist_free (style->icon_factories);
  style->icon_factories = g_slist_copy (src->icon_factories);
  g_slist_foreach (style->icon_factories, (GFunc) g_object_ref, NULL);
}

static void
gtk_style_real_init_from_rc (GtkStyle   *style,
			     GtkRcStyle *rc_style)
{
}

/**
 * gtk_style_get_style_property:
 * @style: a #GtkStyle
 * @widget_type: the #GType of a descendant of #GtkWidget
 * @property_name: the name of the style property to get
 * @value: a #GValue where the value of the property being
 *     queried will be stored
 *
 * Queries the value of a style property corresponding to a
 * widget class is in the given style.
 *
 * Since: 2.16
 */
void 
gtk_style_get_style_property (GtkStyle     *style,
                              GType        widget_type,
                              const gchar *property_name,
                              GValue      *value)
{
  GtkStylePrivate *priv;
  GtkWidgetClass *klass;
  GParamSpec *pspec;
  const GValue *peek_value;

  klass = g_type_class_ref (widget_type);
  pspec = gtk_widget_class_find_style_property (klass, property_name);
  g_type_class_unref (klass);

  if (!pspec)
    {
      g_warning ("%s: widget class `%s' has no property named `%s'",
                 G_STRLOC,
                 g_type_name (widget_type),
                 property_name);
      return;
    }

  priv = GTK_STYLE_GET_PRIVATE (style);
  peek_value = _gtk_style_context_peek_style_property (priv->context,
                                                       widget_type,
                                                       0, pspec);

  if (G_VALUE_TYPE (value) == G_PARAM_SPEC_VALUE_TYPE (pspec))
    g_value_copy (peek_value, value);
  else if (g_value_type_transformable (G_PARAM_SPEC_VALUE_TYPE (pspec), G_VALUE_TYPE (value)))
    g_value_transform (peek_value, value);
  else
    g_warning ("can't retrieve style property `%s' of type `%s' as value of type `%s'",
               pspec->name,
               g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
               G_VALUE_TYPE_NAME (value));
}

/**
 * gtk_style_get_valist:
 * @style: a #GtkStyle
 * @widget_type: the #GType of a descendant of #GtkWidget
 * @first_property_name: the name of the first style property to get
 * @var_args: a <type>va_list</type> of pairs of property names and
 *     locations to return the property values, starting with the
 *     location for @first_property_name.
 *
 * Non-vararg variant of gtk_style_get().
 * Used primarily by language bindings.
 *
 * Since: 2.16
 */
void 
gtk_style_get_valist (GtkStyle    *style,
                      GType        widget_type,
                      const gchar *first_property_name,
                      va_list      var_args)
{
  GtkStylePrivate *priv;
  const char *property_name;
  GtkWidgetClass *klass;

  g_return_if_fail (GTK_IS_STYLE (style));

  klass = g_type_class_ref (widget_type);

  priv = GTK_STYLE_GET_PRIVATE (style);
  property_name = first_property_name;
  while (property_name)
    {
      GParamSpec *pspec;
      const GValue *peek_value;
      gchar *error;

      pspec = gtk_widget_class_find_style_property (klass, property_name);

      if (!pspec)
        {
          g_warning ("%s: widget class `%s' has no property named `%s'",
                     G_STRLOC,
                     g_type_name (widget_type),
                     property_name);
          break;
        }

      peek_value = _gtk_style_context_peek_style_property (priv->context, widget_type,
                                                           0, pspec);
      G_VALUE_LCOPY (peek_value, var_args, 0, &error);
      if (error)
        {
          g_warning ("%s: %s", G_STRLOC, error);
          g_free (error);
          break;
        }

      property_name = va_arg (var_args, gchar*);
    }

  g_type_class_unref (klass);
}

/**
 * gtk_style_get:
 * @style: a #GtkStyle
 * @widget_type: the #GType of a descendant of #GtkWidget
 * @first_property_name: the name of the first style property to get
 * @Varargs: pairs of property names and locations to
 *   return the property values, starting with the location for
 *   @first_property_name, terminated by %NULL.
 *
 * Gets the values of a multiple style properties for @widget_type
 * from @style.
 *
 * Since: 2.16
 */
void
gtk_style_get (GtkStyle    *style,
               GType        widget_type,
               const gchar *first_property_name,
               ...)
{
  va_list var_args;

  va_start (var_args, first_property_name);
  gtk_style_get_valist (style, widget_type, first_property_name, var_args);
  va_end (var_args);
}

static void
gtk_style_real_realize (GtkStyle *style)
{
}

static void
gtk_style_real_unrealize (GtkStyle *style)
{
}

static void
gtk_style_real_set_background (GtkStyle    *style,
			       GdkWindow   *window,
			       GtkStateType state_type)
{
  gdk_window_set_background_pattern (window, style->background[state_type]);
}

/**
 * gtk_style_render_icon:
 * @style: a #GtkStyle
 * @source: the #GtkIconSource specifying the icon to render
 * @direction: a text direction
 * @state: a state
 * @size: (type int): the size to render the icon at. A size of
 *     (GtkIconSize)-1 means render at the size of the source and
 *     don't scale.
 * @widget: (allow-none): the widget
 * @detail: (allow-none): a style detail
 *
 * Renders the icon specified by @source at the given @size
 * according to the given parameters and returns the result in a
 * pixbuf.
 *
 * Return value: (transfer full): a newly-created #GdkPixbuf
 *     containing the rendered icon
 *
 * Deprecated:3.0: Use gtk_render_icon_pixbuf() instead
 */
GdkPixbuf *
gtk_style_render_icon (GtkStyle            *style,
                       const GtkIconSource *source,
                       GtkTextDirection     direction,
                       GtkStateType         state,
                       GtkIconSize          size,
                       GtkWidget           *widget,
                       const gchar         *detail)
{
  GdkPixbuf *pixbuf;
  
  g_return_val_if_fail (GTK_IS_STYLE (style), NULL);
  g_return_val_if_fail (GTK_STYLE_GET_CLASS (style)->render_icon != NULL, NULL);
  
  pixbuf = GTK_STYLE_GET_CLASS (style)->render_icon (style, source, direction, state,
                                                     size, widget, detail);

  g_return_val_if_fail (pixbuf != NULL, NULL);

  return pixbuf;
}

/* Default functions */

/**
 * gtk_style_apply_default_background:
 * @style:
 * @cr: 
 * @window:
 * @set_bg:
 * @state_type:
 * @x:
 * @y:
 * @width:
 * @height:
 *
 * Deprecated:3.0: Use #GtkStyleContext instead
 */
void
gtk_style_apply_default_background (GtkStyle          *style,
                                    cairo_t           *cr,
                                    GdkWindow         *window,
                                    GtkStateType       state_type,
                                    gint               x,
                                    gint               y,
                                    gint               width,
                                    gint               height)
{
  cairo_save (cr);

  if (style->background[state_type] == NULL)
    {
      GdkWindow *parent = gdk_window_get_parent (window);
      int x_offset, y_offset;

      if (parent)
        {
          gdk_window_get_position (window, &x_offset, &y_offset);
          cairo_translate (cr, -x_offset, -y_offset);
          gtk_style_apply_default_background (style, cr,
                                              parent, state_type,
                                              x + x_offset, y + y_offset,
                                              width, height);
          goto out;
        }
      else
        gdk_cairo_set_source_color (cr, &style->bg[state_type]);
    }
  else
    cairo_set_source (cr, style->background[state_type]);

  cairo_rectangle (cr, x, y, width, height);
  cairo_fill (cr);

out:
  cairo_restore (cr);
}

static GdkPixbuf *
gtk_default_render_icon (GtkStyle            *style,
                         const GtkIconSource *source,
                         GtkTextDirection     direction,
                         GtkStateType         state,
                         GtkIconSize          size,
                         GtkWidget           *widget,
                         const gchar         *detail)
{
  GtkStyleContext *context;
  GtkStylePrivate *priv;
  GtkStateFlags flags = 0;
  GdkPixbuf *pixbuf;

  if (widget)
    context = gtk_widget_get_style_context (widget);
  else
    {
      priv = GTK_STYLE_GET_PRIVATE (style);
      context = priv->context;
    }

  if (!context)
    return NULL;

  gtk_style_context_save (context);

  if (detail)
    transform_detail_string (detail, context);

  switch (state)
    {
    case GTK_STATE_PRELIGHT:
      flags |= GTK_STATE_FLAG_PRELIGHT;
      break;
    case GTK_STATE_INSENSITIVE:
      flags |= GTK_STATE_FLAG_INSENSITIVE;
      break;
    default:
      break;
    }

  gtk_style_context_set_state (context, flags);

  pixbuf = gtk_render_icon_pixbuf (context, source, size);

  gtk_style_context_restore (context);

  return pixbuf;
}

static void
_cairo_draw_line (cairo_t  *cr,
                  GdkColor *color,
                  gint      x1,
                  gint      y1,
                  gint      x2,
                  gint      y2)
{
  cairo_save (cr);

  gdk_cairo_set_source_color (cr, color);
  cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);

  cairo_move_to (cr, x1 + 0.5, y1 + 0.5);
  cairo_line_to (cr, x2 + 0.5, y2 + 0.5);
  cairo_stroke (cr);

  cairo_restore (cr);
}

static void
transform_detail_string (const gchar     *detail,
			 GtkStyleContext *context)
{
  if (!detail)
    return;

  if (strcmp (detail, "arrow") == 0)
    gtk_style_context_add_class (context, "arrow");
  else if (strcmp (detail, "button") == 0)
    gtk_style_context_add_class (context, "button");
  else if (strcmp (detail, "buttondefault") == 0)
    {
      gtk_style_context_add_class (context, "button");
      gtk_style_context_add_class (context, "default");
    }
  else if (strcmp (detail, "calendar") == 0)
    gtk_style_context_add_class (context, "calendar");
  else if (strcmp (detail, "cellcheck") == 0)
    {
      gtk_style_context_add_class (context, "cell");
      gtk_style_context_add_class (context, "check");
    }
  else if (strcmp (detail, "cellradio") == 0)
    {
      gtk_style_context_add_class (context, "cell");
      gtk_style_context_add_class (context, "radio");
    }
  else if (strcmp (detail, "checkbutton") == 0)
    gtk_style_context_add_class (context, "check");
  else if (strcmp (detail, "check") == 0)
    {
      gtk_style_context_add_class (context, "check");
      gtk_style_context_add_class (context, "menu");
    }
  else if (strcmp (detail, "radiobutton") == 0)
    {
      gtk_style_context_add_class (context, "radio");
    }
  else if (strcmp (detail, "option") == 0)
    {
      gtk_style_context_add_class (context, "radio");
      gtk_style_context_add_class (context, "menu");
    }
  else if (strcmp (detail, "entry") == 0 ||
           strcmp (detail, "entry_bg") == 0)
    gtk_style_context_add_class (context, "entry");
  else if (strcmp (detail, "expander") == 0)
    gtk_style_context_add_class (context, "expander");
  else if (strcmp (detail, "tooltip") == 0)
    gtk_style_context_add_class (context, "tooltip");
  else if (strcmp (detail, "frame") == 0)
    gtk_style_context_add_class (context, "frame");
  else if (strcmp (detail, "scrolled_window") == 0)
    gtk_style_context_add_class (context, "scrolled-window");
  else if (strcmp (detail, "viewport") == 0 ||
	   strcmp (detail, "viewportbin") == 0)
    gtk_style_context_add_class (context, "viewport");
  else if (strncmp (detail, "trough", 6) == 0)
    gtk_style_context_add_class (context, "trough");
  else if (strcmp (detail, "spinbutton") == 0)
    gtk_style_context_add_class (context, "spinbutton");
  else if (strcmp (detail, "spinbutton_up") == 0)
    {
      gtk_style_context_add_class (context, "spinbutton");
      gtk_style_context_add_class (context, "button");
      gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM);
    }
  else if (strcmp (detail, "spinbutton_down") == 0)
    {
      gtk_style_context_add_class (context, "spinbutton");
      gtk_style_context_add_class (context, "button");
      gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP);
    }
  else if ((detail[0] == 'h' || detail[0] == 'v') &&
           strncmp (&detail[1], "scrollbar_", 10) == 0)
    {
      gtk_style_context_add_class (context, "button");
      gtk_style_context_add_class (context, "scrollbar");
    }
  else if (strcmp (detail, "slider") == 0)
    {
      gtk_style_context_add_class (context, "slider");
      gtk_style_context_add_class (context, "scrollbar");
    }
  else if (strcmp (detail, "vscale") == 0 ||
           strcmp (detail, "hscale") == 0)
    {
      gtk_style_context_add_class (context, "slider");
      gtk_style_context_add_class (context, "scale");
    }
  else if (strcmp (detail, "menuitem") == 0)
    {
      gtk_style_context_add_class (context, "menuitem");
      gtk_style_context_add_class (context, "menu");
    }
  else if (strcmp (detail, "menu") == 0)
    {
      gtk_style_context_add_class (context, "popup");
      gtk_style_context_add_class (context, "menu");
    }
  else if (strcmp (detail, "accellabel") == 0)
    gtk_style_context_add_class (context, "accelerator");
  else if (strcmp (detail, "menubar") == 0)
    gtk_style_context_add_class (context, "menubar");
  else if (strcmp (detail, "base") == 0)
    gtk_style_context_add_class (context, "background");
  else if (strcmp (detail, "bar") == 0 ||
           strcmp (detail, "progressbar") == 0)
    gtk_style_context_add_class (context, "progressbar");
  else if (strcmp (detail, "toolbar") == 0)
    gtk_style_context_add_class (context, "toolbar");
  else if (strcmp (detail, "handlebox_bin") == 0)
    gtk_style_context_add_class (context, "dock");
  else if (strcmp (detail, "notebook") == 0)
    gtk_style_context_add_class (context, "notebook");
  else if (strcmp (detail, "tab") == 0)
    {
      gtk_style_context_add_class (context, "notebook");
      gtk_style_context_add_region (context, GTK_STYLE_REGION_TAB, 0);
    }
  else if (g_str_has_prefix (detail, "cell"))
    {
      GtkRegionFlags row, col;
      gboolean ruled = FALSE;
      GStrv tokens;
      guint i;

      tokens = g_strsplit (detail, "_", -1);
      row = col = 0;
      i = 0;

      while (tokens[i])
        {
          if (strcmp (tokens[i], "even") == 0)
            row |= GTK_REGION_EVEN;
          else if (strcmp (tokens[i], "odd") == 0)
            row |= GTK_REGION_ODD;
          else if (strcmp (tokens[i], "start") == 0)
            col |= GTK_REGION_FIRST;
          else if (strcmp (tokens[i], "end") == 0)
            col |= GTK_REGION_LAST;
          else if (strcmp (tokens[i], "ruled") == 0)
            ruled = TRUE;
          else if (strcmp (tokens[i], "sorted") == 0)
            col |= GTK_REGION_SORTED;

          i++;
        }

      if (!ruled)
        row &= ~(GTK_REGION_EVEN | GTK_REGION_ODD);

      gtk_style_context_add_class (context, "cell");
      gtk_style_context_add_region (context, "row", row);
      gtk_style_context_add_region (context, "column", col);

      g_strfreev (tokens);
    }
}

static void
gtk_default_draw_hline (GtkStyle     *style,
                        cairo_t       *cr,
                        GtkStateType  state_type,
                        GtkWidget     *widget,
                        const gchar   *detail,
                        gint          x1,
                        gint          x2,
                        gint          y)
{
  GtkStyleContext *context;
  GtkStylePrivate *priv;

  if (widget)
    context = gtk_widget_get_style_context (widget);
  else
    {
      priv = GTK_STYLE_GET_PRIVATE (style);
      context = priv->context;
    }

  gtk_style_context_save (context);

  if (detail)
    transform_detail_string (detail, context);

  cairo_save (cr);

  gtk_render_line (context, cr,
                   x1, y, x2, y);

  cairo_restore (cr);

  gtk_style_context_restore (context);
}


static void
gtk_default_draw_vline (GtkStyle      *style,
                        cairo_t       *cr,
                        GtkStateType  state_type,
                        GtkWidget     *widget,
                        const gchar   *detail,
                        gint          y1,
                        gint          y2,
                        gint          x)
{
  GtkStyleContext *context;
  GtkStylePrivate *priv;

  if (widget)
    context = gtk_widget_get_style_context (widget);
  else
    {
      priv = GTK_STYLE_GET_PRIVATE (style);
      context = priv->context;
    }

  gtk_style_context_save (context);

  if (detail)
    transform_detail_string (detail, context);

  cairo_save (cr);

  gtk_render_line (context, cr,
                   x, y1, x, y2);

  cairo_restore (cr);
  gtk_style_context_restore (context);
}

static void
gtk_default_draw_shadow (GtkStyle      *style,
                         cairo_t       *cr,
                         GtkStateType   state_type,
                         GtkShadowType  shadow_type,
                         GtkWidget     *widget,
                         const gchar   *detail,
                         gint           x,
                         gint           y,
                         gint           width,
                         gint           height)
{
  GtkStyleContext *context;
  GtkStylePrivate *priv;

  if (shadow_type == GTK_SHADOW_NONE)
    return;

  if (widget)
    context = gtk_widget_get_style_context (widget);
  else
    {
      priv = GTK_STYLE_GET_PRIVATE (style);
      context = priv->context;
    }

  gtk_style_context_save (context);

  if (detail)
    transform_detail_string (detail, context);

  cairo_save (cr);

  gtk_render_frame (context, cr,
                    (gdouble) x,
                    (gdouble) y,
                    (gdouble) width,
                    (gdouble) height);

  cairo_restore (cr);
  gtk_style_context_restore (context);
}

static void
draw_arrow (cairo_t       *cr,
	    GdkColor      *color,
	    GtkArrowType   arrow_type,
	    gint           x,
	    gint           y,
	    gint           width,
	    gint           height)
{
  gdk_cairo_set_source_color (cr, color);
  cairo_save (cr);
    
  if (arrow_type == GTK_ARROW_DOWN)
    {
      cairo_move_to (cr, x,              y);
      cairo_line_to (cr, x + width,      y);
      cairo_line_to (cr, x + width / 2., y + height);
    }
  else if (arrow_type == GTK_ARROW_UP)
    {
      cairo_move_to (cr, x,              y + height);
      cairo_line_to (cr, x + width / 2., y);
      cairo_line_to (cr, x + width,      y + height);
    }
  else if (arrow_type == GTK_ARROW_LEFT)
    {
      cairo_move_to (cr, x + width,      y);
      cairo_line_to (cr, x + width,      y + height);
      cairo_line_to (cr, x,              y + height / 2.);
    }
  else if (arrow_type == GTK_ARROW_RIGHT)
    {
      cairo_move_to (cr, x,              y);
      cairo_line_to (cr, x + width,      y + height / 2.);
      cairo_line_to (cr, x,              y + height);
    }

  cairo_close_path (cr);
  cairo_fill (cr);

  cairo_restore (cr);
}

static void
gtk_default_draw_arrow (GtkStyle      *style,
			cairo_t       *cr,
			GtkStateType   state,
			GtkShadowType  shadow,
			GtkWidget     *widget,
			const gchar   *detail,
			GtkArrowType   arrow_type,
			gboolean       fill,
			gint           x,
			gint           y,
			gint           width,
			gint           height)
{
  GtkStyleContext *context;
  GtkStylePrivate *priv;
  GtkStateFlags flags = 0;
  gdouble angle, size;

  if (arrow_type == GTK_ARROW_NONE)
    return;

  if (widget)
    context = gtk_widget_get_style_context (widget);
  else
    {
      priv = GTK_STYLE_GET_PRIVATE (style);
      context = priv->context;
    }

  gtk_style_context_save (context);

  if (detail)
    transform_detail_string (detail, context);

  switch (arrow_type)
    {
    case GTK_ARROW_UP:
      angle = 0;
      size = width;
      break;
    case GTK_ARROW_RIGHT:
      angle = G_PI / 2;
      size = height;
      break;
    case GTK_ARROW_DOWN:
      angle = G_PI;
      size = width;
      break;
    case GTK_ARROW_LEFT:
      angle = 3 * (G_PI / 2);
      size = height;
      break;
    default:
      g_assert_not_reached ();
    }

  switch (state)
    {
    case GTK_STATE_PRELIGHT:
      flags |= GTK_STATE_FLAG_PRELIGHT;
      break;
    case GTK_STATE_SELECTED:
      flags |= GTK_STATE_FLAG_SELECTED;
      break;
    case GTK_STATE_INSENSITIVE:
      flags |= GTK_STATE_FLAG_INSENSITIVE;
      break;
    case GTK_STATE_ACTIVE:
      flags |= GTK_STATE_FLAG_ACTIVE;
      break;
    default:
      break;
    }

  gtk_style_context_set_state (context, flags);

  cairo_save (cr);

  gtk_render_arrow (context,
                    cr, angle,
                    (gdouble) x,
                    (gdouble) y,
                    size);

  cairo_restore (cr);
  gtk_style_context_restore (context);
}

static void
gtk_default_draw_diamond (GtkStyle      *style,
                          cairo_t       *cr,
                          GtkStateType   state_type,
                          GtkShadowType  shadow_type,
                          GtkWidget     *widget,
                          const gchar   *detail,
                          gint           x,
                          gint           y,
                          gint           width,
                          gint           height)
{
  gint half_width;
  gint half_height;
  GdkColor *outer_nw = NULL;
  GdkColor *outer_ne = NULL;
  GdkColor *outer_sw = NULL;
  GdkColor *outer_se = NULL;
  GdkColor *middle_nw = NULL;
  GdkColor *middle_ne = NULL;
  GdkColor *middle_sw = NULL;
  GdkColor *middle_se = NULL;
  GdkColor *inner_nw = NULL;
  GdkColor *inner_ne = NULL;
  GdkColor *inner_sw = NULL;
  GdkColor *inner_se = NULL;
  
  half_width = width / 2;
  half_height = height / 2;
  
  switch (shadow_type)
    {
    case GTK_SHADOW_IN:
      inner_sw = inner_se = &style->bg[state_type];
      middle_sw = middle_se = &style->light[state_type];
      outer_sw = outer_se = &style->light[state_type];
      inner_nw = inner_ne = &style->black;
      middle_nw = middle_ne = &style->dark[state_type];
      outer_nw = outer_ne = &style->dark[state_type];
      break;
          
    case GTK_SHADOW_OUT:
      inner_sw = inner_se = &style->dark[state_type];
      middle_sw = middle_se = &style->dark[state_type];
      outer_sw = outer_se = &style->black;
      inner_nw = inner_ne = &style->bg[state_type];
      middle_nw = middle_ne = &style->light[state_type];
      outer_nw = outer_ne = &style->light[state_type];
      break;

    case GTK_SHADOW_ETCHED_IN:
      inner_sw = inner_se = &style->bg[state_type];
      middle_sw = middle_se = &style->dark[state_type];
      outer_sw = outer_se = &style->light[state_type];
      inner_nw = inner_ne = &style->bg[state_type];
      middle_nw = middle_ne = &style->light[state_type];
      outer_nw = outer_ne = &style->dark[state_type];
      break;

    case GTK_SHADOW_ETCHED_OUT:
      inner_sw = inner_se = &style->bg[state_type];
      middle_sw = middle_se = &style->light[state_type];
      outer_sw = outer_se = &style->dark[state_type];
      inner_nw = inner_ne = &style->bg[state_type];
      middle_nw = middle_ne = &style->dark[state_type];
      outer_nw = outer_ne = &style->light[state_type];
      break;
      
    default:

      break;
    }

  if (inner_sw)
    {
      _cairo_draw_line (cr, inner_sw,
                        x + 2, y + half_height,
                        x + half_width, y + height - 2);
      _cairo_draw_line (cr, inner_se,
                        x + half_width, y + height - 2,
                        x + width - 2, y + half_height);
      _cairo_draw_line (cr, middle_sw,
                        x + 1, y + half_height,
                        x + half_width, y + height - 1);
      _cairo_draw_line (cr, middle_se,
                        x + half_width, y + height - 1,
                        x + width - 1, y + half_height);
      _cairo_draw_line (cr, outer_sw,
                        x, y + half_height,
                        x + half_width, y + height);
      _cairo_draw_line (cr, outer_se,
                        x + half_width, y + height,
                        x + width, y + half_height);
  
      _cairo_draw_line (cr, inner_nw,
                        x + 2, y + half_height,
                        x + half_width, y + 2);
      _cairo_draw_line (cr, inner_ne,
                        x + half_width, y + 2,
                        x + width - 2, y + half_height);
      _cairo_draw_line (cr, middle_nw,
                        x + 1, y + half_height,
                        x + half_width, y + 1);
      _cairo_draw_line (cr, middle_ne,
                        x + half_width, y + 1,
                        x + width - 1, y + half_height);
      _cairo_draw_line (cr, outer_nw,
                        x, y + half_height,
                        x + half_width, y);
      _cairo_draw_line (cr, outer_ne,
                        x + half_width, y,
                        x + width, y + half_height);
    }
}

static void
option_menu_get_props (GtkWidget      *widget,
		       GtkRequisition *indicator_size,
		       GtkBorder      *indicator_spacing)
{
  GtkRequisition *tmp_size = NULL;
  GtkBorder *tmp_spacing = NULL;

  if (tmp_size)
    {
      *indicator_size = *tmp_size;
      gtk_requisition_free (tmp_size);
    }
  else
    *indicator_size = default_option_indicator_size;

  if (tmp_spacing)
    {
      *indicator_spacing = *tmp_spacing;
      gtk_border_free (tmp_spacing);
    }
  else
    *indicator_spacing = default_option_indicator_spacing;
}

static void 
gtk_default_draw_box (GtkStyle      *style,
		      cairo_t       *cr,
		      GtkStateType   state_type,
		      GtkShadowType  shadow_type,
		      GtkWidget     *widget,
		      const gchar   *detail,
		      gint           x,
		      gint           y,
		      gint           width,
		      gint           height)
{
  GtkStyleContext *context;
  GtkStylePrivate *priv;
  GtkStateFlags flags = 0;

  if (widget)
    context = gtk_widget_get_style_context (widget);
  else
    {
      priv = GTK_STYLE_GET_PRIVATE (style);
      context = priv->context;
    }

  gtk_style_context_save (context);

  if (detail)
    transform_detail_string (detail, context);

  switch (state_type)
    {
    case GTK_STATE_ACTIVE:
      flags |= GTK_STATE_FLAG_ACTIVE;
      break;
    case GTK_STATE_PRELIGHT:
      flags |= GTK_STATE_FLAG_PRELIGHT;
      break;
    case GTK_STATE_SELECTED:
      flags |= GTK_STATE_FLAG_SELECTED;
      break;
    case GTK_STATE_INSENSITIVE:
      flags |= GTK_STATE_FLAG_INSENSITIVE;
      break;
    default:
      break;
    }

  if (shadow_type == GTK_SHADOW_IN)
    flags |= GTK_STATE_FLAG_ACTIVE;

  gtk_style_context_set_state (context, flags);

  cairo_save (cr);

  if (gtk_style_context_has_class (context, GTK_STYLE_CLASS_PROGRESSBAR))
    gtk_render_activity (context, cr, x, y, width, height);
  else
    {
      gtk_render_background (context, cr, x, y, width, height);

      if (shadow_type != GTK_SHADOW_NONE)
	gtk_render_frame (context, cr, x, y, width, height);
    }

  cairo_restore (cr);
  gtk_style_context_restore (context);
}

static void 
gtk_default_draw_flat_box (GtkStyle      *style,
                           cairo_t       *cr,
                           GtkStateType   state_type,
                           GtkShadowType  shadow_type,
                           GtkWidget     *widget,
                           const gchar   *detail,
                           gint           x,
                           gint           y,
                           gint           width,
                           gint           height)
{
  GtkStyleContext *context;
  GtkStylePrivate *priv;
  GtkStateFlags flags = 0;

  if (widget)
    context = gtk_widget_get_style_context (widget);
  else
    {
      priv = GTK_STYLE_GET_PRIVATE (style);
      context = priv->context;
    }

  gtk_style_context_save (context);

  if (detail)
    transform_detail_string (detail, context);

  switch (state_type)
    {
    case GTK_STATE_PRELIGHT:
      flags |= GTK_STATE_FLAG_PRELIGHT;
      break;
    case GTK_STATE_SELECTED:
      flags |= GTK_STATE_FLAG_SELECTED;
      break;
    case GTK_STATE_INSENSITIVE:
      flags |= GTK_STATE_FLAG_INSENSITIVE;
      break;
    case GTK_STATE_ACTIVE:
      flags |= GTK_STATE_FLAG_ACTIVE;
      break;
    case GTK_STATE_FOCUSED:
      flags |= GTK_STATE_FLAG_FOCUSED;
      break;
    default:
      break;
    }

  gtk_style_context_set_state (context, flags);

  cairo_save (cr);

  gtk_render_background (context, cr,
                         (gdouble) x,
                         (gdouble) y,
                         (gdouble) width,
                         (gdouble) height);

  cairo_restore (cr);
  gtk_style_context_restore (context);
}

static void 
gtk_default_draw_check (GtkStyle      *style,
			cairo_t       *cr,
			GtkStateType   state_type,
			GtkShadowType  shadow_type,
			GtkWidget     *widget,
			const gchar   *detail,
			gint           x,
			gint           y,
			gint           width,
			gint           height)
{
  GtkStyleContext *context;
  GtkStylePrivate *priv;
  GtkStateFlags flags = 0;

  if (widget)
    context = gtk_widget_get_style_context (widget);
  else
    {
      priv = GTK_STYLE_GET_PRIVATE (style);
      context = priv->context;
    }

  gtk_style_context_save (context);

  if (detail)
    transform_detail_string (detail, context);

  switch (state_type)
    {
    case GTK_STATE_PRELIGHT:
      flags |= GTK_STATE_FLAG_PRELIGHT;
      break;
    case GTK_STATE_SELECTED:
      flags |= GTK_STATE_FLAG_SELECTED;
      break;
    case GTK_STATE_INSENSITIVE:
      flags |= GTK_STATE_FLAG_INSENSITIVE;
      break;
    default:
      break;
    }

  if (shadow_type == GTK_SHADOW_IN)
    flags |= GTK_STATE_FLAG_ACTIVE;
  else if (shadow_type == GTK_SHADOW_ETCHED_IN)
    flags |= GTK_STATE_FLAG_INCONSISTENT;

  gtk_style_context_set_state (context, flags);

  cairo_save (cr);

  gtk_render_check (context,
                    cr, x, y,
                    width, height);

  cairo_restore (cr);
  gtk_style_context_restore (context);
}

static void 
gtk_default_draw_option (GtkStyle      *style,
			 cairo_t       *cr,
			 GtkStateType   state_type,
			 GtkShadowType  shadow_type,
			 GtkWidget     *widget,
			 const gchar   *detail,
			 gint           x,
			 gint           y,
			 gint           width,
			 gint           height)
{
  GtkStyleContext *context;
  GtkStylePrivate *priv;
  GtkStateFlags flags = 0;

  if (widget)
    context = gtk_widget_get_style_context (widget);
  else
    {
      priv = GTK_STYLE_GET_PRIVATE (style);
      context = priv->context;
    }

  gtk_style_context_save (context);

  if (detail)
    transform_detail_string (detail, context);

  switch (state_type)
    {
    case GTK_STATE_PRELIGHT:
      flags |= GTK_STATE_FLAG_PRELIGHT;
      break;
    case GTK_STATE_SELECTED:
      flags |= GTK_STATE_FLAG_SELECTED;
      break;
    case GTK_STATE_INSENSITIVE:
      flags |= GTK_STATE_FLAG_INSENSITIVE;
      break;
    default:
      break;
    }

  if (shadow_type == GTK_SHADOW_IN)
    flags |= GTK_STATE_FLAG_ACTIVE;
  else if (shadow_type == GTK_SHADOW_ETCHED_IN)
    flags |= GTK_STATE_FLAG_INCONSISTENT;

  gtk_style_context_set_state (context, flags);

  cairo_save (cr);
  gtk_render_option (context, cr,
                     (gdouble) x,
                     (gdouble) y,
                     (gdouble) width,
                     (gdouble) height);

  cairo_restore (cr);
  gtk_style_context_restore (context);
}

static void
gtk_default_draw_tab (GtkStyle      *style,
		      cairo_t       *cr,
		      GtkStateType   state_type,
		      GtkShadowType  shadow_type,
		      GtkWidget     *widget,
		      const gchar   *detail,
		      gint           x,
		      gint           y,
		      gint           width,
		      gint           height)
{
#define ARROW_SPACE 4

  GtkRequisition indicator_size;
  GtkBorder indicator_spacing;
  gint arrow_height;

  option_menu_get_props (widget, &indicator_size, &indicator_spacing);

  indicator_size.width += (indicator_size.width % 2) - 1;
  arrow_height = indicator_size.width / 2 + 1;

  x += (width - indicator_size.width) / 2;
  y += (height - (2 * arrow_height + ARROW_SPACE)) / 2;

  if (state_type == GTK_STATE_INSENSITIVE)
    {
      draw_arrow (cr, &style->white,
		  GTK_ARROW_UP, x + 1, y + 1,
		  indicator_size.width, arrow_height);
      
      draw_arrow (cr, &style->white,
		  GTK_ARROW_DOWN, x + 1, y + arrow_height + ARROW_SPACE + 1,
		  indicator_size.width, arrow_height);
    }
  
  draw_arrow (cr, &style->fg[state_type],
	      GTK_ARROW_UP, x, y,
	      indicator_size.width, arrow_height);
  
  
  draw_arrow (cr, &style->fg[state_type],
	      GTK_ARROW_DOWN, x, y + arrow_height + ARROW_SPACE,
	      indicator_size.width, arrow_height);
}

static void 
gtk_default_draw_shadow_gap (GtkStyle       *style,
                             cairo_t        *cr,
                             GtkStateType    state_type,
                             GtkShadowType   shadow_type,
                             GtkWidget      *widget,
                             const gchar    *detail,
                             gint            x,
                             gint            y,
                             gint            width,
                             gint            height,
                             GtkPositionType gap_side,
                             gint            gap_x,
                             gint            gap_width)
{
  GtkStyleContext *context;
  GtkStylePrivate *priv;
  GtkStateFlags flags = 0;

  if (shadow_type == GTK_SHADOW_NONE)
    return;

  if (widget)
    context = gtk_widget_get_style_context (widget);
  else
    {
      priv = GTK_STYLE_GET_PRIVATE (style);
      context = priv->context;
    }

  gtk_style_context_save (context);

  if (detail)
    transform_detail_string (detail, context);

  switch (state_type)
    {
    case GTK_STATE_ACTIVE:
      flags |= GTK_STATE_FLAG_ACTIVE;
      break;
    case GTK_STATE_PRELIGHT:
      flags |= GTK_STATE_FLAG_PRELIGHT;
      break;
    case GTK_STATE_SELECTED:
      flags |= GTK_STATE_FLAG_SELECTED;
      break;
    case GTK_STATE_INSENSITIVE:
      flags |= GTK_STATE_FLAG_INSENSITIVE;
      break;
    default:
      break;
    }

  gtk_style_context_set_state (context, flags);

  cairo_save (cr);
  gtk_render_frame_gap (context, cr,
                        (gdouble) x,
                        (gdouble) y,
                        (gdouble) width,
                        (gdouble) height,
                        gap_side,
                        (gdouble) gap_x,
                        (gdouble) gap_x + gap_width);

  cairo_restore (cr);
  gtk_style_context_restore (context);
}

static void 
gtk_default_draw_box_gap (GtkStyle       *style,
                          cairo_t        *cr,
                          GtkStateType    state_type,
                          GtkShadowType   shadow_type,
                          GtkWidget      *widget,
                          const gchar    *detail,
                          gint            x,
                          gint            y,
                          gint            width,
                          gint            height,
                          GtkPositionType gap_side,
                          gint            gap_x,
                          gint            gap_width)
{
  GtkStyleContext *context;
  GtkStylePrivate *priv;
  GtkStateFlags flags = 0;

  if (widget)
    context = gtk_widget_get_style_context (widget);
  else
    {
      priv = GTK_STYLE_GET_PRIVATE (style);
      context = priv->context;
    }

  gtk_style_context_save (context);

  if (detail)
    transform_detail_string (detail, context);

  switch (state_type)
    {
    case GTK_STATE_ACTIVE:
      flags |= GTK_STATE_FLAG_ACTIVE;
      break;
    case GTK_STATE_PRELIGHT:
      flags |= GTK_STATE_FLAG_PRELIGHT;
      break;
    case GTK_STATE_SELECTED:
      flags |= GTK_STATE_FLAG_SELECTED;
      break;
    case GTK_STATE_INSENSITIVE:
      flags |= GTK_STATE_FLAG_INSENSITIVE;
      break;
    default:
      break;
    }

  gtk_style_context_set_state (context, flags);

  cairo_save (cr);
  gtk_render_background (context, cr,
                         (gdouble) x,
                         (gdouble) y,
                         (gdouble) width,
                         (gdouble) height);


  if (shadow_type != GTK_SHADOW_NONE)
    gtk_render_frame_gap (context, cr,
			  (gdouble) x,
			  (gdouble) y,
			  (gdouble) width,
			  (gdouble) height,
			  gap_side,
			  (gdouble) gap_x,
			  (gdouble) gap_x + gap_width);
  
  cairo_restore (cr);
  gtk_style_context_restore (context);
}

static void 
gtk_default_draw_extension (GtkStyle       *style,
                            cairo_t        *cr,
                            GtkStateType    state_type,
                            GtkShadowType   shadow_type,
                            GtkWidget      *widget,
                            const gchar    *detail,
                            gint            x,
                            gint            y,
                            gint            width,
                            gint            height,
                            GtkPositionType gap_side)
{
  GtkStyleContext *context;
  GtkStylePrivate *priv;
  GtkStateFlags flags = 0;

  if (widget)
    context = gtk_widget_get_style_context (widget);
  else
    {
      priv = GTK_STYLE_GET_PRIVATE (style);
      context = priv->context;
    }

  gtk_style_context_save (context);

  if (detail)
    transform_detail_string (detail, context);

  switch (state_type)
    {
    case GTK_STATE_ACTIVE:
      flags |= GTK_STATE_FLAG_ACTIVE;
      break;
    case GTK_STATE_PRELIGHT:
      flags |= GTK_STATE_FLAG_PRELIGHT;
      break;
    case GTK_STATE_SELECTED:
      flags |= GTK_STATE_FLAG_SELECTED;
      break;
    case GTK_STATE_INSENSITIVE:
      flags |= GTK_STATE_FLAG_INSENSITIVE;
      break;
    default:
      break;
    }

  gtk_style_context_set_state (context, flags);

  cairo_save (cr);

  gtk_render_extension (context, cr,
                        (gdouble) x,
                        (gdouble) y,
                        (gdouble) width,
                        (gdouble) height,
                        gap_side);

  cairo_restore (cr);
  gtk_style_context_restore (context);
}

static void 
gtk_default_draw_focus (GtkStyle      *style,
			cairo_t       *cr,
			GtkStateType   state_type,
			GtkWidget     *widget,
			const gchar   *detail,
			gint           x,
			gint           y,
			gint           width,
			gint           height)
{
  GtkStyleContext *context;
  GtkStylePrivate *priv;

  if (widget)
    context = gtk_widget_get_style_context (widget);
  else
    {
      priv = GTK_STYLE_GET_PRIVATE (style);
      context = priv->context;
    }

  gtk_style_context_save (context);

  if (detail)
    transform_detail_string (detail, context);

  cairo_save (cr);

  gtk_render_focus (context, cr,
                    (gdouble) x,
                    (gdouble) y,
                    (gdouble) width,
                    (gdouble) height);

  cairo_restore (cr);
  gtk_style_context_restore (context);
}

static void 
gtk_default_draw_slider (GtkStyle      *style,
                         cairo_t       *cr,
                         GtkStateType   state_type,
                         GtkShadowType  shadow_type,
                         GtkWidget     *widget,
                         const gchar   *detail,
                         gint           x,
                         gint           y,
                         gint           width,
                         gint           height,
                         GtkOrientation orientation)
{
  GtkStyleContext *context;
  GtkStylePrivate *priv;
  GtkStateFlags flags = 0;

  if (widget)
    context = gtk_widget_get_style_context (widget);
  else
    {
      priv = GTK_STYLE_GET_PRIVATE (style);
      context = priv->context;
    }

  gtk_style_context_save (context);

  if (detail)
    transform_detail_string (detail, context);

  switch (state_type)
    {
    case GTK_STATE_PRELIGHT:
      flags |= GTK_STATE_FLAG_PRELIGHT;
      break;
    case GTK_STATE_SELECTED:
      flags |= GTK_STATE_FLAG_SELECTED;
      break;
    case GTK_STATE_INSENSITIVE:
      flags |= GTK_STATE_FLAG_INSENSITIVE;
      break;
    default:
      break;
    }

  gtk_style_context_set_state (context, flags);

  cairo_save (cr);

  gtk_render_slider (context, cr,  x, y, width, height, orientation);

  cairo_restore (cr);
  gtk_style_context_restore (context);
}

static void 
gtk_default_draw_handle (GtkStyle      *style,
			 cairo_t       *cr,
			 GtkStateType   state_type,
			 GtkShadowType  shadow_type,
			 GtkWidget     *widget,
			 const gchar   *detail,
			 gint           x,
			 gint           y,
			 gint           width,
			 gint           height,
			 GtkOrientation orientation)
{
  GtkStyleContext *context;
  GtkStylePrivate *priv;
  GtkStateFlags flags = 0;

  if (widget)
    context = gtk_widget_get_style_context (widget);
  else
    {
      priv = GTK_STYLE_GET_PRIVATE (style);
      context = priv->context;
    }

  gtk_style_context_save (context);

  if (detail)
    transform_detail_string (detail, context);

  switch (state_type)
    {
    case GTK_STATE_PRELIGHT:
      flags |= GTK_STATE_FLAG_PRELIGHT;
      break;
    case GTK_STATE_SELECTED:
      flags |= GTK_STATE_FLAG_SELECTED;
      break;
    case GTK_STATE_INSENSITIVE:
      flags |= GTK_STATE_FLAG_INSENSITIVE;
      break;
    default:
      break;
    }

  gtk_style_context_set_state (context, flags);

  cairo_save (cr);

  gtk_render_handle (context, cr,
                     (gdouble) x,
                     (gdouble) y,
                     (gdouble) width,
                     (gdouble) height);

  cairo_restore (cr);
  gtk_style_context_restore (context);
}

static void
gtk_default_draw_expander (GtkStyle        *style,
                           cairo_t         *cr,
                           GtkStateType     state_type,
                           GtkWidget       *widget,
                           const gchar     *detail,
                           gint             x,
                           gint             y,
			   GtkExpanderStyle expander_style)
{
  GtkStyleContext *context;
  GtkStylePrivate *priv;
  GtkStateFlags flags = 0;
  gint size;

  if (widget)
    context = gtk_widget_get_style_context (widget);
  else
    {
      priv = GTK_STYLE_GET_PRIVATE (style);
      context = priv->context;
    }

  gtk_style_context_save (context);

  if (detail)
    transform_detail_string (detail, context);

  gtk_style_context_add_class (context, "expander");

  switch (state_type)
    {
    case GTK_STATE_PRELIGHT:
      flags |= GTK_STATE_FLAG_PRELIGHT;
      break;
    case GTK_STATE_SELECTED:
      flags |= GTK_STATE_FLAG_SELECTED;
      break;
    case GTK_STATE_INSENSITIVE:
      flags |= GTK_STATE_FLAG_INSENSITIVE;
      break;
    default:
      break;
    }

  if (widget &&
      gtk_widget_class_find_style_property (GTK_WIDGET_GET_CLASS (widget),
                                            "expander-size"))
    gtk_widget_style_get (widget, "expander-size", &size, NULL);
  else
    size = 12;

  if (expander_style == GTK_EXPANDER_EXPANDED)
    flags |= GTK_STATE_FLAG_ACTIVE;

  gtk_style_context_set_state (context, flags);

  cairo_save (cr);

  gtk_render_expander (context, cr,
                       (gdouble) x - (size / 2),
                       (gdouble) y - (size / 2),
                       (gdouble) size,
                       (gdouble) size);

  cairo_restore (cr);
  gtk_style_context_restore (context);
}

static void
gtk_default_draw_layout (GtkStyle        *style,
                         cairo_t         *cr,
                         GtkStateType     state_type,
			 gboolean         use_text,
                         GtkWidget       *widget,
                         const gchar     *detail,
                         gint             x,
                         gint             y,
                         PangoLayout     *layout)
{
  GtkStyleContext *context;
  GtkStylePrivate *priv;
  GtkStateFlags flags = 0;

  if (widget)
    context = gtk_widget_get_style_context (widget);
  else
    {
      priv = GTK_STYLE_GET_PRIVATE (style);
      context = priv->context;
    }

  gtk_style_context_save (context);

  if (detail)
    transform_detail_string (detail, context);

  switch (state_type)
    {
    case GTK_STATE_PRELIGHT:
      flags |= GTK_STATE_FLAG_PRELIGHT;
      break;
    case GTK_STATE_SELECTED:
      flags |= GTK_STATE_FLAG_SELECTED;
      break;
    case GTK_STATE_INSENSITIVE:
      flags |= GTK_STATE_FLAG_INSENSITIVE;
      break;
    default:
      break;
    }

  gtk_style_context_set_state (context, flags);

  cairo_save (cr);

  gtk_render_layout (context, cr,
                     (gdouble) x,
                     (gdouble) y,
                     layout);

  cairo_restore (cr);
  gtk_style_context_restore (context);
}

static void
gtk_default_draw_resize_grip (GtkStyle       *style,
                              cairo_t        *cr,
                              GtkStateType    state_type,
                              GtkWidget      *widget,
                              const gchar    *detail,
                              GdkWindowEdge   edge,
                              gint            x,
                              gint            y,
                              gint            width,
                              gint            height)
{
  GtkStyleContext *context;
  GtkStylePrivate *priv;
  GtkStateFlags flags = 0;
  GtkJunctionSides sides = 0;

  if (widget)
    context = gtk_widget_get_style_context (widget);
  else
    {
      priv = GTK_STYLE_GET_PRIVATE (style);
      context = priv->context;
    }

  gtk_style_context_save (context);

  if (detail)
    transform_detail_string (detail, context);

  gtk_style_context_add_class (context, "grip");

  switch (state_type)
    {
    case GTK_STATE_PRELIGHT:
      flags |= GTK_STATE_FLAG_PRELIGHT;
      break;
    case GTK_STATE_SELECTED:
      flags |= GTK_STATE_FLAG_SELECTED;
      break;
    case GTK_STATE_INSENSITIVE:
      flags |= GTK_STATE_FLAG_INSENSITIVE;
      break;
    default:
      break;
    }

  gtk_style_context_set_state (context, flags);

  switch (edge)
    {
    case GDK_WINDOW_EDGE_NORTH_WEST:
      sides = GTK_JUNCTION_CORNER_TOPLEFT;
      break;
    case GDK_WINDOW_EDGE_NORTH:
      sides = GTK_JUNCTION_TOP;
      break;
    case GDK_WINDOW_EDGE_NORTH_EAST:
      sides = GTK_JUNCTION_CORNER_TOPRIGHT;
      break;
    case GDK_WINDOW_EDGE_WEST:
      sides = GTK_JUNCTION_LEFT;
      break;
    case GDK_WINDOW_EDGE_EAST:
      sides = GTK_JUNCTION_RIGHT;
      break;
    case GDK_WINDOW_EDGE_SOUTH_WEST:
      sides = GTK_JUNCTION_CORNER_BOTTOMLEFT;
      break;
    case GDK_WINDOW_EDGE_SOUTH:
      sides = GTK_JUNCTION_BOTTOM;
      break;
    case GDK_WINDOW_EDGE_SOUTH_EAST:
      sides = GTK_JUNCTION_CORNER_BOTTOMRIGHT;
      break;
    }

  gtk_style_context_set_junction_sides (context, sides);

  cairo_save (cr);

  gtk_render_handle (context, cr,
                     (gdouble) x,
                     (gdouble) y,
                     (gdouble) width,
                     (gdouble) height);

  cairo_restore (cr);
  gtk_style_context_restore (context);
}

static void
gtk_default_draw_spinner (GtkStyle     *style,
                          cairo_t      *cr,
                          GtkStateType  state_type,
                          GtkWidget    *widget,
                          const gchar  *detail,
                          guint         step,
                          gint          x,
                          gint          y,
                          gint          width,
                          gint          height)
{
  GdkColor *color;
  guint num_steps;
  gdouble dx, dy;
  gdouble radius;
  gdouble half;
  gint i;
  guint real_step;

  num_steps = 12;
  real_step = step % num_steps;

  /* set a clip region for the expose event */
  cairo_rectangle (cr, x, y, width, height);
  cairo_clip (cr);

  cairo_translate (cr, x, y);

  /* draw clip region */
  cairo_set_operator (cr, CAIRO_OPERATOR_OVER);

  color = &style->fg[state_type];
  dx = width / 2;
  dy = height / 2;
  radius = MIN (width / 2, height / 2);
  half = num_steps / 2;

  for (i = 0; i < num_steps; i++)
    {
      gint inset = 0.7 * radius;

      /* transparency is a function of time and intial value */
      gdouble t = (gdouble) ((i + num_steps - real_step)
                             % num_steps) / num_steps;

      cairo_save (cr);

      cairo_set_source_rgba (cr,
                             color->red / 65535.,
                             color->green / 65535.,
                             color->blue / 65535.,
                             t);

      cairo_set_line_width (cr, 2.0);
      cairo_move_to (cr,
                     dx + (radius - inset) * cos (i * G_PI / half),
                     dy + (radius - inset) * sin (i * G_PI / half));
      cairo_line_to (cr,
                     dx + radius * cos (i * G_PI / half),
                     dy + radius * sin (i * G_PI / half));
      cairo_stroke (cr);

      cairo_restore (cr);
    }
}

void
_gtk_style_shade (const 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;
}

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;
}

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;
    }
}


/**
 * gtk_paint_hline:
 * @style: a #GtkStyle
 * @cr: a #caio_t
 * @state_type: a state
 * @widget: (allow-none): the widget
 * @detail: (allow-none): a style detail
 * @x1: the starting x coordinate
 * @x2: the ending x coordinate
 * @y: the y coordinate
 *
 * Draws a horizontal line from (@x1, @y) to (@x2, @y) in @cr
 * using the given style and state.
 *
 * Deprecated:3.0: Use gtk_render_line() instead
 **/
void
gtk_paint_hline (GtkStyle           *style,
                 cairo_t            *cr,
                 GtkStateType        state_type,
                 GtkWidget          *widget,
                 const gchar        *detail,
                 gint                x1,
                 gint                x2,
                 gint                y)
{
  g_return_if_fail (GTK_IS_STYLE (style));
  g_return_if_fail (cr != NULL);
  g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_hline != NULL);

  cairo_save (cr);

  GTK_STYLE_GET_CLASS (style)->draw_hline (style, cr, state_type,
                                           widget, detail,
                                           x1, x2, y);

  cairo_restore (cr);
}

/**
 * gtk_paint_vline:
 * @style: a #GtkStyle
 * @cr: a #cairo_t
 * @state_type: a state
 * @widget: (allow-none): the widget
 * @detail: (allow-none): a style detail
 * @y1_: the starting y coordinate
 * @y2_: the ending y coordinate
 * @x: the x coordinate
 *
 * Draws a vertical line from (@x, @y1_) to (@x, @y2_) in @cr
 * using the given style and state.
 *
 * Deprecated:3.0: Use gtk_render_line() instead
 */
void
gtk_paint_vline (GtkStyle           *style,
                 cairo_t            *cr,
                 GtkStateType        state_type,
                 GtkWidget          *widget,
                 const gchar        *detail,
                 gint                y1_,
                 gint                y2_,
                 gint                x)
{
  g_return_if_fail (GTK_IS_STYLE (style));
  g_return_if_fail (cr != NULL);
  g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_vline != NULL);

  cairo_save (cr);

  GTK_STYLE_GET_CLASS (style)->draw_vline (style, cr, state_type,
                                           widget, detail,
                                           y1_, y2_, x);

  cairo_restore (cr);
}

/**
 * gtk_paint_shadow:
 * @style: a #GtkStyle
 * @cr: a #cairo_t
 * @state_type: a state
 * @shadow_type: type of shadow to draw
 * @widget: (allow-none): the widget
 * @detail: (allow-none): a style detail
 * @x: x origin of the rectangle
 * @y: y origin of the rectangle
 * @width: width of the rectangle
 * @height: width of the rectangle
 *
 * Draws a shadow around the given rectangle in @cr
 * using the given style and state and shadow type.
 *
 * Deprecated:3.0: Use gtk_render_frame() instead
 */
void
gtk_paint_shadow (GtkStyle           *style,
                  cairo_t            *cr,
                  GtkStateType        state_type,
                  GtkShadowType       shadow_type,
                  GtkWidget          *widget,
                  const gchar        *detail,
                  gint                x,
                  gint                y,
                  gint                width,
                  gint                height)
{
  g_return_if_fail (GTK_IS_STYLE (style));
  g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_shadow != NULL);
  g_return_if_fail (cr != NULL);
  g_return_if_fail (width >= 0);
  g_return_if_fail (height >= 0);

  cairo_save (cr);

  GTK_STYLE_GET_CLASS (style)->draw_shadow (style, cr, state_type, shadow_type,
                                            widget, detail,
                                            x, y, width, height);

  cairo_restore (cr);
}

/**
 * gtk_paint_arrow:
 * @style: a #GtkStyle
 * @cr: a #cairo_t
 * @state_type: a state
 * @shadow_type: the type of shadow to draw
 * @widget: (allow-none): the widget
 * @detail: (allow-none): a style detail
 * @arrow_type: the type of arrow to draw
 * @fill: %TRUE if the arrow tip should be filled
 * @x: x origin of the rectangle to draw the arrow in
 * @y: y origin of the rectangle to draw the arrow in
 * @width: width of the rectangle to draw the arrow in
 * @height: height of the rectangle to draw the arrow in
 *
 * Draws an arrow in the given rectangle on @cr using the given
 * parameters. @arrow_type determines the direction of the arrow.
 *
 * Deprecated:3.0: Use gtk_render_arrow() instead
 */
void
gtk_paint_arrow (GtkStyle           *style,
                 cairo_t            *cr,
                 GtkStateType        state_type,
                 GtkShadowType       shadow_type,
                 GtkWidget          *widget,
                 const gchar        *detail,
                 GtkArrowType        arrow_type,
                 gboolean            fill,
                 gint                x,
                 gint                y,
                 gint                width,
                 gint                height)
{
  g_return_if_fail (GTK_IS_STYLE (style));
  g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_arrow != NULL);
  g_return_if_fail (cr != NULL);
  g_return_if_fail (width >= 0);
  g_return_if_fail (height >= 0);

  cairo_save (cr);

  GTK_STYLE_GET_CLASS (style)->draw_arrow (style, cr, state_type, shadow_type,
                                           widget, detail,
                                           arrow_type, fill, x, y, width, height);

  cairo_restore (cr);
}

/**
 * gtk_paint_diamond:
 * @style: a #GtkStyle
 * @cr: a #cairo_t
 * @state_type: a state
 * @shadow_type: the type of shadow to draw
 * @widget: (allow-none): the widget
 * @detail: (allow-none): a style detail
 * @x: x origin of the rectangle to draw the diamond in
 * @y: y origin of the rectangle to draw the diamond in
 * @width: width of the rectangle to draw the diamond in
 * @height: height of the rectangle to draw the diamond in
 *
 * Draws a diamond in the given rectangle on @window using the given
 * parameters.
 *
 * Deprecated:3.0: Use cairo instead
 */
void
gtk_paint_diamond (GtkStyle           *style,
                   cairo_t            *cr,
                   GtkStateType        state_type,
                   GtkShadowType       shadow_type,
                   GtkWidget          *widget,
                   const gchar        *detail,
                   gint                x,
                   gint                y,
                   gint                width,
                   gint                height)
{
  g_return_if_fail (GTK_IS_STYLE (style));
  g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_diamond != NULL);
  g_return_if_fail (cr != NULL);
  g_return_if_fail (width >= 0);
  g_return_if_fail (height >= 0);

  cairo_save (cr);

  GTK_STYLE_GET_CLASS (style)->draw_diamond (style, cr, state_type, shadow_type,
                                             widget, detail,
                                             x, y, width, height);

  cairo_restore (cr);
}

/**
 * gtk_paint_box:
 * @style: a #GtkStyle
 * @cr: a #cairo_t
 * @state_type: a state
 * @shadow_type: the type of shadow to draw
 * @widget: (allow-none): the widget
 * @detail: (allow-none): a style detail
 * @x: x origin of the box
 * @y: y origin of the box
 * @width: the width of the box
 * @height: the height of the box
 *
 * Draws a box on @cr with the given parameters.
 *
 * Deprecated:3.0: Use gtk_render_frame() and gtk_render_background() instead
 */
void
gtk_paint_box (GtkStyle           *style,
               cairo_t            *cr,
               GtkStateType        state_type,
               GtkShadowType       shadow_type,
               GtkWidget          *widget,
               const gchar        *detail,
               gint                x,
               gint                y,
               gint                width,
               gint                height)
{
  g_return_if_fail (GTK_IS_STYLE (style));
  g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_box != NULL);
  g_return_if_fail (cr != NULL);

  cairo_save (cr);

  GTK_STYLE_GET_CLASS (style)->draw_box (style, cr, state_type, shadow_type,
                                         widget, detail,
                                         x, y, width, height);

  cairo_restore (cr);
}

/**
 * gtk_paint_flat_box:
 * @style: a #GtkStyle
 * @cr: a #cairo_t
 * @state_type: a state
 * @shadow_type: the type of shadow to draw
 * @widget: (allow-none): the widget
 * @detail: (allow-none): a style detail
 * @x: x origin of the box
 * @y: y origin of the box
 * @width: the width of the box
 * @height: the height of the box
 *
 * Draws a flat box on @cr with the given parameters.
 *
 * Deprecated:3.0: Use gtk_render_frame() and gtk_render_background() instead
 */
void
gtk_paint_flat_box (GtkStyle           *style,
                    cairo_t            *cr,
                    GtkStateType        state_type,
                    GtkShadowType       shadow_type,
                    GtkWidget          *widget,
                    const gchar        *detail,
                    gint                x,
                    gint                y,
                    gint                width,
                    gint                height)
{
  g_return_if_fail (GTK_IS_STYLE (style));
  g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_flat_box != NULL);
  g_return_if_fail (cr != NULL);
  g_return_if_fail (width >= 0);
  g_return_if_fail (height >= 0);

  cairo_save (cr);

  GTK_STYLE_GET_CLASS (style)->draw_flat_box (style, cr, state_type, shadow_type,
                                              widget, detail,
                                              x, y, width, height);

  cairo_restore (cr);
}

/**
 * gtk_paint_check:
 * @style: a #GtkStyle
 * @cr: a #cairo_t
 * @state_type: a state
 * @shadow_type: the type of shadow to draw
 * @widget: (allow-none): the widget
 * @detail: (allow-none): a style detail
 * @x: x origin of the rectangle to draw the check in
 * @y: y origin of the rectangle to draw the check in
 * @width: the width of the rectangle to draw the check in
 * @height: the height of the rectangle to draw the check in
 *
 * Draws a check button indicator in the given rectangle on @cr with
 * the given parameters.
 *
 * Deprecated:3.0: Use gtk_render_check() instead
 */
void
gtk_paint_check (GtkStyle           *style,
                 cairo_t            *cr,
                 GtkStateType        state_type,
                 GtkShadowType       shadow_type,
                 GtkWidget          *widget,
                 const gchar        *detail,
                 gint                x,
                 gint                y,
                 gint                width,
                 gint                height)
{
  g_return_if_fail (GTK_IS_STYLE (style));
  g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_check != NULL);
  g_return_if_fail (cr != NULL);

  cairo_save (cr);

  GTK_STYLE_GET_CLASS (style)->draw_check (style, cr, state_type, shadow_type,
                                           widget, detail,
                                           x, y, width, height);

  cairo_restore (cr);
}

/**
 * gtk_paint_option:
 * @style: a #GtkStyle
 * @cr: a #cairo_t
 * @state_type: a state
 * @shadow_type: the type of shadow to draw
 * @widget: (allow-none): the widget
 * @detail: (allow-none): a style detail
 * @x: x origin of the rectangle to draw the option in
 * @y: y origin of the rectangle to draw the option in
 * @width: the width of the rectangle to draw the option in
 * @height: the height of the rectangle to draw the option in
 *
 * Draws a radio button indicator in the given rectangle on @cr with
 * the given parameters.
 *
 * Deprecated:3.0: Use gtk_render_option() instead
 */
void
gtk_paint_option (GtkStyle           *style,
                  cairo_t            *cr,
                  GtkStateType        state_type,
                  GtkShadowType       shadow_type,
                  GtkWidget          *widget,
                  const gchar        *detail,
                  gint                x,
                  gint                y,
                  gint                width,
                  gint                height)
{
  g_return_if_fail (GTK_IS_STYLE (style));
  g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_option != NULL);
  g_return_if_fail (cr != NULL);

  cairo_save (cr);

  GTK_STYLE_GET_CLASS (style)->draw_option (style, cr, state_type, shadow_type,
                                            widget, detail,
                                            x, y, width, height);

  cairo_restore (cr);
}

/**
 * gtk_paint_tab:
 * @style: a #GtkStyle
 * @cr: a #cairo_t
 * @state_type: a state
 * @shadow_type: the type of shadow to draw
 * @widget: (allow-none): the widget
 * @detail: (allow-none): a style detail
 * @x: x origin of the rectangle to draw the tab in
 * @y: y origin of the rectangle to draw the tab in
 * @width: the width of the rectangle to draw the tab in
 * @height: the height of the rectangle to draw the tab in
 *
 * Draws an option menu tab (i.e. the up and down pointing arrows)
 * in the given rectangle on @cr using the given parameters.
 *
 * Deprecated:3.0: Use cairo instead
 */
void
gtk_paint_tab (GtkStyle           *style,
               cairo_t            *cr,
               GtkStateType        state_type,
               GtkShadowType       shadow_type,
               GtkWidget          *widget,
               const gchar        *detail,
               gint                x,
               gint                y,
               gint                width,
               gint                height)
{
  g_return_if_fail (GTK_IS_STYLE (style));
  g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_tab != NULL);
  g_return_if_fail (cr != NULL);

  cairo_save (cr);

  GTK_STYLE_GET_CLASS (style)->draw_tab (style, cr, state_type, shadow_type,
                                         widget, detail,
                                         x, y, width, height);

  cairo_restore (cr);
}

/**
 * gtk_paint_shadow_gap:
 * @style: a #GtkStyle
 * @cr: a #cairo_t
 * @state_type: a state
 * @shadow_type: type of shadow to draw
 * @widget: (allow-none): the widget
 * @detail: (allow-none): a style detail
 * @x: x origin of the rectangle
 * @y: y origin of the rectangle
 * @width: width of the rectangle
 * @height: width of the rectangle
 * @gap_side: side in which to leave the gap
 * @gap_x: starting position of the gap
 * @gap_width: width of the gap
 *
 * Draws a shadow around the given rectangle in @cr
 * using the given style and state and shadow type, leaving a
 * gap in one side.
 *
 * Deprecated:3.0: Use gtk_render_frame_gap() instead
 */
void
gtk_paint_shadow_gap (GtkStyle           *style,
                      cairo_t            *cr,
                      GtkStateType        state_type,
                      GtkShadowType       shadow_type,
                      GtkWidget          *widget,
                      const gchar        *detail,
                      gint                x,
                      gint                y,
                      gint                width,
                      gint                height,
                      GtkPositionType     gap_side,
                      gint                gap_x,
                      gint                gap_width)
{
  g_return_if_fail (GTK_IS_STYLE (style));
  g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_shadow_gap != NULL);
  g_return_if_fail (cr != NULL);
  g_return_if_fail (width >= 0);
  g_return_if_fail (height >= 0);

  cairo_save (cr);

  GTK_STYLE_GET_CLASS (style)->draw_shadow_gap (style, cr, state_type, shadow_type,
                                                widget, detail,
                                                x, y, width, height, gap_side, gap_x, gap_width);

  cairo_restore (cr);
}

/**
 * gtk_paint_box_gap:
 * @style: a #GtkStyle
 * @cr: a #cairo_t
 * @state_type: a state
 * @shadow_type: type of shadow to draw
 * @widget: (allow-none): the widget
 * @detail: (allow-none): a style detail
 * @x: x origin of the rectangle
 * @y: y origin of the rectangle
 * @width: width of the rectangle
 * @height: width of the rectangle
 * @gap_side: side in which to leave the gap
 * @gap_x: starting position of the gap
 * @gap_width: width of the gap
 *
 * Draws a box in @cr using the given style and state and shadow type,
 * leaving a gap in one side.
 *
 * Deprecated:3.0: Use gtk_render_frame_gap() instead
 */
void
gtk_paint_box_gap (GtkStyle           *style,
                   cairo_t            *cr,
                   GtkStateType        state_type,
                   GtkShadowType       shadow_type,
                   GtkWidget          *widget,
                   const gchar        *detail,
                   gint                x,
                   gint                y,
                   gint                width,
                   gint                height,
                   GtkPositionType     gap_side,
                   gint                gap_x,
                   gint                gap_width)
{
  g_return_if_fail (GTK_IS_STYLE (style));
  g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_box_gap != NULL);
  g_return_if_fail (cr != NULL);
  g_return_if_fail (width >= 0);
  g_return_if_fail (height >= 0);

  cairo_save (cr);

  GTK_STYLE_GET_CLASS (style)->draw_box_gap (style, cr, state_type, shadow_type,
                                             widget, detail,
                                             x, y, width, height, gap_side, gap_x, gap_width);

  cairo_restore (cr);
}

/**
 * gtk_paint_extension:
 * @style: a #GtkStyle
 * @cr: a #cairo_t
 * @state_type: a state
 * @shadow_type: type of shadow to draw
 * @widget: (allow-none): the widget
 * @detail: (allow-none): a style detail
 * @x: x origin of the extension
 * @y: y origin of the extension
 * @width: width of the extension
 * @height: width of the extension
 * @gap_side: the side on to which the extension is attached
 *
 * Draws an extension, i.e. a notebook tab.
 *
 * Deprecated:3.0: Use gtk_render_extension() instead
 **/
void
gtk_paint_extension (GtkStyle           *style,
                     cairo_t            *cr,
                     GtkStateType        state_type,
                     GtkShadowType       shadow_type,
                     GtkWidget          *widget,
                     const gchar        *detail,
                     gint                x,
                     gint                y,
                     gint                width,
                     gint                height,
                     GtkPositionType     gap_side)
{
  g_return_if_fail (GTK_IS_STYLE (style));
  g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_extension != NULL);
  g_return_if_fail (cr != NULL);
  g_return_if_fail (width >= 0);
  g_return_if_fail (height >= 0);

  cairo_save (cr);

  GTK_STYLE_GET_CLASS (style)->draw_extension (style, cr, state_type, shadow_type,
                                               widget, detail,
                                               x, y, width, height, gap_side);

  cairo_restore (cr);
}

/**
 * gtk_paint_focus:
 * @style: a #GtkStyle
 * @cr: a #cairo_t
 * @state_type: a state
 * @widget: (allow-none): the widget
 * @detail: (allow-none): a style detail
 * @x: the x origin of the rectangle around which to draw a focus indicator
 * @y: the y origin of the rectangle around which to draw a focus indicator
 * @width: the width of the rectangle around which to draw a focus indicator
 * @height: the height of the rectangle around which to draw a focus indicator
 *
 * Draws a focus indicator around the given rectangle on @cr using the
 * given style.
 *
 * Deprecated:3.0: Use gtk_render_focus() instead
 */
void
gtk_paint_focus (GtkStyle           *style,
                 cairo_t            *cr,
                 GtkStateType        state_type,
                 GtkWidget          *widget,
                 const gchar        *detail,
                 gint                x,
                 gint                y,
                 gint                width,
                 gint                height)
{
  g_return_if_fail (GTK_IS_STYLE (style));
  g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_focus != NULL);
  g_return_if_fail (cr != NULL);
  g_return_if_fail (width >= 0);
  g_return_if_fail (height >= 0);

  cairo_save (cr);

  GTK_STYLE_GET_CLASS (style)->draw_focus (style, cr, state_type,
                                           widget, detail,
                                           x, y, width, height);

  cairo_restore (cr);
}

/**
 * gtk_paint_slider:
 * @style: a #GtkStyle
 * @cr: a #cairo_t
 * @state_type: a state
 * @shadow_type: a shadow
 * @widget: (allow-none): the widget
 * @detail: (allow-none): a style detail
 * @x: the x origin of the rectangle in which to draw a slider
 * @y: the y origin of the rectangle in which to draw a slider
 * @width: the width of the rectangle in which to draw a slider
 * @height: the height of the rectangle in which to draw a slider
 * @orientation: the orientation to be used
 *
 * Draws a slider in the given rectangle on @cr using the
 * given style and orientation.
 *
 * Deprecated:3.0: Use gtk_render_slider() instead
 **/
void
gtk_paint_slider (GtkStyle           *style,
                  cairo_t            *cr,
                  GtkStateType        state_type,
                  GtkShadowType       shadow_type,
                  GtkWidget          *widget,
                  const gchar        *detail,
                  gint                x,
                  gint                y,
                  gint                width,
                  gint                height,
                  GtkOrientation      orientation)
{
  g_return_if_fail (GTK_IS_STYLE (style));
  g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_slider != NULL);
  g_return_if_fail (cr != NULL);
  g_return_if_fail (width >= 0);
  g_return_if_fail (height >= 0);

  cairo_save (cr);

  GTK_STYLE_GET_CLASS (style)->draw_slider (style, cr, state_type, shadow_type,
                                            widget, detail,
                                            x, y, width, height, orientation);

  cairo_restore (cr);
}

/**
 * gtk_paint_handle:
 * @style: a #GtkStyle
 * @cr: a #cairo_t
 * @state_type: a state
 * @shadow_type: type of shadow to draw
 * @widget: (allow-none): the widget
 * @detail: (allow-none): a style detail
 * @x: x origin of the handle
 * @y: y origin of the handle
 * @width: with of the handle
 * @height: height of the handle
 * @orientation: the orientation of the handle
 *
 * Draws a handle as used in #GtkHandleBox and #GtkPaned.
 *
 * Deprecated:3.0: Use gtk_render_handle() instead
 **/
void
gtk_paint_handle (GtkStyle           *style,
                  cairo_t            *cr,
                  GtkStateType        state_type,
                  GtkShadowType       shadow_type,
                  GtkWidget          *widget,
                  const gchar        *detail,
                  gint                x,
                  gint                y,
                  gint                width,
                  gint                height,
                  GtkOrientation      orientation)
{
  g_return_if_fail (GTK_IS_STYLE (style));
  g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_handle != NULL);
  g_return_if_fail (cr != NULL);
  g_return_if_fail (width >= 0);
  g_return_if_fail (height >= 0);

  cairo_save (cr);

  GTK_STYLE_GET_CLASS (style)->draw_handle (style, cr, state_type, shadow_type,
                                            widget, detail,
                                            x, y, width, height, orientation);

  cairo_restore (cr);
}

/**
 * gtk_paint_expander:
 * @style: a #GtkStyle
 * @cr: a #cairo_t
 * @state_type: a state
 * @widget: (allow-none): the widget
 * @detail: (allow-none): a style detail
 * @x: the x position to draw the expander at
 * @y: the y position to draw the expander at
 * @expander_style: the style to draw the expander in; determines
 *   whether the expander is collapsed, expanded, or in an
 *   intermediate state.
 *
 * Draws an expander as used in #GtkTreeView. @x and @y specify the
 * center the expander. The size of the expander is determined by the
 * "expander-size" style property of @widget.  (If widget is not
 * specified or doesn't have an "expander-size" property, an
 * unspecified default size will be used, since the caller doesn't
 * have sufficient information to position the expander, this is
 * likely not useful.) The expander is expander_size pixels tall
 * in the collapsed position and expander_size pixels wide in the
 * expanded position.
 *
 * Deprecated:3.0: Use gtk_render_expander() instead
 **/
void
gtk_paint_expander (GtkStyle           *style,
                    cairo_t            *cr,
                    GtkStateType        state_type,
                    GtkWidget          *widget,
                    const gchar        *detail,
                    gint                x,
                    gint                y,
                    GtkExpanderStyle    expander_style)
{
  g_return_if_fail (GTK_IS_STYLE (style));
  g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_expander != NULL);
  g_return_if_fail (cr != NULL);

  cairo_save (cr);

  GTK_STYLE_GET_CLASS (style)->draw_expander (style, cr, state_type,
                                              widget, detail,
                                              x, y, expander_style);

  cairo_restore (cr);
}

/**
 * gtk_paint_layout:
 * @style: a #GtkStyle
 * @cr: a #cairo_t
 * @state_type: a state
 * @use_text: whether to use the text or foreground
 *            graphics context of @style
 * @widget: (allow-none): the widget
 * @detail: (allow-none): a style detail
 * @x: x origin
 * @y: y origin
 * @layout: the layout to draw
 *
 * Draws a layout on @cr using the given parameters.
 *
 * Deprecated:3.0: Use gtk_render_layout() instead
 **/
void
gtk_paint_layout (GtkStyle           *style,
                  cairo_t            *cr,
                  GtkStateType        state_type,
                  gboolean            use_text,
                  GtkWidget          *widget,
                  const gchar        *detail,
                  gint                x,
                  gint                y,
                  PangoLayout        *layout)
{
  g_return_if_fail (GTK_IS_STYLE (style));
  g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_layout != NULL);
  g_return_if_fail (cr != NULL);

  cairo_save (cr);

  GTK_STYLE_GET_CLASS (style)->draw_layout (style, cr, state_type, use_text,
                                            widget, detail,
                                            x, y, layout);

  cairo_restore (cr);
}

/**
 * gtk_paint_resize_grip:
 * @style: a #GtkStyle
 * @cr: a #cairo_t
 * @state_type: a state
 * @widget: (allow-none): the widget
 * @detail: (allow-none): a style detail
 * @edge: the edge in which to draw the resize grip
 * @x: the x origin of the rectangle in which to draw the resize grip
 * @y: the y origin of the rectangle in which to draw the resize grip
 * @width: the width of the rectangle in which to draw the resize grip
 * @height: the height of the rectangle in which to draw the resize grip
 *
 * Draws a resize grip in the given rectangle on @cr using the given
 * parameters.
 *
 * Deprecated:3.0: Use gtk_render_handle() instead
 */
void
gtk_paint_resize_grip (GtkStyle           *style,
                       cairo_t            *cr,
                       GtkStateType        state_type,
                       GtkWidget          *widget,
                       const gchar        *detail,
                       GdkWindowEdge       edge,
                       gint                x,
                       gint                y,
                       gint                width,
                       gint                height)
{
  g_return_if_fail (GTK_IS_STYLE (style));
  g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_resize_grip != NULL);
  g_return_if_fail (cr != NULL);

  cairo_save (cr);

  GTK_STYLE_GET_CLASS (style)->draw_resize_grip (style, cr, state_type,
                                                 widget, detail,
                                                 edge, x, y, width, height);
  cairo_restore (cr);
}

/**
 * gtk_paint_spinner:
 * @style: a #GtkStyle
 * @cr: a #cairo_t
 * @state_type: a state
 * @widget: (allow-none): the widget (may be %NULL)
 * @detail: (allow-none): a style detail (may be %NULL)
 * @step: the nth step, a value between 0 and #GtkSpinner:num-steps
 * @x: the x origin of the rectangle in which to draw the spinner
 * @y: the y origin of the rectangle in which to draw the spinner
 * @width: the width of the rectangle in which to draw the spinner
 * @height: the height of the rectangle in which to draw the spinner
 *
 * Draws a spinner on @window using the given parameters.
 *
 * Deprecated:3.0: Use gtk_render_activity() instead
 */
void
gtk_paint_spinner (GtkStyle           *style,
                   cairo_t            *cr,
                   GtkStateType        state_type,
                   GtkWidget          *widget,
                   const gchar        *detail,
                   guint               step,
                   gint                x,
                   gint                y,
                   gint                width,
                   gint                height)
{
  g_return_if_fail (GTK_IS_STYLE (style));
  g_return_if_fail (cr != NULL);
  g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_spinner != NULL);

  cairo_save (cr);

  GTK_STYLE_GET_CLASS (style)->draw_spinner (style, cr, state_type,
                                             widget, detail,
					     step, x, y, width, height);

  cairo_restore (cr);
}

/**
 * gtk_draw_insertion_cursor:
 * @widget:  a #GtkWidget
 * @cr: cairo context to draw to
 * @location: location where to draw the cursor (@location->width is ignored)
 * @is_primary: if the cursor should be the primary cursor color.
 * @direction: whether the cursor is left-to-right or
 *             right-to-left. Should never be #GTK_TEXT_DIR_NONE
 * @draw_arrow: %TRUE to draw a directional arrow on the
 *        cursor. Should be %FALSE unless the cursor is split.
 *
 * Draws a text caret on @cr at @location. This is not a style function
 * but merely a convenience function for drawing the standard cursor shape.
 *
 * Since: 3.0
 */
void
gtk_draw_insertion_cursor (GtkWidget          *widget,
                           cairo_t            *cr,
                           const GdkRectangle *location,
                           gboolean            is_primary,
                           GtkTextDirection    direction,
                           gboolean            draw_arrow)
{
  gint stem_width;
  gint arrow_width;
  gint x, y;
  gfloat cursor_aspect_ratio;
  gint offset;
  GtkStyleContext *context;
  GdkRGBA primary_color;
  GdkRGBA secondary_color;

  g_return_if_fail (GTK_IS_WIDGET (widget));
  g_return_if_fail (cr != NULL);
  g_return_if_fail (location != NULL);
  g_return_if_fail (direction != GTK_TEXT_DIR_NONE);

  context = gtk_widget_get_style_context (widget);

  _gtk_style_context_get_cursor_color (context, &primary_color, &secondary_color);
  gdk_cairo_set_source_rgba (cr, is_primary ? &primary_color : &secondary_color);

  /* When changing the shape or size of the cursor here,
   * propagate the changes to gtktextview.c:text_window_invalidate_cursors().
   */

  gtk_style_context_get_style (context,
                               "cursor-aspect-ratio", &cursor_aspect_ratio,
                               NULL);

  stem_width = location->height * cursor_aspect_ratio + 1;
  arrow_width = stem_width + 1;

  /* put (stem_width % 2) on the proper side of the cursor */
  if (direction == GTK_TEXT_DIR_LTR)
    offset = stem_width / 2;
  else
    offset = stem_width - stem_width / 2;

  cairo_rectangle (cr,
                   location->x - offset, location->y,
                   stem_width, location->height);
  cairo_fill (cr);

  if (draw_arrow)
    {
      if (direction == GTK_TEXT_DIR_RTL)
        {
          x = location->x - offset - 1;
          y = location->y + location->height - arrow_width * 2 - arrow_width + 1;

          cairo_move_to (cr, x, y + 1);
          cairo_line_to (cr, x - arrow_width, y + arrow_width);
          cairo_line_to (cr, x, y + 2 * arrow_width);
          cairo_fill (cr);
        }
      else if (direction == GTK_TEXT_DIR_LTR)
        {
          x = location->x + stem_width - offset;
          y = location->y + location->height - arrow_width * 2 - arrow_width + 1;

          cairo_move_to (cr, x, y + 1);
          cairo_line_to (cr, x + arrow_width, y + arrow_width);
          cairo_line_to (cr, x, y + 2 * arrow_width);
          cairo_fill (cr);
        }
    }
}
