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