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