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