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