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