]> Pileus Git - ~andy/gtk/blob - gtk/gtkthemingengine.c
49dbe44dd615542876557df6ce735689239b7b0e
[~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, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "config.h"
21
22 #include <gtk/gtk.h>
23
24 #include <gtk/gtkthemingengine.h>
25 #include <gtk/gtkstylecontext.h>
26 #include <gtk/gtkintl.h>
27
28 #include "gtkalias.h"
29
30 typedef struct GtkThemingEnginePrivate GtkThemingEnginePrivate;
31
32 enum {
33   SIDE_LEFT   = 1,
34   SIDE_BOTTOM = 1 << 1,
35   SIDE_RIGHT  = 1 << 2,
36   SIDE_TOP    = 1 << 3
37 };
38
39 struct GtkThemingEnginePrivate
40 {
41   GtkStyleContext *context;
42 };
43
44 #define GTK_THEMING_ENGINE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_THEMING_ENGINE, GtkThemingEnginePrivate))
45
46 static void gtk_theming_engine_render_check (GtkThemingEngine *engine,
47                                              cairo_t          *cr,
48                                              gdouble           x,
49                                              gdouble           y,
50                                              gdouble           width,
51                                              gdouble           height);
52 static void gtk_theming_engine_render_option (GtkThemingEngine *engine,
53                                               cairo_t          *cr,
54                                               gdouble           x,
55                                               gdouble           y,
56                                               gdouble           width,
57                                               gdouble           height);
58 static void gtk_theming_engine_render_arrow  (GtkThemingEngine *engine,
59                                               cairo_t          *cr,
60                                               gdouble           angle,
61                                               gdouble           x,
62                                               gdouble           y,
63                                               gdouble           size);
64 static void gtk_theming_engine_render_background (GtkThemingEngine *engine,
65                                                   cairo_t          *cr,
66                                                   gdouble           x,
67                                                   gdouble           y,
68                                                   gdouble           width,
69                                                   gdouble           height);
70 static void gtk_theming_engine_render_frame  (GtkThemingEngine *engine,
71                                               cairo_t          *cr,
72                                               gdouble           x,
73                                               gdouble           y,
74                                               gdouble           width,
75                                               gdouble           height);
76 static void gtk_theming_engine_render_expander (GtkThemingEngine *engine,
77                                                 cairo_t          *cr,
78                                                 gdouble           x,
79                                                 gdouble           y,
80                                                 gdouble           width,
81                                                 gdouble           height);
82 static void gtk_theming_engine_render_focus    (GtkThemingEngine *engine,
83                                                 cairo_t          *cr,
84                                                 gdouble           x,
85                                                 gdouble           y,
86                                                 gdouble           width,
87                                                 gdouble           height);
88
89 G_DEFINE_TYPE (GtkThemingEngine, gtk_theming_engine, G_TYPE_OBJECT)
90
91
92 typedef struct GtkThemingModule GtkThemingModule;
93 typedef struct GtkThemingModuleClass GtkThemingModuleClass;
94
95 struct GtkThemingModule
96 {
97   GTypeModule parent_instance;
98   gchar *name;
99
100   GtkThemingEngine * (*create_engine) (void);
101 };
102
103 struct GtkThemingModuleClass
104 {
105   GTypeModuleClass parent_class;
106 };
107
108 #define GTK_TYPE_THEMING_MODULE  (gtk_theming_module_get_type ())
109 #define GTK_THEMING_MODULE(o)    (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_THEMING_MODULE, GtkThemingModule))
110 #define GTK_IS_THEMING_MODULE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_THEMING_MODULE))
111
112 G_DEFINE_TYPE (GtkThemingModule, gtk_theming_module, G_TYPE_TYPE_MODULE);
113
114 static void
115 gtk_theming_engine_class_init (GtkThemingEngineClass *klass)
116 {
117   GObjectClass *object_class = G_OBJECT_CLASS (klass);
118
119   klass->render_check = gtk_theming_engine_render_check;
120   klass->render_option = gtk_theming_engine_render_option;
121   klass->render_arrow = gtk_theming_engine_render_arrow;
122   klass->render_background = gtk_theming_engine_render_background;
123   klass->render_frame = gtk_theming_engine_render_frame;
124   klass->render_expander = gtk_theming_engine_render_expander;
125   klass->render_focus = gtk_theming_engine_render_focus;
126
127   g_type_class_add_private (object_class, sizeof (GtkThemingEnginePrivate));
128 }
129
130 static void
131 gtk_theming_engine_init (GtkThemingEngine *engine)
132 {
133   engine->priv = GTK_THEMING_ENGINE_GET_PRIVATE (engine);
134 }
135
136 void
137 _gtk_theming_engine_set_context (GtkThemingEngine *engine,
138                                  GtkStyleContext  *context)
139 {
140   GtkThemingEnginePrivate *priv;
141
142   g_return_if_fail (GTK_IS_THEMING_ENGINE (engine));
143   g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
144
145   priv = engine->priv;
146   priv->context = context;
147 }
148
149 void
150 gtk_theming_engine_get_property (GtkThemingEngine *engine,
151                                  const gchar      *property,
152                                  GtkStateType      state,
153                                  GValue           *value)
154 {
155   GtkThemingEnginePrivate *priv;
156
157   g_return_if_fail (GTK_IS_THEMING_ENGINE (engine));
158   g_return_if_fail (property != NULL);
159   g_return_if_fail (state < GTK_STATE_LAST);
160   g_return_if_fail (value != NULL);
161
162   priv = engine->priv;
163   gtk_style_context_get_property (priv->context, property, state, value);
164 }
165
166 void
167 gtk_theming_engine_get_valist (GtkThemingEngine *engine,
168                                GtkStateType      state,
169                                va_list           args)
170 {
171   GtkThemingEnginePrivate *priv;
172
173   g_return_if_fail (GTK_IS_THEMING_ENGINE (engine));
174   g_return_if_fail (state < GTK_STATE_LAST);
175
176   priv = engine->priv;
177   gtk_style_context_get_valist (priv->context, state, args);
178 }
179
180 void
181 gtk_theming_engine_get (GtkThemingEngine *engine,
182                         GtkStateType      state,
183                         ...)
184 {
185   GtkThemingEnginePrivate *priv;
186   va_list args;
187
188   g_return_if_fail (GTK_IS_THEMING_ENGINE (engine));
189   g_return_if_fail (state < GTK_STATE_LAST);
190
191   priv = engine->priv;
192
193   va_start (args, state);
194   gtk_style_context_get_valist (priv->context, state, args);
195   va_end (args);
196 }
197
198 GtkStateFlags
199 gtk_theming_engine_get_state (GtkThemingEngine *engine)
200 {
201   GtkThemingEnginePrivate *priv;
202
203   g_return_val_if_fail (GTK_IS_THEMING_ENGINE (engine), 0);
204
205   priv = engine->priv;
206   return gtk_style_context_get_state (priv->context);
207 }
208
209 gboolean
210 gtk_theming_engine_is_state_set (GtkThemingEngine *engine,
211                                  GtkStateType      state)
212 {
213   GtkThemingEnginePrivate *priv;
214
215   g_return_val_if_fail (GTK_IS_THEMING_ENGINE (engine), 0);
216
217   priv = engine->priv;
218   return gtk_style_context_is_state_set (priv->context, state);
219 }
220
221 G_CONST_RETURN GtkWidgetPath *
222 gtk_theming_engine_get_path (GtkThemingEngine *engine)
223 {
224   GtkThemingEnginePrivate *priv;
225
226   g_return_val_if_fail (GTK_IS_THEMING_ENGINE (engine), NULL);
227
228   priv = engine->priv;
229   return gtk_style_context_get_path (priv->context);
230 }
231
232 gboolean
233 gtk_theming_engine_has_class (GtkThemingEngine *engine,
234                               const gchar      *style_class)
235 {
236   GtkThemingEnginePrivate *priv;
237
238   g_return_val_if_fail (GTK_IS_THEMING_ENGINE (engine), FALSE);
239
240   priv = engine->priv;
241   return gtk_style_context_has_class (priv->context, style_class);
242 }
243
244 gboolean
245 gtk_theming_engine_has_child_class (GtkThemingEngine   *engine,
246                                     const gchar        *style_class,
247                                     GtkChildClassFlags *flags)
248 {
249   GtkThemingEnginePrivate *priv;
250
251   if (flags)
252     *flags = 0;
253
254   g_return_val_if_fail (GTK_IS_THEMING_ENGINE (engine), FALSE);
255
256   priv = engine->priv;
257   return gtk_style_context_has_child_class (priv->context, style_class, flags);
258 }
259
260 /* GtkThemingModule */
261
262 static gboolean
263 gtk_theming_module_load (GTypeModule *type_module)
264 {
265   GtkThemingModule *theming_module;
266   GModule *module;
267   gchar *name, *module_path;
268
269   theming_module = GTK_THEMING_MODULE (type_module);
270   name = theming_module->name;
271   module_path = _gtk_find_module (name, "theming-engines");
272
273   if (!module_path)
274     {
275       g_warning (_("Unable to locate theme engine in module path: \"%s\","), name);
276       return FALSE;
277     }
278
279   module = g_module_open (module_path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
280   g_free (module_path);
281
282   if (!module)
283     {
284       g_warning ("%s", g_module_error ());
285       return FALSE;
286     }
287
288   if (!g_module_symbol (module, "create_engine",
289                         (gpointer *) &theming_module->create_engine))
290     {
291       g_warning ("%s", g_module_error());
292       g_module_close (module);
293
294       return FALSE;
295     }
296
297   g_module_make_resident (module);
298
299   return TRUE;
300 }
301
302 static void
303 gtk_theming_module_class_init (GtkThemingModuleClass *klass)
304 {
305   GTypeModuleClass *module_class = G_TYPE_MODULE_CLASS (klass);
306
307   module_class->load = gtk_theming_module_load;
308 }
309
310 static void
311 gtk_theming_module_init (GtkThemingModule *module)
312 {
313 }
314
315 G_CONST_RETURN GtkThemingEngine *
316 gtk_theming_engine_load (const gchar *name)
317 {
318   static GHashTable *engines = NULL;
319   static GtkThemingEngine *default_engine;
320   GtkThemingEngine *engine = NULL;
321
322   if (name)
323     {
324       if (!engines)
325         engines = g_hash_table_new (g_str_hash, g_str_equal);
326
327       engine = g_hash_table_lookup (engines, name);
328
329       if (!engine)
330         {
331           GtkThemingModule *module;
332
333           module = g_object_new (GTK_TYPE_THEMING_MODULE, NULL);
334           g_type_module_set_name (G_TYPE_MODULE (module), name);
335           module->name = g_strdup (name);
336
337           if (module && g_type_module_use (G_TYPE_MODULE (module)))
338             {
339               engine = (module->create_engine) ();
340
341               if (engine)
342                 g_hash_table_insert (engines, module->name, engine);
343             }
344         }
345     }
346
347   if (!engine)
348     {
349       if (!default_engine)
350         default_engine = g_object_new (GTK_TYPE_THEMING_ENGINE, NULL);
351
352       engine = default_engine;
353     }
354
355   return engine;
356 }
357
358 /* Paint method implementations */
359 static void
360 gtk_theming_engine_render_check (GtkThemingEngine *engine,
361                                  cairo_t          *cr,
362                                  gdouble           x,
363                                  gdouble           y,
364                                  gdouble           width,
365                                  gdouble           height)
366 {
367   GdkColor *fg_color, *base_color, *text_color;
368   const GtkWidgetPath *path;
369   GtkStateFlags flags;
370   GtkStateType state;
371
372   flags = gtk_theming_engine_get_state (engine);
373   path = gtk_theming_engine_get_path (engine);
374   cairo_save (cr);
375
376   if (flags & GTK_STATE_FLAG_PRELIGHT)
377     state = GTK_STATE_PRELIGHT;
378   else
379     state = GTK_STATE_NORMAL;
380
381   gtk_theming_engine_get (engine, state,
382                           "foreground-color", &fg_color,
383                           "base-color", &base_color,
384                           "text-color", &text_color,
385                           NULL);
386
387   if (!gtk_widget_path_has_parent (path, GTK_TYPE_MENU))
388     {
389       cairo_set_line_width (cr, 1);
390
391       cairo_rectangle (cr,
392                        x + 0.5, y + 0.5,
393                        width - 1, height - 1);
394
395       gdk_cairo_set_source_color (cr, base_color);
396       cairo_fill_preserve (cr);
397
398       if (gtk_widget_path_has_parent (path, GTK_TYPE_TREE_VIEW))
399         gdk_cairo_set_source_color (cr, text_color);
400       else
401         gdk_cairo_set_source_color (cr, fg_color);
402
403       cairo_stroke (cr);
404     }
405
406   cairo_set_line_width (cr, 1.5);
407   gdk_cairo_set_source_color (cr, text_color);
408
409   if (gtk_theming_engine_is_state_set (engine, GTK_STATE_INCONSISTENT))
410     {
411       cairo_move_to (cr, x + (width * 0.2), y + (height / 2));
412       cairo_line_to (cr, x + (width * 0.8), y + (height / 2));
413     }
414   else if (gtk_theming_engine_is_state_set (engine, GTK_STATE_ACTIVE))
415     {
416       cairo_move_to (cr, x + (width * 0.2), y + (height / 2));
417       cairo_line_to (cr, x + (width * 0.4), y + (height * 0.8));
418       cairo_line_to (cr, x + (width * 0.8), y + (height * 0.2));
419     }
420
421   cairo_stroke (cr);
422
423   cairo_restore (cr);
424
425   gdk_color_free (fg_color);
426   gdk_color_free (base_color);
427   gdk_color_free (text_color);
428 }
429
430 static void
431 gtk_theming_engine_render_option (GtkThemingEngine *engine,
432                                   cairo_t          *cr,
433                                   gdouble           x,
434                                   gdouble           y,
435                                   gdouble           width,
436                                   gdouble           height)
437 {
438   GtkStateFlags flags;
439   GdkColor *base_color, *fg_color, *text_color;
440   const GtkWidgetPath *path;
441   GtkStateType state;
442   gdouble radius;
443
444   flags = gtk_theming_engine_get_state (engine);
445   path = gtk_theming_engine_get_path (engine);
446   radius = MIN (width, height) / 2 - 0.5;
447
448   cairo_save (cr);
449   cairo_set_line_width (cr, 1);
450
451   if (flags & GTK_STATE_FLAG_PRELIGHT)
452     state = GTK_STATE_PRELIGHT;
453   else
454     state = GTK_STATE_NORMAL;
455
456   gtk_theming_engine_get (engine, state,
457                           "foreground-color", &fg_color,
458                           "base-color", &base_color,
459                           "text-color", &text_color,
460                           NULL);
461
462   if (!gtk_widget_path_has_parent (path, GTK_TYPE_MENU))
463     {
464       cairo_arc (cr,
465                  x + (width / 2),
466                  y + (height / 2),
467                  radius,
468                  0, 2 * G_PI);
469
470       gdk_cairo_set_source_color (cr, base_color);
471       cairo_fill_preserve (cr);
472
473       if (gtk_widget_path_has_parent (path, GTK_TYPE_TREE_VIEW))
474         gdk_cairo_set_source_color (cr, text_color);
475       else
476         gdk_cairo_set_source_color (cr, fg_color);
477
478       cairo_stroke (cr);
479     }
480
481   if (gtk_widget_path_has_parent (path, GTK_TYPE_MENU))
482     gdk_cairo_set_source_color (cr, fg_color);
483   else
484     gdk_cairo_set_source_color (cr, text_color);
485
486   if (gtk_theming_engine_is_state_set (engine, GTK_STATE_INCONSISTENT))
487     {
488       cairo_move_to (cr, x + (width * 0.2), y + (height / 2));
489       cairo_line_to (cr, x + (width * 0.8), y + (height / 2));
490       cairo_stroke (cr);
491     }
492   if (gtk_theming_engine_is_state_set (engine, GTK_STATE_ACTIVE))
493     {
494       cairo_arc (cr,
495                  x + (width / 2),
496                  y + (height / 2),
497                  radius / 2,
498                  0, 2 * G_PI);
499
500       cairo_fill (cr);
501     }
502
503   cairo_restore (cr);
504 }
505
506 static void
507 add_path_arrow (cairo_t *cr,
508                 gdouble  angle,
509                 gdouble  x,
510                 gdouble  y,
511                 gdouble  size)
512 {
513   cairo_save (cr);
514
515   cairo_translate (cr, x + (size / 2), y + (size / 2));
516   cairo_rotate (cr, angle);
517
518   cairo_move_to (cr, 0, - (size / 4) + 0.5);
519   cairo_line_to (cr, - (size / 2), (size / 4) + 0.5);
520   cairo_line_to (cr, (size / 2), (size / 4) + 0.5);
521   cairo_close_path (cr);
522
523   cairo_restore (cr);
524 }
525
526 static void
527 gtk_theming_engine_render_arrow (GtkThemingEngine *engine,
528                                  cairo_t          *cr,
529                                  gdouble           angle,
530                                  gdouble           x,
531                                  gdouble           y,
532                                  gdouble           size)
533 {
534   GtkStateFlags flags;
535   GtkStateType state;
536   GdkColor *fg_color;
537
538   cairo_save (cr);
539
540   flags = gtk_theming_engine_get_state (engine);
541
542   if (flags & GTK_STATE_FLAG_PRELIGHT)
543     state = GTK_STATE_PRELIGHT;
544   else if (flags & GTK_STATE_FLAG_INSENSITIVE)
545     state = GTK_STATE_INSENSITIVE;
546   else
547     state = GTK_STATE_NORMAL;
548
549   gtk_theming_engine_get (engine, state,
550                           "foreground-color", &fg_color,
551                           NULL);
552
553   if (flags & GTK_STATE_FLAG_INSENSITIVE)
554     {
555       add_path_arrow (cr, angle, x + 1, y + 1, size);
556       cairo_set_source_rgb (cr, 1, 1, 1);
557       cairo_fill (cr);
558     }
559
560   add_path_arrow (cr, angle, x, y, size);
561   gdk_cairo_set_source_color (cr, fg_color);
562   cairo_fill (cr);
563
564   cairo_restore (cr);
565
566   gdk_color_free (fg_color);
567 }
568
569 static void
570 add_path_rounded_rectangle (cairo_t           *cr,
571                             gdouble            radius,
572                             guint              sides,
573                             gdouble            x,
574                             gdouble            y,
575                             gdouble            width,
576                             gdouble            height)
577 {
578   gdouble r = 0;
579
580   if (sides & SIDE_BOTTOM)
581     {
582       /* Bottom left corner */
583       if (r == 0)
584         cairo_move_to (cr, x + 0.5, y + height - 0.5);
585       else
586         cairo_arc_negative (cr,
587                             x + r + 0.5,
588                             y + height - r - 0.5,
589                             r,
590                             135 * (G_PI / 180),
591                             90 * (G_PI / 180));
592
593       /* Bottom side */
594       cairo_line_to (cr, x + width - r - 0.5, y + height - 0.5);
595
596       /* Bottom right corner */
597       if (r > 0)
598         cairo_arc_negative (cr,
599                             x + width - r - 0.5,
600                             y + height - r - 0.5,
601                             r,
602                             90 * (G_PI / 180),
603                             45 * (G_PI / 180));
604     }
605
606   if (sides & SIDE_RIGHT)
607     {
608       /* Bottom right corner */
609       if (r == 0)
610         {
611           if ((sides & SIDE_BOTTOM) == 0)
612             cairo_move_to (cr, x + width - 0.5, y + height - 0.5);
613         }
614       else
615         cairo_arc_negative (cr,
616                             x + width - r - 0.5,
617                             y + height - r - 0.5,
618                             r,
619                             45 * (G_PI / 180), 0);
620
621       /* Right side */
622       cairo_line_to (cr, x + width - 0.5, y + r);
623
624       /* Top right corner */
625       if (r > 0)
626         cairo_arc_negative (cr,
627                             x + width - r - 0.5,
628                             y + r + 0.5,
629                             r,
630                             0, 315 * (G_PI / 180));
631     }
632
633   if (sides & SIDE_TOP)
634     {
635       /* Top right corner */
636       if (r == 0)
637         {
638           if ((sides & SIDE_RIGHT) == 0)
639             cairo_move_to (cr, x + width - 1, y + 0.5);
640         }
641       else
642         cairo_arc_negative (cr,
643                             x + width - r - 0.5,
644                             y + r + 0.5,
645                             r,
646                             315 * (G_PI / 180),
647                             270 * (G_PI / 180));
648
649       /* Top side */
650       cairo_line_to (cr, x + 0.5 + r, y + 0.5);
651
652       /* Top left corner */
653       if (r > 0)
654         cairo_arc_negative (cr,
655                             x + r + 0.5,
656                             y + r + 0.5,
657                             r,
658                             270 * (G_PI / 180),
659                             225 * (G_PI / 180));
660     }
661
662   if (sides & SIDE_LEFT)
663     {
664       /* Top left corner */
665       if (r == 0)
666         {
667           if ((sides & SIDE_TOP) == 0)
668             cairo_move_to (cr, x + 0.5, y + 0.5);
669         }
670       else
671         cairo_arc_negative (cr,
672                             x + + r + 0.5,
673                             y + r + 0.5,
674                             r,
675                             225 * (G_PI / 180),
676                             180 * (G_PI / 180));
677
678       /* Left side */
679       cairo_line_to (cr, x + 0.5, y + height - r);
680
681       if (r > 0)
682         cairo_arc_negative (cr,
683                             x + r + 0.5,
684                             y + height - r + 0.5,
685                             r,
686                             180 * (G_PI / 180),
687                             135 * (G_PI / 180));
688     }
689 }
690
691 static void
692 color_shade (const GdkColor *color,
693              gdouble         factor,
694              GdkColor       *color_return)
695 {
696   color_return->red = CLAMP (color->red * factor, 0, 65535);
697   color_return->green = CLAMP (color->green * factor, 0, 65535);
698   color_return->blue = CLAMP (color->blue * factor, 0, 65535);
699 }
700
701 static void
702 gtk_theming_engine_render_background (GtkThemingEngine *engine,
703                                       cairo_t          *cr,
704                                       gdouble           x,
705                                       gdouble           y,
706                                       gdouble           width,
707                                       gdouble           height)
708 {
709   GtkStateFlags flags;
710   GtkStateType state;
711   GdkColor *bg_color;
712
713   cairo_save (cr);
714   flags = gtk_theming_engine_get_state (engine);
715
716   if (flags & GTK_STATE_FLAG_PRELIGHT)
717     state = GTK_STATE_PRELIGHT;
718   else if (flags & GTK_STATE_FLAG_INSENSITIVE)
719     state = GTK_STATE_INSENSITIVE;
720   else
721     state = GTK_STATE_NORMAL;
722
723   gtk_theming_engine_get (engine, state,
724                           "background-color", &bg_color,
725                           NULL);
726
727   add_path_rounded_rectangle (cr, 0,
728                               SIDE_BOTTOM | SIDE_RIGHT | SIDE_TOP | SIDE_LEFT,
729                               x, y, width, height);
730   cairo_close_path (cr);
731
732   gdk_cairo_set_source_color (cr, bg_color);
733   cairo_fill (cr);
734
735   cairo_restore (cr);
736 }
737
738 static void
739 gtk_theming_engine_render_frame (GtkThemingEngine *engine,
740                                  cairo_t          *cr,
741                                  gdouble           x,
742                                  gdouble           y,
743                                  gdouble           width,
744                                  gdouble           height)
745 {
746   GtkStateFlags flags;
747   GtkStateType state;
748   GdkColor *bg_color;
749   GdkColor lighter, darker;
750
751   cairo_save (cr);
752   flags = gtk_theming_engine_get_state (engine);
753
754   if (flags & GTK_STATE_FLAG_PRELIGHT)
755     state = GTK_STATE_PRELIGHT;
756   else if (flags & GTK_STATE_FLAG_INSENSITIVE)
757     state = GTK_STATE_INSENSITIVE;
758   else
759     state = GTK_STATE_NORMAL;
760
761   cairo_set_line_width (cr, 1);
762
763   gtk_theming_engine_get (engine, state,
764                           "background-color", &bg_color,
765                           NULL);
766   color_shade (bg_color, 0.7, &darker);
767   color_shade (bg_color, 1.3, &lighter);
768
769   if (flags & GTK_STATE_FLAG_ACTIVE)
770     {
771       add_path_rounded_rectangle (cr, 0,
772                                   SIDE_BOTTOM | SIDE_RIGHT,
773                                   x, y, width, height);
774
775       gdk_cairo_set_source_color (cr, &lighter);
776       cairo_stroke (cr);
777
778       add_path_rounded_rectangle (cr, 0,
779                                   SIDE_TOP | SIDE_LEFT,
780                                   x + 1, y + 1, width - 2, height - 2);
781       cairo_set_source_rgb (cr, 0, 0, 0);
782       cairo_stroke (cr);
783
784       add_path_rounded_rectangle (cr, 0,
785                                   SIDE_TOP | SIDE_LEFT,
786                                   x, y, width, height);
787       gdk_cairo_set_source_color (cr, &darker);
788       cairo_stroke (cr);
789     }
790   else
791     {
792       add_path_rounded_rectangle (cr, 0,
793                                   SIDE_BOTTOM | SIDE_RIGHT,
794                                   x, y, width, height);
795
796       cairo_set_source_rgb (cr, 0, 0, 0);
797       cairo_stroke (cr);
798
799       add_path_rounded_rectangle (cr, 0,
800                                   SIDE_BOTTOM | SIDE_RIGHT,
801                                   x, y, width - 1, height - 1);
802
803       gdk_cairo_set_source_color (cr, &darker);
804       cairo_stroke (cr);
805
806       add_path_rounded_rectangle (cr, 0,
807                                   SIDE_TOP | SIDE_LEFT,
808                                   x, y, width, height);
809
810       gdk_cairo_set_source_color (cr, &lighter);
811       cairo_stroke (cr);
812     }
813
814   cairo_restore (cr);
815 }
816
817 static void
818 gtk_theming_engine_render_expander (GtkThemingEngine *engine,
819                                     cairo_t          *cr,
820                                     gdouble           x,
821                                     gdouble           y,
822                                     gdouble           width,
823                                     gdouble           height)
824 {
825   GtkStateFlags flags;
826   GdkColor *bg_color, *fg_color, *base_color;
827   GtkStateType state;
828   gdouble angle;
829
830   cairo_save (cr);
831   flags = gtk_theming_engine_get_state (engine);
832
833   if (flags & GTK_STATE_FLAG_PRELIGHT)
834     state = GTK_STATE_PRELIGHT;
835   else if (flags & GTK_STATE_FLAG_INSENSITIVE)
836     state = GTK_STATE_INSENSITIVE;
837   else
838     state = GTK_STATE_NORMAL;
839
840   gtk_theming_engine_get (engine, state,
841                           "foreground-color", &fg_color,
842                           "background-color", &bg_color,
843                           "base-color", &base_color,
844                           NULL);
845
846   if (flags & GTK_STATE_FLAG_ACTIVE)
847     angle = G_PI;
848   else
849     angle = G_PI / 2;
850
851   cairo_set_line_width (cr, 1);
852   add_path_arrow (cr, angle, x + 2, y + 2,
853                   MIN (width - 1, height - 1) - 4);
854
855   if (flags & GTK_STATE_FLAG_PRELIGHT)
856     gdk_cairo_set_source_color (cr, fg_color);
857   else
858     gdk_cairo_set_source_color (cr, base_color);
859
860   cairo_fill_preserve (cr);
861
862   gdk_cairo_set_source_color (cr, fg_color);
863   cairo_stroke (cr);
864
865   cairo_restore (cr);
866
867   gdk_color_free (base_color);
868   gdk_color_free (fg_color);
869   gdk_color_free (bg_color);
870 }
871
872 static void
873 gtk_theming_engine_render_focus (GtkThemingEngine *engine,
874                                  cairo_t          *cr,
875                                  gdouble           x,
876                                  gdouble           y,
877                                  gdouble           width,
878                                  gdouble           height)
879 {
880   const double dashes[] = { 0.5, 1.5 };
881   GdkColor *base_color;
882   GtkStateFlags flags;
883   GtkStateType state;
884
885   cairo_save (cr);
886   flags = gtk_theming_engine_get_state (engine);
887
888   if (flags & GTK_STATE_FLAG_PRELIGHT)
889     state = GTK_STATE_PRELIGHT;
890   else if (flags & GTK_STATE_FLAG_INSENSITIVE)
891     state = GTK_STATE_INSENSITIVE;
892   else
893     state = GTK_STATE_NORMAL;
894
895   gtk_theming_engine_get (engine, state,
896                           "base-color", &base_color,
897                           NULL);
898
899   cairo_set_line_width (cr, 1.0);
900   cairo_set_dash (cr, dashes, 2, 0);
901
902   cairo_rectangle (cr,
903                    x + 0.5,
904                    y + 0.5,
905                    width - 1,
906                    height - 1);
907
908   gdk_cairo_set_source_color (cr, base_color);
909   cairo_stroke (cr);
910
911   cairo_restore (cr);
912
913   gdk_color_free (base_color);
914 }
915
916 #define __GTK_THEMING_ENGINE_C__
917 #include "gtkaliasdef.c"