]> Pileus Git - ~andy/gtk/blob - gtk/gtkthemingengine.c
stylecontext: Deprecate gtk_style_context_get_font()
[~andy/gtk] / gtk / gtkthemingengine.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 2010 Carlos Garnacho <carlosg@gnome.org>
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, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include "config.h"
19
20 #include <math.h>
21 #include <gtk/gtk.h>
22
23 #include <gtk/gtkthemingengine.h>
24 #include <gtk/gtkstylecontext.h>
25 #include <gtk/gtkintl.h>
26
27 #include "gtkprivate.h"
28 #include "gtkmodulesprivate.h"
29 #include "gtkborderimageprivate.h"
30 #include "gtkpango.h"
31 #include "gtkcssarrayvalueprivate.h"
32 #include "gtkcsscornervalueprivate.h"
33 #include "gtkcssenumvalueprivate.h"
34 #include "gtkcssnumbervalueprivate.h"
35 #include "gtkcssrgbavalueprivate.h"
36 #include "gtkcssshadowsvalueprivate.h"
37 #include "gtkcsstypesprivate.h"
38 #include "gtkhslaprivate.h"
39 #include "gtkthemingengineprivate.h"
40 #include "gtkroundedboxprivate.h"
41 #include "gtkthemingbackgroundprivate.h"
42
43 #include "fallback-c89.c"
44
45 /**
46  * SECTION:gtkthemingengine
47  * @Short_description: Theming renderers
48  * @Title: GtkThemingEngine
49  * @See_also: #GtkStyleContext
50  *
51  * #GtkThemingEngine is the object used for rendering themed content
52  * in GTK+ widgets. Even though GTK+ has a default implementation,
53  * it can be overridden in CSS files by enforcing a #GtkThemingEngine
54  * object to be loaded as a module.
55  *
56  * In order to implement a theming engine, a #GtkThemingEngine subclass
57  * must be created, alongside the CSS file that will reference it, the
58  * theming engine would be created as an .so library, and installed in
59  * $(gtk-modules-dir)/theming-engines/.
60  *
61  * #GtkThemingEngine<!-- -->s have limited access to the object they are
62  * rendering, the #GtkThemingEngine API has read-only accessors to the
63  * style information contained in the rendered object's #GtkStyleContext.
64  */
65
66 enum {
67   PROP_0,
68   PROP_NAME
69 };
70
71 struct GtkThemingEnginePrivate
72 {
73   GtkStyleContext *context;
74   gchar *name;
75 };
76
77 #define GTK_THEMING_ENGINE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_THEMING_ENGINE, GtkThemingEnginePrivate))
78
79 static void gtk_theming_engine_finalize          (GObject      *object);
80 static void gtk_theming_engine_impl_set_property (GObject      *object,
81                                                   guint         prop_id,
82                                                   const GValue *value,
83                                                   GParamSpec   *pspec);
84 static void gtk_theming_engine_impl_get_property (GObject      *object,
85                                                   guint         prop_id,
86                                                   GValue       *value,
87                                                   GParamSpec   *pspec);
88
89 static void gtk_theming_engine_render_check (GtkThemingEngine *engine,
90                                              cairo_t          *cr,
91                                              gdouble           x,
92                                              gdouble           y,
93                                              gdouble           width,
94                                              gdouble           height);
95 static void gtk_theming_engine_render_option (GtkThemingEngine *engine,
96                                               cairo_t          *cr,
97                                               gdouble           x,
98                                               gdouble           y,
99                                               gdouble           width,
100                                               gdouble           height);
101 static void gtk_theming_engine_render_arrow  (GtkThemingEngine *engine,
102                                               cairo_t          *cr,
103                                               gdouble           angle,
104                                               gdouble           x,
105                                               gdouble           y,
106                                               gdouble           size);
107 static void gtk_theming_engine_render_background (GtkThemingEngine *engine,
108                                                   cairo_t          *cr,
109                                                   gdouble           x,
110                                                   gdouble           y,
111                                                   gdouble           width,
112                                                   gdouble           height);
113 static void gtk_theming_engine_render_frame  (GtkThemingEngine *engine,
114                                               cairo_t          *cr,
115                                               gdouble           x,
116                                               gdouble           y,
117                                               gdouble           width,
118                                               gdouble           height);
119 static void gtk_theming_engine_render_expander (GtkThemingEngine *engine,
120                                                 cairo_t          *cr,
121                                                 gdouble           x,
122                                                 gdouble           y,
123                                                 gdouble           width,
124                                                 gdouble           height);
125 static void gtk_theming_engine_render_focus    (GtkThemingEngine *engine,
126                                                 cairo_t          *cr,
127                                                 gdouble           x,
128                                                 gdouble           y,
129                                                 gdouble           width,
130                                                 gdouble           height);
131 static void gtk_theming_engine_render_layout   (GtkThemingEngine *engine,
132                                                 cairo_t          *cr,
133                                                 gdouble           x,
134                                                 gdouble           y,
135                                                 PangoLayout      *layout);
136 static void gtk_theming_engine_render_line     (GtkThemingEngine *engine,
137                                                 cairo_t          *cr,
138                                                 gdouble           x0,
139                                                 gdouble           y0,
140                                                 gdouble           x1,
141                                                 gdouble           y1);
142 static void gtk_theming_engine_render_slider   (GtkThemingEngine *engine,
143                                                 cairo_t          *cr,
144                                                 gdouble           x,
145                                                 gdouble           y,
146                                                 gdouble           width,
147                                                 gdouble           height,
148                                                 GtkOrientation    orientation);
149 static void gtk_theming_engine_render_frame_gap (GtkThemingEngine *engine,
150                                                  cairo_t          *cr,
151                                                  gdouble           x,
152                                                  gdouble           y,
153                                                  gdouble           width,
154                                                  gdouble           height,
155                                                  GtkPositionType   gap_side,
156                                                  gdouble           xy0_gap,
157                                                  gdouble           xy1_gap);
158 static void gtk_theming_engine_render_extension (GtkThemingEngine *engine,
159                                                  cairo_t          *cr,
160                                                  gdouble           x,
161                                                  gdouble           y,
162                                                  gdouble           width,
163                                                  gdouble           height,
164                                                  GtkPositionType   gap_side);
165 static void gtk_theming_engine_render_handle    (GtkThemingEngine *engine,
166                                                  cairo_t          *cr,
167                                                  gdouble           x,
168                                                  gdouble           y,
169                                                  gdouble           width,
170                                                  gdouble           height);
171 static void gtk_theming_engine_render_activity  (GtkThemingEngine *engine,
172                                                  cairo_t          *cr,
173                                                  gdouble           x,
174                                                  gdouble           y,
175                                                  gdouble           width,
176                                                  gdouble           height);
177 static GdkPixbuf * gtk_theming_engine_render_icon_pixbuf (GtkThemingEngine    *engine,
178                                                           const GtkIconSource *source,
179                                                           GtkIconSize          size);
180 static void gtk_theming_engine_render_icon (GtkThemingEngine *engine,
181                                             cairo_t *cr,
182                                             GdkPixbuf *pixbuf,
183                                             gdouble x,
184                                             gdouble y);
185
186 G_DEFINE_TYPE (GtkThemingEngine, gtk_theming_engine, G_TYPE_OBJECT)
187
188
189 typedef struct GtkThemingModule GtkThemingModule;
190 typedef struct GtkThemingModuleClass GtkThemingModuleClass;
191
192 struct GtkThemingModule
193 {
194   GTypeModule parent_instance;
195   GModule *module;
196   gchar *name;
197
198   void (*init) (GTypeModule *module);
199   void (*exit) (void);
200   GtkThemingEngine * (*create_engine) (void);
201 };
202
203 struct GtkThemingModuleClass
204 {
205   GTypeModuleClass parent_class;
206 };
207
208 #define GTK_TYPE_THEMING_MODULE  (gtk_theming_module_get_type ())
209 #define GTK_THEMING_MODULE(o)    (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_THEMING_MODULE, GtkThemingModule))
210 #define GTK_IS_THEMING_MODULE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_THEMING_MODULE))
211
212 GType gtk_theming_module_get_type (void);
213
214 G_DEFINE_TYPE (GtkThemingModule, gtk_theming_module, G_TYPE_TYPE_MODULE);
215
216 static void
217 gtk_theming_engine_class_init (GtkThemingEngineClass *klass)
218 {
219   GObjectClass *object_class = G_OBJECT_CLASS (klass);
220
221   object_class->finalize = gtk_theming_engine_finalize;
222   object_class->set_property = gtk_theming_engine_impl_set_property;
223   object_class->get_property = gtk_theming_engine_impl_get_property;
224
225   klass->render_icon = gtk_theming_engine_render_icon;
226   klass->render_check = gtk_theming_engine_render_check;
227   klass->render_option = gtk_theming_engine_render_option;
228   klass->render_arrow = gtk_theming_engine_render_arrow;
229   klass->render_background = gtk_theming_engine_render_background;
230   klass->render_frame = gtk_theming_engine_render_frame;
231   klass->render_expander = gtk_theming_engine_render_expander;
232   klass->render_focus = gtk_theming_engine_render_focus;
233   klass->render_layout = gtk_theming_engine_render_layout;
234   klass->render_line = gtk_theming_engine_render_line;
235   klass->render_slider = gtk_theming_engine_render_slider;
236   klass->render_frame_gap = gtk_theming_engine_render_frame_gap;
237   klass->render_extension = gtk_theming_engine_render_extension;
238   klass->render_handle = gtk_theming_engine_render_handle;
239   klass->render_activity = gtk_theming_engine_render_activity;
240   klass->render_icon_pixbuf = gtk_theming_engine_render_icon_pixbuf;
241
242   /**
243    * GtkThemingEngine:name:
244    *
245    * The theming engine name, this name will be used when registering
246    * custom properties, for a theming engine named "Clearlooks" registering
247    * a "glossy" custom property, it could be referenced in the CSS file as
248    *
249    * <programlisting>
250    * -Clearlooks-glossy: true;
251    * </programlisting>
252    *
253    * Since: 3.0
254    */
255   g_object_class_install_property (object_class,
256                                    PROP_NAME,
257                                    g_param_spec_string ("name",
258                                                         P_("Name"),
259                                                         P_("Theming engine name"),
260                                                         NULL,
261                                                         G_PARAM_CONSTRUCT_ONLY | GTK_PARAM_READWRITE));
262
263   g_type_class_add_private (object_class, sizeof (GtkThemingEnginePrivate));
264 }
265
266 static void
267 gtk_theming_engine_init (GtkThemingEngine *engine)
268 {
269   engine->priv = GTK_THEMING_ENGINE_GET_PRIVATE (engine);
270 }
271
272 static void
273 gtk_theming_engine_finalize (GObject *object)
274 {
275   GtkThemingEnginePrivate *priv;
276
277   priv = GTK_THEMING_ENGINE (object)->priv;
278   g_free (priv->name);
279
280   G_OBJECT_GET_CLASS (gtk_theming_engine_parent_class)->finalize (object);
281 }
282
283 static void
284 gtk_theming_engine_impl_set_property (GObject      *object,
285                                       guint         prop_id,
286                                       const GValue *value,
287                                       GParamSpec   *pspec)
288 {
289   GtkThemingEnginePrivate *priv;
290
291   priv = GTK_THEMING_ENGINE (object)->priv;
292
293   switch (prop_id)
294     {
295     case PROP_NAME:
296       if (priv->name)
297         g_free (priv->name);
298
299       priv->name = g_value_dup_string (value);
300       break;
301     default:
302       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
303       break;
304     }
305 }
306
307 static void
308 gtk_theming_engine_impl_get_property (GObject    *object,
309                                       guint       prop_id,
310                                       GValue     *value,
311                                       GParamSpec *pspec)
312 {
313   GtkThemingEnginePrivate *priv;
314
315   priv = GTK_THEMING_ENGINE (object)->priv;
316
317   switch (prop_id)
318     {
319     case PROP_NAME:
320       g_value_set_string (value, priv->name);
321       break;
322     default:
323       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
324       break;
325     }
326 }
327
328 void
329 _gtk_theming_engine_set_context (GtkThemingEngine *engine,
330                                  GtkStyleContext  *context)
331 {
332   GtkThemingEnginePrivate *priv;
333
334   g_return_if_fail (GTK_IS_THEMING_ENGINE (engine));
335   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
336
337   priv = engine->priv;
338   priv->context = context;
339 }
340
341 GtkStyleContext *
342 _gtk_theming_engine_get_context (GtkThemingEngine *engine)
343 {
344   g_return_val_if_fail (GTK_IS_THEMING_ENGINE (engine), NULL);
345
346   return engine->priv->context;
347 }
348
349 GtkCssValue *
350 _gtk_theming_engine_peek_property (GtkThemingEngine *engine,
351                                    guint             property_id)
352 {
353   g_return_val_if_fail (GTK_IS_THEMING_ENGINE (engine), NULL);
354
355   return _gtk_style_context_peek_property (engine->priv->context, property_id);
356 }
357
358 /**
359  * gtk_theming_engine_get_property:
360  * @engine: a #GtkThemingEngine
361  * @property: the property name
362  * @state: state to retrieve the value for
363  * @value: (out) (transfer full): return location for the property value,
364  *         you must free this memory using g_value_unset() once you are
365  *         done with it.
366  *
367  * Gets a property value as retrieved from the style settings that apply
368  * to the currently rendered element.
369  *
370  * Since: 3.0
371  **/
372 void
373 gtk_theming_engine_get_property (GtkThemingEngine *engine,
374                                  const gchar      *property,
375                                  GtkStateFlags     state,
376                                  GValue           *value)
377 {
378   GtkThemingEnginePrivate *priv;
379
380   g_return_if_fail (GTK_IS_THEMING_ENGINE (engine));
381   g_return_if_fail (property != NULL);
382   g_return_if_fail (value != NULL);
383
384   priv = engine->priv;
385   gtk_style_context_get_property (priv->context, property, state, value);
386 }
387
388 /**
389  * gtk_theming_engine_get_valist:
390  * @engine: a #GtkThemingEngine
391  * @state: state to retrieve values for
392  * @args: va_list of property name/return location pairs, followed by %NULL
393  *
394  * Retrieves several style property values that apply to the currently
395  * rendered element.
396  *
397  * Since: 3.0
398  **/
399 void
400 gtk_theming_engine_get_valist (GtkThemingEngine *engine,
401                                GtkStateFlags     state,
402                                va_list           args)
403 {
404   GtkThemingEnginePrivate *priv;
405
406   g_return_if_fail (GTK_IS_THEMING_ENGINE (engine));
407
408   priv = engine->priv;
409   gtk_style_context_get_valist (priv->context, state, args);
410 }
411
412 /**
413  * gtk_theming_engine_get:
414  * @engine: a #GtkThemingEngine
415  * @state: state to retrieve values for
416  * @...: property name /return value pairs, followed by %NULL
417  *
418  * Retrieves several style property values that apply to the currently
419  * rendered element.
420  *
421  * Since: 3.0
422  **/
423 void
424 gtk_theming_engine_get (GtkThemingEngine *engine,
425                         GtkStateFlags     state,
426                         ...)
427 {
428   GtkThemingEnginePrivate *priv;
429   va_list args;
430
431   g_return_if_fail (GTK_IS_THEMING_ENGINE (engine));
432
433   priv = engine->priv;
434
435   va_start (args, state);
436   gtk_style_context_get_valist (priv->context, state, args);
437   va_end (args);
438 }
439
440 /**
441  * gtk_theming_engine_get_style_property:
442  * @engine: a #GtkThemingEngine
443  * @property_name: the name of the widget style property
444  * @value: Return location for the property value, free with
445  *         g_value_unset() after use.
446  *
447  * Gets the value for a widget style property.
448  *
449  * Since: 3.0
450  **/
451 void
452 gtk_theming_engine_get_style_property (GtkThemingEngine *engine,
453                                        const gchar      *property_name,
454                                        GValue           *value)
455 {
456   GtkThemingEnginePrivate *priv;
457
458   g_return_if_fail (GTK_IS_THEMING_ENGINE (engine));
459   g_return_if_fail (property_name != NULL);
460
461   priv = engine->priv;
462   gtk_style_context_get_style_property (priv->context, property_name, value);
463 }
464
465 /**
466  * gtk_theming_engine_get_style_valist:
467  * @engine: a #GtkThemingEngine
468  * @args: va_list of property name/return location pairs, followed by %NULL
469  *
470  * Retrieves several widget style properties from @engine according to the
471  * currently rendered content's style.
472  *
473  * Since: 3.0
474  **/
475 void
476 gtk_theming_engine_get_style_valist (GtkThemingEngine *engine,
477                                      va_list           args)
478 {
479   GtkThemingEnginePrivate *priv;
480
481   g_return_if_fail (GTK_IS_THEMING_ENGINE (engine));
482
483   priv = engine->priv;
484   gtk_style_context_get_style_valist (priv->context, args);
485 }
486
487 /**
488  * gtk_theming_engine_get_style:
489  * @engine: a #GtkThemingEngine
490  * @...: property name /return value pairs, followed by %NULL
491  *
492  * Retrieves several widget style properties from @engine according
493  * to the currently rendered content's style.
494  *
495  * Since: 3.0
496  **/
497 void
498 gtk_theming_engine_get_style (GtkThemingEngine *engine,
499                               ...)
500 {
501   GtkThemingEnginePrivate *priv;
502   va_list args;
503
504   g_return_if_fail (GTK_IS_THEMING_ENGINE (engine));
505
506   priv = engine->priv;
507
508   va_start (args, engine);
509   gtk_style_context_get_style_valist (priv->context, args);
510   va_end (args);
511 }
512
513 /**
514  * gtk_theming_engine_lookup_color:
515  * @engine: a #GtkThemingEngine
516  * @color_name: color name to lookup
517  * @color: (out): Return location for the looked up color
518  *
519  * Looks up and resolves a color name in the current style's color map.
520  *
521  * Returns: %TRUE if @color_name was found and resolved, %FALSE otherwise
522  **/
523 gboolean
524 gtk_theming_engine_lookup_color (GtkThemingEngine *engine,
525                                  const gchar      *color_name,
526                                  GdkRGBA          *color)
527 {
528   GtkThemingEnginePrivate *priv;
529
530   g_return_val_if_fail (GTK_IS_THEMING_ENGINE (engine), FALSE);
531   g_return_val_if_fail (color_name != NULL, FALSE);
532
533   priv = engine->priv;
534   return gtk_style_context_lookup_color (priv->context, color_name, color);
535 }
536
537 /**
538  * gtk_theming_engine_get_state:
539  * @engine: a #GtkThemingEngine
540  *
541  * returns the state used when rendering.
542  *
543  * Returns: the state flags
544  *
545  * Since: 3.0
546  **/
547 GtkStateFlags
548 gtk_theming_engine_get_state (GtkThemingEngine *engine)
549 {
550   GtkThemingEnginePrivate *priv;
551
552   g_return_val_if_fail (GTK_IS_THEMING_ENGINE (engine), 0);
553
554   priv = engine->priv;
555   return gtk_style_context_get_state (priv->context);
556 }
557
558 /**
559  * gtk_theming_engine_state_is_running:
560  * @engine: a #GtkThemingEngine
561  * @state: a widget state
562  * @progress: (out): return location for the transition progress
563  *
564  * Returns %TRUE if there is a transition animation running for the
565  * current region (see gtk_style_context_push_animatable_region()).
566  *
567  * If @progress is not %NULL, the animation progress will be returned
568  * there, 0.0 means the state is closest to being %FALSE, while 1.0 means
569  * it's closest to being %TRUE. This means transition animations will
570  * run from 0 to 1 when @state is being set to %TRUE and from 1 to 0 when
571  * it's being set to %FALSE.
572  *
573  * Returns: %TRUE if there is a running transition animation for @state.
574  *
575  * Since: 3.0
576  *
577  * Deprecated: 3.6: Always returns %FALSE
578  **/
579 gboolean
580 gtk_theming_engine_state_is_running (GtkThemingEngine *engine,
581                                      GtkStateType      state,
582                                      gdouble          *progress)
583 {
584   g_return_val_if_fail (GTK_IS_THEMING_ENGINE (engine), FALSE);
585
586   return FALSE;
587 }
588
589 /**
590  * gtk_theming_engine_get_path:
591  * @engine: a #GtkThemingEngine
592  *
593  * Returns the widget path used for style matching.
594  *
595  * Returns: (transfer none): A #GtkWidgetPath
596  *
597  * Since: 3.0
598  **/
599 const GtkWidgetPath *
600 gtk_theming_engine_get_path (GtkThemingEngine *engine)
601 {
602   GtkThemingEnginePrivate *priv;
603
604   g_return_val_if_fail (GTK_IS_THEMING_ENGINE (engine), NULL);
605
606   priv = engine->priv;
607   return gtk_style_context_get_path (priv->context);
608 }
609
610 /**
611  * gtk_theming_engine_has_class:
612  * @engine: a #GtkThemingEngine
613  * @style_class: class name to look up
614  *
615  * Returns %TRUE if the currently rendered contents have
616  * defined the given class name.
617  *
618  * Returns: %TRUE if @engine has @class_name defined
619  *
620  * Since: 3.0
621  **/
622 gboolean
623 gtk_theming_engine_has_class (GtkThemingEngine *engine,
624                               const gchar      *style_class)
625 {
626   GtkThemingEnginePrivate *priv;
627
628   g_return_val_if_fail (GTK_IS_THEMING_ENGINE (engine), FALSE);
629
630   priv = engine->priv;
631   return gtk_style_context_has_class (priv->context, style_class);
632 }
633
634 /**
635  * gtk_theming_engine_has_region:
636  * @engine: a #GtkThemingEngine
637  * @style_region: a region name
638  * @flags: (out) (allow-none): return location for region flags
639  *
640  * Returns %TRUE if the currently rendered contents have the
641  * region defined. If @flags_return is not %NULL, it is set
642  * to the flags affecting the region.
643  *
644  * Returns: %TRUE if region is defined
645  *
646  * Since: 3.0
647  **/
648 gboolean
649 gtk_theming_engine_has_region (GtkThemingEngine *engine,
650                                const gchar      *style_region,
651                                GtkRegionFlags   *flags)
652 {
653   GtkThemingEnginePrivate *priv;
654
655   if (flags)
656     *flags = 0;
657
658   g_return_val_if_fail (GTK_IS_THEMING_ENGINE (engine), FALSE);
659
660   priv = engine->priv;
661   return gtk_style_context_has_region (priv->context, style_region, flags);
662 }
663
664 /**
665  * gtk_theming_engine_get_direction:
666  * @engine: a #GtkThemingEngine
667  *
668  * Returns the widget direction used for rendering.
669  *
670  * Returns: the widget direction
671  *
672  * Since: 3.0
673  **/
674 GtkTextDirection
675 gtk_theming_engine_get_direction (GtkThemingEngine *engine)
676 {
677   GtkThemingEnginePrivate *priv;
678
679   g_return_val_if_fail (GTK_IS_THEMING_ENGINE (engine), GTK_TEXT_DIR_LTR);
680
681   priv = engine->priv;
682   return gtk_style_context_get_direction (priv->context);
683 }
684
685 /**
686  * gtk_theming_engine_get_junction_sides:
687  * @engine: a #GtkThemingEngine
688  *
689  * Returns the widget direction used for rendering.
690  *
691  * Returns: the widget direction
692  *
693  * Since: 3.0
694  **/
695 GtkJunctionSides
696 gtk_theming_engine_get_junction_sides (GtkThemingEngine *engine)
697 {
698   GtkThemingEnginePrivate *priv;
699
700   g_return_val_if_fail (GTK_IS_THEMING_ENGINE (engine), 0);
701
702   priv = engine->priv;
703   return gtk_style_context_get_junction_sides (priv->context);
704 }
705
706 /**
707  * gtk_theming_engine_get_color:
708  * @engine: a #GtkThemingEngine
709  * @state: state to retrieve the color for
710  * @color: (out): return value for the foreground color
711  *
712  * Gets the foreground color for a given state.
713  *
714  * Since: 3.0
715  **/
716 void
717 gtk_theming_engine_get_color (GtkThemingEngine *engine,
718                               GtkStateFlags     state,
719                               GdkRGBA          *color)
720 {
721   GtkThemingEnginePrivate *priv;
722
723   g_return_if_fail (GTK_IS_THEMING_ENGINE (engine));
724
725   priv = engine->priv;
726   gtk_style_context_get_color (priv->context, state, color);
727 }
728
729 /**
730  * gtk_theming_engine_get_background_color:
731  * @engine: a #GtkThemingEngine
732  * @state: state to retrieve the color for
733  * @color: (out): return value for the background color
734  *
735  * Gets the background color for a given state.
736  *
737  * Since: 3.0
738  **/
739 void
740 gtk_theming_engine_get_background_color (GtkThemingEngine *engine,
741                                          GtkStateFlags     state,
742                                          GdkRGBA          *color)
743 {
744   GtkThemingEnginePrivate *priv;
745
746   g_return_if_fail (GTK_IS_THEMING_ENGINE (engine));
747
748   priv = engine->priv;
749   gtk_style_context_get_background_color (priv->context, state, color);
750 }
751
752 /**
753  * gtk_theming_engine_get_border_color:
754  * @engine: a #GtkThemingEngine
755  * @state: state to retrieve the color for
756  * @color: (out): return value for the border color
757  *
758  * Gets the border color for a given state.
759  *
760  * Since: 3.0
761  **/
762 void
763 gtk_theming_engine_get_border_color (GtkThemingEngine *engine,
764                                      GtkStateFlags     state,
765                                      GdkRGBA          *color)
766 {
767   GtkThemingEnginePrivate *priv;
768
769   g_return_if_fail (GTK_IS_THEMING_ENGINE (engine));
770
771   priv = engine->priv;
772   gtk_style_context_get_border_color (priv->context, state, color);
773 }
774
775 /**
776  * gtk_theming_engine_get_border:
777  * @engine: a #GtkThemingEngine
778  * @state: state to retrieve the border for
779  * @border: (out): return value for the border settings
780  *
781  * Gets the border for a given state as a #GtkBorder.
782  *
783  * Since: 3.0
784  **/
785 void
786 gtk_theming_engine_get_border (GtkThemingEngine *engine,
787                                GtkStateFlags     state,
788                                GtkBorder        *border)
789 {
790   GtkThemingEnginePrivate *priv;
791
792   g_return_if_fail (GTK_IS_THEMING_ENGINE (engine));
793
794   priv = engine->priv;
795   gtk_style_context_get_border (priv->context, state, border);
796 }
797
798 /**
799  * gtk_theming_engine_get_padding:
800  * @engine: a #GtkThemingEngine
801  * @state: state to retrieve the padding for
802  * @padding: (out): return value for the padding settings
803  *
804  * Gets the padding for a given state as a #GtkBorder.
805  *
806  * Since: 3.0
807  **/
808 void
809 gtk_theming_engine_get_padding (GtkThemingEngine *engine,
810                                 GtkStateFlags     state,
811                                 GtkBorder        *padding)
812 {
813   GtkThemingEnginePrivate *priv;
814
815   g_return_if_fail (GTK_IS_THEMING_ENGINE (engine));
816
817   priv = engine->priv;
818   gtk_style_context_get_padding (priv->context, state, padding);
819 }
820
821 /**
822  * gtk_theming_engine_get_margin:
823  * @engine: a #GtkThemingEngine
824  * @state: state to retrieve the border for
825  * @margin: (out): return value for the margin settings
826  *
827  * Gets the margin for a given state as a #GtkBorder.
828  *
829  * Since: 3.0
830  **/
831 void
832 gtk_theming_engine_get_margin (GtkThemingEngine *engine,
833                                GtkStateFlags     state,
834                                GtkBorder        *margin)
835 {
836   GtkThemingEnginePrivate *priv;
837
838   g_return_if_fail (GTK_IS_THEMING_ENGINE (engine));
839
840   priv = engine->priv;
841   gtk_style_context_get_margin (priv->context, state, margin);
842 }
843
844 /**
845  * gtk_theming_engine_get_font:
846  * @engine: a #GtkThemingEngine
847  * @state: state to retrieve the font for
848  *
849  * Returns the font description for a given state.
850  *
851  * Returns: (transfer none): the #PangoFontDescription for the given
852  *          state. This object is owned by GTK+ and should not be
853  *          freed.
854  *
855  * Since: 3.0
856  *
857  * Deprecated: 3.8: Use gtk_theming_engine_get()
858  **/
859 const PangoFontDescription *
860 gtk_theming_engine_get_font (GtkThemingEngine *engine,
861                              GtkStateFlags     state)
862 {
863   GtkThemingEnginePrivate *priv;
864
865   g_return_val_if_fail (GTK_IS_THEMING_ENGINE (engine), NULL);
866
867   G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
868   priv = engine->priv;
869   return gtk_style_context_get_font (priv->context, state);
870   G_GNUC_END_IGNORE_DEPRECATIONS;
871 }
872
873 /* GtkThemingModule */
874
875 static gboolean
876 gtk_theming_module_load (GTypeModule *type_module)
877 {
878   GtkThemingModule *theming_module;
879   GModule *module;
880   gchar *name, *module_path;
881
882   theming_module = GTK_THEMING_MODULE (type_module);
883   name = theming_module->name;
884   module_path = _gtk_find_module (name, "theming-engines");
885
886   if (!module_path)
887     return FALSE;
888
889   module = g_module_open (module_path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
890   g_free (module_path);
891
892   if (!module)
893     return FALSE;
894
895   if (!g_module_symbol (module, "theme_init",
896                         (gpointer *) &theming_module->init) ||
897       !g_module_symbol (module, "theme_exit",
898                         (gpointer *) &theming_module->exit) ||
899       !g_module_symbol (module, "create_engine",
900                         (gpointer *) &theming_module->create_engine))
901     {
902       g_module_close (module);
903
904       return FALSE;
905     }
906
907   theming_module->module = module;
908
909   theming_module->init (G_TYPE_MODULE (theming_module));
910
911   return TRUE;
912 }
913
914 static void
915 gtk_theming_module_unload (GTypeModule *type_module)
916 {
917   GtkThemingModule *theming_module;
918
919   theming_module = GTK_THEMING_MODULE (type_module);
920
921   theming_module->exit ();
922
923   g_module_close (theming_module->module);
924
925   theming_module->module = NULL;
926   theming_module->init = NULL;
927   theming_module->exit = NULL;
928   theming_module->create_engine = NULL;
929 }
930
931 static void
932 gtk_theming_module_class_init (GtkThemingModuleClass *klass)
933 {
934   GTypeModuleClass *module_class = G_TYPE_MODULE_CLASS (klass);
935
936   module_class->load = gtk_theming_module_load;
937   module_class->unload = gtk_theming_module_unload;
938 }
939
940 static void
941 gtk_theming_module_init (GtkThemingModule *module)
942 {
943 }
944
945 /**
946  * gtk_theming_engine_load:
947  * @name: Theme engine name to load
948  *
949  * Loads and initializes a theming engine module from the
950  * standard directories.
951  *
952  * Returns: (transfer none): A theming engine, or %NULL if
953  * the engine @name doesn't exist.
954  **/
955 GtkThemingEngine *
956 gtk_theming_engine_load (const gchar *name)
957 {
958   static GHashTable *engines = NULL;
959   static GtkThemingEngine *default_engine;
960   GtkThemingEngine *engine = NULL;
961
962   if (name)
963     {
964       if (!engines)
965         engines = g_hash_table_new (g_str_hash, g_str_equal);
966
967       engine = g_hash_table_lookup (engines, name);
968
969       if (!engine)
970         {
971           GtkThemingModule *module;
972
973           module = g_object_new (GTK_TYPE_THEMING_MODULE, NULL);
974           g_type_module_set_name (G_TYPE_MODULE (module), name);
975           module->name = g_strdup (name);
976
977           if (module && g_type_module_use (G_TYPE_MODULE (module)))
978             {
979               engine = (module->create_engine) ();
980
981               if (engine)
982                 g_hash_table_insert (engines, module->name, engine);
983             }
984         }
985     }
986   else
987     {
988       if (G_UNLIKELY (!default_engine))
989         default_engine = g_object_new (GTK_TYPE_THEMING_ENGINE, NULL);
990
991       engine = default_engine;
992     }
993
994   return engine;
995 }
996
997 /**
998  * gtk_theming_engine_get_screen:
999  * @engine: a #GtkThemingEngine
1000  *
1001  * Returns the #GdkScreen to which @engine currently rendering to.
1002  *
1003  * Returns: (transfer none): a #GdkScreen, or %NULL.
1004  **/
1005 GdkScreen *
1006 gtk_theming_engine_get_screen (GtkThemingEngine *engine)
1007 {
1008   GtkThemingEnginePrivate *priv;
1009
1010   g_return_val_if_fail (GTK_IS_THEMING_ENGINE (engine), NULL);
1011
1012   priv = engine->priv;
1013   return gtk_style_context_get_screen (priv->context);
1014 }
1015
1016 /* Paint method implementations */
1017 static void
1018 gtk_theming_engine_render_check (GtkThemingEngine *engine,
1019                                  cairo_t          *cr,
1020                                  gdouble           x,
1021                                  gdouble           y,
1022                                  gdouble           width,
1023                                  gdouble           height)
1024 {
1025   GdkRGBA fg_color, bg_color;
1026   GtkStateFlags flags;
1027   gint exterior_size, interior_size, thickness, pad;
1028   GtkBorderStyle border_style;
1029   GtkBorder border;
1030   gint border_width;
1031   GtkThemingBackground bg;
1032
1033   _gtk_theming_background_init (&bg, engine, 
1034                                 x, y,
1035                                 width, height,
1036                                 gtk_theming_engine_get_junction_sides (engine));
1037
1038   if (_gtk_theming_background_has_background_image (&bg))
1039     {
1040       _gtk_theming_background_render (&bg, cr);
1041       return;
1042     }
1043
1044   flags = gtk_theming_engine_get_state (engine);
1045   cairo_save (cr);
1046
1047   gtk_theming_engine_get_color (engine, flags, &fg_color);
1048   gtk_theming_engine_get_background_color (engine, flags, &bg_color);
1049   gtk_theming_engine_get_border (engine, flags, &border);
1050   border_style = _gtk_css_border_style_value_get 
1051     (_gtk_theming_engine_peek_property (engine, GTK_CSS_PROPERTY_BORDER_TOP_STYLE));
1052
1053   border_width = MIN (MIN (border.top, border.bottom),
1054                       MIN (border.left, border.right));
1055   exterior_size = MIN (width, height);
1056
1057   if (exterior_size % 2 == 0) /* Ensure odd */
1058     exterior_size -= 1;
1059
1060   /* FIXME: thickness */
1061   thickness = 1;
1062   pad = thickness + MAX (1, (exterior_size - 2 * thickness) / 9);
1063   interior_size = MAX (1, exterior_size - 2 * pad);
1064
1065   if (interior_size < 7)
1066     {
1067       interior_size = 7;
1068       pad = MAX (0, (exterior_size - interior_size) / 2);
1069     }
1070
1071   x -= (1 + exterior_size - (gint) width) / 2;
1072   y -= (1 + exterior_size - (gint) height) / 2;
1073
1074   if (border_style == GTK_BORDER_STYLE_SOLID)
1075     {
1076       GdkRGBA border_color;
1077
1078       cairo_set_line_width (cr, border_width);
1079       gtk_theming_engine_get_border_color (engine, flags, &border_color);
1080
1081       cairo_rectangle (cr, x + 0.5, y + 0.5, exterior_size - 1, exterior_size - 1);
1082       gdk_cairo_set_source_rgba (cr, &bg_color);
1083       cairo_fill_preserve (cr);
1084
1085       gdk_cairo_set_source_rgba (cr, &border_color);
1086       cairo_stroke (cr);
1087     }
1088
1089   gdk_cairo_set_source_rgba (cr, &fg_color);
1090
1091   if (flags & GTK_STATE_FLAG_INCONSISTENT)
1092     {
1093       int line_thickness = MAX (1, (3 + interior_size * 2) / 7);
1094
1095       cairo_rectangle (cr,
1096                        x + pad,
1097                        y + pad + (1 + interior_size - line_thickness) / 2,
1098                        interior_size,
1099                        line_thickness);
1100       cairo_fill (cr);
1101     }
1102   else
1103     {
1104       if (flags & GTK_STATE_FLAG_ACTIVE)
1105         {
1106           cairo_translate (cr,
1107                            x + pad, y + pad);
1108
1109           cairo_scale (cr, interior_size / 7., interior_size / 7.);
1110
1111           cairo_rectangle (cr, 0, 0, 7, 7);
1112           cairo_clip (cr);
1113
1114           cairo_move_to  (cr, 7.0, 0.0);
1115           cairo_line_to  (cr, 7.5, 1.0);
1116           cairo_curve_to (cr, 5.3, 2.0,
1117                           4.3, 4.0,
1118                           3.5, 7.0);
1119           cairo_curve_to (cr, 3.0, 5.7,
1120                           1.3, 4.7,
1121                           0.0, 4.7);
1122           cairo_line_to  (cr, 0.2, 3.5);
1123           cairo_curve_to (cr, 1.1, 3.5,
1124                           2.3, 4.3,
1125                           3.0, 5.0);
1126           cairo_curve_to (cr, 1.0, 3.9,
1127                           2.4, 4.1,
1128                           3.2, 4.9);
1129           cairo_curve_to (cr, 3.5, 3.1,
1130                           5.2, 2.0,
1131                           7.0, 0.0);
1132
1133           cairo_fill (cr);
1134         }
1135     }
1136
1137   cairo_restore (cr);
1138 }
1139
1140 static void
1141 gtk_theming_engine_render_option (GtkThemingEngine *engine,
1142                                   cairo_t          *cr,
1143                                   gdouble           x,
1144                                   gdouble           y,
1145                                   gdouble           width,
1146                                   gdouble           height)
1147 {
1148   GtkStateFlags flags;
1149   GdkRGBA fg_color, bg_color;
1150   gint exterior_size, interior_size, pad, thickness, border_width;
1151   GtkBorderStyle border_style;
1152   GtkBorder border;
1153   GtkThemingBackground bg;
1154
1155   _gtk_theming_background_init (&bg, engine, 
1156                                 x, y,
1157                                 width, height,
1158                                 gtk_theming_engine_get_junction_sides (engine));
1159
1160   if (_gtk_theming_background_has_background_image (&bg))
1161     {
1162       _gtk_theming_background_render (&bg, cr);
1163       return;
1164     }
1165
1166   flags = gtk_theming_engine_get_state (engine);
1167
1168   cairo_save (cr);
1169
1170   gtk_theming_engine_get_color (engine, flags, &fg_color);
1171   gtk_theming_engine_get_background_color (engine, flags, &bg_color);
1172   gtk_theming_engine_get_border (engine, flags, &border);
1173   border_style = _gtk_css_border_style_value_get 
1174     (_gtk_theming_engine_peek_property (engine, GTK_CSS_PROPERTY_BORDER_TOP_STYLE));
1175
1176   exterior_size = MIN (width, height);
1177   border_width = MIN (MIN (border.top, border.bottom),
1178                       MIN (border.left, border.right));
1179
1180   if (exterior_size % 2 == 0) /* Ensure odd */
1181     exterior_size -= 1;
1182
1183   x -= (1 + exterior_size - width) / 2;
1184   y -= (1 + exterior_size - height) / 2;
1185
1186   if (border_style == GTK_BORDER_STYLE_SOLID)
1187     {
1188       GdkRGBA border_color;
1189
1190       cairo_set_line_width (cr, border_width);
1191       gtk_theming_engine_get_border_color (engine, flags, &border_color);
1192
1193       cairo_new_sub_path (cr);
1194       cairo_arc (cr,
1195                  x + exterior_size / 2.,
1196                  y + exterior_size / 2.,
1197                  (exterior_size - 1) / 2.,
1198                  0, 2 * G_PI);
1199
1200       gdk_cairo_set_source_rgba (cr, &bg_color);
1201       cairo_fill_preserve (cr);
1202
1203       gdk_cairo_set_source_rgba (cr, &border_color);
1204       cairo_stroke (cr);
1205     }
1206
1207   gdk_cairo_set_source_rgba (cr, &fg_color);
1208
1209   /* FIXME: thickness */
1210   thickness = 1;
1211
1212   if (flags & GTK_STATE_FLAG_INCONSISTENT)
1213     {
1214       gint line_thickness;
1215
1216       pad = thickness + MAX (1, (exterior_size - 2 * thickness) / 9);
1217       interior_size = MAX (1, exterior_size - 2 * pad);
1218
1219       if (interior_size < 7)
1220         {
1221           interior_size = 7;
1222           pad = MAX (0, (exterior_size - interior_size) / 2);
1223         }
1224
1225       line_thickness = MAX (1, (3 + interior_size * 2) / 7);
1226
1227       cairo_rectangle (cr,
1228                        x + pad,
1229                        y + pad + (interior_size - line_thickness) / 2.,
1230                        interior_size,
1231                        line_thickness);
1232       cairo_fill (cr);
1233     }
1234   if (flags & GTK_STATE_FLAG_ACTIVE)
1235     {
1236       pad = thickness + MAX (1, 2 * (exterior_size - 2 * thickness) / 9);
1237       interior_size = MAX (1, exterior_size - 2 * pad);
1238
1239       if (interior_size < 5)
1240         {
1241           interior_size = 7;
1242           pad = MAX (0, (exterior_size - interior_size) / 2);
1243         }
1244
1245       cairo_new_sub_path (cr);
1246       cairo_arc (cr,
1247                  x + pad + interior_size / 2.,
1248                  y + pad + interior_size / 2.,
1249                  interior_size / 2.,
1250                  0, 2 * G_PI);
1251       cairo_fill (cr);
1252     }
1253
1254   cairo_restore (cr);
1255 }
1256
1257 static void
1258 add_path_arrow (cairo_t *cr,
1259                 gdouble  angle,
1260                 gdouble  x,
1261                 gdouble  y,
1262                 gdouble  size)
1263 {
1264   cairo_save (cr);
1265
1266   cairo_translate (cr, x + (size / 2), y + (size / 2));
1267   cairo_rotate (cr, angle);
1268
1269   cairo_move_to (cr, 0, - (size / 4));
1270   cairo_line_to (cr, - (size / 2), (size / 4));
1271   cairo_line_to (cr, (size / 2), (size / 4));
1272   cairo_close_path (cr);
1273
1274   cairo_restore (cr);
1275 }
1276
1277 static void
1278 gtk_theming_engine_render_arrow (GtkThemingEngine *engine,
1279                                  cairo_t          *cr,
1280                                  gdouble           angle,
1281                                  gdouble           x,
1282                                  gdouble           y,
1283                                  gdouble           size)
1284 {
1285   GtkStateFlags flags;
1286   GdkRGBA fg_color;
1287
1288   cairo_save (cr);
1289
1290   flags = gtk_theming_engine_get_state (engine);
1291   gtk_theming_engine_get_color (engine, flags, &fg_color);
1292
1293   if (flags & GTK_STATE_FLAG_INSENSITIVE)
1294     {
1295       add_path_arrow (cr, angle, x + 1, y + 1, size);
1296       cairo_set_source_rgb (cr, 1, 1, 1);
1297       cairo_fill (cr);
1298     }
1299
1300   add_path_arrow (cr, angle, x, y, size);
1301   gdk_cairo_set_source_rgba (cr, &fg_color);
1302   cairo_fill (cr);
1303
1304   cairo_restore (cr);
1305 }
1306
1307 static void
1308 add_path_line (cairo_t        *cr,
1309                gdouble         x1,
1310                gdouble         y1,
1311                gdouble         x2,
1312                gdouble         y2)
1313 {
1314   /* Adjust endpoints */
1315   if (y1 == y2)
1316     {
1317       y1 += 0.5;
1318       y2 += 0.5;
1319       x2 += 1;
1320     }
1321   else if (x1 == x2)
1322     {
1323       x1 += 0.5;
1324       x2 += 0.5;
1325       y2 += 1;
1326     }
1327
1328   cairo_move_to (cr, x1, y1);
1329   cairo_line_to (cr, x2, y2);
1330 }
1331
1332 static void
1333 color_shade (const GdkRGBA *color,
1334              gdouble        factor,
1335              GdkRGBA       *color_return)
1336 {
1337   GtkHSLA hsla;
1338
1339   _gtk_hsla_init_from_rgba (&hsla, color);
1340   _gtk_hsla_shade (&hsla, &hsla, factor);
1341   _gdk_rgba_init_from_hsla (color_return, &hsla);
1342 }
1343
1344 static void
1345 gtk_theming_engine_render_background (GtkThemingEngine *engine,
1346                                       cairo_t          *cr,
1347                                       gdouble           x,
1348                                       gdouble           y,
1349                                       gdouble           width,
1350                                       gdouble           height)
1351 {
1352   GtkThemingBackground bg;
1353
1354   _gtk_theming_background_init (&bg, engine,
1355                                 x, y,
1356                                 width, height,
1357                                 gtk_theming_engine_get_junction_sides (engine));
1358
1359   _gtk_theming_background_render (&bg, cr);
1360 }
1361
1362 static void
1363 gtk_theming_engine_hide_border_sides (double         border[4],
1364                                       GtkBorderStyle border_style[4],
1365                                       guint          hidden_side)
1366 {
1367   guint i;
1368
1369   for (i = 0; i < 4; i++)
1370     {
1371       if (hidden_side & (1 << i) ||
1372           border_style[i] == GTK_BORDER_STYLE_NONE ||
1373           border_style[i] == GTK_BORDER_STYLE_HIDDEN)
1374         border[i] = 0;
1375     }
1376 }
1377
1378 static void
1379 render_frame_fill (cairo_t       *cr,
1380                    GtkRoundedBox *border_box,
1381                    const double   border_width[4],
1382                    GdkRGBA        colors[4],
1383                    guint          hidden_side)
1384 {
1385   GtkRoundedBox padding_box;
1386   guint i, j;
1387
1388   padding_box = *border_box;
1389   _gtk_rounded_box_shrink (&padding_box,
1390                            border_width[GTK_CSS_TOP],
1391                            border_width[GTK_CSS_RIGHT],
1392                            border_width[GTK_CSS_BOTTOM],
1393                            border_width[GTK_CSS_LEFT]);
1394
1395   if (hidden_side == 0 &&
1396       gdk_rgba_equal (&colors[0], &colors[1]) &&
1397       gdk_rgba_equal (&colors[0], &colors[2]) &&
1398       gdk_rgba_equal (&colors[0], &colors[3]))
1399     {
1400       gdk_cairo_set_source_rgba (cr, &colors[0]);
1401
1402       _gtk_rounded_box_path (border_box, cr);
1403       _gtk_rounded_box_path (&padding_box, cr);
1404       cairo_fill (cr);
1405     }
1406   else
1407     {
1408       for (i = 0; i < 4; i++) 
1409         {
1410           if (hidden_side & (1 << i))
1411             continue;
1412
1413           for (j = 0; j < 4; j++)
1414             { 
1415               if (hidden_side & (1 << j))
1416                 continue;
1417
1418               if (i == j || 
1419                   (gdk_rgba_equal (&colors[i], &colors[j])))
1420                 {
1421                   /* We were already painted when i == j */
1422                   if (i > j)
1423                     break;
1424
1425                   if (j == 0)
1426                     _gtk_rounded_box_path_top (border_box, &padding_box, cr);
1427                   else if (j == 1)
1428                     _gtk_rounded_box_path_right (border_box, &padding_box, cr);
1429                   else if (j == 2)
1430                     _gtk_rounded_box_path_bottom (border_box, &padding_box, cr);
1431                   else if (j == 3)
1432                     _gtk_rounded_box_path_left (border_box, &padding_box, cr);
1433                 }
1434             }
1435           /* We were already painted when i == j */
1436           if (i > j)
1437             continue;
1438
1439           gdk_cairo_set_source_rgba (cr, &colors[i]);
1440
1441           cairo_fill (cr);
1442         }
1443     }
1444 }
1445
1446 static void
1447 set_stroke_style (cairo_t        *cr,
1448                   double          line_width,
1449                   GtkBorderStyle  style,
1450                   double          length)
1451 {
1452   double segments[2];
1453   double n;
1454
1455   cairo_set_line_width (cr, line_width);
1456
1457   if (style == GTK_BORDER_STYLE_DOTTED)
1458     {
1459       n = round (0.5 * length / line_width);
1460
1461       segments[0] = 0;
1462       segments[1] = n ? length / n : 2;
1463       cairo_set_dash (cr, segments, G_N_ELEMENTS (segments), 0);
1464
1465       cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
1466       cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
1467     }
1468   else
1469     {
1470       n = length / line_width;
1471       /* Optimize the common case of an integer-sized rectangle
1472        * Again, we care about focus rectangles.
1473        */
1474       if (n == nearbyint (n))
1475         {
1476           segments[0] = 1;
1477           segments[1] = 2;
1478         }
1479       else
1480         {
1481           n = round ((1. / 3) * n);
1482
1483           segments[0] = n ? (1. / 3) * length / n : 1;
1484           segments[1] = 2 * segments[1];
1485         }
1486       cairo_set_dash (cr, segments, G_N_ELEMENTS (segments), 0);
1487
1488       cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
1489       cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER);
1490     }
1491 }
1492
1493 static void
1494 render_frame_stroke (cairo_t       *cr,
1495                      GtkRoundedBox *border_box,
1496                      const double   border_width[4],
1497                      GdkRGBA        colors[4],
1498                      guint          hidden_side,
1499                      GtkBorderStyle stroke_style)
1500 {
1501   gboolean different_colors, different_borders;
1502   GtkRoundedBox stroke_box;
1503   guint i;
1504
1505   different_colors = !gdk_rgba_equal (&colors[0], &colors[1]) ||
1506                      !gdk_rgba_equal (&colors[0], &colors[2]) ||
1507                      !gdk_rgba_equal (&colors[0], &colors[3]);
1508   different_borders = border_width[0] != border_width[1] ||
1509                       border_width[0] != border_width[2] ||
1510                       border_width[0] != border_width[3] ;
1511
1512   stroke_box = *border_box;
1513   _gtk_rounded_box_shrink (&stroke_box,
1514                            border_width[GTK_CSS_TOP] / 2.0,
1515                            border_width[GTK_CSS_RIGHT] / 2.0,
1516                            border_width[GTK_CSS_BOTTOM] / 2.0,
1517                            border_width[GTK_CSS_LEFT] / 2.0);
1518
1519   if (!different_colors && !different_borders && hidden_side == 0)
1520     {
1521       double length = 0;
1522
1523       /* FAST PATH:
1524        * Mostly expected to trigger for focus rectangles */
1525       for (i = 0; i < 4; i++) 
1526         {
1527           length += _gtk_rounded_box_guess_length (&stroke_box, i);
1528           _gtk_rounded_box_path_side (&stroke_box, cr, i);
1529         }
1530
1531       gdk_cairo_set_source_rgba (cr, &colors[0]);
1532       set_stroke_style (cr, border_width[0], stroke_style, length);
1533       cairo_stroke (cr);
1534     }
1535   else
1536     {
1537       GtkRoundedBox padding_box;
1538
1539       padding_box = *border_box;
1540       _gtk_rounded_box_path (&padding_box, cr);
1541       _gtk_rounded_box_shrink (&padding_box,
1542                                border_width[GTK_CSS_TOP],
1543                                border_width[GTK_CSS_RIGHT],
1544                                border_width[GTK_CSS_BOTTOM],
1545                                border_width[GTK_CSS_LEFT]);
1546
1547       for (i = 0; i < 4; i++) 
1548         {
1549           if (hidden_side & (1 << i))
1550             continue;
1551
1552           cairo_save (cr);
1553
1554           if (i == 0)
1555             _gtk_rounded_box_path_top (border_box, &padding_box, cr);
1556           else if (i == 1)
1557             _gtk_rounded_box_path_right (border_box, &padding_box, cr);
1558           else if (i == 2)
1559             _gtk_rounded_box_path_bottom (border_box, &padding_box, cr);
1560           else if (i == 3)
1561             _gtk_rounded_box_path_left (border_box, &padding_box, cr);
1562           cairo_clip (cr);
1563
1564           _gtk_rounded_box_path_side (&stroke_box, cr, i);
1565
1566           gdk_cairo_set_source_rgba (cr, &colors[i]);
1567           set_stroke_style (cr,
1568                             border_width[i],
1569                             stroke_style,
1570                             _gtk_rounded_box_guess_length (&stroke_box, i));
1571           cairo_stroke (cr);
1572
1573           cairo_restore (cr);
1574         }
1575     }
1576 }
1577
1578 static void
1579 render_border (cairo_t       *cr,
1580                GtkRoundedBox *border_box,
1581                const double   border_width[4],
1582                guint          hidden_side,
1583                GdkRGBA        colors[4],
1584                GtkBorderStyle border_style[4])
1585 {
1586   guint i, j;
1587
1588   cairo_save (cr);
1589
1590   cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
1591
1592   for (i = 0; i < 4; i++)
1593     {
1594       if (hidden_side & (1 << i))
1595         continue;
1596
1597       switch (border_style[i])
1598         {
1599         case GTK_BORDER_STYLE_NONE:
1600         case GTK_BORDER_STYLE_HIDDEN:
1601         case GTK_BORDER_STYLE_SOLID:
1602           break;
1603         case GTK_BORDER_STYLE_INSET:
1604           if (i == 1 || i == 2)
1605             color_shade (&colors[i], 1.8, &colors[i]);
1606           break;
1607         case GTK_BORDER_STYLE_OUTSET:
1608           if (i == 0 || i == 3)
1609             color_shade (&colors[i], 1.8, &colors[i]);
1610           break;
1611         case GTK_BORDER_STYLE_DOTTED:
1612         case GTK_BORDER_STYLE_DASHED:
1613           {
1614             guint dont_draw = hidden_side;
1615
1616             for (j = 0; j < 4; j++)
1617               {
1618                 if (border_style[j] == border_style[i])
1619                   hidden_side |= (1 << j);
1620                 else
1621                   dont_draw |= (1 << j);
1622               }
1623             
1624             render_frame_stroke (cr, border_box, border_width, colors, dont_draw, border_style[i]);
1625           }
1626           break;
1627         case GTK_BORDER_STYLE_DOUBLE:
1628           {
1629             GtkRoundedBox other_box;
1630             double other_border[4];
1631             guint dont_draw = hidden_side;
1632
1633             for (j = 0; j < 4; j++)
1634               {
1635                 if (border_style[j] == GTK_BORDER_STYLE_DOUBLE)
1636                   hidden_side |= (1 << j);
1637                 else
1638                   dont_draw |= (1 << j);
1639                 
1640                 other_border[i] = border_width[i] / 3;
1641               }
1642             
1643             render_frame_fill (cr, border_box, other_border, colors, dont_draw);
1644             
1645             other_box = *border_box;
1646             _gtk_rounded_box_shrink (&other_box,
1647                                      2 * other_border[GTK_CSS_TOP],
1648                                      2 * other_border[GTK_CSS_RIGHT],
1649                                      2 * other_border[GTK_CSS_BOTTOM],
1650                                      2 * other_border[GTK_CSS_LEFT]);
1651             render_frame_fill (cr, &other_box, other_border, colors, dont_draw);
1652           }
1653           break;
1654         case GTK_BORDER_STYLE_GROOVE:
1655         case GTK_BORDER_STYLE_RIDGE:
1656           {
1657             GtkRoundedBox other_box;
1658             GdkRGBA other_colors[4];
1659             guint dont_draw = hidden_side;
1660             double other_border[4];
1661
1662             for (j = 0; j < 4; j++)
1663               {
1664                 other_colors[j] = colors[j];
1665                 if ((j == 0 || j == 3) ^ (border_style[j] == GTK_BORDER_STYLE_RIDGE))
1666                   color_shade (&other_colors[j], 1.8, &other_colors[j]);
1667                 else
1668                   color_shade (&colors[j], 1.8, &colors[j]);
1669                 if (border_style[j] == GTK_BORDER_STYLE_GROOVE ||
1670                     border_style[j] == GTK_BORDER_STYLE_RIDGE)
1671                   hidden_side |= (1 << j);
1672                 else
1673                   dont_draw |= (1 << j);
1674                 other_border[i] = border_width[i] / 2;
1675               }
1676             
1677             render_frame_fill (cr, border_box, other_border, colors, dont_draw);
1678             
1679             other_box = *border_box;
1680             _gtk_rounded_box_shrink (&other_box,
1681                                      other_border[GTK_CSS_TOP],
1682                                      other_border[GTK_CSS_RIGHT],
1683                                      other_border[GTK_CSS_BOTTOM],
1684                                      other_border[GTK_CSS_LEFT]);
1685             render_frame_fill (cr, &other_box, other_border, other_colors, dont_draw);
1686           }
1687           break;
1688         default:
1689           g_assert_not_reached ();
1690           break;
1691         }
1692     }
1693   
1694   render_frame_fill (cr, border_box, border_width, colors, hidden_side);
1695
1696   cairo_restore (cr);
1697 }
1698
1699 static void
1700 render_frame_internal (GtkThemingEngine *engine,
1701                        cairo_t          *cr,
1702                        gdouble           x,
1703                        gdouble           y,
1704                        gdouble           width,
1705                        gdouble           height,
1706                        guint             hidden_side,
1707                        GtkJunctionSides  junction)
1708 {
1709   GtkBorderImage border_image;
1710   GtkBorderStyle border_style[4];
1711   GtkRoundedBox border_box;
1712   double border_width[4];
1713   GdkRGBA colors[4];
1714
1715   border_width[0] = _gtk_css_number_value_get (_gtk_theming_engine_peek_property (engine, GTK_CSS_PROPERTY_BORDER_TOP_WIDTH), 100);
1716   border_width[1] = _gtk_css_number_value_get (_gtk_theming_engine_peek_property (engine, GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH), 100);
1717   border_width[2] = _gtk_css_number_value_get (_gtk_theming_engine_peek_property (engine, GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH), 100);
1718   border_width[3] = _gtk_css_number_value_get (_gtk_theming_engine_peek_property (engine, GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH), 100);
1719
1720   border_style[0] = _gtk_css_border_style_value_get (_gtk_theming_engine_peek_property (engine, GTK_CSS_PROPERTY_BORDER_TOP_STYLE));
1721   border_style[1] = _gtk_css_border_style_value_get (_gtk_theming_engine_peek_property (engine, GTK_CSS_PROPERTY_BORDER_RIGHT_STYLE));
1722   border_style[2] = _gtk_css_border_style_value_get (_gtk_theming_engine_peek_property (engine, GTK_CSS_PROPERTY_BORDER_BOTTOM_STYLE));
1723   border_style[3] = _gtk_css_border_style_value_get (_gtk_theming_engine_peek_property (engine, GTK_CSS_PROPERTY_BORDER_LEFT_STYLE));
1724
1725   gtk_theming_engine_hide_border_sides (border_width, border_style, hidden_side);
1726
1727   if (_gtk_border_image_init (&border_image, engine))
1728     _gtk_border_image_render (&border_image, border_width, cr, x, y, width, height);
1729   else
1730     {
1731       colors[0] = *_gtk_css_rgba_value_get_rgba (_gtk_theming_engine_peek_property (engine, GTK_CSS_PROPERTY_BORDER_TOP_COLOR));
1732       colors[1] = *_gtk_css_rgba_value_get_rgba (_gtk_theming_engine_peek_property (engine, GTK_CSS_PROPERTY_BORDER_RIGHT_COLOR));
1733       colors[2] = *_gtk_css_rgba_value_get_rgba (_gtk_theming_engine_peek_property (engine, GTK_CSS_PROPERTY_BORDER_BOTTOM_COLOR));
1734       colors[3] = *_gtk_css_rgba_value_get_rgba (_gtk_theming_engine_peek_property (engine, GTK_CSS_PROPERTY_BORDER_LEFT_COLOR));
1735
1736       _gtk_rounded_box_init_rect (&border_box, x, y, width, height);
1737       _gtk_rounded_box_apply_border_radius_for_engine (&border_box, engine, junction);
1738
1739       render_border (cr, &border_box, border_width, hidden_side, colors, border_style);
1740     }
1741
1742   border_style[0] = _gtk_css_border_style_value_get (_gtk_theming_engine_peek_property (engine, GTK_CSS_PROPERTY_OUTLINE_STYLE));
1743   if (border_style[0] != GTK_BORDER_STYLE_NONE)
1744     {
1745       int offset;
1746
1747       border_style[1] = border_style[2] = border_style[3] = border_style[0];
1748       border_width[0] = _gtk_css_number_value_get (_gtk_theming_engine_peek_property (engine, GTK_CSS_PROPERTY_OUTLINE_WIDTH), 100);
1749       border_width[3] = border_width[2] = border_width[1] = border_width[0];
1750       colors[0] = *_gtk_css_rgba_value_get_rgba (_gtk_theming_engine_peek_property (engine, GTK_CSS_PROPERTY_OUTLINE_COLOR));
1751       colors[3] = colors[2] = colors[1] = colors[0];
1752       offset = _gtk_css_number_value_get (_gtk_theming_engine_peek_property (engine, GTK_CSS_PROPERTY_OUTLINE_OFFSET), 100);
1753       
1754       /* reinit box here - outlines don't have a border radius */
1755       _gtk_rounded_box_init_rect (&border_box, x, y, width, height);
1756       _gtk_rounded_box_shrink (&border_box,
1757                                - border_width[GTK_CSS_TOP] - offset,
1758                                - border_width[GTK_CSS_RIGHT] - offset,
1759                                - border_width[GTK_CSS_LEFT] - offset,
1760                                - border_width[GTK_CSS_BOTTOM] - offset);
1761       
1762       render_border (cr, &border_box, border_width, hidden_side, colors, border_style);
1763     }
1764 }
1765
1766 static void
1767 gtk_theming_engine_render_frame (GtkThemingEngine *engine,
1768                                  cairo_t          *cr,
1769                                  gdouble           x,
1770                                  gdouble           y,
1771                                  gdouble           width,
1772                                  gdouble           height)
1773 {
1774   GtkJunctionSides junction;
1775
1776   junction = gtk_theming_engine_get_junction_sides (engine);
1777
1778   render_frame_internal (engine, cr,
1779                          x, y, width, height,
1780                          0, junction);
1781 }
1782
1783 static void
1784 gtk_theming_engine_render_expander (GtkThemingEngine *engine,
1785                                     cairo_t          *cr,
1786                                     gdouble           x,
1787                                     gdouble           y,
1788                                     gdouble           width,
1789                                     gdouble           height)
1790 {
1791   GtkStateFlags flags;
1792   GdkRGBA outline_color, fg_color;
1793   double vertical_overshoot;
1794   int diameter;
1795   double radius;
1796   double interp;                /* interpolation factor for center position */
1797   double x_double_horz, y_double_horz;
1798   double x_double_vert, y_double_vert;
1799   double x_double, y_double;
1800   gdouble angle;
1801   gint line_width;
1802   gboolean is_rtl;
1803   gdouble progress;
1804
1805   cairo_save (cr);
1806   flags = gtk_theming_engine_get_state (engine);
1807
1808   gtk_theming_engine_get_color (engine, flags, &fg_color);
1809   gtk_theming_engine_get_border_color (engine, flags, &outline_color);
1810
1811   is_rtl = (gtk_theming_engine_get_direction (engine) == GTK_TEXT_DIR_RTL);
1812   line_width = 1;
1813   progress = (flags & GTK_STATE_FLAG_ACTIVE) ? 1 : 0;
1814
1815   if (!gtk_theming_engine_has_class (engine, GTK_STYLE_CLASS_HORIZONTAL))
1816     {
1817       if (is_rtl)
1818         angle = (G_PI) - ((G_PI / 2) * progress);
1819       else
1820         angle = (G_PI / 2) * progress;
1821     }
1822   else
1823     {
1824       if (is_rtl)
1825         angle = (G_PI / 2) + ((G_PI / 2) * progress);
1826       else
1827         angle = (G_PI / 2) - ((G_PI / 2) * progress);
1828     }
1829
1830   interp = progress;
1831
1832   /* Compute distance that the stroke extends beyonds the end
1833    * of the triangle we draw.
1834    */
1835   vertical_overshoot = line_width / 2.0 * (1. / tan (G_PI / 8));
1836
1837   /* For odd line widths, we end the vertical line of the triangle
1838    * at a half pixel, so we round differently.
1839    */
1840   if (line_width % 2 == 1)
1841     vertical_overshoot = ceil (0.5 + vertical_overshoot) - 0.5;
1842   else
1843     vertical_overshoot = ceil (vertical_overshoot);
1844
1845   /* Adjust the size of the triangle we draw so that the entire stroke fits
1846    */
1847   diameter = (gint) MAX (3, width - 2 * vertical_overshoot);
1848
1849   /* If the line width is odd, we want the diameter to be even,
1850    * and vice versa, so force the sum to be odd. This relationship
1851    * makes the point of the triangle look right.
1852    */
1853   diameter -= (1 - (diameter + line_width) % 2);
1854
1855   radius = diameter / 2.;
1856
1857   /* Adjust the center so that the stroke is properly aligned with
1858    * the pixel grid. The center adjustment is different for the
1859    * horizontal and vertical orientations. For intermediate positions
1860    * we interpolate between the two.
1861    */
1862   x_double_vert = floor ((x + width / 2) - (radius + line_width) / 2.) + (radius + line_width) / 2.;
1863   y_double_vert = (y + height / 2) - 0.5;
1864
1865   x_double_horz = (x + width / 2) - 0.5;
1866   y_double_horz = floor ((y + height / 2) - (radius + line_width) / 2.) + (radius + line_width) / 2.;
1867
1868   x_double = x_double_vert * (1 - interp) + x_double_horz * interp;
1869   y_double = y_double_vert * (1 - interp) + y_double_horz * interp;
1870
1871   cairo_translate (cr, x_double, y_double);
1872   cairo_rotate (cr, angle);
1873
1874   cairo_move_to (cr, - radius / 2., - radius);
1875   cairo_line_to (cr,   radius / 2.,   0);
1876   cairo_line_to (cr, - radius / 2.,   radius);
1877   cairo_close_path (cr);
1878
1879   cairo_set_line_width (cr, line_width);
1880
1881   gdk_cairo_set_source_rgba (cr, &fg_color);
1882
1883   cairo_fill_preserve (cr);
1884
1885   gdk_cairo_set_source_rgba (cr, &outline_color);
1886   cairo_stroke (cr);
1887
1888   cairo_restore (cr);
1889 }
1890
1891 static void
1892 gtk_theming_engine_render_focus (GtkThemingEngine *engine,
1893                                  cairo_t          *cr,
1894                                  gdouble           x,
1895                                  gdouble           y,
1896                                  gdouble           width,
1897                                  gdouble           height)
1898 {
1899   GtkStateFlags flags;
1900   GdkRGBA color;
1901   gint line_width;
1902   gint8 *dash_list;
1903
1904   cairo_save (cr);
1905   flags = gtk_theming_engine_get_state (engine);
1906
1907   gtk_theming_engine_get_color (engine, flags, &color);
1908
1909   gtk_theming_engine_get_style (engine,
1910                                 "focus-line-width", &line_width,
1911                                 "focus-line-pattern", (gchar *) &dash_list,
1912                                 NULL);
1913
1914   cairo_set_line_width (cr, (gdouble) line_width);
1915
1916   if (dash_list[0])
1917     {
1918       gint n_dashes = strlen ((const gchar *) dash_list);
1919       gdouble *dashes = g_new (gdouble, n_dashes);
1920       gdouble total_length = 0;
1921       gdouble dash_offset;
1922       gint i;
1923
1924       for (i = 0; i < n_dashes; i++)
1925         {
1926           dashes[i] = dash_list[i];
1927           total_length += dash_list[i];
1928         }
1929
1930       /* The dash offset here aligns the pattern to integer pixels
1931        * by starting the dash at the right side of the left border
1932        * Negative dash offsets in cairo don't work
1933        * (https://bugs.freedesktop.org/show_bug.cgi?id=2729)
1934        */
1935       dash_offset = - line_width / 2.;
1936
1937       while (dash_offset < 0)
1938         dash_offset += total_length;
1939
1940       cairo_set_dash (cr, dashes, n_dashes, dash_offset);
1941       g_free (dashes);
1942     }
1943
1944   cairo_rectangle (cr,
1945                    x + line_width / 2.,
1946                    y + line_width / 2.,
1947                    width - line_width,
1948                    height - line_width);
1949
1950   gdk_cairo_set_source_rgba (cr, &color);
1951   cairo_stroke (cr);
1952
1953   cairo_restore (cr);
1954
1955   g_free (dash_list);
1956 }
1957
1958 static void
1959 gtk_theming_engine_render_line (GtkThemingEngine *engine,
1960                                 cairo_t          *cr,
1961                                 gdouble           x0,
1962                                 gdouble           y0,
1963                                 gdouble           x1,
1964                                 gdouble           y1)
1965 {
1966   GdkRGBA color;
1967   GtkStateFlags flags;
1968
1969   flags = gtk_theming_engine_get_state (engine);
1970   cairo_save (cr);
1971
1972   gtk_theming_engine_get_color (engine, flags, &color);
1973
1974   cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
1975   cairo_set_line_width (cr, 1);
1976
1977   cairo_move_to (cr, x0 + 0.5, y0 + 0.5);
1978   cairo_line_to (cr, x1 + 0.5, y1 + 0.5);
1979
1980   gdk_cairo_set_source_rgba (cr, &color);
1981   cairo_stroke (cr);
1982
1983   cairo_restore (cr);
1984 }
1985
1986 static void
1987 prepare_context_for_layout (cairo_t *cr,
1988                             gdouble x,
1989                             gdouble y,
1990                             PangoLayout *layout)
1991 {
1992   const PangoMatrix *matrix;
1993
1994   matrix = pango_context_get_matrix (pango_layout_get_context (layout));
1995
1996   cairo_move_to (cr, x, y);
1997
1998   if (matrix)
1999     {
2000       cairo_matrix_t cairo_matrix;
2001
2002       cairo_matrix_init (&cairo_matrix,
2003                          matrix->xx, matrix->yx,
2004                          matrix->xy, matrix->yy,
2005                          matrix->x0, matrix->y0);
2006
2007       cairo_transform (cr, &cairo_matrix);
2008     }
2009 }
2010
2011 static void
2012 gtk_theming_engine_render_layout (GtkThemingEngine *engine,
2013                                   cairo_t          *cr,
2014                                   gdouble           x,
2015                                   gdouble           y,
2016                                   PangoLayout      *layout)
2017 {
2018   GdkRGBA fg_color;
2019   GtkStateFlags flags;
2020
2021   cairo_save (cr);
2022   flags = gtk_theming_engine_get_state (engine);
2023   gtk_theming_engine_get_color (engine, flags, &fg_color);
2024
2025   prepare_context_for_layout (cr, x, y, layout);
2026
2027   _gtk_css_shadows_value_paint_layout (_gtk_theming_engine_peek_property (engine, GTK_CSS_PROPERTY_TEXT_SHADOW),
2028                                        cr, layout);
2029
2030   gdk_cairo_set_source_rgba (cr, &fg_color);
2031   pango_cairo_show_layout (cr, layout);
2032
2033   cairo_restore (cr);
2034 }
2035
2036 static void
2037 gtk_theming_engine_render_slider (GtkThemingEngine *engine,
2038                                   cairo_t          *cr,
2039                                   gdouble           x,
2040                                   gdouble           y,
2041                                   gdouble           width,
2042                                   gdouble           height,
2043                                   GtkOrientation    orientation)
2044 {
2045   gtk_theming_engine_render_background (engine, cr, x, y, width, height);
2046   gtk_theming_engine_render_frame (engine, cr, x, y, width, height);
2047 }
2048
2049 static void
2050 gtk_theming_engine_render_frame_gap (GtkThemingEngine *engine,
2051                                      cairo_t          *cr,
2052                                      gdouble           x,
2053                                      gdouble           y,
2054                                      gdouble           width,
2055                                      gdouble           height,
2056                                      GtkPositionType   gap_side,
2057                                      gdouble           xy0_gap,
2058                                      gdouble           xy1_gap)
2059 {
2060   GtkJunctionSides junction;
2061   GtkStateFlags state;
2062   gint border_width;
2063   GtkCssValue *corner[4];
2064   gdouble x0, y0, x1, y1, xc, yc, wc, hc;
2065   GtkBorder border;
2066
2067   xc = yc = wc = hc = 0;
2068   state = gtk_theming_engine_get_state (engine);
2069   junction = gtk_theming_engine_get_junction_sides (engine);
2070
2071   gtk_theming_engine_get_border (engine, state, &border);
2072   corner[GTK_CSS_TOP_LEFT] = _gtk_theming_engine_peek_property (engine, GTK_CSS_PROPERTY_BORDER_TOP_LEFT_RADIUS);
2073   corner[GTK_CSS_TOP_RIGHT] = _gtk_theming_engine_peek_property (engine, GTK_CSS_PROPERTY_BORDER_TOP_RIGHT_RADIUS);
2074   corner[GTK_CSS_BOTTOM_LEFT] = _gtk_theming_engine_peek_property (engine, GTK_CSS_PROPERTY_BORDER_BOTTOM_LEFT_RADIUS);
2075   corner[GTK_CSS_BOTTOM_RIGHT] = _gtk_theming_engine_peek_property (engine, GTK_CSS_PROPERTY_BORDER_BOTTOM_RIGHT_RADIUS);
2076
2077   border_width = MIN (MIN (border.top, border.bottom),
2078                       MIN (border.left, border.right));
2079
2080   cairo_save (cr);
2081
2082   switch (gap_side)
2083     {
2084     case GTK_POS_TOP:
2085       xc = x + xy0_gap + border_width;
2086       yc = y;
2087       wc = MAX (xy1_gap - xy0_gap - 2 * border_width, 0);
2088       hc = border_width;
2089
2090       if (xy0_gap < _gtk_css_corner_value_get_x (corner[GTK_CSS_TOP_LEFT], width))
2091         junction |= GTK_JUNCTION_CORNER_TOPLEFT;
2092
2093       if (xy1_gap > width - _gtk_css_corner_value_get_x (corner[GTK_CSS_TOP_RIGHT], width))
2094         junction |= GTK_JUNCTION_CORNER_TOPRIGHT;
2095       break;
2096     case GTK_POS_BOTTOM:
2097       xc = x + xy0_gap + border_width;
2098       yc = y + height - border_width;
2099       wc = MAX (xy1_gap - xy0_gap - 2 * border_width, 0);
2100       hc = border_width;
2101
2102       if (xy0_gap < _gtk_css_corner_value_get_x (corner[GTK_CSS_BOTTOM_LEFT], width))
2103         junction |= GTK_JUNCTION_CORNER_BOTTOMLEFT;
2104
2105       if (xy1_gap > width - _gtk_css_corner_value_get_x (corner[GTK_CSS_BOTTOM_RIGHT], width))
2106         junction |= GTK_JUNCTION_CORNER_BOTTOMRIGHT;
2107
2108       break;
2109     case GTK_POS_LEFT:
2110       xc = x;
2111       yc = y + xy0_gap + border_width;
2112       wc = border_width;
2113       hc = MAX (xy1_gap - xy0_gap - 2 * border_width, 0);
2114
2115       if (xy0_gap < _gtk_css_corner_value_get_y (corner[GTK_CSS_TOP_LEFT], height))
2116         junction |= GTK_JUNCTION_CORNER_TOPLEFT;
2117
2118       if (xy1_gap > height - _gtk_css_corner_value_get_y (corner[GTK_CSS_BOTTOM_LEFT], height))
2119         junction |= GTK_JUNCTION_CORNER_BOTTOMLEFT;
2120
2121       break;
2122     case GTK_POS_RIGHT:
2123       xc = x + width - border_width;
2124       yc = y + xy0_gap + border_width;
2125       wc = border_width;
2126       hc = MAX (xy1_gap - xy0_gap - 2 * border_width, 0);
2127
2128       if (xy0_gap < _gtk_css_corner_value_get_y (corner[GTK_CSS_TOP_RIGHT], height))
2129         junction |= GTK_JUNCTION_CORNER_TOPRIGHT;
2130
2131       if (xy1_gap > height - _gtk_css_corner_value_get_y (corner[GTK_CSS_BOTTOM_RIGHT], height))
2132         junction |= GTK_JUNCTION_CORNER_BOTTOMRIGHT;
2133
2134       break;
2135     }
2136
2137   cairo_clip_extents (cr, &x0, &y0, &x1, &y1);
2138   cairo_rectangle (cr, x0, y0, x1 - x0, yc - y0);
2139   cairo_rectangle (cr, x0, yc, xc - x0, hc);
2140   cairo_rectangle (cr, xc + wc, yc, x1 - (xc + wc), hc);
2141   cairo_rectangle (cr, x0, yc + hc, x1 - x0, y1 - (yc + hc));
2142   cairo_clip (cr);
2143
2144   render_frame_internal (engine, cr,
2145                          x, y, width, height,
2146                          0, junction);
2147
2148   cairo_restore (cr);
2149 }
2150
2151 static void
2152 gtk_theming_engine_render_extension (GtkThemingEngine *engine,
2153                                      cairo_t          *cr,
2154                                      gdouble           x,
2155                                      gdouble           y,
2156                                      gdouble           width,
2157                                      gdouble           height,
2158                                      GtkPositionType   gap_side)
2159 {
2160   GtkThemingBackground bg;
2161   GtkJunctionSides junction = 0;
2162   guint hidden_side = 0;
2163
2164   switch (gap_side)
2165     {
2166     case GTK_POS_LEFT:
2167       junction = GTK_JUNCTION_LEFT;
2168       hidden_side = (1 << GTK_CSS_LEFT);
2169       break;
2170     case GTK_POS_RIGHT:
2171       junction = GTK_JUNCTION_RIGHT;
2172       hidden_side = (1 << GTK_CSS_RIGHT);
2173       break;
2174     case GTK_POS_TOP:
2175       junction = GTK_JUNCTION_TOP;
2176       hidden_side = (1 << GTK_CSS_TOP);
2177       break;
2178     case GTK_POS_BOTTOM:
2179       junction = GTK_JUNCTION_BOTTOM;
2180       hidden_side = (1 << GTK_CSS_BOTTOM);
2181       break;
2182     }
2183
2184   _gtk_theming_background_init (&bg, engine, 
2185                                 x, y,
2186                                 width, height,
2187                                 junction);
2188   _gtk_theming_background_render (&bg, cr);
2189
2190   render_frame_internal (engine, cr,
2191                          x, y, width, height,
2192                          hidden_side, junction);
2193 }
2194
2195 static void
2196 render_dot (cairo_t       *cr,
2197             const GdkRGBA *lighter,
2198             const GdkRGBA *darker,
2199             gdouble        x,
2200             gdouble        y,
2201             gdouble        size)
2202 {
2203   size = CLAMP ((gint) size, 2, 3);
2204
2205   if (size == 2)
2206     {
2207       gdk_cairo_set_source_rgba (cr, lighter);
2208       cairo_rectangle (cr, x, y, 1, 1);
2209       cairo_rectangle (cr, x + 1, y + 1, 1, 1);
2210       cairo_fill (cr);
2211     }
2212   else if (size == 3)
2213     {
2214       gdk_cairo_set_source_rgba (cr, lighter);
2215       cairo_rectangle (cr, x, y, 2, 1);
2216       cairo_rectangle (cr, x, y, 1, 2);
2217       cairo_fill (cr);
2218
2219       gdk_cairo_set_source_rgba (cr, darker);
2220       cairo_rectangle (cr, x + 1, y + 1, 2, 1);
2221       cairo_rectangle (cr, x + 2, y, 1, 2);
2222       cairo_fill (cr);
2223     }
2224 }
2225
2226 static void
2227 gtk_theming_engine_render_handle (GtkThemingEngine *engine,
2228                                   cairo_t          *cr,
2229                                   gdouble           x,
2230                                   gdouble           y,
2231                                   gdouble           width,
2232                                   gdouble           height)
2233 {
2234   GtkStateFlags flags;
2235   GdkRGBA bg_color, lighter, darker;
2236   GtkJunctionSides sides;
2237   GtkThemingBackground bg;
2238   gint xx, yy;
2239   gboolean has_image;
2240
2241   cairo_save (cr);
2242   flags = gtk_theming_engine_get_state (engine);
2243
2244   cairo_set_line_width (cr, 1.0);
2245   sides = gtk_theming_engine_get_junction_sides (engine);
2246   gtk_theming_engine_get_background_color (engine, flags, &bg_color);
2247
2248   color_shade (&bg_color, 0.7, &darker);
2249   color_shade (&bg_color, 1.3, &lighter);
2250
2251   _gtk_theming_background_init (&bg, engine, x, y, width, height, sides);
2252   has_image = _gtk_theming_background_has_background_image (&bg);
2253   _gtk_theming_background_render (&bg, cr);
2254
2255   gtk_theming_engine_render_frame (engine, cr, x, y, width, height);
2256
2257   if (gtk_theming_engine_has_class (engine, GTK_STYLE_CLASS_GRIP))
2258     {
2259       /* reduce confusing values to a meaningful state */
2260       if ((sides & (GTK_JUNCTION_CORNER_TOPLEFT | GTK_JUNCTION_CORNER_BOTTOMRIGHT)) == (GTK_JUNCTION_CORNER_TOPLEFT | GTK_JUNCTION_CORNER_BOTTOMRIGHT))
2261         sides &= ~GTK_JUNCTION_CORNER_TOPLEFT;
2262
2263       if ((sides & (GTK_JUNCTION_CORNER_TOPRIGHT | GTK_JUNCTION_CORNER_BOTTOMLEFT)) == (GTK_JUNCTION_CORNER_TOPRIGHT | GTK_JUNCTION_CORNER_BOTTOMLEFT))
2264         sides &= ~GTK_JUNCTION_CORNER_TOPRIGHT;
2265
2266       if (sides == 0)
2267         sides = GTK_JUNCTION_CORNER_BOTTOMRIGHT;
2268
2269       /* align drawing area to the connected side */
2270       if (sides == GTK_JUNCTION_LEFT)
2271         {
2272           if (height < width)
2273             width = height;
2274         }
2275       else if (sides == GTK_JUNCTION_CORNER_TOPLEFT)
2276         {
2277           if (width < height)
2278             height = width;
2279           else if (height < width)
2280             width = height;
2281         }
2282       else if (sides == GTK_JUNCTION_CORNER_BOTTOMLEFT)
2283         {
2284           /* make it square, aligning to bottom left */
2285           if (width < height)
2286             {
2287               y += (height - width);
2288               height = width;
2289             }
2290           else if (height < width)
2291             width = height;
2292         }
2293       else if (sides == GTK_JUNCTION_RIGHT)
2294         {
2295           /* aligning to right */
2296           if (height < width)
2297             {
2298               x += (width - height);
2299               width = height;
2300             }
2301         }
2302       else if (sides == GTK_JUNCTION_CORNER_TOPRIGHT)
2303         {
2304           if (width < height)
2305             height = width;
2306           else if (height < width)
2307             {
2308               x += (width - height);
2309               width = height;
2310             }
2311         }
2312       else if (sides == GTK_JUNCTION_CORNER_BOTTOMRIGHT)
2313         {
2314           /* make it square, aligning to bottom right */
2315           if (width < height)
2316             {
2317               y += (height - width);
2318               height = width;
2319             }
2320           else if (height < width)
2321             {
2322               x += (width - height);
2323               width = height;
2324             }
2325         }
2326       else if (sides == GTK_JUNCTION_TOP)
2327         {
2328           if (width < height)
2329             height = width;
2330         }
2331       else if (sides == GTK_JUNCTION_BOTTOM)
2332         {
2333           /* align to bottom */
2334           if (width < height)
2335             {
2336               y += (height - width);
2337               height = width;
2338             }
2339         }
2340       else
2341         g_assert_not_reached ();
2342
2343       if (sides == GTK_JUNCTION_LEFT ||
2344           sides == GTK_JUNCTION_RIGHT)
2345         {
2346           gint xi;
2347
2348           xi = x;
2349
2350           while (xi < x + width)
2351             {
2352               gdk_cairo_set_source_rgba (cr, &lighter);
2353               add_path_line (cr, x, y, x, y + height);
2354               cairo_stroke (cr);
2355               xi++;
2356
2357               gdk_cairo_set_source_rgba (cr, &darker);
2358               add_path_line (cr, xi, y, xi, y + height);
2359               cairo_stroke (cr);
2360               xi += 2;
2361             }
2362         }
2363       else if (sides == GTK_JUNCTION_TOP ||
2364                sides == GTK_JUNCTION_BOTTOM)
2365         {
2366           gint yi;
2367
2368           yi = y;
2369
2370           while (yi < y + height)
2371             {
2372               gdk_cairo_set_source_rgba (cr, &lighter);
2373               add_path_line (cr, x, yi, x + width, yi);
2374               cairo_stroke (cr);
2375               yi++;
2376
2377               gdk_cairo_set_source_rgba (cr, &darker);
2378               add_path_line (cr, x, yi, x + width, yi);
2379               cairo_stroke (cr);
2380               yi += 2;
2381             }
2382         }
2383       else if (sides == GTK_JUNCTION_CORNER_TOPLEFT)
2384         {
2385           gint xi, yi;
2386
2387           xi = x + width;
2388           yi = y + height;
2389
2390           while (xi > x + 3)
2391             {
2392               gdk_cairo_set_source_rgba (cr, &darker);
2393               add_path_line (cr, xi, y, x, yi);
2394               cairo_stroke (cr);
2395
2396               --xi;
2397               --yi;
2398
2399               add_path_line (cr, xi, y, x, yi);
2400               cairo_stroke (cr);
2401
2402               --xi;
2403               --yi;
2404
2405               gdk_cairo_set_source_rgba (cr, &lighter);
2406               add_path_line (cr, xi, y, x, yi);
2407               cairo_stroke (cr);
2408
2409               xi -= 3;
2410               yi -= 3;
2411             }
2412         }
2413       else if (sides == GTK_JUNCTION_CORNER_TOPRIGHT)
2414         {
2415           gint xi, yi;
2416
2417           xi = x;
2418           yi = y + height;
2419
2420           while (xi < (x + width - 3))
2421             {
2422               gdk_cairo_set_source_rgba (cr, &lighter);
2423               add_path_line (cr, xi, y, x + width, yi);
2424               cairo_stroke (cr);
2425
2426               ++xi;
2427               --yi;
2428
2429               gdk_cairo_set_source_rgba (cr, &darker);
2430               add_path_line (cr, xi, y, x + width, yi);
2431               cairo_stroke (cr);
2432
2433               ++xi;
2434               --yi;
2435
2436               add_path_line (cr, xi, y, x + width, yi);
2437               cairo_stroke (cr);
2438
2439               xi += 3;
2440               yi -= 3;
2441             }
2442         }
2443       else if (sides == GTK_JUNCTION_CORNER_BOTTOMLEFT)
2444         {
2445           gint xi, yi;
2446
2447           xi = x + width;
2448           yi = y;
2449
2450           while (xi > x + 3)
2451             {
2452               gdk_cairo_set_source_rgba (cr, &darker);
2453               add_path_line (cr, x, yi, xi, y + height);
2454               cairo_stroke (cr);
2455
2456               --xi;
2457               ++yi;
2458
2459               add_path_line (cr, x, yi, xi, y + height);
2460               cairo_stroke (cr);
2461
2462               --xi;
2463               ++yi;
2464
2465               gdk_cairo_set_source_rgba (cr, &lighter);
2466               add_path_line (cr, x, yi, xi, y + height);
2467               cairo_stroke (cr);
2468
2469               xi -= 3;
2470               yi += 3;
2471             }
2472         }
2473       else if (sides == GTK_JUNCTION_CORNER_BOTTOMRIGHT)
2474         {
2475           gint xi, yi;
2476
2477           xi = x;
2478           yi = y;
2479
2480           while (xi < (x + width - 3))
2481             {
2482               gdk_cairo_set_source_rgba (cr, &lighter);
2483               add_path_line (cr, xi, y + height, x + width, yi);
2484               cairo_stroke (cr);
2485
2486               ++xi;
2487               ++yi;
2488
2489               gdk_cairo_set_source_rgba (cr, &darker);
2490               add_path_line (cr, xi, y + height, x + width, yi);
2491               cairo_stroke (cr);
2492
2493               ++xi;
2494               ++yi;
2495
2496               add_path_line (cr, xi, y + height, x + width, yi);
2497               cairo_stroke (cr);
2498
2499               xi += 3;
2500               yi += 3;
2501             }
2502         }
2503     }
2504   else if (gtk_theming_engine_has_class (engine, GTK_STYLE_CLASS_PANE_SEPARATOR))
2505     {
2506       if (!has_image)
2507         {
2508           if (width > height)
2509             for (xx = x + width / 2 - 15; xx <= x + width / 2 + 15; xx += 5)
2510               render_dot (cr, &lighter, &darker, xx, y + height / 2 - 1, 3);
2511           else
2512             for (yy = y + height / 2 - 15; yy <= y + height / 2 + 15; yy += 5)
2513               render_dot (cr, &lighter, &darker, x + width / 2 - 1, yy, 3);
2514         }
2515     }
2516   else
2517     {
2518       for (yy = y; yy < y + height; yy += 3)
2519         for (xx = x; xx < x + width; xx += 6)
2520           {
2521             render_dot (cr, &lighter, &darker, xx, yy, 2);
2522             render_dot (cr, &lighter, &darker, xx + 3, yy + 1, 2);
2523           }
2524     }
2525
2526   cairo_restore (cr);
2527 }
2528
2529 void
2530 _gtk_theming_engine_paint_spinner (cairo_t       *cr,
2531                                    gdouble        radius,
2532                                    gdouble        progress,
2533                                    const GdkRGBA *color)
2534 {
2535   guint num_steps, step;
2536   gdouble half;
2537   gint i;
2538
2539   num_steps = 12;
2540
2541   if (progress >= 0)
2542     step = (guint) (progress * num_steps);
2543   else
2544     step = 0;
2545
2546   cairo_save (cr);
2547
2548   cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
2549   cairo_set_line_width (cr, 2.0);
2550
2551   half = num_steps / 2;
2552
2553   for (i = 0; i < num_steps; i++)
2554     {
2555       gint inset = 0.7 * radius;
2556
2557       /* transparency is a function of time and intial value */
2558       gdouble t = 1.0 - (gdouble) ((i + step) % num_steps) / num_steps;
2559       gdouble xscale = - sin (i * G_PI / half);
2560       gdouble yscale = - cos (i * G_PI / half);
2561
2562       cairo_set_source_rgba (cr,
2563                              color->red,
2564                              color->green,
2565                              color->blue,
2566                              color->alpha * t);
2567
2568       cairo_move_to (cr,
2569                      (radius - inset) * xscale,
2570                      (radius - inset) * yscale);
2571       cairo_line_to (cr,
2572                      radius * xscale,
2573                      radius * yscale);
2574
2575       cairo_stroke (cr);
2576     }
2577
2578   cairo_restore (cr);
2579 }
2580
2581 static void
2582 render_spinner (GtkThemingEngine *engine,
2583                 cairo_t          *cr,
2584                 gdouble           x,
2585                 gdouble           y,
2586                 gdouble           width,
2587                 gdouble           height)
2588 {
2589   GtkStateFlags state;
2590   GdkRGBA color;
2591   gdouble radius;
2592
2593   state = gtk_theming_engine_get_state (engine);
2594   radius = MIN (width / 2, height / 2);
2595
2596   gtk_theming_engine_get_color (engine, state, &color);
2597
2598   cairo_save (cr);
2599   cairo_translate (cr, x + width / 2, y + height / 2);
2600
2601   _gtk_css_shadows_value_paint_spinner (_gtk_theming_engine_peek_property (engine, GTK_CSS_PROPERTY_ICON_SHADOW),
2602                                         cr,
2603                                         radius,
2604                                         -1);
2605
2606   _gtk_theming_engine_paint_spinner (cr,
2607                                      radius,
2608                                      -1,
2609                                      &color);
2610
2611   cairo_restore (cr);
2612 }
2613
2614 static void
2615 gtk_theming_engine_render_activity (GtkThemingEngine *engine,
2616                                     cairo_t          *cr,
2617                                     gdouble           x,
2618                                     gdouble           y,
2619                                     gdouble           width,
2620                                     gdouble           height)
2621 {
2622   GtkThemingBackground bg;
2623   
2624   _gtk_theming_background_init (&bg, engine, x, y, width, height, 0);
2625   
2626   if (gtk_theming_engine_has_class (engine, GTK_STYLE_CLASS_SPINNER) &&
2627       !_gtk_theming_background_has_background_image (&bg))
2628     {
2629       render_spinner (engine, cr, x, y, width, height);
2630     }
2631   else
2632     {
2633       _gtk_theming_background_render (&bg, cr);
2634       gtk_theming_engine_render_frame (engine, cr, x, y, width, height);
2635     }
2636 }
2637
2638 static GdkPixbuf *
2639 scale_or_ref (GdkPixbuf *src,
2640               gint       width,
2641               gint       height)
2642 {
2643   if (width == gdk_pixbuf_get_width (src) &&
2644       height == gdk_pixbuf_get_height (src))
2645     return g_object_ref (src);
2646   else
2647     return gdk_pixbuf_scale_simple (src,
2648                                     width, height,
2649                                     GDK_INTERP_BILINEAR);
2650 }
2651
2652 static gboolean
2653 lookup_icon_size (GtkThemingEngine *engine,
2654                   GtkIconSize       size,
2655                   gint             *width,
2656                   gint             *height)
2657 {
2658   GdkScreen *screen;
2659   GtkSettings *settings;
2660
2661   screen = gtk_theming_engine_get_screen (engine);
2662   settings = gtk_settings_get_for_screen (screen);
2663
2664   return gtk_icon_size_lookup_for_settings (settings, size, width, height);
2665 }
2666
2667 static void
2668 colorshift_source (cairo_t *cr,
2669                    gdouble shift)
2670 {
2671   cairo_pattern_t *source;
2672
2673   cairo_save (cr);
2674   cairo_paint (cr);
2675
2676   source = cairo_pattern_reference (cairo_get_source (cr));
2677
2678   cairo_set_source_rgb (cr, shift, shift, shift);
2679   cairo_set_operator (cr, CAIRO_OPERATOR_COLOR_DODGE);
2680
2681   cairo_mask (cr, source);
2682
2683   cairo_pattern_destroy (source);
2684   cairo_restore (cr);
2685 }
2686
2687 static GdkPixbuf *
2688 gtk_theming_engine_render_icon_pixbuf (GtkThemingEngine    *engine,
2689                                        const GtkIconSource *source,
2690                                        GtkIconSize          size)
2691 {
2692   GdkPixbuf *scaled;
2693   GdkPixbuf *stated;
2694   GdkPixbuf *base_pixbuf;
2695   GtkStateFlags state;
2696   gint width = 1;
2697   gint height = 1;
2698   cairo_t *cr;
2699   cairo_surface_t *surface;
2700
2701   base_pixbuf = gtk_icon_source_get_pixbuf (source);
2702   state = gtk_theming_engine_get_state (engine);
2703
2704   g_return_val_if_fail (base_pixbuf != NULL, NULL);
2705
2706   if (size != (GtkIconSize) -1 &&
2707       !lookup_icon_size (engine, size, &width, &height))
2708     {
2709       g_warning (G_STRLOC ": invalid icon size '%d'", size);
2710       return NULL;
2711     }
2712
2713   /* If the size was wildcarded, and we're allowed to scale, then scale; otherwise,
2714    * leave it alone.
2715    */
2716   if (size != (GtkIconSize) -1 &&
2717       gtk_icon_source_get_size_wildcarded (source))
2718     scaled = scale_or_ref (base_pixbuf, width, height);
2719   else
2720     scaled = g_object_ref (base_pixbuf);
2721
2722   /* If the state was wildcarded, then generate a state. */
2723   if (gtk_icon_source_get_state_wildcarded (source))
2724     {
2725       if (state & GTK_STATE_FLAG_INSENSITIVE)
2726         {
2727           surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
2728                                                 gdk_pixbuf_get_width (scaled),
2729                                                 gdk_pixbuf_get_height (scaled));
2730           cr = cairo_create (surface);
2731           gdk_cairo_set_source_pixbuf (cr, scaled, 0, 0);
2732           cairo_paint_with_alpha (cr, 0.5);
2733
2734           cairo_destroy (cr);
2735
2736           g_object_unref (scaled);
2737           stated = gdk_pixbuf_get_from_surface (surface, 0, 0,
2738                                                 cairo_image_surface_get_width (surface),
2739                                                 cairo_image_surface_get_height (surface));
2740           cairo_surface_destroy (surface);
2741         }
2742       else if (state & GTK_STATE_FLAG_PRELIGHT)
2743         {
2744           surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
2745                                                 gdk_pixbuf_get_width (scaled),
2746                                                 gdk_pixbuf_get_height (scaled));
2747
2748           cr = cairo_create (surface);
2749           gdk_cairo_set_source_pixbuf (cr, scaled, 0, 0);
2750           colorshift_source (cr, 0.10);
2751
2752           cairo_destroy (cr);
2753
2754           g_object_unref (scaled);
2755           stated = gdk_pixbuf_get_from_surface (surface, 0, 0,
2756                                                 cairo_image_surface_get_width (surface),
2757                                                 cairo_image_surface_get_height (surface));
2758           cairo_surface_destroy (surface);
2759         }
2760       else
2761         stated = scaled;
2762     }
2763   else
2764     stated = scaled;
2765
2766   return stated;
2767 }
2768
2769 static void
2770 gtk_theming_engine_render_icon (GtkThemingEngine *engine,
2771                                 cairo_t *cr,
2772                                 GdkPixbuf *pixbuf,
2773                                 gdouble x,
2774                                 gdouble y)
2775 {
2776   cairo_save (cr);
2777
2778   gdk_cairo_set_source_pixbuf (cr, pixbuf, x, y);
2779
2780   _gtk_css_shadows_value_paint_icon (_gtk_theming_engine_peek_property (engine, GTK_CSS_PROPERTY_ICON_SHADOW), cr);
2781
2782   cairo_paint (cr);
2783
2784   cairo_restore (cr);
2785 }
2786