]> Pileus Git - ~andy/gtk/blob - gtk/gtkstyle.c
2e0ad1ce43711f5dec9ad71a2e593f5f8af2cbc4
[~andy/gtk] / gtk / gtkstyle.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "config.h"
28 #include <math.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <gobject/gvaluecollector.h>
32 #include "gtkmarshalers.h"
33 #include "gtkpango.h"
34 #include "gtkrc.h"
35 #include "gtkspinbutton.h"
36 #include "gtkstyle.h"
37 #include "gtkwidget.h"
38 #include "gtkthemes.h"
39 #include "gtkiconfactory.h"
40 #include "gtksettings.h"        /* _gtk_settings_parse_convert() */
41 #include "gtkintl.h"
42 #include "gtkspinner.h"
43
44
45 /**
46  * SECTION:gtkstyle
47  * @Short_description: An object that hold style information for widgets
48  * @Title: GtkStyle
49  *
50  * A #GtkStyle object encapsulates the information that provides the look and
51  * feel for a widget. Each #GtkWidget has an associated #GTkStyle object that
52  * is used when rendering that widget. Also, a #GtkStyle holds information for
53  * the five possible widget states though not every widget supports all five
54  * states; see #GtkStateType.
55  *
56  * Usually the #GtkStyle for a widget is the same as the default style that is
57  * set by GTK+ and modified the theme engine.
58  *
59  * Usually applications should not need to use or modify the #GtkStyle of their
60  * widgets.
61  */
62
63
64 #define LIGHTNESS_MULT  1.3
65 #define DARKNESS_MULT   0.7
66
67 /* --- typedefs & structures --- */
68 typedef struct {
69   GType       widget_type;
70   GParamSpec *pspec;
71   GValue      value;
72 } PropertyValue;
73
74 #define GTK_STYLE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_STYLE, GtkStylePrivate))
75
76 typedef struct _GtkStylePrivate GtkStylePrivate;
77
78 struct _GtkStylePrivate {
79   GSList *color_hashes;
80 };
81
82 /* --- prototypes --- */
83 static void      gtk_style_finalize             (GObject        *object);
84 static void      gtk_style_realize              (GtkStyle       *style,
85                                                  GdkVisual      *visual);
86 static void      gtk_style_real_realize        (GtkStyle        *style);
87 static void      gtk_style_real_unrealize      (GtkStyle        *style);
88 static void      gtk_style_real_copy           (GtkStyle        *style,
89                                                 GtkStyle        *src);
90 static void      gtk_style_real_set_background (GtkStyle        *style,
91                                                 GdkWindow       *window,
92                                                 GtkStateType     state_type);
93 static GtkStyle *gtk_style_real_clone          (GtkStyle        *style);
94 static void      gtk_style_real_init_from_rc   (GtkStyle        *style,
95                                                 GtkRcStyle      *rc_style);
96 static GdkPixbuf *gtk_default_render_icon      (GtkStyle            *style,
97                                                 const GtkIconSource *source,
98                                                 GtkTextDirection     direction,
99                                                 GtkStateType         state,
100                                                 GtkIconSize          size,
101                                                 GtkWidget           *widget,
102                                                 const gchar         *detail);
103 static void gtk_default_draw_hline      (GtkStyle        *style,
104                                          cairo_t         *cr,
105                                          GtkStateType     state_type,
106                                          GtkWidget       *widget,
107                                          const gchar     *detail,
108                                          gint             x1,
109                                          gint             x2,
110                                          gint             y);
111 static void gtk_default_draw_vline      (GtkStyle        *style,
112                                          cairo_t         *cr,
113                                          GtkStateType     state_type,
114                                          GtkWidget       *widget,
115                                          const gchar     *detail,
116                                          gint             y1,
117                                          gint             y2,
118                                          gint             x);
119 static void gtk_default_draw_shadow     (GtkStyle        *style,
120                                          cairo_t         *cr,
121                                          GtkStateType     state_type,
122                                          GtkShadowType    shadow_type,
123                                          GtkWidget       *widget,
124                                          const gchar     *detail,
125                                          gint             x,
126                                          gint             y,
127                                          gint             width,
128                                          gint             height);
129 static void gtk_default_draw_arrow      (GtkStyle        *style,
130                                          cairo_t         *cr,
131                                          GtkStateType     state_type,
132                                          GtkShadowType    shadow_type,
133                                          GtkWidget       *widget,
134                                          const gchar     *detail,
135                                          GtkArrowType     arrow_type,
136                                          gboolean         fill,
137                                          gint             x,
138                                          gint             y,
139                                          gint             width,
140                                          gint             height);
141 static void gtk_default_draw_diamond    (GtkStyle        *style,
142                                          cairo_t         *cr,
143                                          GtkStateType     state_type,
144                                          GtkShadowType    shadow_type,
145                                          GtkWidget       *widget,
146                                          const gchar     *detail,
147                                          gint             x,
148                                          gint             y,
149                                          gint             width,
150                                          gint             height);
151 static void gtk_default_draw_box        (GtkStyle        *style,
152                                          cairo_t         *cr,
153                                          GtkStateType     state_type,
154                                          GtkShadowType    shadow_type,
155                                          GtkWidget       *widget,
156                                          const gchar     *detail,
157                                          gint             x,
158                                          gint             y,
159                                          gint             width,
160                                          gint             height);
161 static void gtk_default_draw_flat_box   (GtkStyle        *style,
162                                          cairo_t         *cr,
163                                          GtkStateType     state_type,
164                                          GtkShadowType    shadow_type,
165                                          GtkWidget       *widget,
166                                          const gchar     *detail,
167                                          gint             x,
168                                          gint             y,
169                                          gint             width,
170                                          gint             height);
171 static void gtk_default_draw_check      (GtkStyle        *style,
172                                          cairo_t         *cr,
173                                          GtkStateType     state_type,
174                                          GtkShadowType    shadow_type,
175                                          GtkWidget       *widget,
176                                          const gchar     *detail,
177                                          gint             x,
178                                          gint             y,
179                                          gint             width,
180                                          gint             height);
181 static void gtk_default_draw_option     (GtkStyle        *style,
182                                          cairo_t         *cr,
183                                          GtkStateType     state_type,
184                                          GtkShadowType    shadow_type,
185                                          GtkWidget       *widget,
186                                          const gchar     *detail,
187                                          gint             x,
188                                          gint             y,
189                                          gint             width,
190                                          gint             height);
191 static void gtk_default_draw_tab        (GtkStyle        *style,
192                                          cairo_t         *cr,
193                                          GtkStateType     state_type,
194                                          GtkShadowType    shadow_type,
195                                          GtkWidget       *widget,
196                                          const gchar     *detail,
197                                          gint             x,
198                                          gint             y,
199                                          gint             width,
200                                          gint             height);
201 static void gtk_default_draw_shadow_gap (GtkStyle        *style,
202                                          cairo_t         *cr,
203                                          GtkStateType     state_type,
204                                          GtkShadowType    shadow_type,
205                                          GtkWidget       *widget,
206                                          const gchar     *detail,
207                                          gint             x,
208                                          gint             y,
209                                          gint             width,
210                                          gint             height,
211                                          GtkPositionType  gap_side,
212                                          gint             gap_x,
213                                          gint             gap_width);
214 static void gtk_default_draw_box_gap    (GtkStyle        *style,
215                                          cairo_t         *cr,
216                                          GtkStateType     state_type,
217                                          GtkShadowType    shadow_type,
218                                          GtkWidget       *widget,
219                                          const gchar     *detail,
220                                          gint             x,
221                                          gint             y,
222                                          gint             width,
223                                          gint             height,
224                                          GtkPositionType  gap_side,
225                                          gint             gap_x,
226                                          gint             gap_width);
227 static void gtk_default_draw_extension  (GtkStyle        *style,
228                                          cairo_t         *cr,
229                                          GtkStateType     state_type,
230                                          GtkShadowType    shadow_type,
231                                          GtkWidget       *widget,
232                                          const gchar     *detail,
233                                          gint             x,
234                                          gint             y,
235                                          gint             width,
236                                          gint             height,
237                                          GtkPositionType  gap_side);
238 static void gtk_default_draw_focus      (GtkStyle        *style,
239                                          cairo_t         *cr,
240                                          GtkStateType     state_type,
241                                          GtkWidget       *widget,
242                                          const gchar     *detail,
243                                          gint             x,
244                                          gint             y,
245                                          gint             width,
246                                          gint             height);
247 static void gtk_default_draw_slider     (GtkStyle        *style,
248                                          cairo_t         *cr,
249                                          GtkStateType     state_type,
250                                          GtkShadowType    shadow_type,
251                                          GtkWidget       *widget,
252                                          const gchar     *detail,
253                                          gint             x,
254                                          gint             y,
255                                          gint             width,
256                                          gint             height,
257                                          GtkOrientation   orientation);
258 static void gtk_default_draw_handle     (GtkStyle        *style,
259                                          cairo_t         *cr,
260                                          GtkStateType     state_type,
261                                          GtkShadowType    shadow_type,
262                                          GtkWidget       *widget,
263                                          const gchar     *detail,
264                                          gint             x,
265                                          gint             y,
266                                          gint             width,
267                                          gint             height,
268                                          GtkOrientation   orientation);
269 static void gtk_default_draw_expander   (GtkStyle        *style,
270                                          cairo_t         *cr,
271                                          GtkStateType     state_type,
272                                          GtkWidget       *widget,
273                                          const gchar     *detail,
274                                          gint             x,
275                                          gint             y,
276                                          GtkExpanderStyle expander_style);
277 static void gtk_default_draw_layout     (GtkStyle        *style,
278                                          cairo_t         *cr,
279                                          GtkStateType     state_type,
280                                          gboolean         use_text,
281                                          GtkWidget       *widget,
282                                          const gchar     *detail,
283                                          gint             x,
284                                          gint             y,
285                                          PangoLayout     *layout);
286 static void gtk_default_draw_resize_grip (GtkStyle       *style,
287                                           cairo_t        *cr,
288                                           GtkStateType    state_type,
289                                           GtkWidget      *widget,
290                                           const gchar    *detail,
291                                           GdkWindowEdge   edge,
292                                           gint            x,
293                                           gint            y,
294                                           gint            width,
295                                           gint            height);
296 static void gtk_default_draw_spinner     (GtkStyle       *style,
297                                           cairo_t        *cr,
298                                           GtkStateType    state_type,
299                                           GtkWidget      *widget,
300                                           const gchar    *detail,
301                                           guint           step,
302                                           gint            x,
303                                           gint            y,
304                                           gint            width,
305                                           gint            height);
306
307 static void rgb_to_hls                  (gdouble         *r,
308                                          gdouble         *g,
309                                          gdouble         *b);
310 static void hls_to_rgb                  (gdouble         *h,
311                                          gdouble         *l,
312                                          gdouble         *s);
313
314 static void style_unrealize_cursors     (GtkStyle *style);
315
316 /*
317  * Data for default check and radio buttons
318  */
319
320 static const GtkRequisition default_option_indicator_size = { 7, 13 };
321 static const GtkBorder default_option_indicator_spacing = { 7, 5, 2, 2 };
322
323 #define GTK_GRAY                0xdcdc, 0xdada, 0xd5d5
324 #define GTK_DARK_GRAY           0xc4c4, 0xc2c2, 0xbdbd
325 #define GTK_LIGHT_GRAY          0xeeee, 0xebeb, 0xe7e7
326 #define GTK_WHITE               0xffff, 0xffff, 0xffff
327 #define GTK_BLUE                0x4b4b, 0x6969, 0x8383
328 #define GTK_VERY_DARK_GRAY      0x9c9c, 0x9a9a, 0x9494
329 #define GTK_BLACK               0x0000, 0x0000, 0x0000
330 #define GTK_WEAK_GRAY           0x7530, 0x7530, 0x7530
331
332 /* --- variables --- */
333 static const GdkColor gtk_default_normal_fg =      { 0, GTK_BLACK };
334 static const GdkColor gtk_default_active_fg =      { 0, GTK_BLACK };
335 static const GdkColor gtk_default_prelight_fg =    { 0, GTK_BLACK };
336 static const GdkColor gtk_default_selected_fg =    { 0, GTK_WHITE };
337 static const GdkColor gtk_default_insensitive_fg = { 0, GTK_WEAK_GRAY };
338
339 static const GdkColor gtk_default_normal_bg =      { 0, GTK_GRAY };
340 static const GdkColor gtk_default_active_bg =      { 0, GTK_DARK_GRAY };
341 static const GdkColor gtk_default_prelight_bg =    { 0, GTK_LIGHT_GRAY };
342 static const GdkColor gtk_default_selected_bg =    { 0, GTK_BLUE };
343 static const GdkColor gtk_default_insensitive_bg = { 0, GTK_GRAY };
344 static const GdkColor gtk_default_selected_base =  { 0, GTK_BLUE };
345 static const GdkColor gtk_default_active_base =    { 0, GTK_VERY_DARK_GRAY };
346
347 /* --- signals --- */
348 static guint realize_signal = 0;
349 static guint unrealize_signal = 0;
350
351 G_DEFINE_TYPE (GtkStyle, gtk_style, G_TYPE_OBJECT)
352
353 /* --- functions --- */
354
355 /**
356  * _gtk_style_init_for_settings:
357  * @style: a #GtkStyle
358  * @settings: a #GtkSettings
359  * 
360  * Initializes the font description in @style according to the default
361  * font name of @settings. This is called for gtk_style_new() with
362  * the settings for the default screen (if any); if we are creating
363  * a style for a particular screen, we then call it again in a
364  * location where we know the correct settings.
365  * The reason for this is that gtk_rc_style_create_style() doesn't
366  * take the screen for an argument.
367  **/
368 void
369 _gtk_style_init_for_settings (GtkStyle    *style,
370                               GtkSettings *settings)
371 {
372   const gchar *font_name = _gtk_rc_context_get_default_font_name (settings);
373
374   if (style->font_desc)
375     pango_font_description_free (style->font_desc);
376   
377   style->font_desc = pango_font_description_from_string (font_name);
378       
379   if (!pango_font_description_get_family (style->font_desc))
380     {
381       g_warning ("Default font does not have a family set");
382       pango_font_description_set_family (style->font_desc, "Sans");
383     }
384   if (pango_font_description_get_size (style->font_desc) <= 0)
385     {
386       g_warning ("Default font does not have a positive size");
387       pango_font_description_set_size (style->font_desc, 10 * PANGO_SCALE);
388     }
389 }
390
391 static void
392 gtk_style_init (GtkStyle *style)
393 {
394   gint i;
395   
396   GtkSettings *settings = gtk_settings_get_default ();
397   
398   if (settings)
399     _gtk_style_init_for_settings (style, settings);
400   else
401     style->font_desc = pango_font_description_from_string ("Sans 10");
402   
403   style->attach_count = 0;
404   
405   style->black.red = 0;
406   style->black.green = 0;
407   style->black.blue = 0;
408   
409   style->white.red = 65535;
410   style->white.green = 65535;
411   style->white.blue = 65535;
412   
413   style->fg[GTK_STATE_NORMAL] = gtk_default_normal_fg;
414   style->fg[GTK_STATE_ACTIVE] = gtk_default_active_fg;
415   style->fg[GTK_STATE_PRELIGHT] = gtk_default_prelight_fg;
416   style->fg[GTK_STATE_SELECTED] = gtk_default_selected_fg;
417   style->fg[GTK_STATE_INSENSITIVE] = gtk_default_insensitive_fg;
418   
419   style->bg[GTK_STATE_NORMAL] = gtk_default_normal_bg;
420   style->bg[GTK_STATE_ACTIVE] = gtk_default_active_bg;
421   style->bg[GTK_STATE_PRELIGHT] = gtk_default_prelight_bg;
422   style->bg[GTK_STATE_SELECTED] = gtk_default_selected_bg;
423   style->bg[GTK_STATE_INSENSITIVE] = gtk_default_insensitive_bg;
424   
425   for (i = 0; i < 4; i++)
426     {
427       style->text[i] = style->fg[i];
428       style->base[i] = style->white;
429     }
430
431   style->base[GTK_STATE_SELECTED] = gtk_default_selected_base;
432   style->text[GTK_STATE_SELECTED] = style->white;
433   style->base[GTK_STATE_ACTIVE] = gtk_default_active_base;
434   style->text[GTK_STATE_ACTIVE] = style->white;
435   style->base[GTK_STATE_INSENSITIVE] = gtk_default_prelight_bg;
436   style->text[GTK_STATE_INSENSITIVE] = gtk_default_insensitive_fg;
437   
438   style->rc_style = NULL;
439   
440   style->xthickness = 2;
441   style->ythickness = 2;
442
443   style->property_cache = NULL;
444 }
445
446 static void
447 gtk_style_class_init (GtkStyleClass *klass)
448 {
449   GObjectClass *object_class = G_OBJECT_CLASS (klass);
450   
451   object_class->finalize = gtk_style_finalize;
452
453   klass->clone = gtk_style_real_clone;
454   klass->copy = gtk_style_real_copy;
455   klass->init_from_rc = gtk_style_real_init_from_rc;
456   klass->realize = gtk_style_real_realize;
457   klass->unrealize = gtk_style_real_unrealize;
458   klass->set_background = gtk_style_real_set_background;
459   klass->render_icon = gtk_default_render_icon;
460
461   klass->draw_hline = gtk_default_draw_hline;
462   klass->draw_vline = gtk_default_draw_vline;
463   klass->draw_shadow = gtk_default_draw_shadow;
464   klass->draw_arrow = gtk_default_draw_arrow;
465   klass->draw_diamond = gtk_default_draw_diamond;
466   klass->draw_box = gtk_default_draw_box;
467   klass->draw_flat_box = gtk_default_draw_flat_box;
468   klass->draw_check = gtk_default_draw_check;
469   klass->draw_option = gtk_default_draw_option;
470   klass->draw_tab = gtk_default_draw_tab;
471   klass->draw_shadow_gap = gtk_default_draw_shadow_gap;
472   klass->draw_box_gap = gtk_default_draw_box_gap;
473   klass->draw_extension = gtk_default_draw_extension;
474   klass->draw_focus = gtk_default_draw_focus;
475   klass->draw_slider = gtk_default_draw_slider;
476   klass->draw_handle = gtk_default_draw_handle;
477   klass->draw_expander = gtk_default_draw_expander;
478   klass->draw_layout = gtk_default_draw_layout;
479   klass->draw_resize_grip = gtk_default_draw_resize_grip;
480   klass->draw_spinner = gtk_default_draw_spinner;
481
482   g_type_class_add_private (object_class, sizeof (GtkStylePrivate));
483
484   /**
485    * GtkStyle::realize:
486    * @style: the object which received the signal
487    *
488    * Emitted when the style has been initialized for a particular
489    * visual. Connecting to this signal is probably seldom
490    * useful since most of the time applications and widgets only
491    * deal with styles that have been already realized.
492    *
493    * Since: 2.4
494    */
495   realize_signal = g_signal_new (I_("realize"),
496                                  G_TYPE_FROM_CLASS (object_class),
497                                  G_SIGNAL_RUN_FIRST,
498                                  G_STRUCT_OFFSET (GtkStyleClass, realize),
499                                  NULL, NULL,
500                                  _gtk_marshal_VOID__VOID,
501                                  G_TYPE_NONE, 0);
502   /**
503    * GtkStyle::unrealize:
504    * @style: the object which received the signal
505    *
506    * Emitted when the aspects of the style specific to a particular visual
507    * is being cleaned up. A connection to this signal can be useful
508    * if a widget wants to cache objects as object data on #GtkStyle.
509    * This signal provides a convenient place to free such cached objects.
510    *
511    * Since: 2.4
512    */
513   unrealize_signal = g_signal_new (I_("unrealize"),
514                                    G_TYPE_FROM_CLASS (object_class),
515                                    G_SIGNAL_RUN_FIRST,
516                                    G_STRUCT_OFFSET (GtkStyleClass, unrealize),
517                                    NULL, NULL,
518                                    _gtk_marshal_VOID__VOID,
519                                    G_TYPE_NONE, 0);
520 }
521
522 static void
523 clear_property_cache (GtkStyle *style)
524 {
525   if (style->property_cache)
526     {
527       guint i;
528
529       for (i = 0; i < style->property_cache->len; i++)
530         {
531           PropertyValue *node = &g_array_index (style->property_cache, PropertyValue, i);
532
533           g_param_spec_unref (node->pspec);
534           g_value_unset (&node->value);
535         }
536       g_array_free (style->property_cache, TRUE);
537       style->property_cache = NULL;
538     }
539 }
540
541 static void
542 gtk_style_finalize (GObject *object)
543 {
544   GtkStyle *style = GTK_STYLE (object);
545   GtkStylePrivate *priv = GTK_STYLE_GET_PRIVATE (style);
546
547   g_return_if_fail (style->attach_count == 0);
548
549   clear_property_cache (style);
550   
551   /* All the styles in the list have the same 
552    * style->styles pointer. If we delete the 
553    * *first* style from the list, we need to update
554    * the style->styles pointers from all the styles.
555    * Otherwise we simply remove the node from
556    * the list.
557    */
558   if (style->styles)
559     {
560       if (style->styles->data != style)
561         style->styles = g_slist_remove (style->styles, style);
562       else
563         {
564           GSList *tmp_list = style->styles->next;
565           
566           while (tmp_list)
567             {
568               GTK_STYLE (tmp_list->data)->styles = style->styles->next;
569               tmp_list = tmp_list->next;
570             }
571           g_slist_free_1 (style->styles);
572         }
573     }
574
575   g_slist_foreach (style->icon_factories, (GFunc) g_object_unref, NULL);
576   g_slist_free (style->icon_factories);
577
578   g_slist_foreach (priv->color_hashes, (GFunc) g_hash_table_unref, NULL);
579   g_slist_free (priv->color_hashes);
580
581   pango_font_description_free (style->font_desc);
582
583   if (style->private_font_desc)
584     pango_font_description_free (style->private_font_desc);
585
586   if (style->rc_style)
587     g_object_unref (style->rc_style);
588
589   G_OBJECT_CLASS (gtk_style_parent_class)->finalize (object);
590 }
591
592
593 /**
594  * gtk_style_copy:
595  * @style: a #GtkStyle
596  *
597  * Creates a copy of the passed in #GtkStyle object.
598  *
599  * Returns: (transfer full): a copy of @style
600  */
601 GtkStyle*
602 gtk_style_copy (GtkStyle *style)
603 {
604   GtkStyle *new_style;
605   
606   g_return_val_if_fail (GTK_IS_STYLE (style), NULL);
607   
608   new_style = GTK_STYLE_GET_CLASS (style)->clone (style);
609   GTK_STYLE_GET_CLASS (style)->copy (new_style, style);
610
611   return new_style;
612 }
613
614 static GtkStyle*
615 gtk_style_duplicate (GtkStyle *style)
616 {
617   GtkStyle *new_style;
618   
619   g_return_val_if_fail (GTK_IS_STYLE (style), NULL);
620   
621   new_style = gtk_style_copy (style);
622   
623   /* All the styles in the list have the same 
624    * style->styles pointer. When we insert a new 
625    * style, we append it to the list to avoid having 
626    * to update the existing ones. 
627    */
628   style->styles = g_slist_append (style->styles, new_style);
629   new_style->styles = style->styles;  
630   
631   return new_style;
632 }
633
634 /**
635  * gtk_style_new:
636  * @returns: a new #GtkStyle.
637  *
638  * Creates a new #GtkStyle.
639  **/
640 GtkStyle*
641 gtk_style_new (void)
642 {
643   GtkStyle *style;
644   
645   style = g_object_new (GTK_TYPE_STYLE, NULL);
646   
647   return style;
648 }
649
650 /**
651  * gtk_style_attach:
652  * @style: a #GtkStyle.
653  * @window: a #GdkWindow.
654  *
655  * Attaches a style to a window; this process allocates the
656  * colors and creates the GC's for the style - it specializes
657  * it to a particular visual. The process may involve the creation
658  * of a new style if the style has already been attached to a
659  * window with a different style and visual.
660  *
661  * Since this function may return a new object, you have to use it
662  * in the following way:
663  * <literal>style = gtk_style_attach (style, window)</literal>
664  *
665  * Returns: Either @style, or a newly-created #GtkStyle.
666  *   If the style is newly created, the style parameter
667  *   will be unref'ed, and the new style will have
668  *   a reference count belonging to the caller.
669  */
670 GtkStyle*
671 gtk_style_attach (GtkStyle  *style,
672                   GdkWindow *window)
673 {
674   GSList *styles;
675   GtkStyle *new_style = NULL;
676   GdkVisual *visual;
677   
678   g_return_val_if_fail (GTK_IS_STYLE (style), NULL);
679   g_return_val_if_fail (window != NULL, NULL);
680   
681   visual = gdk_window_get_visual (window);
682   
683   if (!style->styles)
684     style->styles = g_slist_append (NULL, style);
685   
686   styles = style->styles;
687   while (styles)
688     {
689       new_style = styles->data;
690       
691       if (new_style->visual == visual)
692         break;
693
694       new_style = NULL;
695       styles = styles->next;
696     }
697
698   if (!new_style)
699     {
700       styles = style->styles;
701       
702       while (styles)
703         {
704           new_style = styles->data;
705           
706           if (new_style->attach_count == 0)
707             {
708               gtk_style_realize (new_style, visual);
709               break;
710             }
711           
712           new_style = NULL;
713           styles = styles->next;
714         }
715     }
716   
717   if (!new_style)
718     {
719       new_style = gtk_style_duplicate (style);
720       gtk_style_realize (new_style, visual);
721     }
722
723   /* A style gets a refcount from being attached */
724   if (new_style->attach_count == 0)
725     g_object_ref (new_style);
726
727   /* Another refcount belongs to the parent */
728   if (style != new_style) 
729     {
730       g_object_unref (style);
731       g_object_ref (new_style);
732     }
733   
734   new_style->attach_count++;
735   
736   return new_style;
737 }
738
739 /**
740  * gtk_style_detach:
741  * @style: a #GtkStyle
742  *
743  * Detaches a style from a window. If the style is not attached
744  * to any windows anymore, it is unrealized. See gtk_style_attach().
745  * 
746  */
747 void
748 gtk_style_detach (GtkStyle *style)
749 {
750   g_return_if_fail (GTK_IS_STYLE (style));
751   g_return_if_fail (style->attach_count > 0);
752   
753   style->attach_count -= 1;
754   if (style->attach_count == 0)
755     {
756       g_signal_emit (style, unrealize_signal, 0);
757       
758       g_object_unref (style->visual);
759       style->visual = NULL;
760
761       if (style->private_font_desc)
762         {
763           pango_font_description_free (style->private_font_desc);
764           style->private_font_desc = NULL;
765         }
766
767       g_object_unref (style);
768     }
769 }
770
771 static void
772 gtk_style_realize (GtkStyle  *style,
773                    GdkVisual *visual)
774 {
775   style->visual = g_object_ref (visual);
776
777   g_signal_emit (style, realize_signal, 0);
778 }
779
780 /**
781  * gtk_style_lookup_icon_set:
782  * @style: a #GtkStyle
783  * @stock_id: an icon name
784  *
785  * Looks up @stock_id in the icon factories associated with @style
786  * and the default icon factory, returning an icon set if found,
787  * otherwise %NULL.
788  *
789  * Return value: icon set of @stock_id
790  */
791 GtkIconSet*
792 gtk_style_lookup_icon_set (GtkStyle   *style,
793                            const char *stock_id)
794 {
795   GSList *iter;
796
797   g_return_val_if_fail (GTK_IS_STYLE (style), NULL);
798   g_return_val_if_fail (stock_id != NULL, NULL);
799   
800   iter = style->icon_factories;
801   while (iter != NULL)
802     {
803       GtkIconSet *icon_set = gtk_icon_factory_lookup (GTK_ICON_FACTORY (iter->data),
804                                                       stock_id);
805       if (icon_set)
806         return icon_set;
807       
808       iter = g_slist_next (iter);
809     }
810
811   return gtk_icon_factory_lookup_default (stock_id);
812 }
813
814 /**
815  * gtk_style_lookup_color:
816  * @style: a #GtkStyle
817  * @color_name: the name of the logical color to look up
818  * @color: the #GdkColor to fill in
819  *
820  * Looks up @color_name in the style's logical color mappings,
821  * filling in @color and returning %TRUE if found, otherwise
822  * returning %FALSE. Do not cache the found mapping, because
823  * it depends on the #GtkStyle and might change when a theme
824  * switch occurs.
825  *
826  * Return value: %TRUE if the mapping was found.
827  *
828  * Since: 2.10
829  **/
830 gboolean
831 gtk_style_lookup_color (GtkStyle   *style,
832                         const char *color_name,
833                         GdkColor   *color)
834 {
835   GtkStylePrivate *priv;
836   GSList *iter;
837
838   g_return_val_if_fail (GTK_IS_STYLE (style), FALSE);
839   g_return_val_if_fail (color_name != NULL, FALSE);
840   g_return_val_if_fail (color != NULL, FALSE);
841
842   priv = GTK_STYLE_GET_PRIVATE (style);
843
844   for (iter = priv->color_hashes; iter != NULL; iter = iter->next)
845     {
846       GHashTable *hash    = iter->data;
847       GdkColor   *mapping = g_hash_table_lookup (hash, color_name);
848
849       if (mapping)
850         {
851           color->red = mapping->red;
852           color->green = mapping->green;
853           color->blue = mapping->blue;
854           return TRUE;
855         }
856     }
857
858   return FALSE;
859 }
860
861 /**
862  * gtk_style_set_background:
863  * @style: a #GtkStyle
864  * @window: a #GdkWindow
865  * @state_type: a state
866  * 
867  * Sets the background of @window to the background color or pixmap
868  * specified by @style for the given state.
869  */
870 void
871 gtk_style_set_background (GtkStyle    *style,
872                           GdkWindow   *window,
873                           GtkStateType state_type)
874 {
875   g_return_if_fail (GTK_IS_STYLE (style));
876   g_return_if_fail (window != NULL);
877   
878   GTK_STYLE_GET_CLASS (style)->set_background (style, window, state_type);
879 }
880
881 /* Default functions */
882 static GtkStyle *
883 gtk_style_real_clone (GtkStyle *style)
884 {
885   return g_object_new (G_OBJECT_TYPE (style), NULL);
886 }
887
888 static void
889 gtk_style_real_copy (GtkStyle *style,
890                      GtkStyle *src)
891 {
892   GtkStylePrivate *priv = GTK_STYLE_GET_PRIVATE (style);
893   GtkStylePrivate *src_priv = GTK_STYLE_GET_PRIVATE (src);
894   gint i;
895   
896   for (i = 0; i < 5; i++)
897     {
898       style->fg[i] = src->fg[i];
899       style->bg[i] = src->bg[i];
900       style->text[i] = src->text[i];
901       style->base[i] = src->base[i];
902
903       if (style->background[i])
904         cairo_pattern_destroy (style->background[i]),
905       style->background[i] = src->background[i];
906       if (style->background[i])
907         cairo_pattern_reference (style->background[i]);
908     }
909
910   if (style->font_desc)
911     pango_font_description_free (style->font_desc);
912   if (src->font_desc)
913     style->font_desc = pango_font_description_copy (src->font_desc);
914   else
915     style->font_desc = NULL;
916   
917   style->xthickness = src->xthickness;
918   style->ythickness = src->ythickness;
919
920   if (style->rc_style)
921     g_object_unref (style->rc_style);
922   style->rc_style = src->rc_style;
923   if (src->rc_style)
924     g_object_ref (src->rc_style);
925
926   g_slist_foreach (style->icon_factories, (GFunc) g_object_unref, NULL);
927   g_slist_free (style->icon_factories);
928   style->icon_factories = g_slist_copy (src->icon_factories);
929   g_slist_foreach (style->icon_factories, (GFunc) g_object_ref, NULL);
930
931   g_slist_foreach (priv->color_hashes, (GFunc) g_hash_table_unref, NULL);
932   g_slist_free (priv->color_hashes);
933   priv->color_hashes = g_slist_copy (src_priv->color_hashes);
934   g_slist_foreach (priv->color_hashes, (GFunc) g_hash_table_ref, NULL);
935
936   /* don't copy, just clear cache */
937   clear_property_cache (style);
938 }
939
940 static void
941 gtk_style_real_init_from_rc (GtkStyle   *style,
942                              GtkRcStyle *rc_style)
943 {
944   GtkStylePrivate *priv = GTK_STYLE_GET_PRIVATE (style);
945   gint i;
946
947   /* cache _should_ be still empty */
948   clear_property_cache (style);
949
950   if (rc_style->font_desc)
951     pango_font_description_merge (style->font_desc, rc_style->font_desc, TRUE);
952     
953   for (i = 0; i < 5; i++)
954     {
955       if (rc_style->color_flags[i] & GTK_RC_FG)
956         style->fg[i] = rc_style->fg[i];
957       if (rc_style->color_flags[i] & GTK_RC_BG)
958         style->bg[i] = rc_style->bg[i];
959       if (rc_style->color_flags[i] & GTK_RC_TEXT)
960         style->text[i] = rc_style->text[i];
961       if (rc_style->color_flags[i] & GTK_RC_BASE)
962         style->base[i] = rc_style->base[i];
963     }
964
965   if (rc_style->xthickness >= 0)
966     style->xthickness = rc_style->xthickness;
967   if (rc_style->ythickness >= 0)
968     style->ythickness = rc_style->ythickness;
969
970   style->icon_factories = g_slist_copy (rc_style->icon_factories);
971   g_slist_foreach (style->icon_factories, (GFunc) g_object_ref, NULL);
972
973   priv->color_hashes = g_slist_copy (_gtk_rc_style_get_color_hashes (rc_style));
974   g_slist_foreach (priv->color_hashes, (GFunc) g_hash_table_ref, NULL);
975 }
976
977 static gint
978 style_property_values_cmp (gconstpointer bsearch_node1,
979                            gconstpointer bsearch_node2)
980 {
981   const PropertyValue *val1 = bsearch_node1;
982   const PropertyValue *val2 = bsearch_node2;
983
984   if (val1->widget_type == val2->widget_type)
985     return val1->pspec < val2->pspec ? -1 : val1->pspec == val2->pspec ? 0 : 1;
986   else
987     return val1->widget_type < val2->widget_type ? -1 : 1;
988 }
989
990 /**
991  * gtk_style_get_style_property:
992  * @style: a #GtkStyle
993  * @widget_type: the #GType of a descendant of #GtkWidget
994  * @property_name: the name of the style property to get
995  * @value: a #GValue where the value of the property being
996  *     queried will be stored
997  *
998  * Queries the value of a style property corresponding to a
999  * widget class is in the given style.
1000  *
1001  * Since: 2.16
1002  */
1003 void 
1004 gtk_style_get_style_property (GtkStyle     *style,
1005                               GType        widget_type,
1006                               const gchar *property_name,
1007                               GValue      *value)
1008 {
1009   GtkWidgetClass *klass;
1010   GParamSpec *pspec;
1011   GtkRcPropertyParser parser;
1012   const GValue *peek_value;
1013
1014   klass = g_type_class_ref (widget_type);
1015   pspec = gtk_widget_class_find_style_property (klass, property_name);
1016   g_type_class_unref (klass);
1017
1018   if (!pspec)
1019     {
1020       g_warning ("%s: widget class `%s' has no property named `%s'",
1021                  G_STRLOC,
1022                  g_type_name (widget_type),
1023                  property_name);
1024       return;
1025     }
1026
1027   parser = g_param_spec_get_qdata (pspec,
1028                                    g_quark_from_static_string ("gtk-rc-property-parser"));
1029
1030   peek_value = _gtk_style_peek_property_value (style, widget_type, pspec, parser);
1031
1032   if (G_VALUE_TYPE (value) == G_PARAM_SPEC_VALUE_TYPE (pspec))
1033     g_value_copy (peek_value, value);
1034   else if (g_value_type_transformable (G_PARAM_SPEC_VALUE_TYPE (pspec), G_VALUE_TYPE (value)))
1035     g_value_transform (peek_value, value);
1036   else
1037     g_warning ("can't retrieve style property `%s' of type `%s' as value of type `%s'",
1038                pspec->name,
1039                g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
1040                G_VALUE_TYPE_NAME (value));
1041 }
1042
1043 /**
1044  * gtk_style_get_valist:
1045  * @style: a #GtkStyle
1046  * @widget_type: the #GType of a descendant of #GtkWidget
1047  * @first_property_name: the name of the first style property to get
1048  * @var_args: a <type>va_list</type> of pairs of property names and
1049  *     locations to return the property values, starting with the
1050  *     location for @first_property_name.
1051  *
1052  * Non-vararg variant of gtk_style_get().
1053  * Used primarily by language bindings.
1054  *
1055  * Since: 2.16
1056  */
1057 void 
1058 gtk_style_get_valist (GtkStyle    *style,
1059                       GType        widget_type,
1060                       const gchar *first_property_name,
1061                       va_list      var_args)
1062 {
1063   const char *property_name;
1064   GtkWidgetClass *klass;
1065
1066   g_return_if_fail (GTK_IS_STYLE (style));
1067
1068   klass = g_type_class_ref (widget_type);
1069
1070   property_name = first_property_name;
1071   while (property_name)
1072     {
1073       GParamSpec *pspec;
1074       GtkRcPropertyParser parser;
1075       const GValue *peek_value;
1076       gchar *error;
1077
1078       pspec = gtk_widget_class_find_style_property (klass, property_name);
1079
1080       if (!pspec)
1081         {
1082           g_warning ("%s: widget class `%s' has no property named `%s'",
1083                      G_STRLOC,
1084                      g_type_name (widget_type),
1085                      property_name);
1086           break;
1087         }
1088
1089       parser = g_param_spec_get_qdata (pspec,
1090                                        g_quark_from_static_string ("gtk-rc-property-parser"));
1091
1092       peek_value = _gtk_style_peek_property_value (style, widget_type, pspec, parser);
1093       G_VALUE_LCOPY (peek_value, var_args, 0, &error);
1094       if (error)
1095         {
1096           g_warning ("%s: %s", G_STRLOC, error);
1097           g_free (error);
1098           break;
1099         }
1100
1101       property_name = va_arg (var_args, gchar*);
1102     }
1103
1104   g_type_class_unref (klass);
1105 }
1106
1107 /**
1108  * gtk_style_get:
1109  * @style: a #GtkStyle
1110  * @widget_type: the #GType of a descendant of #GtkWidget
1111  * @first_property_name: the name of the first style property to get
1112  * @Varargs: pairs of property names and locations to
1113  *   return the property values, starting with the location for
1114  *   @first_property_name, terminated by %NULL.
1115  *
1116  * Gets the values of a multiple style properties for @widget_type
1117  * from @style.
1118  *
1119  * Since: 2.16
1120  */
1121 void
1122 gtk_style_get (GtkStyle    *style,
1123                GType        widget_type,
1124                const gchar *first_property_name,
1125                ...)
1126 {
1127   va_list var_args;
1128
1129   va_start (var_args, first_property_name);
1130   gtk_style_get_valist (style, widget_type, first_property_name, var_args);
1131   va_end (var_args);
1132 }
1133
1134 const GValue*
1135 _gtk_style_peek_property_value (GtkStyle           *style,
1136                                 GType               widget_type,
1137                                 GParamSpec         *pspec,
1138                                 GtkRcPropertyParser parser)
1139 {
1140   PropertyValue *pcache, key = { 0, NULL, { 0, } };
1141   const GtkRcProperty *rcprop = NULL;
1142   guint i;
1143
1144   g_return_val_if_fail (GTK_IS_STYLE (style), NULL);
1145   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL);
1146   g_return_val_if_fail (g_type_is_a (pspec->owner_type, GTK_TYPE_WIDGET), NULL);
1147   g_return_val_if_fail (g_type_is_a (widget_type, pspec->owner_type), NULL);
1148
1149   key.widget_type = widget_type;
1150   key.pspec = pspec;
1151
1152   /* need value cache array */
1153   if (!style->property_cache)
1154     style->property_cache = g_array_new (FALSE, FALSE, sizeof (PropertyValue));
1155   else
1156     {
1157       pcache = bsearch (&key,
1158                         style->property_cache->data, style->property_cache->len,
1159                         sizeof (PropertyValue), style_property_values_cmp);
1160       if (pcache)
1161         return &pcache->value;
1162     }
1163
1164   i = 0;
1165   while (i < style->property_cache->len &&
1166          style_property_values_cmp (&key, &g_array_index (style->property_cache, PropertyValue, i)) >= 0)
1167     i++;
1168
1169   g_array_insert_val (style->property_cache, i, key);
1170   pcache = &g_array_index (style->property_cache, PropertyValue, i);
1171
1172   /* cache miss, initialize value type, then set contents */
1173   g_param_spec_ref (pcache->pspec);
1174   g_value_init (&pcache->value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1175
1176   /* value provided by rc style? */
1177   if (style->rc_style)
1178     {
1179       GQuark prop_quark = g_quark_from_string (pspec->name);
1180
1181       do
1182         {
1183           rcprop = _gtk_rc_style_lookup_rc_property (style->rc_style,
1184                                                      g_type_qname (widget_type),
1185                                                      prop_quark);
1186           if (rcprop)
1187             break;
1188           widget_type = g_type_parent (widget_type);
1189         }
1190       while (g_type_is_a (widget_type, pspec->owner_type));
1191     }
1192
1193   /* when supplied by rc style, we need to convert */
1194   if (rcprop && !_gtk_settings_parse_convert (parser, &rcprop->value,
1195                                               pspec, &pcache->value))
1196     {
1197       gchar *contents = g_strdup_value_contents (&rcprop->value);
1198       
1199       g_message ("%s: failed to retrieve property `%s::%s' of type `%s' from rc file value \"%s\" of type `%s'",
1200                  rcprop->origin ? rcprop->origin : "(for origin information, set GTK_DEBUG)",
1201                  g_type_name (pspec->owner_type), pspec->name,
1202                  g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
1203                  contents,
1204                  G_VALUE_TYPE_NAME (&rcprop->value));
1205       g_free (contents);
1206       rcprop = NULL; /* needs default */
1207     }
1208   
1209   /* not supplied by rc style (or conversion failed), revert to default */
1210   if (!rcprop)
1211     g_param_value_set_default (pspec, &pcache->value);
1212
1213   return &pcache->value;
1214 }
1215
1216 static cairo_pattern_t *
1217 load_background (GdkVisual   *visual,
1218                  GdkColor    *bg_color,
1219                  const gchar *filename)
1220 {
1221   if (filename == NULL)
1222     {
1223       return cairo_pattern_create_rgb (bg_color->red   / 65535.0,
1224                                        bg_color->green / 65535.0,
1225                                        bg_color->blue  / 65535.0);
1226     }
1227   if (strcmp (filename, "<parent>") == 0)
1228     return NULL;
1229   else
1230     {
1231       GdkPixbuf *pixbuf;
1232       cairo_surface_t *surface;
1233       cairo_pattern_t *pattern;
1234       cairo_t *cr;
1235       GdkScreen *screen = gdk_visual_get_screen (visual);
1236   
1237       pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
1238       if (!pixbuf)
1239         return NULL;
1240
1241       surface = gdk_window_create_similar_surface (gdk_screen_get_root_window (screen),
1242                                                    CAIRO_CONTENT_COLOR,
1243                                                    gdk_pixbuf_get_width (pixbuf),
1244                                                    gdk_pixbuf_get_height (pixbuf));
1245   
1246       cr = cairo_create (surface);
1247
1248       gdk_cairo_set_source_color (cr, bg_color);
1249       cairo_paint (cr);
1250
1251       gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
1252       cairo_paint (cr);
1253
1254       cairo_destroy (cr);
1255       g_object_unref (pixbuf);
1256
1257       pattern = cairo_pattern_create_for_surface (surface);
1258
1259       cairo_surface_destroy (surface);
1260
1261       return pattern;
1262     }
1263 }
1264
1265 static void
1266 gtk_style_real_realize (GtkStyle *style)
1267 {
1268   gint i;
1269
1270   for (i = 0; i < 5; i++)
1271     {
1272       _gtk_style_shade (&style->bg[i], &style->light[i], LIGHTNESS_MULT);
1273       _gtk_style_shade (&style->bg[i], &style->dark[i], DARKNESS_MULT);
1274
1275       style->mid[i].red = (style->light[i].red + style->dark[i].red) / 2;
1276       style->mid[i].green = (style->light[i].green + style->dark[i].green) / 2;
1277       style->mid[i].blue = (style->light[i].blue + style->dark[i].blue) / 2;
1278
1279       style->text_aa[i].red = (style->text[i].red + style->base[i].red) / 2;
1280       style->text_aa[i].green = (style->text[i].green + style->base[i].green) / 2;
1281       style->text_aa[i].blue = (style->text[i].blue + style->base[i].blue) / 2;
1282     }
1283
1284   style->black.red = 0x0000;
1285   style->black.green = 0x0000;
1286   style->black.blue = 0x0000;
1287
1288   style->white.red = 0xffff;
1289   style->white.green = 0xffff;
1290   style->white.blue = 0xffff;
1291
1292   for (i = 0; i < 5; i++)
1293     {
1294       const char *image_name;
1295
1296       if (style->rc_style)
1297         image_name = style->rc_style->bg_pixmap_name[i];
1298       else
1299         image_name = NULL;
1300
1301       style->background[i] = load_background (style->visual,
1302                                               &style->bg[i],
1303                                               image_name);
1304     }
1305 }
1306
1307 static void
1308 gtk_style_real_unrealize (GtkStyle *style)
1309 {
1310   int i;
1311
1312   for (i = 0; i < 5; i++)
1313     {
1314       if (style->background[i])
1315         {
1316           cairo_pattern_destroy (style->background[i]);
1317           style->background[i] = NULL;
1318         }
1319       
1320     }
1321   
1322   style_unrealize_cursors (style);
1323 }
1324
1325 static void
1326 gtk_style_real_set_background (GtkStyle    *style,
1327                                GdkWindow   *window,
1328                                GtkStateType state_type)
1329 {
1330   gdk_window_set_background_pattern (window, style->background[state_type]);
1331 }
1332
1333 /**
1334  * gtk_style_render_icon:
1335  * @style: a #GtkStyle
1336  * @source: the #GtkIconSource specifying the icon to render
1337  * @direction: a text direction
1338  * @state: a state
1339  * @size: (type int): the size to render the icon at. A size of
1340  *     (GtkIconSize)-1 means render at the size of the source and
1341  *     don't scale.
1342  * @widget: (allow-none): the widget
1343  * @detail: (allow-none): a style detail
1344  *
1345  * Renders the icon specified by @source at the given @size
1346  * according to the given parameters and returns the result in a
1347  * pixbuf.
1348  *
1349  * Return value: (transfer full): a newly-created #GdkPixbuf
1350  *     containing the rendered icon
1351  */
1352 GdkPixbuf *
1353 gtk_style_render_icon (GtkStyle            *style,
1354                        const GtkIconSource *source,
1355                        GtkTextDirection     direction,
1356                        GtkStateType         state,
1357                        GtkIconSize          size,
1358                        GtkWidget           *widget,
1359                        const gchar         *detail)
1360 {
1361   GdkPixbuf *pixbuf;
1362   
1363   g_return_val_if_fail (GTK_IS_STYLE (style), NULL);
1364   g_return_val_if_fail (GTK_STYLE_GET_CLASS (style)->render_icon != NULL, NULL);
1365   
1366   pixbuf = GTK_STYLE_GET_CLASS (style)->render_icon (style, source, direction, state,
1367                                                      size, widget, detail);
1368
1369   g_return_val_if_fail (pixbuf != NULL, NULL);
1370
1371   return pixbuf;
1372 }
1373
1374 /* Default functions */
1375
1376 /**
1377  * gtk_style_apply_default_background:
1378  * @style:
1379  * @cr: 
1380  * @window:
1381  * @set_bg:
1382  * @state_type:
1383  * @area: (allow-none):
1384  * @x:
1385  * @y:
1386  * @width:
1387  * @height:
1388  */
1389 void
1390 gtk_style_apply_default_background (GtkStyle          *style,
1391                                     cairo_t           *cr,
1392                                     GdkWindow         *window,
1393                                     GtkStateType       state_type,
1394                                     gint               x,
1395                                     gint               y,
1396                                     gint               width,
1397                                     gint               height)
1398 {
1399   cairo_save (cr);
1400
1401   if (style->background[state_type] == NULL)
1402     {
1403       GdkWindow *parent = gdk_window_get_parent (window);
1404       int x_offset, y_offset;
1405
1406       if (parent)
1407         {
1408           gdk_window_get_position (window, &x_offset, &y_offset);
1409           cairo_translate (cr, -x_offset, -y_offset);
1410           gtk_style_apply_default_background (style, cr,
1411                                               parent, state_type,
1412                                               x + x_offset, y + y_offset,
1413                                               width, height);
1414           goto out;
1415         }
1416       else
1417         gdk_cairo_set_source_color (cr, &style->bg[state_type]);
1418     }
1419   else
1420     cairo_set_source (cr, style->background[state_type]);
1421
1422   cairo_rectangle (cr, x, y, width, height);
1423   cairo_fill (cr);
1424
1425 out:
1426   cairo_restore (cr);
1427 }
1428
1429 static GdkPixbuf *
1430 scale_or_ref (GdkPixbuf *src,
1431               gint       width,
1432               gint       height)
1433 {
1434   if (width == gdk_pixbuf_get_width (src) &&
1435       height == gdk_pixbuf_get_height (src))
1436     {
1437       return g_object_ref (src);
1438     }
1439   else
1440     {
1441       return gdk_pixbuf_scale_simple (src,
1442                                       width, height,
1443                                       GDK_INTERP_BILINEAR);
1444     }
1445 }
1446
1447 static gboolean
1448 lookup_icon_size (GtkStyle    *style,
1449                   GtkWidget   *widget,
1450                   GtkIconSize  size,
1451                   gint        *width,
1452                   gint        *height)
1453 {
1454   GdkScreen *screen;
1455   GtkSettings *settings;
1456
1457   if (widget && gtk_widget_has_screen (widget))
1458     {
1459       screen = gtk_widget_get_screen (widget);
1460       settings = gtk_settings_get_for_screen (screen);
1461     }
1462   else if (style && style->visual)
1463     {
1464       screen = gdk_visual_get_screen (style->visual);
1465       settings = gtk_settings_get_for_screen (screen);
1466     }
1467   else
1468     {
1469       settings = gtk_settings_get_default ();
1470       GTK_NOTE (MULTIHEAD,
1471                 g_warning ("Using the default screen for gtk_default_render_icon()"));
1472     }
1473
1474   return gtk_icon_size_lookup_for_settings (settings, size, width, height);
1475 }
1476
1477 static GdkPixbuf *
1478 gtk_default_render_icon (GtkStyle            *style,
1479                          const GtkIconSource *source,
1480                          GtkTextDirection     direction,
1481                          GtkStateType         state,
1482                          GtkIconSize          size,
1483                          GtkWidget           *widget,
1484                          const gchar         *detail)
1485 {
1486   gint width = 1;
1487   gint height = 1;
1488   GdkPixbuf *scaled;
1489   GdkPixbuf *stated;
1490   GdkPixbuf *base_pixbuf;
1491
1492   /* Oddly, style can be NULL in this function, because
1493    * GtkIconSet can be used without a style and if so
1494    * it uses this function.
1495    */
1496
1497   base_pixbuf = gtk_icon_source_get_pixbuf (source);
1498
1499   g_return_val_if_fail (base_pixbuf != NULL, NULL);
1500
1501   if (size != (GtkIconSize) -1 && !lookup_icon_size(style, widget, size, &width, &height))
1502     {
1503       g_warning (G_STRLOC ": invalid icon size '%d'", size);
1504       return NULL;
1505     }
1506
1507   /* If the size was wildcarded, and we're allowed to scale, then scale; otherwise,
1508    * leave it alone.
1509    */
1510   if (size != (GtkIconSize)-1 && gtk_icon_source_get_size_wildcarded (source))
1511     scaled = scale_or_ref (base_pixbuf, width, height);
1512   else
1513     scaled = g_object_ref (base_pixbuf);
1514
1515   /* If the state was wildcarded, then generate a state. */
1516   if (gtk_icon_source_get_state_wildcarded (source))
1517     {
1518       if (state == GTK_STATE_INSENSITIVE)
1519         {
1520           stated = gdk_pixbuf_copy (scaled);      
1521           
1522           gdk_pixbuf_saturate_and_pixelate (scaled, stated,
1523                                             0.8, TRUE);
1524           
1525           g_object_unref (scaled);
1526         }
1527       else if (state == GTK_STATE_PRELIGHT)
1528         {
1529           stated = gdk_pixbuf_copy (scaled);      
1530           
1531           gdk_pixbuf_saturate_and_pixelate (scaled, stated,
1532                                             1.2, FALSE);
1533           
1534           g_object_unref (scaled);
1535         }
1536       else
1537         {
1538           stated = scaled;
1539         }
1540     }
1541   else
1542     stated = scaled;
1543   
1544   return stated;
1545 }
1546
1547 static void
1548 _cairo_draw_line (cairo_t  *cr,
1549                   GdkColor *color,
1550                   gint      x1,
1551                   gint      y1,
1552                   gint      x2,
1553                   gint      y2)
1554 {
1555   cairo_save (cr);
1556
1557   gdk_cairo_set_source_color (cr, color);
1558   cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
1559
1560   cairo_move_to (cr, x1 + 0.5, y1 + 0.5);
1561   cairo_line_to (cr, x2 + 0.5, y2 + 0.5);
1562   cairo_stroke (cr);
1563
1564   cairo_restore (cr);
1565 }
1566
1567 static void
1568 _cairo_draw_rectangle (cairo_t *cr,
1569                        GdkColor *color,
1570                        gboolean filled,
1571                        gint x,
1572                        gint y,
1573                        gint width,
1574                        gint height)
1575 {
1576   gdk_cairo_set_source_color (cr, color);
1577
1578   if (filled)
1579     {
1580       cairo_rectangle (cr, x, y, width, height);
1581       cairo_fill (cr);
1582     }
1583   else
1584     {
1585       cairo_rectangle (cr, x + 0.5, y + 0.5, width, height);
1586       cairo_stroke (cr);
1587     }
1588 }
1589
1590 static void
1591 _cairo_draw_point (cairo_t *cr,
1592                    GdkColor *color,
1593                    gint x,
1594                    gint y)
1595 {
1596   gdk_cairo_set_source_color (cr, color);
1597   cairo_rectangle (cr, x, y, 1, 1);
1598   cairo_fill (cr);
1599 }
1600
1601 static void
1602 gtk_default_draw_hline (GtkStyle      *style,
1603                         cairo_t       *cr,
1604                         GtkStateType  state_type,
1605                         GtkWidget     *widget,
1606                         const gchar   *detail,
1607                         gint          x1,
1608                         gint          x2,
1609                         gint          y)
1610 {
1611   gint thickness_light;
1612   gint thickness_dark;
1613   gint i;
1614   
1615   thickness_light = style->ythickness / 2;
1616   thickness_dark = style->ythickness - thickness_light;
1617   
1618   cairo_set_line_width (cr, 1.0);
1619
1620   if (detail && !strcmp (detail, "label"))
1621     {
1622       if (state_type == GTK_STATE_INSENSITIVE)
1623         _cairo_draw_line (cr, &style->white, x1 + 1, y + 1, x2 + 1, y + 1);
1624       _cairo_draw_line (cr, &style->fg[state_type], x1, y, x2, y);
1625     }
1626   else
1627     {
1628       for (i = 0; i < thickness_dark; i++)
1629         {
1630           _cairo_draw_line (cr, &style->dark[state_type], x1, y + i, x2 - i - 1, y + i);
1631           _cairo_draw_line (cr, &style->light[state_type], x2 - i, y + i, x2, y + i);
1632         }
1633       
1634       y += thickness_dark;
1635       for (i = 0; i < thickness_light; i++)
1636         {
1637           _cairo_draw_line (cr, &style->dark[state_type], x1, y + i, x1 + thickness_light - i - 1, y + i);
1638           _cairo_draw_line (cr, &style->light[state_type], x1 + thickness_light - i, y + i, x2, y + i);
1639         }
1640     }
1641 }
1642
1643
1644 static void
1645 gtk_default_draw_vline (GtkStyle      *style,
1646                         cairo_t       *cr,
1647                         GtkStateType  state_type,
1648                         GtkWidget     *widget,
1649                         const gchar   *detail,
1650                         gint          y1,
1651                         gint          y2,
1652                         gint          x)
1653 {
1654   gint thickness_light;
1655   gint thickness_dark;
1656   gint i;
1657   
1658   thickness_light = style->xthickness / 2;
1659   thickness_dark = style->xthickness - thickness_light;
1660
1661   cairo_set_line_width (cr, 1.0);
1662
1663   for (i = 0; i < thickness_dark; i++)
1664     { 
1665       _cairo_draw_line (cr, &style->dark[state_type],
1666                         x + i, y1, x + i, y2 - i - 1);
1667       _cairo_draw_line (cr, &style->light[state_type],
1668                         x + i, y2 - i, x + i, y2);
1669     }
1670   
1671   x += thickness_dark;
1672   for (i = 0; i < thickness_light; i++)
1673     {
1674       _cairo_draw_line (cr, &style->dark[state_type],
1675                         x + i, y1, x + i, y1 + thickness_light - i - 1);
1676       _cairo_draw_line (cr, &style->light[state_type],
1677                         x + i, y1 + thickness_light - i, x + i, y2);
1678     }
1679 }
1680
1681 static void
1682 draw_thin_shadow (GtkStyle      *style,
1683                   cairo_t       *cr,
1684                   GtkStateType   state,
1685                   gint           x,
1686                   gint           y,
1687                   gint           width,
1688                   gint           height)
1689 {
1690   GdkColor *gc1, *gc2;
1691
1692   gc1 = &style->light[state];
1693   gc2 = &style->dark[state];
1694
1695   _cairo_draw_line (cr, gc1,
1696                     x, y + height - 1, x + width - 1, y + height - 1);
1697   _cairo_draw_line (cr, gc1,
1698                     x + width - 1, y,  x + width - 1, y + height - 1);
1699       
1700   _cairo_draw_line (cr, gc2,
1701                     x, y, x + width - 2, y);
1702   _cairo_draw_line (cr, gc2,
1703                     x, y, x, y + height - 2);
1704 }
1705
1706 static void
1707 draw_spinbutton_shadow (GtkStyle        *style,
1708                         cairo_t         *cr,
1709                         GtkStateType     state,
1710                         GtkTextDirection direction,
1711                         gint             x,
1712                         gint             y,
1713                         gint             width,
1714                         gint             height)
1715 {
1716
1717   if (direction == GTK_TEXT_DIR_LTR)
1718     {
1719       _cairo_draw_line (cr, &style->dark[state],
1720                         x, y, x + width - 1, y);
1721       _cairo_draw_line (cr, &style->black,
1722                         x, y + 1, x + width - 2, y + 1);
1723       _cairo_draw_line (cr, &style->black,
1724                         x + width - 2, y + 2, x + width - 2, y + height - 3);
1725       _cairo_draw_line (cr, &style->light[state],
1726                         x + width - 1, y + 1, x + width - 1, y + height - 2);
1727       _cairo_draw_line (cr, &style->light[state],
1728                         x, y + height - 1, x + width - 1, y + height - 1);
1729       _cairo_draw_line (cr, &style->bg[state],
1730                         x, y + height - 2, x + width - 2, y + height - 2);
1731       _cairo_draw_line (cr, &style->black,
1732                         x, y + 2, x, y + height - 3);
1733     }
1734   else
1735     {
1736       _cairo_draw_line (cr, &style->dark[state],
1737                         x, y, x + width - 1, y);
1738       _cairo_draw_line (cr, &style->dark[state],
1739                         x, y + 1, x, y + height - 1);
1740       _cairo_draw_line (cr, &style->black,
1741                         x + 1, y + 1, x + width - 1, y + 1);
1742       _cairo_draw_line (cr, &style->black,
1743                         x + 1, y + 2, x + 1, y + height - 2);
1744       _cairo_draw_line (cr, &style->black,
1745                         x + width - 1, y + 2, x + width - 1, y + height - 3);
1746       _cairo_draw_line (cr, &style->light[state],
1747                         x + 1, y + height - 1, x + width - 1, y + height - 1);
1748       _cairo_draw_line (cr, &style->bg[state],
1749                         x + 2, y + height - 2, x + width - 1, y + height - 2);
1750     }
1751 }
1752
1753 static void
1754 draw_menu_shadow (GtkStyle        *style,
1755                   cairo_t         *cr,
1756                   GtkStateType     state,
1757                   gint             x,
1758                   gint             y,
1759                   gint             width,
1760                   gint             height)
1761 {
1762   if (style->ythickness > 0)
1763     {
1764       if (style->ythickness > 1)
1765         {
1766           _cairo_draw_line (cr, &style->dark[state],
1767                             x + 1, y + height - 2,
1768                             x + width - 2, y + height - 2);
1769           _cairo_draw_line (cr, &style->black,
1770                             x, y + height - 1, x + width - 1, y + height - 1);
1771         }
1772       else
1773         {
1774           _cairo_draw_line (cr, &style->dark[state],
1775                             x + 1, y + height - 1, x + width - 1, y + height - 1);
1776         }
1777     }
1778   
1779   if (style->xthickness > 0)
1780     {
1781       if (style->xthickness > 1)
1782         {
1783           _cairo_draw_line (cr, &style->dark[state],
1784                             x + width - 2, y + 1,
1785                             x + width - 2, y + height - 2);
1786
1787           _cairo_draw_line (cr, &style->black,
1788                             x + width - 1, y, x + width - 1, y + height - 1);
1789         }
1790       else
1791         {
1792           _cairo_draw_line (cr, &style->dark[state],
1793                             x + width - 1, y + 1, x + width - 1, y + height - 1);
1794         }
1795     }
1796   
1797   /* Light around top and left */
1798   
1799   if (style->ythickness > 0)
1800     _cairo_draw_line (cr, &style->black,
1801                    x, y, x + width - 2, y);
1802   if (style->xthickness > 0)
1803     _cairo_draw_line (cr, &style->black,
1804                       x, y, x, y + height - 2);
1805   
1806   if (style->ythickness > 1)
1807     _cairo_draw_line (cr, &style->light[state],
1808                       x + 1, y + 1, x + width - 3, y + 1);
1809   if (style->xthickness > 1)
1810     _cairo_draw_line (cr, &style->light[state],
1811                       x + 1, y + 1, x + 1, y + height - 3);
1812 }
1813
1814 static GtkTextDirection
1815 get_direction (GtkWidget *widget)
1816 {
1817   GtkTextDirection dir;
1818   
1819   if (widget)
1820     dir = gtk_widget_get_direction (widget);
1821   else
1822     dir = GTK_TEXT_DIR_LTR;
1823   
1824   return dir;
1825 }
1826
1827
1828 static void
1829 gtk_default_draw_shadow (GtkStyle      *style,
1830                          cairo_t       *cr,
1831                          GtkStateType   state_type,
1832                          GtkShadowType  shadow_type,
1833                          GtkWidget     *widget,
1834                          const gchar   *detail,
1835                          gint           x,
1836                          gint           y,
1837                          gint           width,
1838                          gint           height)
1839 {
1840   GdkColor *gc1 = NULL;
1841   GdkColor *gc2 = NULL;
1842   gint thickness_light;
1843   gint thickness_dark;
1844   gint i;
1845
1846   cairo_set_line_width (cr, 1.0);
1847
1848   if (shadow_type == GTK_SHADOW_IN)
1849     {
1850       if (detail && strcmp (detail, "buttondefault") == 0)
1851         {
1852           _cairo_draw_rectangle (cr, &style->black, FALSE,
1853                                  x, y, width - 1, height - 1);
1854
1855           return;
1856         }
1857       if (detail && strcmp (detail, "trough") == 0)
1858         {
1859           draw_thin_shadow (style, cr, state_type,
1860                             x, y, width, height);
1861
1862           return;
1863         }
1864       if (GTK_IS_SPIN_BUTTON (widget) &&
1865          detail && strcmp (detail, "spinbutton") == 0)
1866         {
1867           draw_spinbutton_shadow (style, cr, state_type, 
1868                                   get_direction (widget), x, y, width, height);
1869           
1870           return;
1871         }
1872     }
1873
1874   if (shadow_type == GTK_SHADOW_OUT && detail && strcmp (detail, "menu") == 0)
1875     {
1876       draw_menu_shadow (style, cr, state_type, x, y, width, height);
1877       return;
1878     }
1879   
1880   switch (shadow_type)
1881     {
1882     case GTK_SHADOW_NONE:
1883       return;
1884     case GTK_SHADOW_IN:
1885     case GTK_SHADOW_ETCHED_IN:
1886       gc1 = &style->light[state_type];
1887       gc2 = &style->dark[state_type];
1888       break;
1889     case GTK_SHADOW_OUT:
1890     case GTK_SHADOW_ETCHED_OUT:
1891       gc1 = &style->dark[state_type];
1892       gc2 = &style->light[state_type];
1893       break;
1894     }
1895   
1896   switch (shadow_type)
1897     {
1898     case GTK_SHADOW_NONE:
1899       break;
1900       
1901     case GTK_SHADOW_IN:
1902       /* Light around right and bottom edge */
1903
1904       if (style->ythickness > 0)
1905         _cairo_draw_line (cr, gc1,
1906                           x, y + height - 1, x + width - 1, y + height - 1);
1907       if (style->xthickness > 0)
1908         _cairo_draw_line (cr, gc1,
1909                           x + width - 1, y, x + width - 1, y + height - 1);
1910
1911       if (style->ythickness > 1)
1912         _cairo_draw_line (cr, &style->bg[state_type],
1913                           x + 1, y + height - 2, x + width - 2, y + height - 2);
1914       if (style->xthickness > 1)
1915         _cairo_draw_line (cr, &style->bg[state_type],
1916                           x + width - 2, y + 1, x + width - 2, y + height - 2);
1917
1918       /* Dark around left and top */
1919
1920       if (style->ythickness > 1)
1921         _cairo_draw_line (cr, &style->black,
1922                           x + 1, y + 1, x + width - 2, y + 1);
1923       if (style->xthickness > 1)
1924         _cairo_draw_line (cr, &style->black,
1925                           x + 1, y + 1, x + 1, y + height - 2);
1926
1927       if (style->ythickness > 0)
1928         _cairo_draw_line (cr, gc2,
1929                           x, y, x + width - 1, y);
1930       if (style->xthickness > 0)
1931         _cairo_draw_line (cr, gc2,
1932                           x, y, x, y + height - 1);
1933       break;
1934       
1935     case GTK_SHADOW_OUT:
1936       /* Dark around right and bottom edge */
1937
1938       if (style->ythickness > 0)
1939         {
1940           if (style->ythickness > 1)
1941             {
1942               _cairo_draw_line (cr, gc1,
1943                                 x + 1, y + height - 2, x + width - 2, y + height - 2);
1944               _cairo_draw_line (cr, &style->black,
1945                                 x, y + height - 1, x + width - 1, y + height - 1);
1946             }
1947           else
1948             {
1949               _cairo_draw_line (cr, gc1,
1950                                 x + 1, y + height - 1, x + width - 1, y + height - 1);
1951             }
1952         }
1953
1954       if (style->xthickness > 0)
1955         {
1956           if (style->xthickness > 1)
1957             {
1958               _cairo_draw_line (cr, gc1,
1959                                 x + width - 2, y + 1, x + width - 2, y + height - 2);
1960               
1961               _cairo_draw_line (cr, &style->black,
1962                                 x + width - 1, y, x + width - 1, y + height - 1);
1963             }
1964           else
1965             {
1966               _cairo_draw_line (cr, gc1,
1967                                 x + width - 1, y + 1, x + width - 1, y + height - 1);
1968             }
1969         }
1970       
1971       /* Light around top and left */
1972
1973       if (style->ythickness > 0)
1974         _cairo_draw_line (cr, gc2,
1975                           x, y, x + width - 2, y);
1976       if (style->xthickness > 0)
1977         _cairo_draw_line (cr, gc2,
1978                           x, y, x, y + height - 2);
1979
1980       if (style->ythickness > 1)
1981         _cairo_draw_line (cr, &style->bg[state_type],
1982                           x + 1, y + 1, x + width - 3, y + 1);
1983       if (style->xthickness > 1)
1984         _cairo_draw_line (cr, &style->bg[state_type],
1985                           x + 1, y + 1, x + 1, y + height - 3);
1986       break;
1987       
1988     case GTK_SHADOW_ETCHED_IN:
1989     case GTK_SHADOW_ETCHED_OUT:
1990       if (style->xthickness > 0)
1991         {
1992           if (style->xthickness > 1)
1993             {
1994               thickness_light = 1;
1995               thickness_dark = 1;
1996       
1997               for (i = 0; i < thickness_dark; i++)
1998                 {
1999                   _cairo_draw_line (cr, gc1,
2000                                     x + width - i - 1,
2001                                     y + i,
2002                                     x + width - i - 1,
2003                                     y + height - i - 1);
2004                   _cairo_draw_line (cr, gc2,
2005                                     x + i,
2006                                     y + i,
2007                                     x + i,
2008                                     y + height - i - 2);
2009                 }
2010       
2011               for (i = 0; i < thickness_light; i++)
2012                 {
2013                   _cairo_draw_line (cr, gc1,
2014                                     x + thickness_dark + i,
2015                                     y + thickness_dark + i,
2016                                     x + thickness_dark + i,
2017                                     y + height - thickness_dark - i - 1);
2018                   _cairo_draw_line (cr, gc2,
2019                                     x + width - thickness_light - i - 1,
2020                                     y + thickness_dark + i,
2021                                     x + width - thickness_light - i - 1,
2022                                     y + height - thickness_light - 1);
2023                 }
2024             }
2025           else
2026             {
2027               _cairo_draw_line (cr,
2028                                 &style->dark[state_type],
2029                                 x, y, x, y + height);
2030               _cairo_draw_line (cr,
2031                                 &style->dark[state_type],
2032                                 x + width, y, x + width, y + height);
2033             }
2034         }
2035
2036       if (style->ythickness > 0)
2037         {
2038           if (style->ythickness > 1)
2039             {
2040               thickness_light = 1;
2041               thickness_dark = 1;
2042       
2043               for (i = 0; i < thickness_dark; i++)
2044                 {
2045                   _cairo_draw_line (cr, gc1,
2046                                     x + i,
2047                                     y + height - i - 1,
2048                                     x + width - i - 1,
2049                                     y + height - i - 1);
2050           
2051                   _cairo_draw_line (cr, gc2,
2052                                     x + i,
2053                                     y + i,
2054                                     x + width - i - 2,
2055                                     y + i);
2056                 }
2057       
2058               for (i = 0; i < thickness_light; i++)
2059                 {
2060                   _cairo_draw_line (cr, gc1,
2061                                     x + thickness_dark + i,
2062                                     y + thickness_dark + i,
2063                                     x + width - thickness_dark - i - 2,
2064                                     y + thickness_dark + i);
2065           
2066                   _cairo_draw_line (cr, gc2,
2067                                     x + thickness_dark + i,
2068                                     y + height - thickness_light - i - 1,
2069                                     x + width - thickness_light - 1,
2070                                     y + height - thickness_light - i - 1);
2071                 }
2072             }
2073           else
2074             {
2075               _cairo_draw_line (cr,
2076                                 &style->dark[state_type],
2077                                 x, y, x + width, y);
2078               _cairo_draw_line (cr,
2079                                 &style->dark[state_type],
2080                                 x, y + height, x + width, y + height);
2081             }
2082         }
2083       
2084       break;
2085     }
2086
2087   if (shadow_type == GTK_SHADOW_IN &&
2088       GTK_IS_SPIN_BUTTON (widget) &&
2089       detail && strcmp (detail, "entry") == 0)
2090     {
2091       if (get_direction (widget) == GTK_TEXT_DIR_LTR)
2092         {
2093           _cairo_draw_line (cr,
2094                             &style->base[state_type],
2095                             x + width - 1, y + 2,
2096                             x + width - 1, y + height - 3);
2097           _cairo_draw_line (cr,
2098                             &style->base[state_type],
2099                             x + width - 2, y + 2,
2100                             x + width - 2, y + height - 3);
2101           /* draw point */
2102           _cairo_draw_point (cr,
2103                              &style->black,
2104                              x + width - 1, y + 1);
2105           _cairo_draw_point (cr,
2106                              &style->bg[state_type],
2107                              x + width - 1, y + height - 2);
2108         }
2109       else
2110         {
2111           _cairo_draw_line (cr,
2112                             &style->base[state_type],
2113                             x, y + 2,
2114                             x, y + height - 3);
2115           _cairo_draw_line (cr,
2116                             &style->base[state_type],
2117                             x + 1, y + 2,
2118                             x + 1, y + height - 3);
2119
2120           _cairo_draw_point (cr,
2121                              &style->black,
2122                              x, y + 1);
2123
2124           _cairo_draw_line (cr,
2125                             &style->bg[state_type],
2126                             x, y + height - 2,
2127                             x + 1, y + height - 2);
2128           _cairo_draw_point (cr,
2129                              &style->light[state_type],
2130                              x, y + height - 1);
2131         }
2132     }
2133 }
2134
2135 static void
2136 draw_arrow (cairo_t       *cr,
2137             GdkColor      *color,
2138             GtkArrowType   arrow_type,
2139             gint           x,
2140             gint           y,
2141             gint           width,
2142             gint           height)
2143 {
2144   gdk_cairo_set_source_color (cr, color);
2145   cairo_save (cr);
2146     
2147   if (arrow_type == GTK_ARROW_DOWN)
2148     {
2149       cairo_move_to (cr, x,              y);
2150       cairo_line_to (cr, x + width,      y);
2151       cairo_line_to (cr, x + width / 2., y + height);
2152     }
2153   else if (arrow_type == GTK_ARROW_UP)
2154     {
2155       cairo_move_to (cr, x,              y + height);
2156       cairo_line_to (cr, x + width / 2., y);
2157       cairo_line_to (cr, x + width,      y + height);
2158     }
2159   else if (arrow_type == GTK_ARROW_LEFT)
2160     {
2161       cairo_move_to (cr, x + width,      y);
2162       cairo_line_to (cr, x + width,      y + height);
2163       cairo_line_to (cr, x,              y + height / 2.);
2164     }
2165   else if (arrow_type == GTK_ARROW_RIGHT)
2166     {
2167       cairo_move_to (cr, x,              y);
2168       cairo_line_to (cr, x + width,      y + height / 2.);
2169       cairo_line_to (cr, x,              y + height);
2170     }
2171
2172   cairo_close_path (cr);
2173   cairo_fill (cr);
2174
2175   cairo_restore (cr);
2176 }
2177
2178 static void
2179 calculate_arrow_geometry (GtkArrowType  arrow_type,
2180                           gint         *x,
2181                           gint         *y,
2182                           gint         *width,
2183                           gint         *height)
2184 {
2185   gint w = *width;
2186   gint h = *height;
2187   
2188   switch (arrow_type)
2189     {
2190     case GTK_ARROW_UP:
2191     case GTK_ARROW_DOWN:
2192       w += (w % 2) - 1;
2193       h = (w / 2 + 1);
2194       
2195       if (h > *height)
2196         {
2197           h = *height;
2198           w = 2 * h - 1;
2199         }
2200       
2201       if (arrow_type == GTK_ARROW_DOWN)
2202         {
2203           if (*height % 2 == 1 || h % 2 == 0)
2204             *height += 1;
2205         }
2206       else
2207         {
2208           if (*height % 2 == 0 || h % 2 == 0)
2209             *height -= 1;
2210         }
2211       break;
2212
2213     case GTK_ARROW_RIGHT:
2214     case GTK_ARROW_LEFT:
2215       h += (h % 2) - 1;
2216       w = (h / 2 + 1);
2217       
2218       if (w > *width)
2219         {
2220           w = *width;
2221           h = 2 * w - 1;
2222         }
2223       
2224       if (arrow_type == GTK_ARROW_RIGHT)
2225         {
2226           if (*width % 2 == 1 || w % 2 == 0)
2227             *width += 1;
2228         }
2229       else
2230         {
2231           if (*width % 2 == 0 || w % 2 == 0)
2232             *width -= 1;
2233         }
2234       break;
2235       
2236     default:
2237       /* should not be reached */
2238       break;
2239     }
2240
2241   *x += (*width - w) / 2;
2242   *y += (*height - h) / 2;
2243   *height = h;
2244   *width = w;
2245 }
2246
2247 static void
2248 gtk_default_draw_arrow (GtkStyle      *style,
2249                         cairo_t       *cr,
2250                         GtkStateType   state,
2251                         GtkShadowType  shadow,
2252                         GtkWidget     *widget,
2253                         const gchar   *detail,
2254                         GtkArrowType   arrow_type,
2255                         gboolean       fill,
2256                         gint           x,
2257                         gint           y,
2258                         gint           width,
2259                         gint           height)
2260 {
2261   calculate_arrow_geometry (arrow_type, &x, &y, &width, &height);
2262
2263   if (detail && strcmp (detail, "menu_scroll_arrow_up") == 0)
2264     y++;
2265
2266   if (state == GTK_STATE_INSENSITIVE)
2267     draw_arrow (cr, &style->white, arrow_type,
2268                 x + 1, y + 1, width, height);
2269   draw_arrow (cr, &style->fg[state], arrow_type,
2270               x, y, width, height);
2271 }
2272
2273 static void
2274 gtk_default_draw_diamond (GtkStyle      *style,
2275                           cairo_t       *cr,
2276                           GtkStateType   state_type,
2277                           GtkShadowType  shadow_type,
2278                           GtkWidget     *widget,
2279                           const gchar   *detail,
2280                           gint           x,
2281                           gint           y,
2282                           gint           width,
2283                           gint           height)
2284 {
2285   gint half_width;
2286   gint half_height;
2287   GdkColor *outer_nw = NULL;
2288   GdkColor *outer_ne = NULL;
2289   GdkColor *outer_sw = NULL;
2290   GdkColor *outer_se = NULL;
2291   GdkColor *middle_nw = NULL;
2292   GdkColor *middle_ne = NULL;
2293   GdkColor *middle_sw = NULL;
2294   GdkColor *middle_se = NULL;
2295   GdkColor *inner_nw = NULL;
2296   GdkColor *inner_ne = NULL;
2297   GdkColor *inner_sw = NULL;
2298   GdkColor *inner_se = NULL;
2299   
2300   half_width = width / 2;
2301   half_height = height / 2;
2302   
2303   switch (shadow_type)
2304     {
2305     case GTK_SHADOW_IN:
2306       inner_sw = inner_se = &style->bg[state_type];
2307       middle_sw = middle_se = &style->light[state_type];
2308       outer_sw = outer_se = &style->light[state_type];
2309       inner_nw = inner_ne = &style->black;
2310       middle_nw = middle_ne = &style->dark[state_type];
2311       outer_nw = outer_ne = &style->dark[state_type];
2312       break;
2313           
2314     case GTK_SHADOW_OUT:
2315       inner_sw = inner_se = &style->dark[state_type];
2316       middle_sw = middle_se = &style->dark[state_type];
2317       outer_sw = outer_se = &style->black;
2318       inner_nw = inner_ne = &style->bg[state_type];
2319       middle_nw = middle_ne = &style->light[state_type];
2320       outer_nw = outer_ne = &style->light[state_type];
2321       break;
2322
2323     case GTK_SHADOW_ETCHED_IN:
2324       inner_sw = inner_se = &style->bg[state_type];
2325       middle_sw = middle_se = &style->dark[state_type];
2326       outer_sw = outer_se = &style->light[state_type];
2327       inner_nw = inner_ne = &style->bg[state_type];
2328       middle_nw = middle_ne = &style->light[state_type];
2329       outer_nw = outer_ne = &style->dark[state_type];
2330       break;
2331
2332     case GTK_SHADOW_ETCHED_OUT:
2333       inner_sw = inner_se = &style->bg[state_type];
2334       middle_sw = middle_se = &style->light[state_type];
2335       outer_sw = outer_se = &style->dark[state_type];
2336       inner_nw = inner_ne = &style->bg[state_type];
2337       middle_nw = middle_ne = &style->dark[state_type];
2338       outer_nw = outer_ne = &style->light[state_type];
2339       break;
2340       
2341     default:
2342
2343       break;
2344     }
2345
2346   if (inner_sw)
2347     {
2348       _cairo_draw_line (cr, inner_sw,
2349                         x + 2, y + half_height,
2350                         x + half_width, y + height - 2);
2351       _cairo_draw_line (cr, inner_se,
2352                         x + half_width, y + height - 2,
2353                         x + width - 2, y + half_height);
2354       _cairo_draw_line (cr, middle_sw,
2355                         x + 1, y + half_height,
2356                         x + half_width, y + height - 1);
2357       _cairo_draw_line (cr, middle_se,
2358                         x + half_width, y + height - 1,
2359                         x + width - 1, y + half_height);
2360       _cairo_draw_line (cr, outer_sw,
2361                         x, y + half_height,
2362                         x + half_width, y + height);
2363       _cairo_draw_line (cr, outer_se,
2364                         x + half_width, y + height,
2365                         x + width, y + half_height);
2366   
2367       _cairo_draw_line (cr, inner_nw,
2368                         x + 2, y + half_height,
2369                         x + half_width, y + 2);
2370       _cairo_draw_line (cr, inner_ne,
2371                         x + half_width, y + 2,
2372                         x + width - 2, y + half_height);
2373       _cairo_draw_line (cr, middle_nw,
2374                         x + 1, y + half_height,
2375                         x + half_width, y + 1);
2376       _cairo_draw_line (cr, middle_ne,
2377                         x + half_width, y + 1,
2378                         x + width - 1, y + half_height);
2379       _cairo_draw_line (cr, outer_nw,
2380                         x, y + half_height,
2381                         x + half_width, y);
2382       _cairo_draw_line (cr, outer_ne,
2383                         x + half_width, y,
2384                         x + width, y + half_height);
2385     }
2386 }
2387
2388 static void
2389 option_menu_get_props (GtkWidget      *widget,
2390                        GtkRequisition *indicator_size,
2391                        GtkBorder      *indicator_spacing)
2392 {
2393   GtkRequisition *tmp_size = NULL;
2394   GtkBorder *tmp_spacing = NULL;
2395
2396   if (tmp_size)
2397     {
2398       *indicator_size = *tmp_size;
2399       gtk_requisition_free (tmp_size);
2400     }
2401   else
2402     *indicator_size = default_option_indicator_size;
2403
2404   if (tmp_spacing)
2405     {
2406       *indicator_spacing = *tmp_spacing;
2407       gtk_border_free (tmp_spacing);
2408     }
2409   else
2410     *indicator_spacing = default_option_indicator_spacing;
2411 }
2412
2413 static gboolean
2414 background_is_solid (GtkStyle     *style,
2415                      GtkStateType  type)
2416 {
2417   if (style->background[type] == NULL)
2418     return FALSE;
2419
2420   return cairo_pattern_get_type (style->background[type]) == CAIRO_PATTERN_TYPE_SOLID;
2421 }
2422
2423 static void 
2424 gtk_default_draw_box (GtkStyle      *style,
2425                       cairo_t       *cr,
2426                       GtkStateType   state_type,
2427                       GtkShadowType  shadow_type,
2428                       GtkWidget     *widget,
2429                       const gchar   *detail,
2430                       gint           x,
2431                       gint           y,
2432                       gint           width,
2433                       gint           height)
2434 {
2435   gboolean is_spinbutton_box = FALSE;
2436   
2437   if (GTK_IS_SPIN_BUTTON (widget) && detail)
2438     {
2439       if (strcmp (detail, "spinbutton_up") == 0)
2440         {
2441           y += 2;
2442           width -= 3;
2443           height -= 2;
2444
2445           if (get_direction (widget) == GTK_TEXT_DIR_RTL)
2446             x += 2;
2447           else
2448             x += 1;
2449
2450           is_spinbutton_box = TRUE;
2451         }
2452       else if (strcmp (detail, "spinbutton_down") == 0)
2453         {
2454           width -= 3;
2455           height -= 2;
2456
2457           if (get_direction (widget) == GTK_TEXT_DIR_RTL)
2458             x += 2;
2459           else
2460             x += 1;
2461
2462           is_spinbutton_box = TRUE;
2463         }
2464     }
2465   
2466   if (background_is_solid (style, state_type))
2467     {
2468       GdkColor *gc = &style->bg[state_type];
2469
2470       if (state_type == GTK_STATE_SELECTED && detail && strcmp (detail, "paned") == 0)
2471         {
2472           if (widget && !gtk_widget_has_focus (widget))
2473             gc = &style->base[GTK_STATE_ACTIVE];
2474         }
2475
2476       _cairo_draw_rectangle (cr, gc, TRUE,
2477                              x, y, width, height);
2478     }
2479   else
2480     gtk_style_apply_default_background (style, cr, gtk_widget_get_window (widget),
2481                                         state_type, x, y, width, height);
2482
2483
2484   if (is_spinbutton_box)
2485     {
2486       GdkColor *upper;
2487       GdkColor *lower;
2488
2489       lower = &style->dark[state_type];
2490       if (shadow_type == GTK_SHADOW_OUT)
2491         upper = &style->light[state_type];
2492       else
2493         upper = &style->dark[state_type];
2494
2495       _cairo_draw_line (cr, upper, x, y, x + width - 1, y);
2496       _cairo_draw_line (cr, lower, x, y + height - 1, x + width - 1, y + height - 1);
2497
2498       return;
2499     }
2500
2501   gtk_paint_shadow (style, cr, state_type, shadow_type, widget, detail,
2502                           x, y, width, height);
2503
2504   if (detail && strcmp (detail, "optionmenu") == 0)
2505     {
2506       GtkRequisition indicator_size;
2507       GtkBorder indicator_spacing;
2508       gint vline_x;
2509
2510       option_menu_get_props (widget, &indicator_size, &indicator_spacing);
2511
2512       if (get_direction (widget) == GTK_TEXT_DIR_RTL)
2513         vline_x = x + indicator_size.width + indicator_spacing.left + indicator_spacing.right;
2514       else 
2515         vline_x = x + width - (indicator_size.width + indicator_spacing.left + indicator_spacing.right) - style->xthickness;
2516
2517       gtk_paint_vline (style, cr, state_type, widget,
2518                              detail,
2519                              y + style->ythickness + 1,
2520                              y + height - style->ythickness - 3,
2521                              vline_x);
2522     }
2523 }
2524
2525 static GdkColor *
2526 get_darkened (const GdkColor *color,
2527                  gint            darken_count)
2528 {
2529   GdkColor src = *color;
2530   GdkColor shaded = *color;
2531   
2532   while (darken_count)
2533     {
2534       _gtk_style_shade (&src, &shaded, 0.93);
2535       src = shaded;
2536       --darken_count;
2537     }
2538    
2539   return gdk_color_copy (&shaded);
2540 }
2541
2542 static void 
2543 gtk_default_draw_flat_box (GtkStyle      *style,
2544                            cairo_t       *cr,
2545                            GtkStateType   state_type,
2546                            GtkShadowType  shadow_type,
2547                            GtkWidget     *widget,
2548                            const gchar   *detail,
2549                            gint           x,
2550                            gint           y,
2551                            gint           width,
2552                            gint           height)
2553 {
2554   GdkColor *gc1;
2555   GdkColor *freeme = NULL;
2556   
2557   cairo_set_line_width (cr, 1.0);
2558
2559   if (detail)
2560     {
2561       int trimmed_len = strlen (detail);
2562
2563       if (g_str_has_prefix (detail, "cell_"))
2564         {
2565           if (g_str_has_suffix (detail, "_start"))
2566             trimmed_len -= 6;
2567           else if (g_str_has_suffix (detail, "_middle"))
2568             trimmed_len -= 7;
2569           else if (g_str_has_suffix (detail, "_end"))
2570             trimmed_len -= 4;
2571         }
2572
2573       if (state_type == GTK_STATE_SELECTED)
2574         {
2575           if (!strcmp ("text", detail))
2576             gc1 = &style->bg[GTK_STATE_SELECTED];
2577           else if (!strncmp ("cell_even", detail, trimmed_len) ||
2578                    !strncmp ("cell_odd", detail, trimmed_len) ||
2579                    !strncmp ("cell_even_ruled", detail, trimmed_len) ||
2580                    !strncmp ("cell_even_ruled_sorted", detail, trimmed_len))
2581             {
2582               /* This has to be really broken; alex made me do it. -jrb */
2583               if (widget && gtk_widget_has_focus (widget))
2584                 gc1 = &style->base[state_type];
2585               else
2586                 gc1 = &style->base[GTK_STATE_ACTIVE];
2587             }
2588           else if (!strncmp ("cell_odd_ruled", detail, trimmed_len) ||
2589                    !strncmp ("cell_odd_ruled_sorted", detail, trimmed_len))
2590             {
2591               if (widget && gtk_widget_has_focus (widget))
2592                 freeme = get_darkened (&style->base[state_type], 1);
2593               else
2594                 freeme = get_darkened (&style->base[GTK_STATE_ACTIVE], 1);
2595               gc1 = freeme;
2596             }
2597           else
2598             {
2599               gc1 = &style->bg[state_type];
2600             }
2601         }
2602       else
2603         {
2604           if (!strcmp ("viewportbin", detail))
2605             gc1 = &style->bg[GTK_STATE_NORMAL];
2606           else if (!strcmp ("entry_bg", detail))
2607             gc1 = &style->base[gtk_widget_get_state (widget)];
2608
2609           /* For trees: even rows are base color, odd rows are a shade of
2610            * the base color, the sort column is a shade of the original color
2611            * for that row.
2612            */
2613
2614           else if (!strncmp ("cell_even", detail, trimmed_len) ||
2615                    !strncmp ("cell_odd", detail, trimmed_len) ||
2616                    !strncmp ("cell_even_ruled", detail, trimmed_len))
2617             {
2618               GdkColor *color = NULL;
2619
2620               gtk_widget_style_get (widget,
2621                                     "even-row-color", &color,
2622                                     NULL);
2623
2624               if (color)
2625                 {
2626                   freeme = get_darkened (color, 0);
2627                   gc1 = freeme;
2628
2629                   gdk_color_free (color);
2630                 }
2631               else
2632                 gc1 = &style->base[state_type];
2633             }
2634           else if (!strncmp ("cell_odd_ruled", detail, trimmed_len))
2635             {
2636               GdkColor *color = NULL;
2637
2638               gtk_widget_style_get (widget,
2639                                     "odd-row-color", &color,
2640                                     NULL);
2641
2642               if (color)
2643                 {
2644                   freeme = get_darkened (color, 0);
2645                   gc1 = freeme;
2646
2647                   gdk_color_free (color);
2648                 }
2649               else
2650                 {
2651                   gtk_widget_style_get (widget,
2652                                         "even-row-color", &color,
2653                                         NULL);
2654
2655                   if (color)
2656                     {
2657                       freeme = get_darkened (color, 1);
2658                       gdk_color_free (color);
2659                     }
2660                   else
2661                     freeme = get_darkened (&style->base[state_type], 1);
2662                   gc1 = freeme;
2663                 }
2664             }
2665           else if (!strncmp ("cell_even_sorted", detail, trimmed_len) ||
2666                    !strncmp ("cell_odd_sorted", detail, trimmed_len) ||
2667                    !strncmp ("cell_even_ruled_sorted", detail, trimmed_len))
2668             {
2669               GdkColor *color = NULL;
2670
2671               if (!strncmp ("cell_odd_sorted", detail, trimmed_len))
2672                 gtk_widget_style_get (widget,
2673                                       "odd-row-color", &color,
2674                                       NULL);
2675               else
2676                 gtk_widget_style_get (widget,
2677                                       "even-row-color", &color,
2678                                       NULL);
2679
2680               if (color)
2681                 {
2682                   freeme = get_darkened (color, 1);
2683                   gc1 = freeme;
2684
2685                   gdk_color_free (color);
2686                 }
2687               else
2688                 {
2689                   freeme = get_darkened (&style->base[state_type], 1);
2690                   gc1 = freeme;
2691                 }
2692             }
2693           else if (!strncmp ("cell_odd_ruled_sorted", detail, trimmed_len))
2694             {
2695               GdkColor *color = NULL;
2696
2697               gtk_widget_style_get (widget,
2698                                     "odd-row-color", &color,
2699                                     NULL);
2700
2701               if (color)
2702                 {
2703                   freeme = get_darkened (color, 1);
2704                   gc1 = freeme;
2705
2706                   gdk_color_free (color);
2707                 }
2708               else
2709                 {
2710                   gtk_widget_style_get (widget,
2711                                         "even-row-color", &color,
2712                                         NULL);
2713
2714                   if (color)
2715                     {
2716                       freeme = get_darkened (color, 2);
2717                       gdk_color_free (color);
2718                     }
2719                   else
2720                     freeme = get_darkened (&style->base[state_type], 2);
2721                   gc1 = freeme;
2722                 }
2723             }
2724           else
2725             gc1 = &style->bg[state_type];
2726         }
2727     }
2728   else
2729     gc1 = &style->bg[state_type];
2730   
2731   if (background_is_solid (style, state_type) || gc1 != &style->bg[state_type])
2732     {
2733       _cairo_draw_rectangle (cr, gc1, TRUE,
2734                              x, y, width, height);
2735
2736       if (detail && !strcmp ("tooltip", detail))
2737         _cairo_draw_rectangle (cr, &style->black, FALSE,
2738                                x, y, width - 1, height - 1);
2739     }
2740   else
2741     gtk_style_apply_default_background (style, cr, gtk_widget_get_window (widget),
2742                                         state_type, x, y, width, height);
2743
2744   if (freeme)
2745     gdk_color_free (freeme);
2746 }
2747
2748 static void 
2749 gtk_default_draw_check (GtkStyle      *style,
2750                         cairo_t       *cr,
2751                         GtkStateType   state_type,
2752                         GtkShadowType  shadow_type,
2753                         GtkWidget     *widget,
2754                         const gchar   *detail,
2755                         gint           x,
2756                         gint           y,
2757                         gint           width,
2758                         gint           height)
2759 {
2760   enum { BUTTON, MENU, CELL } type = BUTTON;
2761   int exterior_size;
2762   int interior_size;
2763   int pad;
2764   
2765   if (detail)
2766     {
2767       if (strcmp (detail, "cellcheck") == 0)
2768         type = CELL;
2769       else if (strcmp (detail, "check") == 0)
2770         type = MENU;
2771     }
2772       
2773   exterior_size = MIN (width, height);
2774   if (exterior_size % 2 == 0) /* Ensure odd */
2775     exterior_size -= 1;
2776
2777   pad = style->xthickness + MAX (1, (exterior_size - 2 * style->xthickness) / 9);
2778   interior_size = MAX (1, exterior_size - 2 * pad);
2779
2780   if (interior_size < 7)
2781     {
2782       interior_size = 7;
2783       pad = MAX (0, (exterior_size - interior_size) / 2);
2784     }
2785
2786   x -= (1 + exterior_size - width) / 2;
2787   y -= (1 + exterior_size - height) / 2;
2788
2789   switch (type)
2790     {
2791     case BUTTON:
2792     case CELL:
2793       if (type == BUTTON)
2794         gdk_cairo_set_source_color (cr, &style->fg[state_type]);
2795       else
2796         gdk_cairo_set_source_color (cr, &style->text[state_type]);
2797         
2798       cairo_set_line_width (cr, 1.0);
2799       cairo_rectangle (cr, x + 0.5, y + 0.5, exterior_size - 1, exterior_size - 1);
2800       cairo_stroke (cr);
2801
2802       gdk_cairo_set_source_color (cr, &style->base[state_type]);
2803       cairo_rectangle (cr, x + 1, y + 1, exterior_size - 2, exterior_size - 2);
2804       cairo_fill (cr);
2805       break;
2806
2807     case MENU:
2808       break;
2809     }
2810       
2811   switch (type)
2812     {
2813     case BUTTON:
2814     case CELL:
2815       gdk_cairo_set_source_color (cr, &style->text[state_type]);
2816       break;
2817     case MENU:
2818       gdk_cairo_set_source_color (cr, &style->fg[state_type]);
2819       break;
2820     }
2821
2822   if (shadow_type == GTK_SHADOW_IN)
2823     {
2824       cairo_translate (cr,
2825                        x + pad, y + pad);
2826       
2827       cairo_scale (cr, interior_size / 7., interior_size / 7.);
2828       
2829       cairo_move_to  (cr, 7.0, 0.0);
2830       cairo_line_to  (cr, 7.5, 1.0);
2831       cairo_curve_to (cr, 5.3, 2.0,
2832                       4.3, 4.0,
2833                       3.5, 7.0);
2834       cairo_curve_to (cr, 3.0, 5.7,
2835                       1.3, 4.7,
2836                       0.0, 4.7);
2837       cairo_line_to  (cr, 0.2, 3.5);
2838       cairo_curve_to (cr, 1.1, 3.5,
2839                       2.3, 4.3,
2840                       3.0, 5.0);
2841       cairo_curve_to (cr, 1.0, 3.9,
2842                       2.4, 4.1,
2843                       3.2, 4.9);
2844       cairo_curve_to (cr, 3.5, 3.1,
2845                       5.2, 2.0,
2846                       7.0, 0.0);
2847       
2848       cairo_fill (cr);
2849     }
2850   else if (shadow_type == GTK_SHADOW_ETCHED_IN) /* inconsistent */
2851     {
2852       int line_thickness = MAX (1, (3 + interior_size * 2) / 7);
2853
2854       cairo_rectangle (cr,
2855                        x + pad,
2856                        y + pad + (1 + interior_size - line_thickness) / 2,
2857                        interior_size,
2858                        line_thickness);
2859       cairo_fill (cr);
2860     }
2861 }
2862
2863 static void 
2864 gtk_default_draw_option (GtkStyle      *style,
2865                          cairo_t       *cr,
2866                          GtkStateType   state_type,
2867                          GtkShadowType  shadow_type,
2868                          GtkWidget     *widget,
2869                          const gchar   *detail,
2870                          gint           x,
2871                          gint           y,
2872                          gint           width,
2873                          gint           height)
2874 {
2875   enum { BUTTON, MENU, CELL } type = BUTTON;
2876   int exterior_size;
2877   
2878   if (detail)
2879     {
2880       if (strcmp (detail, "radio") == 0)
2881         type = CELL;
2882       else if (strcmp (detail, "option") == 0)
2883         type = MENU;
2884     }
2885       
2886   exterior_size = MIN (width, height);
2887   if (exterior_size % 2 == 0) /* Ensure odd */
2888     exterior_size -= 1;
2889   
2890   x -= (1 + exterior_size - width) / 2;
2891   y -= (1 + exterior_size - height) / 2;
2892
2893   switch (type)
2894     {
2895     case BUTTON:
2896     case CELL:
2897       gdk_cairo_set_source_color (cr, &style->base[state_type]);
2898       
2899       cairo_arc (cr,
2900                  x + exterior_size / 2.,
2901                  y + exterior_size / 2.,
2902                  (exterior_size - 1) / 2.,
2903                  0, 2 * G_PI);
2904
2905       cairo_fill_preserve (cr);
2906
2907       if (type == BUTTON)
2908         gdk_cairo_set_source_color (cr, &style->fg[state_type]);
2909       else
2910         gdk_cairo_set_source_color (cr, &style->text[state_type]);
2911         
2912       cairo_set_line_width (cr, 1.);
2913       cairo_stroke (cr);
2914       break;
2915
2916     case MENU:
2917       break;
2918     }
2919       
2920   switch (type)
2921     {
2922     case BUTTON:
2923       gdk_cairo_set_source_color (cr, &style->text[state_type]);
2924       break;
2925     case CELL:
2926       break;
2927     case MENU:
2928       gdk_cairo_set_source_color (cr, &style->fg[state_type]);
2929       break;
2930     }
2931
2932   if (shadow_type == GTK_SHADOW_IN)
2933     {
2934       int pad = style->xthickness + MAX (1, 2 * (exterior_size - 2 * style->xthickness) / 9);
2935       int interior_size = MAX (1, exterior_size - 2 * pad);
2936
2937       if (interior_size < 5)
2938         {
2939           interior_size = 7;
2940           pad = MAX (0, (exterior_size - interior_size) / 2);
2941         }
2942
2943       cairo_arc (cr,
2944                  x + pad + interior_size / 2.,
2945                  y + pad + interior_size / 2.,
2946                  interior_size / 2.,
2947                  0, 2 * G_PI);
2948       cairo_fill (cr);
2949     }
2950   else if (shadow_type == GTK_SHADOW_ETCHED_IN) /* inconsistent */
2951     {
2952       int pad = style->xthickness + MAX (1, (exterior_size - 2 * style->xthickness) / 9);
2953       int interior_size = MAX (1, exterior_size - 2 * pad);
2954       int line_thickness;
2955
2956       if (interior_size < 7)
2957         {
2958           interior_size = 7;
2959           pad = MAX (0, (exterior_size - interior_size) / 2);
2960         }
2961
2962       line_thickness = MAX (1, (3 + interior_size * 2) / 7);
2963
2964       cairo_rectangle (cr,
2965                        x + pad,
2966                        y + pad + (interior_size - line_thickness) / 2.,
2967                        interior_size,
2968                        line_thickness);
2969       cairo_fill (cr);
2970     }
2971 }
2972
2973 static void
2974 gtk_default_draw_tab (GtkStyle      *style,
2975                       cairo_t       *cr,
2976                       GtkStateType   state_type,
2977                       GtkShadowType  shadow_type,
2978                       GtkWidget     *widget,
2979                       const gchar   *detail,
2980                       gint           x,
2981                       gint           y,
2982                       gint           width,
2983                       gint           height)
2984 {
2985 #define ARROW_SPACE 4
2986
2987   GtkRequisition indicator_size;
2988   GtkBorder indicator_spacing;
2989   gint arrow_height;
2990
2991   option_menu_get_props (widget, &indicator_size, &indicator_spacing);
2992
2993   indicator_size.width += (indicator_size.width % 2) - 1;
2994   arrow_height = indicator_size.width / 2 + 1;
2995
2996   x += (width - indicator_size.width) / 2;
2997   y += (height - (2 * arrow_height + ARROW_SPACE)) / 2;
2998
2999   if (state_type == GTK_STATE_INSENSITIVE)
3000     {
3001       draw_arrow (cr, &style->white,
3002                   GTK_ARROW_UP, x + 1, y + 1,
3003                   indicator_size.width, arrow_height);
3004       
3005       draw_arrow (cr, &style->white,
3006                   GTK_ARROW_DOWN, x + 1, y + arrow_height + ARROW_SPACE + 1,
3007                   indicator_size.width, arrow_height);
3008     }
3009   
3010   draw_arrow (cr, &style->fg[state_type],
3011               GTK_ARROW_UP, x, y,
3012               indicator_size.width, arrow_height);
3013   
3014   
3015   draw_arrow (cr, &style->fg[state_type],
3016               GTK_ARROW_DOWN, x, y + arrow_height + ARROW_SPACE,
3017               indicator_size.width, arrow_height);
3018 }
3019
3020 static void 
3021 gtk_default_draw_shadow_gap (GtkStyle       *style,
3022                              cairo_t        *cr,
3023                              GtkStateType    state_type,
3024                              GtkShadowType   shadow_type,
3025                              GtkWidget      *widget,
3026                              const gchar    *detail,
3027                              gint            x,
3028                              gint            y,
3029                              gint            width,
3030                              gint            height,
3031                              GtkPositionType gap_side,
3032                              gint            gap_x,
3033                              gint            gap_width)
3034 {
3035   GdkColor *color1 = NULL;
3036   GdkColor *color2 = NULL;
3037   GdkColor *color3 = NULL;
3038   GdkColor *color4 = NULL;
3039   
3040   switch (shadow_type)
3041     {
3042     case GTK_SHADOW_NONE:
3043     default:
3044       return;
3045     case GTK_SHADOW_IN:
3046       color1 = &style->dark[state_type];
3047       color2 = &style->black;
3048       color3 = &style->bg[state_type];
3049       color4 = &style->light[state_type];
3050       break;
3051     case GTK_SHADOW_ETCHED_IN:
3052       color1 = &style->dark[state_type];
3053       color2 = &style->light[state_type];
3054       color3 = &style->dark[state_type];
3055       color4 = &style->light[state_type];
3056       break;
3057     case GTK_SHADOW_OUT:
3058       color1 = &style->light[state_type];
3059       color2 = &style->bg[state_type];
3060       color3 = &style->dark[state_type];
3061       color4 = &style->black;
3062       break;
3063     case GTK_SHADOW_ETCHED_OUT:
3064       color1 = &style->light[state_type];
3065       color2 = &style->dark[state_type];
3066       color3 = &style->light[state_type];
3067       color4 = &style->dark[state_type];
3068       break;
3069     }
3070
3071   switch (shadow_type)
3072     {
3073     case GTK_SHADOW_NONE:
3074     case GTK_SHADOW_IN:
3075     case GTK_SHADOW_OUT:
3076     case GTK_SHADOW_ETCHED_IN:
3077     case GTK_SHADOW_ETCHED_OUT:
3078       switch (gap_side)
3079         {
3080         case GTK_POS_TOP:
3081           _cairo_draw_line (cr, color1,
3082                             x, y, x, y + height - 1);
3083           _cairo_draw_line (cr, color2,
3084                             x + 1, y, x + 1, y + height - 2);
3085           
3086           _cairo_draw_line (cr, color3,
3087                             x + 1, y + height - 2, x + width - 2, y + height - 2);
3088           _cairo_draw_line (cr, color3,
3089                             x + width - 2, y, x + width - 2, y + height - 2);
3090           _cairo_draw_line (cr, color4,
3091                             x, y + height - 1, x + width - 1, y + height - 1);
3092           _cairo_draw_line (cr, color4,
3093                             x + width - 1, y, x + width - 1, y + height - 1);
3094           if (gap_x > 0)
3095             {
3096               _cairo_draw_line (cr, color1,
3097                                 x, y, x + gap_x - 1, y);
3098               _cairo_draw_line (cr, color2,
3099                                 x + 1, y + 1, x + gap_x - 1, y + 1);
3100               _cairo_draw_line (cr, color2,
3101                                 x + gap_x, y, x + gap_x, y);
3102             }
3103           if ((width - (gap_x + gap_width)) > 0)
3104             {
3105               _cairo_draw_line (cr, color1,
3106                                 x + gap_x + gap_width, y, x + width - 2, y);
3107               _cairo_draw_line (cr, color2,
3108                                 x + gap_x + gap_width, y + 1, x + width - 3, y + 1);
3109               _cairo_draw_line (cr, color2,
3110                                 x + gap_x + gap_width - 1, y, x + gap_x + gap_width - 1, y);
3111             }
3112           break;
3113         case GTK_POS_BOTTOM:
3114           _cairo_draw_line (cr, color1,
3115                             x, y, x + width - 1, y);
3116           _cairo_draw_line (cr, color1,
3117                             x, y, x, y + height - 1);
3118           _cairo_draw_line (cr, color2,
3119                             x + 1, y + 1, x + width - 2, y + 1);
3120           _cairo_draw_line (cr, color2,
3121                             x + 1, y + 1, x + 1, y + height - 1);
3122           
3123           _cairo_draw_line (cr, color3,
3124                             x + width - 2, y + 1, x + width - 2, y + height - 1);
3125           _cairo_draw_line (cr, color4,
3126                             x + width - 1, y, x + width - 1, y + height - 1);
3127           if (gap_x > 0)
3128             {
3129               _cairo_draw_line (cr, color4,
3130                                 x, y + height - 1, x + gap_x - 1, y + height - 1);
3131               _cairo_draw_line (cr, color3,
3132                                 x + 1, y + height - 2, x + gap_x - 1, y + height - 2);
3133               _cairo_draw_line (cr, color3,
3134                                 x + gap_x, y + height - 1, x + gap_x, y + height - 1);
3135             }
3136           if ((width - (gap_x + gap_width)) > 0)
3137             {
3138               _cairo_draw_line (cr, color4,
3139                                 x + gap_x + gap_width, y + height - 1, x + width - 2, y + height - 1);
3140               _cairo_draw_line (cr, color3,
3141                                 x + gap_x + gap_width, y + height - 2, x + width - 2, y + height - 2);
3142               _cairo_draw_line (cr, color3,
3143                                 x + gap_x + gap_width - 1, y + height - 1, x + gap_x + gap_width - 1, y + height - 1);
3144             }
3145           break;
3146         case GTK_POS_LEFT:
3147           _cairo_draw_line (cr, color1,
3148                             x, y, x + width - 1, y);
3149           _cairo_draw_line (cr, color2,
3150                             x, y + 1, x + width - 2, y + 1);
3151           
3152           _cairo_draw_line (cr, color3,
3153                             x, y + height - 2, x + width - 2, y + height - 2);
3154           _cairo_draw_line (cr, color3,
3155                             x + width - 2, y + 1, x + width - 2, y + height - 2);
3156           _cairo_draw_line (cr, color4,
3157                             x, y + height - 1, x + width - 1, y + height - 1);
3158           _cairo_draw_line (cr, color4,
3159                             x + width - 1, y, x + width - 1, y + height - 1);
3160           if (gap_x > 0)
3161             {
3162               _cairo_draw_line (cr, color1,
3163                                 x, y, x, y + gap_x - 1);
3164               _cairo_draw_line (cr, color2,
3165                                 x + 1, y + 1, x + 1, y + gap_x - 1);
3166               _cairo_draw_line (cr, color2,
3167                                 x, y + gap_x, x, y + gap_x);
3168             }
3169           if ((width - (gap_x + gap_width)) > 0)
3170             {
3171               _cairo_draw_line (cr, color1,
3172                                 x, y + gap_x + gap_width, x, y + height - 2);
3173               _cairo_draw_line (cr, color2,
3174                                 x + 1, y + gap_x + gap_width, x + 1, y + height - 2);
3175               _cairo_draw_line (cr, color2,
3176                                 x, y + gap_x + gap_width - 1, x, y + gap_x + gap_width - 1);
3177             }
3178           break;
3179         case GTK_POS_RIGHT:
3180           _cairo_draw_line (cr, color1,
3181                             x, y, x + width - 1, y);
3182           _cairo_draw_line (cr, color1,
3183                             x, y, x, y + height - 1);
3184           _cairo_draw_line (cr, color2,
3185                             x + 1, y + 1, x + width - 1, y + 1);
3186           _cairo_draw_line (cr, color2,
3187                             x + 1, y + 1, x + 1, y + height - 2);
3188           
3189           _cairo_draw_line (cr, color3,
3190                             x + 1, y + height - 2, x + width - 1, y + height - 2);
3191           _cairo_draw_line (cr, color4,
3192                             x, y + height - 1, x + width - 1, y + height - 1);
3193           if (gap_x > 0)
3194             {
3195               _cairo_draw_line (cr, color4,
3196                                 x + width - 1, y, x + width - 1, y + gap_x - 1);
3197               _cairo_draw_line (cr, color3,
3198                                 x + width - 2, y + 1, x + width - 2, y + gap_x - 1);
3199               _cairo_draw_line (cr, color3,
3200                                 x + width - 1, y + gap_x, x + width - 1, y + gap_x);
3201             }
3202           if ((width - (gap_x + gap_width)) > 0)
3203             {
3204               _cairo_draw_line (cr, color4,
3205                                 x + width - 1, y + gap_x + gap_width, x + width - 1, y + height - 2);
3206               _cairo_draw_line (cr, color3,
3207                                 x + width - 2, y + gap_x + gap_width, x + width - 2, y + height - 2);
3208               _cairo_draw_line (cr, color3,
3209                                 x + width - 1, y + gap_x + gap_width - 1, x + width - 1, y + gap_x + gap_width - 1);
3210             }
3211           break;
3212         }
3213     }
3214 }
3215
3216 static void 
3217 gtk_default_draw_box_gap (GtkStyle       *style,
3218                           cairo_t        *cr,
3219                           GtkStateType    state_type,
3220                           GtkShadowType   shadow_type,
3221                           GtkWidget      *widget,
3222                           const gchar    *detail,
3223                           gint            x,
3224                           gint            y,
3225                           gint            width,
3226                           gint            height,
3227                           GtkPositionType gap_side,
3228                           gint            gap_x,
3229                           gint            gap_width)
3230 {
3231   GdkColor color1;
3232   GdkColor color2;
3233   GdkColor color3;
3234   GdkColor color4;
3235   
3236   gtk_style_apply_default_background (style, cr, gtk_widget_get_window (widget),
3237                                       state_type, x, y, width, height);
3238
3239   switch (shadow_type)
3240     {
3241     case GTK_SHADOW_NONE:
3242       return;
3243     case GTK_SHADOW_IN:
3244       color1 = style->dark[state_type];
3245       color2 = style->black;
3246       color3 = style->bg[state_type];
3247       color4 = style->light[state_type];
3248       break;
3249     case GTK_SHADOW_ETCHED_IN:
3250       color1 = style->dark[state_type];
3251       color2 = style->light[state_type];
3252       color3 = style->dark[state_type];
3253       color4 = style->light[state_type];
3254       break;
3255     case GTK_SHADOW_OUT:
3256       color1 = style->light[state_type];
3257       color2 = style->bg[state_type];
3258       color3 = style->dark[state_type];
3259       color4 = style->black;
3260       break;
3261     case GTK_SHADOW_ETCHED_OUT:
3262       color1 = style->light[state_type];
3263       color2 = style->dark[state_type];
3264       color3 = style->light[state_type];
3265       color4 = style->dark[state_type];
3266       break;
3267     }
3268   
3269   cairo_set_line_width (cr, 1.0);
3270
3271   switch (shadow_type)
3272     {
3273     case GTK_SHADOW_NONE:
3274     case GTK_SHADOW_IN:
3275     case GTK_SHADOW_OUT:
3276     case GTK_SHADOW_ETCHED_IN:
3277     case GTK_SHADOW_ETCHED_OUT:
3278       switch (gap_side)
3279         {
3280         case GTK_POS_TOP:
3281           _cairo_draw_line (cr, &color1,
3282                             x, y, x, y + height - 1);
3283           _cairo_draw_line (cr, &color2,
3284                             x + 1, y, x + 1, y + height - 2);
3285           
3286           _cairo_draw_line (cr, &color3,
3287                             x + 1, y + height - 2, x + width - 2, y + height - 2);
3288           _cairo_draw_line (cr, &color3,
3289                             x + width - 2, y, x + width - 2, y + height - 2);
3290           _cairo_draw_line (cr, &color4,
3291                             x, y + height - 1, x + width - 1, y + height - 1);
3292           _cairo_draw_line (cr, &color4,
3293                             x + width - 1, y, x + width - 1, y + height - 1);
3294           if (gap_x > 0)
3295             {
3296               _cairo_draw_line (cr, &color1,
3297                                 x, y, x + gap_x - 1, y);
3298               _cairo_draw_line (cr, &color2,
3299                                 x + 1, y + 1, x + gap_x - 1, y + 1);
3300               _cairo_draw_line (cr, &color2,
3301                                 x + gap_x, y, x + gap_x, y);
3302             }
3303           if ((width - (gap_x + gap_width)) > 0)
3304             {
3305               _cairo_draw_line (cr, &color1,
3306                                 x + gap_x + gap_width, y, x + width - 2, y);
3307               _cairo_draw_line (cr, &color2,
3308                                 x + gap_x + gap_width, y + 1, x + width - 2, y + 1);
3309               _cairo_draw_line (cr, &color2,
3310                                 x + gap_x + gap_width - 1, y, x + gap_x + gap_width - 1, y);
3311             }
3312           break;
3313         case  GTK_POS_BOTTOM:
3314           _cairo_draw_line (cr, &color1,
3315                             x, y, x + width - 1, y);
3316           _cairo_draw_line (cr, &color1,
3317                             x, y, x, y + height - 1);
3318           _cairo_draw_line (cr, &color2,
3319                             x + 1, y + 1, x + width - 2, y + 1);
3320           _cairo_draw_line (cr, &color2,
3321                             x + 1, y + 1, x + 1, y + height - 1);
3322           
3323           _cairo_draw_line (cr, &color3,
3324                             x + width - 2, y + 1, x + width - 2, y + height - 1);
3325           _cairo_draw_line (cr, &color4,
3326                             x + width - 1, y, x + width - 1, y + height - 1);
3327           if (gap_x > 0)
3328             {
3329               _cairo_draw_line (cr, &color4,
3330                                 x, y + height - 1, x + gap_x - 1, y + height - 1);
3331               _cairo_draw_line (cr, &color3,
3332                                 x + 1, y + height - 2, x + gap_x - 1, y + height - 2);
3333               _cairo_draw_line (cr, &color3,
3334                                 x + gap_x, y + height - 1, x + gap_x, y + height - 1);
3335             }
3336           if ((width - (gap_x + gap_width)) > 0)
3337             {
3338               _cairo_draw_line (cr, &color4,
3339                                 x + gap_x + gap_width, y + height - 1, x + width - 2, y + height - 1);
3340               _cairo_draw_line (cr, &color3,
3341                                 x + gap_x + gap_width, y + height - 2, x + width - 2, y + height - 2);
3342               _cairo_draw_line (cr, &color3,
3343                                 x + gap_x + gap_width - 1, y + height - 1, x + gap_x + gap_width - 1, y + height - 1);
3344             }
3345           break;
3346         case GTK_POS_LEFT:
3347           _cairo_draw_line (cr, &color1,
3348                             x, y, x + width - 1, y);
3349           _cairo_draw_line (cr, &color2,
3350                             x, y + 1, x + width - 2, y + 1);
3351           
3352           _cairo_draw_line (cr, &color3,
3353                             x, y + height - 2, x + width - 2, y + height - 2);
3354           _cairo_draw_line (cr, &color3,
3355                             x + width - 2, y + 1, x + width - 2, y + height - 2);
3356           _cairo_draw_line (cr, &color4,
3357                             x, y + height - 1, x + width - 1, y + height - 1);
3358           _cairo_draw_line (cr, &color4,
3359                             x + width - 1, y, x + width - 1, y + height - 1);
3360           if (gap_x > 0)
3361             {
3362               _cairo_draw_line (cr, &color1,
3363                                 x, y, x, y + gap_x - 1);
3364               _cairo_draw_line (cr, &color2,
3365                                 x + 1, y + 1, x + 1, y + gap_x - 1);
3366               _cairo_draw_line (cr, &color2,
3367                                 x, y + gap_x, x, y + gap_x);
3368             }
3369           if ((height - (gap_x + gap_width)) > 0)
3370             {
3371               _cairo_draw_line (cr, &color1,
3372                                 x, y + gap_x + gap_width, x, y + height - 2);
3373               _cairo_draw_line (cr, &color2,
3374                                 x + 1, y + gap_x + gap_width, x + 1, y + height - 2);
3375               _cairo_draw_line (cr, &color2,
3376                                 x, y + gap_x + gap_width - 1, x, y + gap_x + gap_width - 1);
3377             }
3378           break;
3379         case GTK_POS_RIGHT:
3380           _cairo_draw_line (cr, &color1,
3381                             x, y, x + width - 1, y);
3382           _cairo_draw_line (cr, &color1,
3383                             x, y, x, y + height - 1);
3384           _cairo_draw_line (cr, &color2,
3385                             x + 1, y + 1, x + width - 1, y + 1);
3386           _cairo_draw_line (cr, &color2,
3387                             x + 1, y + 1, x + 1, y + height - 2);
3388           
3389           _cairo_draw_line (cr, &color3,
3390                             x + 1, y + height - 2, x + width - 1, y + height - 2);
3391           _cairo_draw_line (cr, &color4,
3392                             x, y + height - 1, x + width - 1, y + height - 1);
3393           if (gap_x > 0)
3394             {
3395               _cairo_draw_line (cr, &color4,
3396                                 x + width - 1, y, x + width - 1, y + gap_x - 1);
3397               _cairo_draw_line (cr, &color3,
3398                                 x + width - 2, y + 1, x + width - 2, y + gap_x - 1);
3399               _cairo_draw_line (cr, &color3,
3400                                 x + width - 1, y + gap_x, x + width - 1, y + gap_x);
3401             }
3402           if ((height - (gap_x + gap_width)) > 0)
3403             {
3404               _cairo_draw_line (cr, &color4,
3405                                 x + width - 1, y + gap_x + gap_width, x + width - 1, y + height - 2);
3406               _cairo_draw_line (cr, &color3,
3407                                 x + width - 2, y + gap_x + gap_width, x + width - 2, y + height - 2);
3408               _cairo_draw_line (cr, &color3,
3409                                 x + width - 1, y + gap_x + gap_width - 1, x + width - 1, y + gap_x + gap_width - 1);
3410             }
3411           break;
3412         }
3413     }
3414 }
3415
3416 static void 
3417 gtk_default_draw_extension (GtkStyle       *style,
3418                             cairo_t        *cr,
3419                             GtkStateType    state_type,
3420                             GtkShadowType   shadow_type,
3421                             GtkWidget      *widget,
3422                             const gchar    *detail,
3423                             gint            x,
3424                             gint            y,
3425                             gint            width,
3426                             gint            height,
3427                             GtkPositionType gap_side)
3428 {
3429   GdkWindow *window = gtk_widget_get_window (widget);
3430   GdkColor color1;
3431   GdkColor color2;
3432   GdkColor color3;
3433   GdkColor color4;
3434   
3435   switch (gap_side)
3436     {
3437     case GTK_POS_TOP:
3438       gtk_style_apply_default_background (style, cr, window,
3439                                           state_type,
3440                                           x + 1,
3441                                           y,
3442                                           width - 2,
3443                                           height - 1);
3444       break;
3445     case GTK_POS_BOTTOM:
3446       gtk_style_apply_default_background (style, cr, window,
3447                                           state_type,
3448                                           x + 1,
3449                                           y + 1,
3450                                           width - 2,
3451                                           height - 1);
3452       break;
3453     case GTK_POS_LEFT:
3454       gtk_style_apply_default_background (style, cr, window,
3455                                           state_type,
3456                                           x,
3457                                           y + 1,
3458                                           width - 1,
3459                                           height - 2);
3460       break;
3461     case GTK_POS_RIGHT:
3462       gtk_style_apply_default_background (style, cr, window,
3463                                           state_type,
3464                                           x + 1,
3465                                           y + 1,
3466                                           width - 1,
3467                                           height - 2);
3468       break;
3469     }
3470
3471   switch (shadow_type)
3472     {
3473     case GTK_SHADOW_NONE:
3474       return;
3475     case GTK_SHADOW_IN:
3476       color1 = style->dark[state_type];
3477       color2 = style->black;
3478       color3 = style->bg[state_type];
3479       color4 = style->light[state_type];
3480       break;
3481     case GTK_SHADOW_ETCHED_IN:
3482       color1 = style->dark[state_type];
3483       color2 = style->light[state_type];
3484       color3 = style->dark[state_type];
3485       color4 = style->light[state_type];
3486       break;
3487     case GTK_SHADOW_OUT:
3488       color1 = style->light[state_type];
3489       color2 = style->bg[state_type];
3490       color3 = style->dark[state_type];
3491       color4 = style->black;
3492       break;
3493     case GTK_SHADOW_ETCHED_OUT:
3494       color1 = style->light[state_type];
3495       color2 = style->dark[state_type];
3496       color3 = style->light[state_type];
3497       color4 = style->dark[state_type];
3498       break;
3499     }
3500
3501   cairo_set_line_width (cr, 1.0);
3502
3503   switch (shadow_type)
3504     {
3505     case GTK_SHADOW_NONE:
3506     case GTK_SHADOW_IN:
3507     case GTK_SHADOW_OUT:
3508     case GTK_SHADOW_ETCHED_IN:
3509     case GTK_SHADOW_ETCHED_OUT:
3510       switch (gap_side)
3511         {
3512         case GTK_POS_TOP:
3513           _cairo_draw_line (cr, &color1,
3514                             x, y, x, y + height - 2);
3515           _cairo_draw_line (cr, &color2,
3516                             x + 1, y, x + 1, y + height - 2);
3517           
3518           _cairo_draw_line (cr, &color3,
3519                             x + 2, y + height - 2, x + width - 2, y + height - 2);
3520           _cairo_draw_line (cr, &color3,
3521                             x + width - 2, y, x + width - 2, y + height - 2);
3522           _cairo_draw_line (cr, &color4,
3523                             x + 1, y + height - 1, x + width - 2, y + height - 1);
3524           _cairo_draw_line (cr, &color4,
3525                             x + width - 1, y, x + width - 1, y + height - 2);
3526           break;
3527         case GTK_POS_BOTTOM:
3528           _cairo_draw_line (cr, &color1,
3529                             x + 1, y, x + width - 2, y);
3530           _cairo_draw_line (cr, &color1,
3531                             x, y + 1, x, y + height - 1);
3532           _cairo_draw_line (cr, &color2,
3533                             x + 1, y + 1, x + width - 2, y + 1);
3534           _cairo_draw_line (cr, &color2,
3535                             x + 1, y + 1, x + 1, y + height - 1);
3536           
3537           _cairo_draw_line (cr, &color3,
3538                             x + width - 2, y + 2, x + width - 2, y + height - 1);
3539           _cairo_draw_line (cr, &color4,
3540                             x + width - 1, y + 1, x + width - 1, y + height - 1);
3541           break;
3542         case GTK_POS_LEFT:
3543           _cairo_draw_line (cr, &color1,
3544                             x, y, x + width - 2, y);
3545           _cairo_draw_line (cr, &color2,
3546                             x + 1, y + 1, x + width - 2, y + 1);
3547           
3548           _cairo_draw_line (cr, &color3,
3549                             x, y + height - 2, x + width - 2, y + height - 2);
3550           _cairo_draw_line (cr, &color3,
3551                             x + width - 2, y + 2, x + width - 2, y + height - 2);
3552           _cairo_draw_line (cr, &color4,
3553                             x, y + height - 1, x + width - 2, y + height - 1);
3554           _cairo_draw_line (cr, &color4,
3555                             x + width - 1, y + 1, x + width - 1, y + height - 2);
3556           break;
3557         case GTK_POS_RIGHT:
3558           _cairo_draw_line (cr, &color1,
3559                             x + 1, y, x + width - 1, y);
3560           _cairo_draw_line (cr, &color1,
3561                             x, y + 1, x, y + height - 2);
3562           _cairo_draw_line (cr, &color2,
3563                             x + 1, y + 1, x + width - 1, y + 1);
3564           _cairo_draw_line (cr, &color2,
3565                             x + 1, y + 1, x + 1, y + height - 2);
3566           
3567           _cairo_draw_line (cr, &color3,
3568                             x + 2, y + height - 2, x + width - 1, y + height - 2);
3569           _cairo_draw_line (cr, &color4,
3570                             x + 1, y + height - 1, x + width - 1, y + height - 1);
3571           break;
3572         }
3573     }
3574 }
3575
3576 static void 
3577 gtk_default_draw_focus (GtkStyle      *style,
3578                         cairo_t       *cr,
3579                         GtkStateType   state_type,
3580                         GtkWidget     *widget,
3581                         const gchar   *detail,
3582                         gint           x,
3583                         gint           y,
3584                         gint           width,
3585                         gint           height)
3586 {
3587   gboolean free_dash_list = FALSE;
3588   gint line_width = 1;
3589   gint8 *dash_list = (gint8 *) "\1\1";
3590
3591   if (widget)
3592     {
3593       gtk_widget_style_get (widget,
3594                             "focus-line-width", &line_width,
3595                             "focus-line-pattern", (gchar *)&dash_list,
3596                             NULL);
3597
3598       free_dash_list = TRUE;
3599   }
3600
3601   if (detail && !strcmp (detail, "add-mode"))
3602     {
3603       if (free_dash_list)
3604         g_free (dash_list);
3605
3606       dash_list = (gint8 *) "\4\4";
3607       free_dash_list = FALSE;
3608     }
3609
3610   if (detail && !strcmp (detail, "colorwheel_light"))
3611     cairo_set_source_rgb (cr, 0., 0., 0.);
3612   else if (detail && !strcmp (detail, "colorwheel_dark"))
3613     cairo_set_source_rgb (cr, 1., 1., 1.);
3614   else
3615     gdk_cairo_set_source_color (cr, &style->fg[state_type]);
3616
3617   cairo_set_line_width (cr, line_width);
3618
3619   if (dash_list[0])
3620     {
3621       gint n_dashes = strlen ((const gchar *) dash_list);
3622       gdouble *dashes = g_new (gdouble, n_dashes);
3623       gdouble total_length = 0;
3624       gdouble dash_offset;
3625       gint i;
3626
3627       for (i = 0; i < n_dashes; i++)
3628         {
3629           dashes[i] = dash_list[i];
3630           total_length += dash_list[i];
3631         }
3632
3633       /* The dash offset here aligns the pattern to integer pixels
3634        * by starting the dash at the right side of the left border
3635        * Negative dash offsets in cairo don't work
3636        * (https://bugs.freedesktop.org/show_bug.cgi?id=2729)
3637        */
3638       dash_offset = - line_width / 2.;
3639       while (dash_offset < 0)
3640         dash_offset += total_length;
3641       
3642       cairo_set_dash (cr, dashes, n_dashes, dash_offset);
3643       g_free (dashes);
3644     }
3645
3646   cairo_rectangle (cr,
3647                    x + line_width / 2.,
3648                    y + line_width / 2.,
3649                    width - line_width,
3650                    height - line_width);
3651   cairo_stroke (cr);
3652
3653   if (free_dash_list)
3654     g_free (dash_list);
3655 }
3656
3657 static void 
3658 gtk_default_draw_slider (GtkStyle      *style,
3659                          cairo_t       *cr,
3660                          GtkStateType   state_type,
3661                          GtkShadowType  shadow_type,
3662                          GtkWidget     *widget,
3663                          const gchar   *detail,
3664                          gint           x,
3665                          gint           y,
3666                          gint           width,
3667                          gint           height,
3668                          GtkOrientation orientation)
3669 {
3670   gtk_paint_box (style, cr, state_type, shadow_type,
3671                        widget, detail, x, y, width, height);
3672
3673   if (detail &&
3674       (strcmp ("hscale", detail) == 0 ||
3675        strcmp ("vscale", detail) == 0))
3676     {
3677       if (orientation == GTK_ORIENTATION_HORIZONTAL)
3678         gtk_paint_vline (style, cr, state_type, widget, detail, 
3679                                y + style->ythickness, 
3680                                y + height - style->ythickness - 1, x + width / 2);
3681       else
3682         gtk_paint_hline (style, cr, state_type, widget, detail, 
3683                                x + style->xthickness, 
3684                                x + width - style->xthickness - 1, y + height / 2);
3685     }
3686 }
3687
3688 static void
3689 draw_dot (cairo_t    *cr,
3690           GdkColor   *light,
3691           GdkColor   *dark,
3692           gint        x,
3693           gint        y,
3694           gushort     size)
3695 {
3696   size = CLAMP (size, 2, 3);
3697
3698   if (size == 2)
3699     {
3700       _cairo_draw_point (cr, light, x, y);
3701       _cairo_draw_point (cr, light, x+1, y+1);
3702     }
3703   else if (size == 3)
3704     {
3705       _cairo_draw_point (cr, light, x, y);
3706       _cairo_draw_point (cr, light, x+1, y);
3707       _cairo_draw_point (cr, light, x, y+1);
3708       _cairo_draw_point (cr, dark, x+1, y+2);
3709       _cairo_draw_point (cr, dark, x+2, y+1);
3710       _cairo_draw_point (cr, dark, x+2, y+2);
3711     }
3712 }
3713
3714 static void 
3715 gtk_default_draw_handle (GtkStyle      *style,
3716                          cairo_t       *cr,
3717                          GtkStateType   state_type,
3718                          GtkShadowType  shadow_type,
3719                          GtkWidget     *widget,
3720                          const gchar   *detail,
3721                          gint           x,
3722                          gint           y,
3723                          gint           width,
3724                          gint           height,
3725                          GtkOrientation orientation)
3726 {
3727   gint xx, yy;
3728   gint xthick, ythick;
3729   GdkColor light, dark;
3730   
3731   gtk_paint_box (style, cr, state_type, shadow_type, widget, 
3732                        detail, x, y, width, height);
3733   
3734   if (detail && !strcmp (detail, "paned"))
3735     {
3736       /* we want to ignore the shadow border in paned widgets */
3737       xthick = 0;
3738       ythick = 0;
3739
3740       if (state_type == GTK_STATE_SELECTED && widget && !gtk_widget_has_focus (widget))
3741           _gtk_style_shade (&style->base[GTK_STATE_ACTIVE], &light,
3742                             LIGHTNESS_MULT);
3743       else
3744         light = style->light[state_type];
3745
3746       dark = style->black;
3747     }
3748   else
3749     {
3750       xthick = style->xthickness;
3751       ythick = style->ythickness;
3752
3753       light = style->light[state_type];
3754       dark = style->dark[state_type];
3755     }
3756   
3757   cairo_rectangle(cr, x + xthick, y + ythick,
3758                   width - (xthick * 2), height - (ythick * 2));
3759   cairo_clip (cr);
3760
3761   if (detail && !strcmp (detail, "paned"))
3762     {
3763       if (orientation == GTK_ORIENTATION_HORIZONTAL)
3764         for (xx = x + width/2 - 15; xx <= x + width/2 + 15; xx += 5)
3765           draw_dot (cr, &light, &dark, xx, y + height/2 - 1, 3);
3766       else
3767         for (yy = y + height/2 - 15; yy <= y + height/2 + 15; yy += 5)
3768           draw_dot (cr, &light, &dark, x + width/2 - 1, yy, 3);
3769     }
3770   else
3771     {
3772       for (yy = y + ythick; yy < (y + height - ythick); yy += 3)
3773         for (xx = x + xthick; xx < (x + width - xthick); xx += 6)
3774           {
3775             draw_dot (cr, &light, &dark, xx, yy, 2);
3776             draw_dot (cr, &light, &dark, xx + 3, yy + 1, 2);
3777           }
3778     }
3779 }
3780
3781 static void
3782 gtk_default_draw_expander (GtkStyle        *style,
3783                            cairo_t         *cr,
3784                            GtkStateType     state_type,
3785                            GtkWidget       *widget,
3786                            const gchar     *detail,
3787                            gint             x,
3788                            gint             y,
3789                            GtkExpanderStyle expander_style)
3790 {
3791 #define DEFAULT_EXPANDER_SIZE 12
3792
3793   gint expander_size;
3794   gint line_width;
3795   double vertical_overshoot;
3796   int diameter;
3797   double radius;
3798   double interp;                /* interpolation factor for center position */
3799   double x_double_horz, y_double_horz;
3800   double x_double_vert, y_double_vert;
3801   double x_double, y_double;
3802   gint degrees = 0;
3803
3804   if (widget &&
3805       gtk_widget_class_find_style_property (GTK_WIDGET_GET_CLASS (widget),
3806                                             "expander-size"))
3807     {
3808       gtk_widget_style_get (widget,
3809                             "expander-size", &expander_size,
3810                             NULL);
3811     }
3812   else
3813     expander_size = DEFAULT_EXPANDER_SIZE;
3814     
3815   line_width = MAX (1, expander_size/9);
3816
3817   switch (expander_style)
3818     {
3819     case GTK_EXPANDER_COLLAPSED:
3820       degrees = (get_direction (widget) == GTK_TEXT_DIR_RTL) ? 180 : 0;
3821       interp = 0.0;
3822       break;
3823     case GTK_EXPANDER_SEMI_COLLAPSED:
3824       degrees = (get_direction (widget) == GTK_TEXT_DIR_RTL) ? 150 : 30;
3825       interp = 0.25;
3826       break;
3827     case GTK_EXPANDER_SEMI_EXPANDED:
3828       degrees = (get_direction (widget) == GTK_TEXT_DIR_RTL) ? 120 : 60;
3829       interp = 0.75;
3830       break;
3831     case GTK_EXPANDER_EXPANDED:
3832       degrees = 90;
3833       interp = 1.0;
3834       break;
3835     default:
3836       g_assert_not_reached ();
3837     }
3838
3839   /* Compute distance that the stroke extends beyonds the end
3840    * of the triangle we draw.
3841    */
3842   vertical_overshoot = line_width / 2.0 * (1. / tan (G_PI / 8));
3843
3844   /* For odd line widths, we end the vertical line of the triangle
3845    * at a half pixel, so we round differently.
3846    */
3847   if (line_width % 2 == 1)
3848     vertical_overshoot = ceil (0.5 + vertical_overshoot) - 0.5;
3849   else
3850     vertical_overshoot = ceil (vertical_overshoot);
3851
3852   /* Adjust the size of the triangle we draw so that the entire stroke fits
3853    */
3854   diameter = MAX (3, expander_size - 2 * vertical_overshoot);
3855
3856   /* If the line width is odd, we want the diameter to be even,
3857    * and vice versa, so force the sum to be odd. This relationship
3858    * makes the point of the triangle look right.
3859    */
3860   diameter -= (1 - (diameter + line_width) % 2);
3861   
3862   radius = diameter / 2.;
3863
3864   /* Adjust the center so that the stroke is properly aligned with
3865    * the pixel grid. The center adjustment is different for the
3866    * horizontal and vertical orientations. For intermediate positions
3867    * we interpolate between the two.
3868    */
3869   x_double_vert = floor (x - (radius + line_width) / 2.) + (radius + line_width) / 2.;
3870   y_double_vert = y - 0.5;
3871
3872   x_double_horz = x - 0.5;
3873   y_double_horz = floor (y - (radius + line_width) / 2.) + (radius + line_width) / 2.;
3874
3875   x_double = x_double_vert * (1 - interp) + x_double_horz * interp;
3876   y_double = y_double_vert * (1 - interp) + y_double_horz * interp;
3877   
3878   cairo_translate (cr, x_double, y_double);
3879   cairo_rotate (cr, degrees * G_PI / 180);
3880
3881   cairo_move_to (cr, - radius / 2., - radius);
3882   cairo_line_to (cr,   radius / 2.,   0);
3883   cairo_line_to (cr, - radius / 2.,   radius);
3884   cairo_close_path (cr);
3885   
3886   cairo_set_line_width (cr, line_width);
3887
3888   if (state_type == GTK_STATE_PRELIGHT)
3889     gdk_cairo_set_source_color (cr,
3890                                 &style->fg[GTK_STATE_PRELIGHT]);
3891   else if (state_type == GTK_STATE_ACTIVE)
3892     gdk_cairo_set_source_color (cr,
3893                                 &style->light[GTK_STATE_ACTIVE]);
3894   else
3895     gdk_cairo_set_source_color (cr,
3896                                 &style->base[GTK_STATE_NORMAL]);
3897   
3898   cairo_fill_preserve (cr);
3899   
3900   gdk_cairo_set_source_color (cr, &style->fg[state_type]);
3901   cairo_stroke (cr);
3902 }
3903
3904 static void
3905 gtk_default_draw_layout (GtkStyle        *style,
3906                          cairo_t         *cr,
3907                          GtkStateType     state_type,
3908                          gboolean         use_text,
3909                          GtkWidget       *widget,
3910                          const gchar     *detail,
3911                          gint             x,
3912                          gint             y,
3913                          PangoLayout     *layout)
3914 {
3915   GdkColor *gc;
3916   const PangoMatrix *matrix;
3917
3918   matrix = pango_context_get_matrix (pango_layout_get_context (layout));
3919   if (matrix)
3920     {
3921       cairo_matrix_t cairo_matrix;
3922       PangoMatrix tmp_matrix;
3923       PangoRectangle rect;
3924       
3925       cairo_matrix_init (&cairo_matrix,
3926                          matrix->xx, matrix->yx,
3927                          matrix->xy, matrix->yy,
3928                          matrix->x0, matrix->y0);
3929
3930       pango_layout_get_extents (layout, NULL, &rect);
3931       pango_matrix_transform_rectangle (matrix, &rect);
3932       pango_extents_to_pixels (&rect, NULL);
3933                                           
3934       tmp_matrix = *matrix;
3935       cairo_matrix.x0 += x - rect.x;
3936       cairo_matrix.y0 += y - rect.y;
3937
3938       cairo_set_matrix (cr, &cairo_matrix);
3939     }
3940   else
3941     cairo_translate (cr, x, y);
3942
3943   cairo_new_path (cr);
3944
3945   if (state_type == GTK_STATE_INSENSITIVE)
3946     {
3947       gdk_cairo_set_source_color (cr, &style->white);
3948       cairo_move_to (cr, 1, 1);
3949       _gtk_pango_fill_layout (cr, layout);
3950       cairo_new_path (cr);
3951     }
3952
3953   gc = use_text ? &style->text[state_type] : &style->fg[state_type];
3954
3955   gdk_cairo_set_source_color (cr, gc);
3956
3957   pango_cairo_show_layout (cr, layout);
3958 }
3959
3960 static void
3961 gtk_default_draw_resize_grip (GtkStyle       *style,
3962                               cairo_t        *cr,
3963                               GtkStateType    state_type,
3964                               GtkWidget      *widget,
3965                               const gchar    *detail,
3966                               GdkWindowEdge   edge,
3967                               gint            x,
3968                               gint            y,
3969                               gint            width,
3970                               gint            height)
3971 {
3972   gint skip;
3973
3974   cairo_rectangle (cr, x, y, width, height);
3975   cairo_clip (cr);
3976
3977   cairo_set_line_width (cr, 1.0);
3978
3979   skip = -1;
3980   switch (edge)
3981     {
3982     case GDK_WINDOW_EDGE_NORTH_WEST:
3983       /* make it square */
3984       if (width < height)
3985         height = width;
3986       else if (height < width)
3987         width = height;
3988       skip = 2;
3989       break;
3990     case GDK_WINDOW_EDGE_NORTH:
3991       if (width < height)
3992         height = width;
3993       break;
3994     case GDK_WINDOW_EDGE_NORTH_EAST:
3995       /* make it square, aligning to top right */
3996       if (width < height)
3997         height = width;
3998       else if (height < width)
3999         {
4000           x += (width - height);
4001           width = height;
4002         }
4003       skip = 3;
4004       break;
4005     case GDK_WINDOW_EDGE_WEST:
4006       if (height < width)
4007         width = height;
4008       break;
4009     case GDK_WINDOW_EDGE_EAST:
4010       /* aligning to right */
4011       if (height < width)
4012         {
4013           x += (width - height);
4014           width = height;
4015         }
4016       break;
4017     case GDK_WINDOW_EDGE_SOUTH_WEST:
4018       /* make it square, aligning to bottom left */
4019       if (width < height)
4020         {
4021           y += (height - width);
4022           height = width;
4023         }
4024       else if (height < width)
4025         width = height;
4026       skip = 1;
4027       break;
4028     case GDK_WINDOW_EDGE_SOUTH:
4029       /* align to bottom */
4030       if (width < height)
4031         {
4032           y += (height - width);
4033           height = width;
4034         }
4035       break;
4036     case GDK_WINDOW_EDGE_SOUTH_EAST:
4037       /* make it square, aligning to bottom right */
4038       if (width < height)
4039         {
4040           y += (height - width);
4041           height = width;
4042         }
4043       else if (height < width)
4044         {
4045           x += (width - height);
4046           width = height;
4047         }
4048       skip = 0;
4049       break;
4050     default:
4051       g_assert_not_reached ();
4052     }
4053   
4054   switch (edge)
4055     {
4056     case GDK_WINDOW_EDGE_WEST:
4057     case GDK_WINDOW_EDGE_EAST:
4058       {
4059         gint xi;
4060
4061         xi = x;
4062
4063         while (xi < x + width)
4064           {
4065             _cairo_draw_line (cr,
4066                               &style->light[state_type],
4067                               xi, y,
4068                               xi, y + height);
4069
4070             xi++;
4071             _cairo_draw_line (cr,
4072                               &style->dark[state_type],
4073                               xi, y,
4074                               xi, y + height);
4075
4076             xi += 2;
4077           }
4078       }
4079       break;
4080     case GDK_WINDOW_EDGE_NORTH:
4081     case GDK_WINDOW_EDGE_SOUTH:
4082       {
4083         gint yi;
4084
4085         yi = y;
4086
4087         while (yi < y + height)
4088           {
4089             _cairo_draw_line (cr,
4090                               &style->light[state_type],
4091                               x, yi,
4092                               x + width, yi);
4093
4094             yi++;
4095             _cairo_draw_line (cr,
4096                               &style->dark[state_type],
4097                               x, yi,
4098                               x + width, yi);
4099
4100             yi+= 2;
4101           }
4102       }
4103       break;
4104     case GDK_WINDOW_EDGE_NORTH_WEST:
4105       {
4106         gint xi, yi;
4107
4108         xi = x + width;
4109         yi = y + height;
4110
4111         while (xi > x + 3)
4112           {
4113             _cairo_draw_line (cr,
4114                               &style->dark[state_type],
4115                               xi, y,
4116                               x, yi);
4117
4118             --xi;
4119             --yi;
4120
4121             _cairo_draw_line (cr,
4122                               &style->dark[state_type],
4123                               xi, y,
4124                               x, yi);
4125
4126             --xi;
4127             --yi;
4128
4129             _cairo_draw_line (cr,
4130                               &style->light[state_type],
4131                               xi, y,
4132                               x, yi);
4133
4134             xi -= 3;
4135             yi -= 3;
4136             
4137           }
4138       }
4139       break;
4140     case GDK_WINDOW_EDGE_NORTH_EAST:
4141       {
4142         gint xi, yi;
4143
4144         xi = x;
4145         yi = y + height;
4146
4147         while (xi < (x + width - 3))
4148           {
4149             _cairo_draw_line (cr,
4150                               &style->light[state_type],
4151                               xi, y,
4152                               x + width, yi);                           
4153
4154             ++xi;
4155             --yi;
4156             
4157             _cairo_draw_line (cr,
4158                               &style->dark[state_type],
4159                               xi, y,
4160                               x + width, yi);                           
4161
4162             ++xi;
4163             --yi;
4164             
4165             _cairo_draw_line (cr,
4166                               &style->dark[state_type],
4167                               xi, y,
4168                               x + width, yi);
4169
4170             xi += 3;
4171             yi -= 3;
4172           }
4173       }
4174       break;
4175     case GDK_WINDOW_EDGE_SOUTH_WEST:
4176       {
4177         gint xi, yi;
4178
4179         xi = x + width;
4180         yi = y;
4181
4182         while (xi > x + 3)
4183           {
4184             _cairo_draw_line (cr,
4185                               &style->dark[state_type],
4186                               x, yi,
4187                               xi, y + height);
4188
4189             --xi;
4190             ++yi;
4191
4192             _cairo_draw_line (cr,
4193                               &style->dark[state_type],
4194                               x, yi,
4195                               xi, y + height);
4196
4197             --xi;
4198             ++yi;
4199
4200             _cairo_draw_line (cr,
4201                               &style->light[state_type],
4202                               x, yi,
4203                               xi, y + height);
4204
4205             xi -= 3;
4206             yi += 3;
4207             
4208           }
4209       }
4210       break;
4211     case GDK_WINDOW_EDGE_SOUTH_EAST:
4212       {
4213         gint xi, yi;
4214
4215         xi = x;
4216         yi = y;
4217
4218         while (xi < (x + width - 3))
4219           {
4220             _cairo_draw_line (cr,
4221                               &style->light[state_type],
4222                               xi, y + height,
4223                               x + width, yi);                           
4224
4225             ++xi;
4226             ++yi;
4227             
4228             _cairo_draw_line (cr,
4229                               &style->dark[state_type],
4230                               xi, y + height,
4231                               x + width, yi);                           
4232
4233             ++xi;
4234             ++yi;
4235             
4236             _cairo_draw_line (cr,
4237                               &style->dark[state_type],
4238                               xi, y + height,
4239                               x + width, yi);
4240
4241             xi += 3;
4242             yi += 3;
4243           }
4244       }
4245       break;
4246     default:
4247       g_assert_not_reached ();
4248       break;
4249     }
4250 }
4251
4252 static void
4253 gtk_default_draw_spinner (GtkStyle     *style,
4254                           cairo_t      *cr,
4255                           GtkStateType  state_type,
4256                           GtkWidget    *widget,
4257                           const gchar  *detail,
4258                           guint         step,
4259                           gint          x,
4260                           gint          y,
4261                           gint          width,
4262                           gint          height)
4263 {
4264   GdkColor *color;
4265   guint num_steps;
4266   gdouble dx, dy;
4267   gdouble radius;
4268   gdouble half;
4269   gint i;
4270   guint real_step;
4271
4272   gtk_style_get (style, GTK_TYPE_SPINNER,
4273                  "num-steps", &num_steps,
4274                  NULL);
4275   real_step = step % num_steps;
4276
4277   /* set a clip region for the expose event */
4278   cairo_rectangle (cr, x, y, width, height);
4279   cairo_clip (cr);
4280
4281   cairo_translate (cr, x, y);
4282
4283   /* draw clip region */
4284   cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
4285
4286   color = &style->fg[state_type];
4287   dx = width / 2;
4288   dy = height / 2;
4289   radius = MIN (width / 2, height / 2);
4290   half = num_steps / 2;
4291
4292   for (i = 0; i < num_steps; i++)
4293     {
4294       gint inset = 0.7 * radius;
4295
4296       /* transparency is a function of time and intial value */
4297       gdouble t = (gdouble) ((i + num_steps - real_step)
4298                              % num_steps) / num_steps;
4299
4300       cairo_save (cr);
4301
4302       cairo_set_source_rgba (cr,
4303                              color->red / 65535.,
4304                              color->green / 65535.,
4305                              color->blue / 65535.,
4306                              t);
4307
4308       cairo_set_line_width (cr, 2.0);
4309       cairo_move_to (cr,
4310                      dx + (radius - inset) * cos (i * G_PI / half),
4311                      dy + (radius - inset) * sin (i * G_PI / half));
4312       cairo_line_to (cr,
4313                      dx + radius * cos (i * G_PI / half),
4314                      dy + radius * sin (i * G_PI / half));
4315       cairo_stroke (cr);
4316
4317       cairo_restore (cr);
4318     }
4319 }
4320
4321 void
4322 _gtk_style_shade (const GdkColor *a,
4323                   GdkColor       *b,
4324                   gdouble         k)
4325 {
4326   gdouble red;
4327   gdouble green;
4328   gdouble blue;
4329   
4330   red = (gdouble) a->red / 65535.0;
4331   green = (gdouble) a->green / 65535.0;
4332   blue = (gdouble) a->blue / 65535.0;
4333   
4334   rgb_to_hls (&red, &green, &blue);
4335   
4336   green *= k;
4337   if (green > 1.0)
4338     green = 1.0;
4339   else if (green < 0.0)
4340     green = 0.0;
4341   
4342   blue *= k;
4343   if (blue > 1.0)
4344     blue = 1.0;
4345   else if (blue < 0.0)
4346     blue = 0.0;
4347   
4348   hls_to_rgb (&red, &green, &blue);
4349   
4350   b->red = red * 65535.0;
4351   b->green = green * 65535.0;
4352   b->blue = blue * 65535.0;
4353 }
4354
4355 static void
4356 rgb_to_hls (gdouble *r,
4357             gdouble *g,
4358             gdouble *b)
4359 {
4360   gdouble min;
4361   gdouble max;
4362   gdouble red;
4363   gdouble green;
4364   gdouble blue;
4365   gdouble h, l, s;
4366   gdouble delta;
4367   
4368   red = *r;
4369   green = *g;
4370   blue = *b;
4371   
4372   if (red > green)
4373     {
4374       if (red > blue)
4375         max = red;
4376       else
4377         max = blue;
4378       
4379       if (green < blue)
4380         min = green;
4381       else
4382         min = blue;
4383     }
4384   else
4385     {
4386       if (green > blue)
4387         max = green;
4388       else
4389         max = blue;
4390       
4391       if (red < blue)
4392         min = red;
4393       else
4394         min = blue;
4395     }
4396   
4397   l = (max + min) / 2;
4398   s = 0;
4399   h = 0;
4400   
4401   if (max != min)
4402     {
4403       if (l <= 0.5)
4404         s = (max - min) / (max + min);
4405       else
4406         s = (max - min) / (2 - max - min);
4407       
4408       delta = max -min;
4409       if (red == max)
4410         h = (green - blue) / delta;
4411       else if (green == max)
4412         h = 2 + (blue - red) / delta;
4413       else if (blue == max)
4414         h = 4 + (red - green) / delta;
4415       
4416       h *= 60;
4417       if (h < 0.0)
4418         h += 360;
4419     }
4420   
4421   *r = h;
4422   *g = l;
4423   *b = s;
4424 }
4425
4426 static void
4427 hls_to_rgb (gdouble *h,
4428             gdouble *l,
4429             gdouble *s)
4430 {
4431   gdouble hue;
4432   gdouble lightness;
4433   gdouble saturation;
4434   gdouble m1, m2;
4435   gdouble r, g, b;
4436   
4437   lightness = *l;
4438   saturation = *s;
4439   
4440   if (lightness <= 0.5)
4441     m2 = lightness * (1 + saturation);
4442   else
4443     m2 = lightness + saturation - lightness * saturation;
4444   m1 = 2 * lightness - m2;
4445   
4446   if (saturation == 0)
4447     {
4448       *h = lightness;
4449       *l = lightness;
4450       *s = lightness;
4451     }
4452   else
4453     {
4454       hue = *h + 120;
4455       while (hue > 360)
4456         hue -= 360;
4457       while (hue < 0)
4458         hue += 360;
4459       
4460       if (hue < 60)
4461         r = m1 + (m2 - m1) * hue / 60;
4462       else if (hue < 180)
4463         r = m2;
4464       else if (hue < 240)
4465         r = m1 + (m2 - m1) * (240 - hue) / 60;
4466       else
4467         r = m1;
4468       
4469       hue = *h;
4470       while (hue > 360)
4471         hue -= 360;
4472       while (hue < 0)
4473         hue += 360;
4474       
4475       if (hue < 60)
4476         g = m1 + (m2 - m1) * hue / 60;
4477       else if (hue < 180)
4478         g = m2;
4479       else if (hue < 240)
4480         g = m1 + (m2 - m1) * (240 - hue) / 60;
4481       else
4482         g = m1;
4483       
4484       hue = *h - 120;
4485       while (hue > 360)
4486         hue -= 360;
4487       while (hue < 0)
4488         hue += 360;
4489       
4490       if (hue < 60)
4491         b = m1 + (m2 - m1) * hue / 60;
4492       else if (hue < 180)
4493         b = m2;
4494       else if (hue < 240)
4495         b = m1 + (m2 - m1) * (240 - hue) / 60;
4496       else
4497         b = m1;
4498       
4499       *h = r;
4500       *l = g;
4501       *s = b;
4502     }
4503 }
4504
4505
4506 /**
4507  * gtk_paint_hline:
4508  * @style: a #GtkStyle
4509  * @cr: a #caio_t
4510  * @state_type: a state
4511  * @widget: (allow-none): the widget
4512  * @detail: (allow-none): a style detail
4513  * @x1: the starting x coordinate
4514  * @x2: the ending x coordinate
4515  * @y: the y coordinate
4516  *
4517  * Draws a horizontal line from (@x1, @y) to (@x2, @y) in @cr
4518  * using the given style and state.
4519  **/ 
4520 void 
4521 gtk_paint_hline (GtkStyle           *style,
4522                  cairo_t            *cr,
4523                  GtkStateType        state_type,
4524                  GtkWidget          *widget,
4525                  const gchar        *detail,
4526                  gint                x1,
4527                  gint                x2,
4528                  gint                y)
4529 {
4530   g_return_if_fail (GTK_IS_STYLE (style));
4531   g_return_if_fail (cr != NULL);
4532   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_hline != NULL);
4533
4534   cairo_save (cr);
4535
4536   GTK_STYLE_GET_CLASS (style)->draw_hline (style, cr, state_type,
4537                                            widget, detail,
4538                                            x1, x2, y);
4539
4540   cairo_restore (cr);
4541 }
4542
4543 /**
4544  * gtk_paint_vline:
4545  * @style: a #GtkStyle
4546  * @cr: a #cairo_t
4547  * @state_type: a state
4548  * @widget: (allow-none): the widget
4549  * @detail: (allow-none): a style detail
4550  * @y1_: the starting y coordinate
4551  * @y2_: the ending y coordinate
4552  * @x: the x coordinate
4553  *
4554  * Draws a vertical line from (@x, @y1_) to (@x, @y2_) in @cr
4555  * using the given style and state.
4556  */
4557 void
4558 gtk_paint_vline (GtkStyle           *style,
4559                  cairo_t            *cr,
4560                  GtkStateType        state_type,
4561                  GtkWidget          *widget,
4562                  const gchar        *detail,
4563                  gint                y1_,
4564                  gint                y2_,
4565                  gint                x)
4566 {
4567   g_return_if_fail (GTK_IS_STYLE (style));
4568   g_return_if_fail (cr != NULL);
4569   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_vline != NULL);
4570
4571   cairo_save (cr);
4572
4573   GTK_STYLE_GET_CLASS (style)->draw_vline (style, cr, state_type,
4574                                            widget, detail,
4575                                            y1_, y2_, x);
4576
4577   cairo_restore (cr);
4578 }
4579
4580 /**
4581  * gtk_paint_shadow:
4582  * @style: a #GtkStyle
4583  * @cr: a #cairo_t
4584  * @state_type: a state
4585  * @shadow_type: type of shadow to draw
4586  * @widget: (allow-none): the widget
4587  * @detail: (allow-none): a style detail
4588  * @x: x origin of the rectangle
4589  * @y: y origin of the rectangle
4590  * @width: width of the rectangle
4591  * @height: width of the rectangle
4592  *
4593  * Draws a shadow around the given rectangle in @cr 
4594  * using the given style and state and shadow type.
4595  */
4596 void
4597 gtk_paint_shadow (GtkStyle           *style,
4598                   cairo_t            *cr,
4599                   GtkStateType        state_type,
4600                   GtkShadowType       shadow_type,
4601                   GtkWidget          *widget,
4602                   const gchar        *detail,
4603                   gint                x,
4604                   gint                y,
4605                   gint                width,
4606                   gint                height)
4607 {
4608   g_return_if_fail (GTK_IS_STYLE (style));
4609   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_shadow != NULL);
4610   g_return_if_fail (cr != NULL);
4611   g_return_if_fail (width >= 0);
4612   g_return_if_fail (height >= 0);
4613
4614   cairo_save (cr);
4615
4616   GTK_STYLE_GET_CLASS (style)->draw_shadow (style, cr, state_type, shadow_type,
4617                                             widget, detail,
4618                                             x, y, width, height);
4619
4620   cairo_restore (cr);
4621 }
4622
4623 /**
4624  * gtk_paint_arrow:
4625  * @style: a #GtkStyle
4626  * @cr: a #cairo_t
4627  * @state_type: a state
4628  * @shadow_type: the type of shadow to draw
4629  * @widget: (allow-none): the widget
4630  * @detail: (allow-none): a style detail
4631  * @arrow_type: the type of arrow to draw
4632  * @fill: %TRUE if the arrow tip should be filled
4633  * @x: x origin of the rectangle to draw the arrow in
4634  * @y: y origin of the rectangle to draw the arrow in
4635  * @width: width of the rectangle to draw the arrow in
4636  * @height: height of the rectangle to draw the arrow in
4637  * 
4638  * Draws an arrow in the given rectangle on @cr using the given 
4639  * parameters. @arrow_type determines the direction of the arrow.
4640  */
4641 void
4642 gtk_paint_arrow (GtkStyle           *style,
4643                  cairo_t            *cr,
4644                  GtkStateType        state_type,
4645                  GtkShadowType       shadow_type,
4646                  GtkWidget          *widget,
4647                  const gchar        *detail,
4648                  GtkArrowType        arrow_type,
4649                  gboolean            fill,
4650                  gint                x,
4651                  gint                y,
4652                  gint                width,
4653                  gint                height)
4654 {
4655   g_return_if_fail (GTK_IS_STYLE (style));
4656   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_arrow != NULL);
4657   g_return_if_fail (cr != NULL);
4658   g_return_if_fail (width >= 0);
4659   g_return_if_fail (height >= 0);
4660
4661   cairo_save (cr);
4662
4663   GTK_STYLE_GET_CLASS (style)->draw_arrow (style, cr, state_type, shadow_type,
4664                                            widget, detail,
4665                                            arrow_type, fill, x, y, width, height);
4666
4667   cairo_restore (cr);
4668 }
4669
4670 /**
4671  * gtk_paint_diamond:
4672  * @style: a #GtkStyle
4673  * @cr: a #cairo_t
4674  * @state_type: a state
4675  * @shadow_type: the type of shadow to draw
4676  * @widget: (allow-none): the widget
4677  * @detail: (allow-none): a style detail
4678  * @x: x origin of the rectangle to draw the diamond in
4679  * @y: y origin of the rectangle to draw the diamond in
4680  * @width: width of the rectangle to draw the diamond in
4681  * @height: height of the rectangle to draw the diamond in
4682  *
4683  * Draws a diamond in the given rectangle on @window using the given
4684  * parameters.
4685  */
4686 void
4687 gtk_paint_diamond (GtkStyle           *style,
4688                    cairo_t            *cr,
4689                    GtkStateType        state_type,
4690                    GtkShadowType       shadow_type,
4691                    GtkWidget          *widget,
4692                    const gchar        *detail,
4693                    gint                x,
4694                    gint                y,
4695                    gint                width,
4696                    gint                height)
4697 {
4698   g_return_if_fail (GTK_IS_STYLE (style));
4699   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_diamond != NULL);
4700   g_return_if_fail (cr != NULL);
4701   g_return_if_fail (width >= 0);
4702   g_return_if_fail (height >= 0);
4703
4704   cairo_save (cr);
4705
4706   GTK_STYLE_GET_CLASS (style)->draw_diamond (style, cr, state_type, shadow_type,
4707                                              widget, detail,
4708                                              x, y, width, height);
4709
4710   cairo_restore (cr);
4711 }
4712
4713 /**
4714  * gtk_paint_box:
4715  * @style: a #GtkStyle
4716  * @cr: a #cairo_t
4717  * @state_type: a state
4718  * @shadow_type: the type of shadow to draw
4719  * @widget: (allow-none): the widget
4720  * @detail: (allow-none): a style detail
4721  * @x: x origin of the box
4722  * @y: y origin of the box
4723  * @width: the width of the box
4724  * @height: the height of the box
4725  * 
4726  * Draws a box on @cr with the given parameters.
4727  */
4728 void
4729 gtk_paint_box (GtkStyle           *style,
4730                cairo_t            *cr,
4731                GtkStateType        state_type,
4732                GtkShadowType       shadow_type,
4733                GtkWidget          *widget,
4734                const gchar        *detail,
4735                gint                x,
4736                gint                y,
4737                gint                width,
4738                gint                height)
4739 {
4740   g_return_if_fail (GTK_IS_STYLE (style));
4741   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_box != NULL);
4742   g_return_if_fail (cr != NULL);
4743
4744   cairo_save (cr);
4745
4746   GTK_STYLE_GET_CLASS (style)->draw_box (style, cr, state_type, shadow_type,
4747                                          widget, detail,
4748                                          x, y, width, height);
4749
4750   cairo_restore (cr);
4751 }
4752
4753 /**
4754  * gtk_paint_flat_box:
4755  * @style: a #GtkStyle
4756  * @cr: a #cairo_t
4757  * @state_type: a state
4758  * @shadow_type: the type of shadow to draw
4759  * @area: (allow-none): clip rectangle, or %NULL if the
4760  *        output should not be clipped
4761  * @widget: (allow-none): the widget
4762  * @detail: (allow-none): a style detail
4763  * @x: x origin of the box
4764  * @y: y origin of the box
4765  * @width: the width of the box
4766  * @height: the height of the box
4767  * 
4768  * Draws a flat box on @cr with the given parameters.
4769  */
4770 void
4771 gtk_paint_flat_box (GtkStyle           *style,
4772                     cairo_t            *cr,
4773                     GtkStateType        state_type,
4774                     GtkShadowType       shadow_type,
4775                     GtkWidget          *widget,
4776                     const gchar        *detail,
4777                     gint                x,
4778                     gint                y,
4779                     gint                width,
4780                     gint                height)
4781 {
4782   g_return_if_fail (GTK_IS_STYLE (style));
4783   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_flat_box != NULL);
4784   g_return_if_fail (cr != NULL);
4785   g_return_if_fail (width >= 0);
4786   g_return_if_fail (height >= 0);
4787
4788   cairo_save (cr);
4789
4790   GTK_STYLE_GET_CLASS (style)->draw_flat_box (style, cr, state_type, shadow_type,
4791                                               widget, detail,
4792                                               x, y, width, height);
4793
4794   cairo_restore (cr);
4795 }
4796
4797 /**
4798  * gtk_paint_check:
4799  * @style: a #GtkStyle
4800  * @cr: a #cairo_t
4801  * @state_type: a state
4802  * @shadow_type: the type of shadow to draw
4803  * @widget: (allow-none): the widget
4804  * @detail: (allow-none): a style detail
4805  * @x: x origin of the rectangle to draw the check in
4806  * @y: y origin of the rectangle to draw the check in
4807  * @width: the width of the rectangle to draw the check in
4808  * @height: the height of the rectangle to draw the check in
4809  * 
4810  * Draws a check button indicator in the given rectangle on @cr with 
4811  * the given parameters.
4812  */
4813 void
4814 gtk_paint_check (GtkStyle           *style,
4815                  cairo_t            *cr,
4816                  GtkStateType        state_type,
4817                  GtkShadowType       shadow_type,
4818                  GtkWidget          *widget,
4819                  const gchar        *detail,
4820                  gint                x,
4821                  gint                y,
4822                  gint                width,
4823                  gint                height)
4824 {
4825   g_return_if_fail (GTK_IS_STYLE (style));
4826   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_check != NULL);
4827   g_return_if_fail (cr != NULL);
4828
4829   cairo_save (cr);
4830
4831   GTK_STYLE_GET_CLASS (style)->draw_check (style, cr, state_type, shadow_type,
4832                                            widget, detail,
4833                                            x, y, width, height);
4834
4835   cairo_restore (cr);
4836 }
4837
4838 /**
4839  * gtk_paint_option:
4840  * @style: a #GtkStyle
4841  * @cr: a #cairo_t
4842  * @state_type: a state
4843  * @shadow_type: the type of shadow to draw
4844  * @widget: (allow-none): the widget
4845  * @detail: (allow-none): a style detail
4846  * @x: x origin of the rectangle to draw the option in
4847  * @y: y origin of the rectangle to draw the option in
4848  * @width: the width of the rectangle to draw the option in
4849  * @height: the height of the rectangle to draw the option in
4850  *
4851  * Draws a radio button indicator in the given rectangle on @cr with 
4852  * the given parameters.
4853  */
4854 void
4855 gtk_paint_option (GtkStyle           *style,
4856                   cairo_t            *cr,
4857                   GtkStateType        state_type,
4858                   GtkShadowType       shadow_type,
4859                   GtkWidget          *widget,
4860                   const gchar        *detail,
4861                   gint                x,
4862                   gint                y,
4863                   gint                width,
4864                   gint                height)
4865 {
4866   g_return_if_fail (GTK_IS_STYLE (style));
4867   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_option != NULL);
4868   g_return_if_fail (cr != NULL);
4869
4870   cairo_save (cr);
4871
4872   GTK_STYLE_GET_CLASS (style)->draw_option (style, cr, state_type, shadow_type,
4873                                             widget, detail,
4874                                             x, y, width, height);
4875
4876   cairo_restore (cr);
4877 }
4878
4879 /**
4880  * gtk_paint_tab:
4881  * @style: a #GtkStyle
4882  * @cr: a #cairo_t
4883  * @state_type: a state
4884  * @shadow_type: the type of shadow to draw
4885  * @widget: (allow-none): the widget
4886  * @detail: (allow-none): a style detail
4887  * @x: x origin of the rectangle to draw the tab in
4888  * @y: y origin of the rectangle to draw the tab in
4889  * @width: the width of the rectangle to draw the tab in
4890  * @height: the height of the rectangle to draw the tab in
4891  *
4892  * Draws an option menu tab (i.e. the up and down pointing arrows)
4893  * in the given rectangle on @cr using the given parameters.
4894  */ 
4895 void
4896 gtk_paint_tab (GtkStyle           *style,
4897                cairo_t            *cr,
4898                GtkStateType        state_type,
4899                GtkShadowType       shadow_type,
4900                GtkWidget          *widget,
4901                const gchar        *detail,
4902                gint                x,
4903                gint                y,
4904                gint                width,
4905                gint                height)
4906 {
4907   g_return_if_fail (GTK_IS_STYLE (style));
4908   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_tab != NULL);
4909   g_return_if_fail (cr != NULL);
4910
4911   cairo_save (cr);
4912
4913   GTK_STYLE_GET_CLASS (style)->draw_tab (style, cr, state_type, shadow_type,
4914                                          widget, detail,
4915                                          x, y, width, height);
4916
4917   cairo_restore (cr);
4918 }
4919
4920 /**
4921  * gtk_paint_shadow_gap:
4922  * @style: a #GtkStyle
4923  * @cr: a #cairo_t
4924  * @state_type: a state
4925  * @shadow_type: type of shadow to draw
4926  * @widget: (allow-none): the widget
4927  * @detail: (allow-none): a style detail
4928  * @x: x origin of the rectangle
4929  * @y: y origin of the rectangle
4930  * @width: width of the rectangle
4931  * @height: width of the rectangle
4932  * @gap_side: side in which to leave the gap
4933  * @gap_x: starting position of the gap
4934  * @gap_width: width of the gap
4935  *
4936  * Draws a shadow around the given rectangle in @cr
4937  * using the given style and state and shadow type, leaving a 
4938  * gap in one side.
4939 */
4940 void
4941 gtk_paint_shadow_gap (GtkStyle           *style,
4942                       cairo_t            *cr,
4943                       GtkStateType        state_type,
4944                       GtkShadowType       shadow_type,
4945                       GtkWidget          *widget,
4946                       const gchar        *detail,
4947                       gint                x,
4948                       gint                y,
4949                       gint                width,
4950                       gint                height,
4951                       GtkPositionType     gap_side,
4952                       gint                gap_x,
4953                       gint                gap_width)
4954 {
4955   g_return_if_fail (GTK_IS_STYLE (style));
4956   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_shadow_gap != NULL);
4957   g_return_if_fail (cr != NULL);
4958   g_return_if_fail (width >= 0);
4959   g_return_if_fail (height >= 0);
4960
4961   cairo_save (cr);
4962
4963   GTK_STYLE_GET_CLASS (style)->draw_shadow_gap (style, cr, state_type, shadow_type,
4964                                                 widget, detail,
4965                                                 x, y, width, height, gap_side, gap_x, gap_width);
4966
4967   cairo_restore (cr);
4968 }
4969
4970 /**
4971  * gtk_paint_box_gap:
4972  * @style: a #GtkStyle
4973  * @cr: a #cairo_t
4974  * @state_type: a state
4975  * @shadow_type: type of shadow to draw
4976  * @widget: (allow-none): the widget
4977  * @detail: (allow-none): a style detail
4978  * @x: x origin of the rectangle
4979  * @y: y origin of the rectangle
4980  * @width: width of the rectangle
4981  * @height: width of the rectangle
4982  * @gap_side: side in which to leave the gap
4983  * @gap_x: starting position of the gap
4984  * @gap_width: width of the gap
4985  *
4986  * Draws a box in @cr using the given style and state and shadow type, 
4987  * leaving a gap in one side.
4988  */
4989 void
4990 gtk_paint_box_gap (GtkStyle           *style,
4991                    cairo_t            *cr,
4992                    GtkStateType        state_type,
4993                    GtkShadowType       shadow_type,
4994                    GtkWidget          *widget,
4995                    const gchar        *detail,
4996                    gint                x,
4997                    gint                y,
4998                    gint                width,
4999                    gint                height,
5000                    GtkPositionType     gap_side,
5001                    gint                gap_x,
5002                    gint                gap_width)
5003 {
5004   g_return_if_fail (GTK_IS_STYLE (style));
5005   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_box_gap != NULL);
5006   g_return_if_fail (cr != NULL);
5007   g_return_if_fail (width >= 0);
5008   g_return_if_fail (height >= 0);
5009
5010   cairo_save (cr);
5011
5012   GTK_STYLE_GET_CLASS (style)->draw_box_gap (style, cr, state_type, shadow_type,
5013                                              widget, detail,
5014                                              x, y, width, height, gap_side, gap_x, gap_width);
5015
5016   cairo_restore (cr);
5017 }
5018
5019 /**
5020  * gtk_paint_extension: 
5021  * @style: a #GtkStyle
5022  * @cr: a #cairo_t
5023  * @state_type: a state
5024  * @shadow_type: type of shadow to draw
5025  * @widget: (allow-none): the widget
5026  * @detail: (allow-none): a style detail
5027  * @x: x origin of the extension
5028  * @y: y origin of the extension
5029  * @width: width of the extension
5030  * @height: width of the extension
5031  * @gap_side: the side on to which the extension is attached
5032  * 
5033  * Draws an extension, i.e. a notebook tab.
5034  **/
5035 void
5036 gtk_paint_extension (GtkStyle           *style,
5037                      cairo_t            *cr,
5038                      GtkStateType        state_type,
5039                      GtkShadowType       shadow_type,
5040                      GtkWidget          *widget,
5041                      const gchar        *detail,
5042                      gint                x,
5043                      gint                y,
5044                      gint                width,
5045                      gint                height,
5046                      GtkPositionType     gap_side)
5047 {
5048   g_return_if_fail (GTK_IS_STYLE (style));
5049   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_extension != NULL);
5050   g_return_if_fail (cr != NULL);
5051   g_return_if_fail (width >= 0);
5052   g_return_if_fail (height >= 0);
5053
5054   cairo_save (cr);
5055
5056   GTK_STYLE_GET_CLASS (style)->draw_extension (style, cr, state_type, shadow_type,
5057                                                widget, detail,
5058                                                x, y, width, height, gap_side);
5059
5060   cairo_restore (cr);
5061 }
5062
5063 /**
5064  * gtk_paint_focus:
5065  * @style: a #GtkStyle
5066  * @cr: a #cairo_t
5067  * @state_type: a state
5068  * @widget: (allow-none): the widget
5069  * @detail: (allow-none): a style detail
5070  * @x: the x origin of the rectangle around which to draw a focus indicator
5071  * @y: the y origin of the rectangle around which to draw a focus indicator
5072  * @width: the width of the rectangle around which to draw a focus indicator
5073  * @height: the height of the rectangle around which to draw a focus indicator
5074  *
5075  * Draws a focus indicator around the given rectangle on @cr using the
5076  * given style.
5077  */
5078 void
5079 gtk_paint_focus (GtkStyle           *style,
5080                  cairo_t            *cr,
5081                  GtkStateType        state_type,
5082                  GtkWidget          *widget,
5083                  const gchar        *detail,
5084                  gint                x,
5085                  gint                y,
5086                  gint                width,
5087                  gint                height)
5088 {
5089   g_return_if_fail (GTK_IS_STYLE (style));
5090   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_focus != NULL);
5091   g_return_if_fail (cr != NULL);
5092   g_return_if_fail (width >= 0);
5093   g_return_if_fail (height >= 0);
5094
5095   cairo_save (cr);
5096
5097   GTK_STYLE_GET_CLASS (style)->draw_focus (style, cr, state_type,
5098                                            widget, detail,
5099                                            x, y, width, height);
5100
5101   cairo_restore (cr);
5102 }
5103
5104 /**
5105  * gtk_paint_slider:
5106  * @style: a #GtkStyle
5107  * @cr: a #cairo_t
5108  * @state_type: a state
5109  * @shadow_type: a shadow
5110  * @widget: (allow-none): the widget
5111  * @detail: (allow-none): a style detail
5112  * @x: the x origin of the rectangle in which to draw a slider
5113  * @y: the y origin of the rectangle in which to draw a slider
5114  * @width: the width of the rectangle in which to draw a slider
5115  * @height: the height of the rectangle in which to draw a slider
5116  * @orientation: the orientation to be used
5117  *
5118  * Draws a slider in the given rectangle on @cr using the
5119  * given style and orientation.
5120  **/
5121 void
5122 gtk_paint_slider (GtkStyle           *style,
5123                   cairo_t            *cr,
5124                   GtkStateType        state_type,
5125                   GtkShadowType       shadow_type,
5126                   GtkWidget          *widget,
5127                   const gchar        *detail,
5128                   gint                x,
5129                   gint                y,
5130                   gint                width,
5131                   gint                height,
5132                   GtkOrientation      orientation)
5133 {
5134   g_return_if_fail (GTK_IS_STYLE (style));
5135   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_slider != NULL);
5136   g_return_if_fail (cr != NULL);
5137   g_return_if_fail (width >= 0);
5138   g_return_if_fail (height >= 0);
5139
5140   cairo_save (cr);
5141
5142   GTK_STYLE_GET_CLASS (style)->draw_slider (style, cr, state_type, shadow_type,
5143                                             widget, detail,
5144                                             x, y, width, height, orientation);
5145
5146   cairo_restore (cr);
5147 }
5148
5149 /**
5150  * gtk_paint_handle:
5151  * @style: a #GtkStyle
5152  * @cr: a #cairo_t
5153  * @state_type: a state
5154  * @shadow_type: type of shadow to draw
5155  * @widget: (allow-none): the widget
5156  * @detail: (allow-none): a style detail
5157  * @x: x origin of the handle
5158  * @y: y origin of the handle
5159  * @width: with of the handle
5160  * @height: height of the handle
5161  * @orientation: the orientation of the handle
5162  * 
5163  * Draws a handle as used in #GtkHandleBox and #GtkPaned.
5164  **/
5165 void
5166 gtk_paint_handle (GtkStyle           *style,
5167                   cairo_t            *cr,
5168                   GtkStateType        state_type,
5169                   GtkShadowType       shadow_type,
5170                   GtkWidget          *widget,
5171                   const gchar        *detail,
5172                   gint                x,
5173                   gint                y,
5174                   gint                width,
5175                   gint                height,
5176                   GtkOrientation      orientation)
5177 {
5178   g_return_if_fail (GTK_IS_STYLE (style));
5179   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_handle != NULL);
5180   g_return_if_fail (cr != NULL);
5181   g_return_if_fail (width >= 0);
5182   g_return_if_fail (height >= 0);
5183
5184   cairo_save (cr);
5185
5186   GTK_STYLE_GET_CLASS (style)->draw_handle (style, cr, state_type, shadow_type,
5187                                             widget, detail,
5188                                             x, y, width, height, orientation);
5189
5190   cairo_restore (cr);
5191 }
5192
5193 /**
5194  * gtk_paint_expander:
5195  * @style: a #GtkStyle
5196  * @cr: a #cairo_t
5197  * @state_type: a state
5198  * @widget: (allow-none): the widget
5199  * @detail: (allow-none): a style detail
5200  * @x: the x position to draw the expander at
5201  * @y: the y position to draw the expander at
5202  * @expander_style: the style to draw the expander in; determines
5203  *   whether the expander is collapsed, expanded, or in an
5204  *   intermediate state.
5205  * 
5206  * Draws an expander as used in #GtkTreeView. @x and @y specify the
5207  * center the expander. The size of the expander is determined by the
5208  * "expander-size" style property of @widget.  (If widget is not
5209  * specified or doesn't have an "expander-size" property, an
5210  * unspecified default size will be used, since the caller doesn't
5211  * have sufficient information to position the expander, this is
5212  * likely not useful.) The expander is expander_size pixels tall
5213  * in the collapsed position and expander_size pixels wide in the
5214  * expanded position.
5215  **/
5216 void
5217 gtk_paint_expander (GtkStyle           *style,
5218                     cairo_t            *cr,
5219                     GtkStateType        state_type,
5220                     GtkWidget          *widget,
5221                     const gchar        *detail,
5222                     gint                x,
5223                     gint                y,
5224                     GtkExpanderStyle    expander_style)
5225 {
5226   g_return_if_fail (GTK_IS_STYLE (style));
5227   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_expander != NULL);
5228   g_return_if_fail (cr != NULL);
5229
5230   cairo_save (cr);
5231
5232   GTK_STYLE_GET_CLASS (style)->draw_expander (style, cr, state_type,
5233                                               widget, detail,
5234                                               x, y, expander_style);
5235
5236   cairo_restore (cr);
5237 }
5238
5239 /**
5240  * gtk_paint_layout:
5241  * @style: a #GtkStyle
5242  * @cr: a #cairo_t
5243  * @state_type: a state
5244  * @use_text: whether to use the text or foreground
5245  *            graphics context of @style
5246  * @widget: (allow-none): the widget
5247  * @detail: (allow-none): a style detail
5248  * @x: x origin
5249  * @y: y origin
5250  * @layout: the layout to draw
5251  *
5252  * Draws a layout on @cr using the given parameters.
5253  **/
5254 void
5255 gtk_paint_layout (GtkStyle           *style,
5256                   cairo_t            *cr,
5257                   GtkStateType        state_type,
5258                   gboolean            use_text,
5259                   GtkWidget          *widget,
5260                   const gchar        *detail,
5261                   gint                x,
5262                   gint                y,
5263                   PangoLayout        *layout)
5264 {
5265   g_return_if_fail (GTK_IS_STYLE (style));
5266   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_layout != NULL);
5267   g_return_if_fail (cr != NULL);
5268
5269   cairo_save (cr);
5270
5271   GTK_STYLE_GET_CLASS (style)->draw_layout (style, cr, state_type, use_text,
5272                                             widget, detail,
5273                                             x, y, layout);
5274
5275   cairo_restore (cr);
5276 }
5277
5278 /**
5279  * gtk_paint_resize_grip:
5280  * @style: a #GtkStyle
5281  * @cr: a #cairo_t
5282  * @state_type: a state
5283  * @widget: (allow-none): the widget
5284  * @detail: (allow-none): a style detail
5285  * @edge: the edge in which to draw the resize grip
5286  * @x: the x origin of the rectangle in which to draw the resize grip
5287  * @y: the y origin of the rectangle in which to draw the resize grip
5288  * @width: the width of the rectangle in which to draw the resize grip
5289  * @height: the height of the rectangle in which to draw the resize grip
5290  *
5291  * Draws a resize grip in the given rectangle on @cr using the given
5292  * parameters. 
5293  */
5294 void
5295 gtk_paint_resize_grip (GtkStyle           *style,
5296                        cairo_t            *cr,
5297                        GtkStateType        state_type,
5298                        GtkWidget          *widget,
5299                        const gchar        *detail,
5300                        GdkWindowEdge       edge,
5301                        gint                x,
5302                        gint                y,
5303                        gint                width,
5304                        gint                height)
5305 {
5306   g_return_if_fail (GTK_IS_STYLE (style));
5307   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_resize_grip != NULL);
5308   g_return_if_fail (cr != NULL);
5309
5310   cairo_save (cr);
5311
5312   GTK_STYLE_GET_CLASS (style)->draw_resize_grip (style, cr, state_type,
5313                                                  widget, detail,
5314                                                  edge, x, y, width, height);
5315   cairo_restore (cr);
5316 }
5317
5318 /**
5319  * gtk_paint_spinner:
5320  * @style: a #GtkStyle
5321  * @cr: a #cairo_t
5322  * @state_type: a state
5323  * @widget: (allow-none): the widget (may be %NULL)
5324  * @detail: (allow-none): a style detail (may be %NULL)
5325  * @step: the nth step, a value between 0 and #GtkSpinner:num-steps
5326  * @x: the x origin of the rectangle in which to draw the spinner
5327  * @y: the y origin of the rectangle in which to draw the spinner
5328  * @width: the width of the rectangle in which to draw the spinner
5329  * @height: the height of the rectangle in which to draw the spinner
5330  *
5331  * Draws a spinner on @window using the given parameters.
5332  */
5333 void
5334 gtk_paint_spinner (GtkStyle           *style,
5335                    cairo_t            *cr,
5336                    GtkStateType        state_type,
5337                    GtkWidget          *widget,
5338                    const gchar        *detail,
5339                    guint               step,
5340                    gint                x,
5341                    gint                y,
5342                    gint                width,
5343                    gint                height)
5344 {
5345   g_return_if_fail (GTK_IS_STYLE (style));
5346   g_return_if_fail (cr != NULL);
5347   g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_spinner != NULL);
5348
5349   cairo_save (cr);
5350
5351   GTK_STYLE_GET_CLASS (style)->draw_spinner (style, cr, state_type,
5352                                              widget, detail,
5353                                              step, x, y, width, height);
5354
5355   cairo_restore (cr);
5356 }
5357
5358 /**
5359  * gtk_border_new:
5360  *
5361  * Allocates a new #GtkBorder structure and initializes its elements to zero.
5362  * 
5363  * Returns: a new empty #GtkBorder. The newly allocated #GtkBorder should be 
5364  *     freed with gtk_border_free()
5365  *
5366  * Since: 2.14
5367  **/
5368 GtkBorder *
5369 gtk_border_new (void)
5370 {
5371   return g_slice_new0 (GtkBorder);
5372 }
5373
5374 /**
5375  * gtk_border_copy:
5376  * @border_: a #GtkBorder.
5377  * @returns: a copy of @border_.
5378  *
5379  * Copies a #GtkBorder structure.
5380  **/
5381 GtkBorder *
5382 gtk_border_copy (const GtkBorder *border)
5383 {
5384   g_return_val_if_fail (border != NULL, NULL);
5385
5386   return g_slice_dup (GtkBorder, border);
5387 }
5388
5389 /**
5390  * gtk_border_free:
5391  * @border_: a #GtkBorder.
5392  * 
5393  * Frees a #GtkBorder structure.
5394  **/
5395 void
5396 gtk_border_free (GtkBorder *border)
5397 {
5398   g_slice_free (GtkBorder, border);
5399 }
5400
5401 G_DEFINE_BOXED_TYPE (GtkBorder, gtk_border,
5402                      gtk_border_copy,
5403                      gtk_border_free)
5404
5405 typedef struct _CursorInfo CursorInfo;
5406
5407 struct _CursorInfo
5408 {
5409   GType for_type;
5410   GdkColor primary;
5411   GdkColor secondary;
5412 };
5413
5414 static void
5415 style_unrealize_cursors (GtkStyle *style)
5416 {
5417   CursorInfo *
5418   
5419   cursor_info = g_object_get_data (G_OBJECT (style), "gtk-style-cursor-info");
5420   if (cursor_info)
5421     {
5422       g_free (cursor_info);
5423       g_object_set_data (G_OBJECT (style), I_("gtk-style-cursor-info"), NULL);
5424     }
5425 }
5426
5427 static const GdkColor *
5428 get_insertion_cursor_color (GtkWidget *widget,
5429                             gboolean   is_primary)
5430 {
5431   CursorInfo *cursor_info;
5432   GtkStyle *style;
5433   GdkColor *cursor_color;
5434
5435   style = gtk_widget_get_style (widget);
5436
5437   cursor_info = g_object_get_data (G_OBJECT (style), "gtk-style-cursor-info");
5438   if (!cursor_info)
5439     {
5440       cursor_info = g_new0 (CursorInfo, 1);
5441       g_object_set_data (G_OBJECT (style), I_("gtk-style-cursor-info"), cursor_info);
5442       cursor_info->for_type = G_TYPE_INVALID;
5443     }
5444
5445   /* We have to keep track of the type because gtk_widget_style_get()
5446    * can return different results when called on the same property and
5447    * same style but for different widgets. :-(. That is,
5448    * GtkEntry::cursor-color = "red" in a style will modify the cursor
5449    * color for entries but not for text view.
5450    */
5451   if (cursor_info->for_type != G_OBJECT_TYPE (widget))
5452     {
5453       cursor_info->for_type = G_OBJECT_TYPE (widget);
5454
5455       /* Cursors in text widgets are drawn only in NORMAL state,
5456        * so we can use text[GTK_STATE_NORMAL] as text color here */
5457       gtk_widget_style_get (widget, "cursor-color", &cursor_color, NULL);
5458       if (cursor_color)
5459         {
5460           cursor_info->primary = *cursor_color;
5461           gdk_color_free (cursor_color);
5462         }
5463       else
5464         {
5465           cursor_info->primary = style->text[GTK_STATE_NORMAL];
5466         }
5467
5468       gtk_widget_style_get (widget, "secondary-cursor-color", &cursor_color, NULL);
5469       if (cursor_color)
5470         {
5471           cursor_info->secondary = *cursor_color;
5472           gdk_color_free (cursor_color);
5473         }
5474       else
5475         {
5476           /* text_aa is the average of text and base colors,
5477            * in usual black-on-white case it's grey. */
5478           cursor_info->secondary = style->text_aa[GTK_STATE_NORMAL];
5479         }
5480     }
5481
5482   if (is_primary)
5483     return &cursor_info->primary;
5484   else
5485     return &cursor_info->secondary;
5486 }
5487
5488 void
5489 _gtk_widget_get_cursor_color (GtkWidget *widget,
5490                               GdkColor  *color)
5491 {
5492   GdkColor *style_color;
5493
5494   g_return_if_fail (GTK_IS_WIDGET (widget));
5495   g_return_if_fail (color != NULL);
5496
5497   gtk_widget_style_get (widget, "cursor-color", &style_color, NULL);
5498
5499   if (style_color)
5500     {
5501       *color = *style_color;
5502       gdk_color_free (style_color);
5503     }
5504   else
5505     *color = gtk_widget_get_style (widget)->text[GTK_STATE_NORMAL];
5506 }
5507
5508 /**
5509  * gtk_draw_insertion_cursor:
5510  * @widget:  a #GtkWidget
5511  * @cr: cairo context to draw to
5512  * @location: location where to draw the cursor (@location->width is ignored)
5513  * @is_primary: if the cursor should be the primary cursor color.
5514  * @direction: whether the cursor is left-to-right or
5515  *             right-to-left. Should never be #GTK_TEXT_DIR_NONE
5516  * @draw_arrow: %TRUE to draw a directional arrow on the
5517  *        cursor. Should be %FALSE unless the cursor is split.
5518  * 
5519  * Draws a text caret on @cr at @location. This is not a style function
5520  * but merely a convenience function for drawing the standard cursor shape.
5521  *
5522  * Since: 3.0
5523  **/
5524 void
5525 gtk_draw_insertion_cursor (GtkWidget          *widget,
5526                            cairo_t            *cr,
5527                            const GdkRectangle *location,
5528                            gboolean            is_primary,
5529                            GtkTextDirection    direction,
5530                            gboolean            draw_arrow)
5531 {
5532   gint stem_width;
5533   gint arrow_width;
5534   gint x, y;
5535   gfloat cursor_aspect_ratio;
5536   gint offset;
5537   
5538   g_return_if_fail (GTK_IS_WIDGET (widget));
5539   g_return_if_fail (cr != NULL);
5540   g_return_if_fail (location != NULL);
5541   g_return_if_fail (direction != GTK_TEXT_DIR_NONE);
5542
5543   gdk_cairo_set_source_color (cr, get_insertion_cursor_color (widget, is_primary));
5544
5545   /* When changing the shape or size of the cursor here,
5546    * propagate the changes to gtktextview.c:text_window_invalidate_cursors().
5547    */
5548
5549   gtk_widget_style_get (widget, "cursor-aspect-ratio", &cursor_aspect_ratio, NULL);
5550   
5551   stem_width = location->height * cursor_aspect_ratio + 1;
5552   arrow_width = stem_width + 1;
5553
5554   /* put (stem_width % 2) on the proper side of the cursor */
5555   if (direction == GTK_TEXT_DIR_LTR)
5556     offset = stem_width / 2;
5557   else
5558     offset = stem_width - stem_width / 2;
5559   
5560   cairo_rectangle (cr, 
5561                    location->x - offset, location->y,
5562                    stem_width, location->height);
5563   cairo_fill (cr);
5564
5565   if (draw_arrow)
5566     {
5567       if (direction == GTK_TEXT_DIR_RTL)
5568         {
5569           x = location->x - offset - 1;
5570           y = location->y + location->height - arrow_width * 2 - arrow_width + 1;
5571   
5572           cairo_move_to (cr, x, y + 1);
5573           cairo_line_to (cr, x - arrow_width, y + arrow_width);
5574           cairo_line_to (cr, x, y + 2 * arrow_width);
5575           cairo_fill (cr);
5576         }
5577       else if (direction == GTK_TEXT_DIR_LTR)
5578         {
5579           x = location->x + stem_width - offset;
5580           y = location->y + location->height - arrow_width * 2 - arrow_width + 1;
5581   
5582           cairo_move_to (cr, x, y + 1);
5583           cairo_line_to (cr, x + arrow_width, y + arrow_width);
5584           cairo_line_to (cr, x, y + 2 * arrow_width);
5585           cairo_fill (cr);
5586         }
5587     }
5588 }